Beispiel #1
0
 def show_dpi():
     wmm, hmm = RandR.get_screen_size_mm()  #ie: (1280, 1024)
     screenlog("RandR.get_screen_size_mm=%s,%s", wmm, hmm)
     actual_xdpi = iround(root_w * 25.4 / wmm)
     actual_ydpi = iround(root_h * 25.4 / hmm)
     if abs(actual_xdpi - xdpi) <= 1 and abs(actual_ydpi -
                                             ydpi) <= 1:
         screenlog.info("DPI set to %s x %s", actual_xdpi,
                        actual_ydpi)
         screenlog("wanted: %s x %s", xdpi, ydpi)
     else:
         #should this be a warning:
         l = screenlog.info
         maxdelta = max(abs(actual_xdpi - xdpi),
                        abs(actual_ydpi - ydpi))
         if maxdelta >= 10:
             l = log.warn
         messages = [
             "DPI set to %s x %s (wanted %s x %s)" %
             (actual_xdpi, actual_ydpi, xdpi, ydpi),
         ]
         if maxdelta >= 10:
             messages.append(
                 "you may experience scaling problems, such as huge or small fonts, etc"
             )
             messages.append(
                 "to fix this issue, try the dpi switch, or use a patched Xorg dummy driver"
             )
             self.notify_dpi_warning("\n".join(messages))
         for i, message in enumerate(messages):
             l("%s%s", ["", " "][i > 0], message)
Beispiel #2
0
    def scale_reinit(self, xchange=1.0, ychange=1.0):
        #wait at least one second before changing again:
        self.scale_change_embargo = monotonic_time() + SCALING_EMBARGO_TIME
        if fequ(self.xscale, self.yscale):
            scalinglog.info("setting scaling to %i%%:",
                            iround(100 * self.xscale))
        else:
            scalinglog.info("setting scaling to %i%% x %i%%:",
                            iround(100 * self.xscale),
                            iround(100 * self.yscale))
        self.update_screen_size()

        #re-initialize all the windows with their new size
        def new_size_fn(w, h):
            minx, miny = 16384, 16384
            if self.max_window_size != (0, 0):
                minx, miny = self.max_window_size
            return max(1,
                       min(minx,
                           int(w * xchange))), max(1,
                                                   min(miny, int(h * ychange)))

        self.reinit_windows(new_size_fn)
        self.reinit_window_icons()
        self.emit("scaling-changed")
Beispiel #3
0
 def get_dpi_caps(self):
     #command line (or config file) override supplied:
     caps = {}
     dpi = 0
     if self.dpi > 0:
         #scale it:
         dpi = iround((self.cx(self.dpi) + self.cy(self.dpi)) / 2.0)
     else:
         #not supplied, use platform detection code:
         #platforms may also provide per-axis dpi (later win32 versions do)
         xdpi = self.get_xdpi()
         ydpi = self.get_ydpi()
         log("xdpi=%i, ydpi=%i", xdpi, ydpi)
         if xdpi > 0 and ydpi > 0:
             xdpi = self.cx(xdpi)
             ydpi = self.cy(ydpi)
             dpi = iround((xdpi + ydpi) / 2.0)
             caps = {
                 "x": xdpi,
                 "y": ydpi,
             }
     if dpi:
         caps[""] = dpi
     log("get_gpi_caps()=%s", caps)
     return caps
Beispiel #4
0
 def draw():
     v = pix.increase()
     img_data = bytes([v % 256]*stride*h)
     options["flush"] = 1
     window.draw_region(0, 0, w, h, coding, img_data, stride, v, options, [paint_callback])
     options["flush"] = 0
     mx = w//2-icon_w//2
     my = h//2-icon_h//2
     x = iround(mx*(1+sin(v/100)))
     y = iround(my*(1+cos(v/100)))
     window.draw_region(x, y, icon_w, icon_h, icon_format, icon_data, icon_stride, v, options, [paint_callback])
     return REPAINT_DELAY>0
Beispiel #5
0
def _get_randr_dpi():
    try:
        from xpra.x11.bindings.randr_bindings import RandRBindings  #@UnresolvedImport
        randr_bindings = RandRBindings()
        wmm, hmm = randr_bindings.get_screen_size_mm()
        w, h =  randr_bindings.get_screen_size()
        dpix = iround(w * 25.4 / wmm)
        dpiy = iround(h * 25.4 / hmm)
        screenlog("xdpi=%s, ydpi=%s - size-mm=%ix%i, size=%ix%i", dpix, dpiy, wmm, hmm, w, h)
        return dpix, dpiy
    except Exception as e:
        screenlog.warn("failed to get dpi: %s", e)
    return -1, -1
Beispiel #6
0
def _get_randr_dpi():
    try:
        from xpra.x11.bindings.randr_bindings import RandRBindings  #@UnresolvedImport
        randr_bindings = RandRBindings()
        wmm, hmm = randr_bindings.get_screen_size_mm()
        w, h =  randr_bindings.get_screen_size()
        dpix = iround(w * 25.4 / wmm)
        dpiy = iround(h * 25.4 / hmm)
        screenlog("dpix=%s, dpiy=%s", dpix, dpiy)
        return dpix, dpiy
    except Exception as e:
        screenlog.warn("failed to get dpi: %s", e)
    return -1, -1
Beispiel #7
0
def _get_randr_dpi():
    if RANDR_DPI and not is_Wayland():
        from xpra.gtk_common.error import xlog
        from xpra.x11.bindings.randr_bindings import RandRBindings  #@UnresolvedImport
        with xlog:
            randr_bindings = RandRBindings()
            wmm, hmm = randr_bindings.get_screen_size_mm()
            w, h = randr_bindings.get_screen_size()
            dpix = iround(w * 25.4 / wmm)
            dpiy = iround(h * 25.4 / hmm)
            screenlog("xdpi=%s, ydpi=%s - size-mm=%ix%i, size=%ix%i", dpix,
                      dpiy, wmm, hmm, w, h)
            return dpix, dpiy
    return -1, -1
Beispiel #8
0
    def get_caps(self) -> dict:
        caps = {
            "randr_notify": True,
            "show-desktop": True,
            "vrefresh": self.get_vrefresh(),
        }
        wm_name = get_wm_name()
        if wm_name:
            caps["wm_name"] = wm_name

        self._last_screen_settings = self.get_screen_settings()
        root_w, root_h, sss, ndesktops, desktop_names, u_root_w, u_root_h = self._last_screen_settings[:
                                                                                                       7]
        if u_root_w and u_root_h:
            caps["desktop_size"] = self.cp(u_root_w, u_root_h)
        if ndesktops:
            caps["desktops"] = ndesktops
            caps["desktop.names"] = tuple(desktop_names)

        ss = self.get_screen_sizes()
        self._current_screen_sizes = ss

        log.info(" desktop size is %sx%s:", u_root_w, u_root_h)
        log_screen_sizes(u_root_w, u_root_h, ss)
        if self.xscale != 1 or self.yscale != 1:
            caps["screen_sizes.unscaled"] = ss
            caps["desktop_size.unscaled"] = u_root_w, u_root_h
            root_w, root_h = self.cp(u_root_w, u_root_h)
            if fequ(self.xscale, self.yscale):
                sinfo = "%i%%" % iround(self.xscale * 100)
            else:
                sinfo = "%i%% x %i%%" % (iround(
                    self.xscale * 100), iround(self.yscale * 100))
            scaled_up = u_root_w > root_w or u_root_h > root_h
            log.info(" %sscaled to %s, virtual screen size: %ix%i",
                     "up" if scaled_up else "down", sinfo, root_w, root_h)
            log_screen_sizes(root_w, root_h, sss)
        else:
            root_w, root_h = u_root_w, u_root_h
            sss = ss
        caps["screen_sizes"] = sss

        caps.update(self.get_screen_caps())
        caps.update(
            flatten_dict({
                "dpi": self.get_dpi_caps(),
                "screen-scaling": self.get_scaling_caps(),
            }))
        return caps
Beispiel #9
0
    def get_caps(self):
        caps = {
            "randr_notify": True,
            "show-desktop": True,
        }
        wm_name = get_wm_name()
        if wm_name:
            caps["wm_name"] = wm_name

        self._last_screen_settings = self.get_screen_settings()
        root_w, root_h, sss, ndesktops, desktop_names, u_root_w, u_root_h, _, _ = self._last_screen_settings
        if u_root_w and u_root_h:
            caps["desktop_size"] = self.cp(u_root_w, u_root_h)
        if ndesktops:
            caps["desktops"] = ndesktops
            caps["desktop.names"] = desktop_names

        ss = self.get_screen_sizes()
        self._current_screen_sizes = ss

        log.info(" desktop size is %sx%s with %s screen%s:", u_root_w,
                 u_root_h, len(ss), engs(ss))
        log_screen_sizes(u_root_w, u_root_h, ss)
        if self.xscale != 1 or self.yscale != 1:
            caps["screen_sizes.unscaled"] = ss
            caps["desktop_size.unscaled"] = u_root_w, u_root_h
            root_w, root_h = self.cp(u_root_w, u_root_h)
            if fequ(self.xscale, self.yscale):
                sinfo = "%i%%" % iround(self.xscale * 100)
            else:
                sinfo = "%i%% x %i%%" % (iround(
                    self.xscale * 100), iround(self.yscale * 100))
            log.info(" %sscaled by %s, virtual screen size: %ix%i",
                     ["down",
                      "up"][int(u_root_w > root_w
                                or u_root_h > root_h)], sinfo, root_w, root_h)
            log_screen_sizes(root_w, root_h, sss)
        else:
            root_w, root_h = u_root_w, u_root_h
            sss = ss
        caps["screen_sizes"] = sss

        caps.update(self.get_screen_caps())
        caps.update(
            flatten_dict({
                "dpi": self.get_dpi_caps(),
                "screen-scaling": self.get_scaling_caps(),
            }))
        return caps
Beispiel #10
0
def _get_randr_dpi():
    if RANDR_DPI and not is_Wayland():
        from xpra.gtk_common.error import xlog
        with xlog:
            randr_bindings = X11RandRBindings()
            if randr_bindings and randr_bindings.has_randr():
                wmm, hmm = randr_bindings.get_screen_size_mm()
                if wmm > 0 and hmm > 0:
                    w, h = randr_bindings.get_screen_size()
                    dpix = iround(w * 25.4 / wmm)
                    dpiy = iround(h * 25.4 / hmm)
                    screenlog("xdpi=%s, ydpi=%s - size-mm=%ix%i, size=%ix%i",
                              dpix, dpiy, wmm, hmm, w, h)
                    return dpix, dpiy
    return -1, -1
Beispiel #11
0
 def _process_desktop_size(self, proto, packet):
     width, height = packet[1:3]
     ss = self._server_sources.get(proto)
     if ss is None:
         return
     ss.desktop_size = (width, height)
     if len(packet) >= 10:
         #added in 0.16 for scaled client displays:
         xdpi, ydpi = packet[8:10]
         if xdpi != self.xdpi or ydpi != self.ydpi:
             self.xdpi, self.ydpi = xdpi, ydpi
             log("new dpi: %ix%i", self.xdpi, self.ydpi)
             self.dpi = iround((self.xdpi + self.ydpi) / 2.0)
             self.dpi_changed()
     if len(packet) >= 8:
         #added in 0.16 for scaled client displays:
         ss.desktop_size_unscaled = packet[6:8]
     if len(packet) >= 6:
         desktops, desktop_names = packet[4:6]
         ss.set_desktops(desktops, desktop_names)
         self.calculate_desktops()
     if len(packet) >= 4:
         ss.set_screen_sizes(packet[3])
     log("client requesting new size: %sx%s", width, height)
     self.set_screen_size(width, height)
     if len(packet) >= 4:
         log.info("received updated display dimensions")
         log.info("client display size is %sx%s with %s screen%s:", width,
                  height, len(ss.screen_sizes), engs(ss.screen_sizes))
         log_screen_sizes(width, height, ss.screen_sizes)
         self.calculate_workarea(width, height)
     #ensures that DPI and antialias information gets reset:
     self.update_all_server_settings()
Beispiel #12
0
def _get_randr_dpi():
    try:
        from xpra.gtk_common.error import xsync
        from xpra.x11.bindings.randr_bindings import RandRBindings  #@UnresolvedImport
        with xsync:
            randr_bindings = RandRBindings()
            wmm, hmm = randr_bindings.get_screen_size_mm()
            w, h = randr_bindings.get_screen_size()
            dpix = iround(w * 25.4 / wmm)
            dpiy = iround(h * 25.4 / hmm)
            screenlog("xdpi=%s, ydpi=%s - size-mm=%ix%i, size=%ix%i", dpix,
                      dpiy, wmm, hmm, w, h)
            return dpix, dpiy
    except Exception as e:
        screenlog.warn("failed to get dpi: %s", e)
    return -1, -1
Beispiel #13
0
 def t(v, ea, era):
     a, ra = cystats.calculate_size_weighted_average(v)
     self.assertEqual(
         iround(a), iround(ea),
         "average should be %s, got %s" % (iround(ea), iround(a)))
     self.assertEqual(
         iround(ra), iround(era),
         "recent average should be %s, got %s" %
         (iround(era), iround(ra)))
Beispiel #14
0
 def show_dpi():
     wmm, hmm = RandR.get_screen_size_mm()      #ie: (1280, 1024)
     screenlog("RandR.get_screen_size_mm=%s,%s", wmm, hmm)
     actual_xdpi = iround(root_w * 25.4 / wmm)
     actual_ydpi = iround(root_h * 25.4 / hmm)
     if abs(actual_xdpi-xdpi)<=1 and abs(actual_ydpi-ydpi)<=1:
         screenlog.info("DPI set to %s x %s", xdpi, ydpi)
     else:
         #should this be a warning:
         l = screenlog.info
         maxdelta = max(abs(actual_xdpi-xdpi), abs(actual_ydpi-ydpi))
         if maxdelta>=10:
             l = log.warn
         l("DPI set to %s x %s (wanted %s x %s)", actual_xdpi, actual_ydpi, xdpi, ydpi)
         if maxdelta>=10:
             l(" you may experience scaling problems, such as huge or small fonts, etc")
             l(" to fix this issue, try the dpi switch, or use a patched Xorg dummy driver")
    def set_screen_sizes(self, screen_sizes):
        log("set_screen_sizes(%s)", screen_sizes)
        self.screen_sizes = screen_sizes or []
        #validate dpi / screen size in mm
        #(ticket 2480: GTK3 on macos can return bogus values)
        MIN_DPI = envint("XPRA_MIN_DPI", 10)
        MAX_DPI = envint("XPRA_MIN_DPI", 500)

        def dpi(size_pixels, size_mm):
            if size_mm == 0:
                return 0
            return int(size_pixels * 254 / size_mm / 10)

        for i, screen in enumerate(screen_sizes):
            if len(screen) < 10:
                continue
            sw, sh, wmm, hmm, monitors = screen[1:6]
            xdpi = dpi(sw, wmm)
            ydpi = dpi(sh, hmm)
            if xdpi < MIN_DPI or xdpi > MAX_DPI or ydpi < MIN_DPI or ydpi > MAX_DPI:
                warn = first_time("invalid-screen-size-%ix%i" % (wmm, hmm))
                if warn:
                    log.warn(
                        "Warning: sanitizing invalid screen size %ix%i mm",
                        wmm, hmm)
                if monitors:
                    #[plug_name, xs(geom.x), ys(geom.y), xs(geom.width), ys(geom.height), wmm, hmm]
                    wmm = sum(monitor[5] for monitor in monitors)
                    hmm = sum(monitor[6] for monitor in monitors)
                    xdpi = dpi(sw, wmm)
                    ydpi = dpi(sh, hmm)
                if xdpi < MIN_DPI or xdpi > MAX_DPI or ydpi < MIN_DPI or ydpi > MAX_DPI:
                    #still invalid, generate one from DPI=96
                    wmm = iround(sw * 254 / 10 / 96.0)
                    hmm = iround(sh * 254 / 10 / 96.0)
                if warn:
                    log.warn(" using %ix%i mm", wmm, hmm)
                screen = list(screen)
                screen[3] = wmm
                screen[4] = hmm
                screen_sizes[i] = tuple(screen)
        log("client validated screen sizes: %s", screen_sizes)
Beispiel #16
0
 def scalingitem(scalingvalue=1.0):
     pct = iround(100.0*scalingvalue)
     label = {100 : "None"}.get(pct, "%i%%" % pct)
     c = CheckMenuItem(label)
     c.scalingvalue = scalingvalue
     c.set_draw_as_radio(True)
     c.set_active(scalecmp(scalingvalue))
     def scaling_activated(item):
         if scaling_submenu.updating:
             return
         ensure_item_selected(scaling_submenu, item)
         self.client.scaleset(item.scalingvalue, item.scalingvalue)
     c.connect('activate', scaling_activated)
     return c
Beispiel #17
0
def get_icon_size():
    xdpi = get_xdpi()
    ydpi = get_ydpi()
    if xdpi > 0 and ydpi > 0:
        from xpra.util import iround
        dpi = iround((xdpi + ydpi) / 2.0)
    else:
        dpi = 96
    if dpi > 144:
        return 48
    if dpi > 120:
        return 32
    if dpi > 96:
        return 24
    return 16
Beispiel #18
0
def get_icon_size():
    xdpi = get_xdpi()
    ydpi = get_ydpi()
    if xdpi>0 and ydpi>0:
        from xpra.util import iround
        dpi = iround((xdpi + ydpi)/2.0)
    else:
        dpi = 96
    if dpi > 144:
        return 48
    elif dpi > 120:
        return 32
    elif dpi > 96:
        return 24
    else:
        return 16
Beispiel #19
0
 def _process_desktop_size(self, proto, packet):
     log("new desktop size from %s: %s", proto, packet)
     width, height = packet[1:3]
     ss = self.get_server_source(proto)
     if ss is None:
         return
     ss.desktop_size = (width, height)
     if len(packet)>=11:
         vrefresh = packet[10]
         log("new vrefresh=%s", vrefresh)
         #update clientdisplay mixin:
         if hasattr(ss, "vrefresh") and getattr(ss, "refresh")!=vrefresh:
             ss.vrefresh = vrefresh
             #update all batch configs:
             if hasattr(ss, "all_window_sources"):
                 for window_source in ss.all_window_sources():
                     bc = window_source.batch_config
                     if bc:
                         bc.match_vrefresh(vrefresh)
     if len(packet)>=10:
         #added in 0.16 for scaled client displays:
         xdpi, ydpi = packet[8:10]
         if xdpi!=self.xdpi or ydpi!=self.ydpi:
             self.xdpi, self.ydpi = xdpi, ydpi
             log("new dpi: %ix%i", self.xdpi, self.ydpi)
             self.dpi = iround((self.xdpi + self.ydpi)/2.0)
             self.dpi_changed()
     if len(packet)>=8:
         #added in 0.16 for scaled client displays:
         ss.desktop_size_unscaled = packet[6:8]
     if len(packet)>=6:
         desktops, desktop_names = packet[4:6]
         ss.set_desktops(desktops, desktop_names)
         self.calculate_desktops()
     if len(packet)>=4:
         ss.set_screen_sizes(packet[3])
     bigger = ss.screen_resize_bigger
     log("client requesting new size: %sx%s (bigger=%s)", width, height, bigger)
     self.set_screen_size(width, height, bigger)
     if len(packet)>=4:
         log.info("received updated display dimensions")
         log.info("client display size is %sx%s",
                  width, height)
         log_screen_sizes(width, height, ss.screen_sizes)
         self.calculate_workarea(width, height)
     #ensures that DPI and antialias information gets reset:
     self.update_all_server_settings()
Beispiel #20
0
 def sx(self, v):
     """ convert X coordinate from server to client """
     return iround(v * self.xscale)
Beispiel #21
0
 def xs(v):
     return iround(v/xscale)
Beispiel #22
0
    def do_update_server_settings(self,
                                  settings,
                                  reset=False,
                                  dpi=0,
                                  double_click_time=0,
                                  double_click_distance=(-1, -1),
                                  antialias={},
                                  cursor_size=-1):
        if not self._xsettings_enabled:
            log("ignoring xsettings update: %s", settings)
            return
        if reset:
            #FIXME: preserve serial? (what happens when we change values which had the same serial?)
            self.reset_settings()
            self._settings = {}
            if self._default_xsettings:
                #try to parse default xsettings into a dict:
                try:
                    for _, prop_name, value, _ in self._default_xsettings[1]:
                        self._settings[prop_name] = value
                except Exception as e:
                    log("failed to parse %s", self._default_xsettings)
                    log.warn("Warning: failed to parse default XSettings:")
                    log.warn(" %s", e)
        old_settings = dict(self._settings)
        log("server_settings: old=%s, updating with=%s", nonl(old_settings),
            nonl(settings))
        log(
            "overrides: dpi=%s, double click time=%s, double click distance=%s",
            dpi, double_click_time, double_click_distance)
        log("overrides: antialias=%s", antialias)
        self._settings.update(settings)
        for k, v in settings.items():
            #cook the "resource-manager" value to add the DPI and/or antialias values:
            if k == b"resource-manager" and (dpi > 0 or antialias
                                             or cursor_size > 0):
                value = bytestostr(v)
                #parse the resources into a dict:
                values = {}
                options = value.split("\n")
                for option in options:
                    if not option:
                        continue
                    parts = option.split(":\t", 1)
                    if len(parts) != 2:
                        log("skipped invalid option: '%s'", option)
                        continue
                    if parts[0] in BLACKLISTED_XSETTINGS:
                        log("skipped blacklisted option: '%s'", option)
                        continue
                    values[parts[0]] = parts[1]
                if cursor_size > 0:
                    values["Xcursor.size"] = cursor_size
                if dpi > 0:
                    values["Xft.dpi"] = dpi
                    values["Xft/DPI"] = dpi * 1024
                    values["gnome.Xft/DPI"] = dpi * 1024
                if antialias:
                    ad = typedict(antialias)
                    subpixel_order = "none"
                    sss = tuple(self._server_sources.values())
                    if len(sss) == 1:
                        #only honour sub-pixel hinting if a single client is connected
                        #and only when it is not using any scaling (or overriden with SCALED_FONT_ANTIALIAS):
                        ss = sss[0]
                        ds_unscaled = getattr(ss, "desktop_size_unscaled",
                                              None)
                        ds_scaled = getattr(ss, "desktop_size", None)
                        if SCALED_FONT_ANTIALIAS or (not ds_unscaled or
                                                     ds_unscaled == ds_scaled):
                            subpixel_order = ad.strget("orientation",
                                                       "none").lower()
                    values.update({
                        "Xft.antialias": ad.intget("enabled", -1),
                        "Xft.hinting": ad.intget("hinting", -1),
                        "Xft.rgba": subpixel_order,
                        "Xft.hintstyle": _get_antialias_hintstyle(ad)
                    })
                log("server_settings: resource-manager values=%s",
                    nonl(values))
                #convert the dict back into a resource string:
                value = ''
                for vk, vv in values.items():
                    value += "%s:\t%s\n" % (vk, vv)
                #record the actual value used
                self._settings[b"resource-manager"] = value
                v = value.encode("utf-8")

            #cook xsettings to add various settings:
            #(as those may not be present in xsettings on some platforms.. like win32 and osx)
            if k==b"xsettings-blob" and \
            (self.double_click_time>0 or self.double_click_distance!=(-1, -1) or antialias or dpi>0):
                #start by removing blacklisted options:
                def filter_blacklisted():
                    serial, values = v
                    new_values = []
                    for _t, _n, _v, _s in values:
                        if bytestostr(_n) in BLACKLISTED_XSETTINGS:
                            log("skipped blacklisted option %s",
                                (_t, _n, _v, _s))
                        else:
                            new_values.append((_t, _n, _v, _s))
                    return serial, new_values

                v = filter_blacklisted()

                def set_xsettings_value(name, value_type, value):
                    #remove existing one, if any:
                    serial, values = v
                    new_values = [(_t, _n, _v, _s)
                                  for (_t, _n, _v, _s) in values if _n != name]
                    new_values.append((value_type, name, value, 0))
                    return serial, new_values

                def set_xsettings_int(name, value):
                    if value < 0:  #not set, return v unchanged
                        return v
                    return set_xsettings_value(name, XSettingsTypeInteger,
                                               value)

                if dpi > 0:
                    v = set_xsettings_int(b"Xft/DPI", dpi * 1024)
                if double_click_time > 0:
                    v = set_xsettings_int(b"Net/DoubleClickTime",
                                          self.double_click_time)
                if antialias:
                    ad = typedict(antialias)
                    v = set_xsettings_int(b"Xft/Antialias",
                                          ad.intget("enabled", -1))
                    v = set_xsettings_int(b"Xft/Hinting",
                                          ad.intget("hinting", -1))
                    v = set_xsettings_value(
                        b"Xft/RGBA", XSettingsTypeString,
                        ad.strget("orientation", "none").lower())
                    v = set_xsettings_value(b"Xft/HintStyle",
                                            XSettingsTypeString,
                                            _get_antialias_hintstyle(ad))
                if double_click_distance != (-1, -1):
                    #some platforms give us a value for each axis,
                    #but X11 only has one, so take the average
                    try:
                        x, y = double_click_distance
                        if x > 0 and y > 0:
                            d = iround((x + y) / 2.0)
                            d = max(1, min(128, d))  #sanitize it a bit
                            v = set_xsettings_int(b"Net/DoubleClickDistance",
                                                  d)
                    except Exception as e:
                        log.warn(
                            "error setting double click distance from %s: %s",
                            double_click_distance, e)

            if k not in old_settings or v != old_settings[k]:
                if k == b"xsettings-blob":
                    self.set_xsettings(v)
                elif k == b"resource-manager":
                    from xpra.x11.gtk_x11.prop import prop_set
                    p = "RESOURCE_MANAGER"
                    log("server_settings: setting %s to %s", nonl(p), nonl(v))
                    prop_set(self.root_window, p, "latin1",
                             strtobytes(v).decode("latin1"))
                else:
                    log.warn("Warning: unexpected setting '%s'", bytestostr(k))
Beispiel #23
0
 def dpi(size_pixels, size_mm):
     if size_mm == 0:
         return 0
     return iround(size_pixels * 254 / size_mm / 10)
Beispiel #24
0
 def make_cursor(self, cursor_data):
     #if present, try cursor ny name:
     display = display_get_default()
     cursorlog("make_cursor: has-name=%s, has-cursor-types=%s, xscale=%s, yscale=%s, USE_LOCAL_CURSORS=%s", len(cursor_data)>=9, bool(cursor_types), self.xscale, self.yscale, USE_LOCAL_CURSORS)
     #named cursors cannot be scaled (round to 10 to compare so 0.95 and 1.05 are considered the same as 1.0, no scaling):
     if len(cursor_data)>=9 and cursor_types and iround(self.xscale*10)==10 and iround(self.yscale*10)==10:
         cursor_name = bytestostr(cursor_data[8])
         if cursor_name and USE_LOCAL_CURSORS:
             gdk_cursor = cursor_types.get(cursor_name.upper())
             if gdk_cursor is not None:
                 cursorlog("setting new cursor by name: %s=%s", cursor_name, gdk_cursor)
                 return new_Cursor_for_display(display, gdk_cursor)
             else:
                 global missing_cursor_names
                 if cursor_name not in missing_cursor_names:
                     cursorlog("cursor name '%s' not found", cursor_name)
                     missing_cursor_names.add(cursor_name)
     #create cursor from the pixel data:
     w, h, xhot, yhot, serial, pixels = cursor_data[2:8]
     if len(pixels)<w*h*4:
         import binascii
         cursorlog.warn("not enough pixels provided in cursor data: %s needed and only %s bytes found (%s)", w*h*4, len(pixels), binascii.hexlify(pixels)[:100])
         return
     pixbuf = get_pixbuf_from_data(pixels, True, w, h, w*4)
     x = max(0, min(xhot, w-1))
     y = max(0, min(yhot, h-1))
     csize = display.get_default_cursor_size()
     cmaxw, cmaxh = display.get_maximal_cursor_size()
     if len(cursor_data)>=11:
         ssize = cursor_data[9]
         smax = cursor_data[10]
         cursorlog("server cursor sizes: default=%s, max=%s", ssize, smax)
     cursorlog("new cursor at %s,%s with serial=%s, dimensions: %sx%s, len(pixels)=%s, default cursor size is %s, maximum=%s", xhot,yhot, serial, w,h, len(pixels), csize, (cmaxw, cmaxh))
     fw, fh = get_fixed_cursor_size()
     if fw>0 and fh>0 and (w!=fw or h!=fh):
         #OS wants a fixed cursor size! (win32 does, and GTK doesn't do this for us)
         if w<=fw and h<=fh:
             cursorlog("pasting cursor of size %ix%i onto clear pixbuf of size %ix%i", w, h, fw, fh)
             cursor_pixbuf = get_pixbuf_from_data("\0"*fw*fh*4, True, fw, fh, fw*4)
             pixbuf.copy_area(0, 0, w, h, cursor_pixbuf, 0, 0)
         else:
             cursorlog("scaling cursor from %ix%i to fixed OS size %ix%i", w, h, fw, fh)
             cursor_pixbuf = pixbuf.scale_simple(fw, fh, INTERP_BILINEAR)
             xratio, yratio = float(w)/fw, float(h)/fh
             x, y = iround(x/xratio), iround(y/yratio)
     else:
         sx, sy, sw, sh = x, y, w, h
         #scale the cursors:
         if self.xscale!=1 or self.yscale!=1:
             sx, sy, sw, sh = self.srect(x, y, w, h)
         sw = max(1, sw)
         sh = max(1, sh)
         #ensure we honour the max size if there is one:
         if (cmaxw>0 and sw>cmaxw) or (cmaxh>0 and sh>cmaxh):
             ratio = 1.0
             if cmaxw>0:
                 ratio = max(ratio, float(w)/cmaxw)
             if cmaxh>0:
                 ratio = max(ratio, float(h)/cmaxh)
             cursorlog("clamping cursor size to %ix%i using ratio=%s", cmaxw, cmaxh, ratio)
             sx, sy, sw, sh = iround(x/ratio), iround(y/ratio), min(cmaxw, iround(w/ratio)), min(cmaxh, iround(h/ratio))
         if sw!=w or sh!=h:
             cursorlog("scaling cursor from %ix%i hotspot at %ix%i to %ix%i hotspot at %ix%i", w, h, x, y, sw, sh, sx, sy)
             cursor_pixbuf = pixbuf.scale_simple(sw, sh, INTERP_BILINEAR)
             x, y = sx, sy
         else:
             cursor_pixbuf = pixbuf
     #clamp to pixbuf size:
     w = cursor_pixbuf.get_width()
     h = cursor_pixbuf.get_height()
     x = max(0, min(x, w-1))
     y = max(0, min(y, h-1))
     try:
         c = new_Cursor_from_pixbuf(display, cursor_pixbuf, x, y)
     except RuntimeError as e:
         log.error("Error: failed to create cursor:")
         log.error(" %s", e)
         log.error(" using %s of size %ix%i with hotspot at %ix%i", cursor_pixbuf, w, h, x, y)
         c = None
     return c
Beispiel #25
0
    def set_screen_size(self, desired_w, desired_h, bigger=True):
        screenlog("set_screen_size%s", (desired_w, desired_h, bigger))
        root_w, root_h = self.root_window.get_geometry()[2:4]
        if not self.randr:
            return root_w,root_h
        if desired_w==root_w and desired_h==root_h and not self.fake_xinerama:
            return root_w,root_h    #unlikely: perfect match already!
        #clients may supply "xdpi" and "ydpi" (v0.15 onwards), or just "dpi", or nothing...
        xdpi = self.xdpi or self.dpi
        ydpi = self.ydpi or self.dpi
        screenlog("set_screen_size(%s, %s, %s) xdpi=%s, ydpi=%s",
                  desired_w, desired_h, bigger, xdpi, ydpi)
        if xdpi<=0 or ydpi<=0:
            #use some sane defaults: either the command line option, or fallback to 96
            #(96 is better than nothing, because we do want to set the dpi
            # to avoid Xdummy setting a crazy dpi from the virtual screen dimensions)
            xdpi = self.default_dpi or 96
            ydpi = self.default_dpi or 96
            #find the "physical" screen dimensions, so we can calculate the required dpi
            #(and do this before changing the resolution)
            wmm, hmm = 0, 0
            client_w, client_h = 0, 0
            sss = self._server_sources.values()
            for ss in sss:
                for s in ss.screen_sizes:
                    if len(s)>=10:
                        #(display_name, width, height, width_mm, height_mm, monitors,
                        # work_x, work_y, work_width, work_height)
                        client_w = max(client_w, s[1])
                        client_h = max(client_h, s[2])
                        wmm = max(wmm, s[3])
                        hmm = max(hmm, s[4])
            if wmm>0 and hmm>0 and client_w>0 and client_h>0:
                #calculate "real" dpi:
                xdpi = iround(client_w * 25.4 / wmm)
                ydpi = iround(client_h * 25.4 / hmm)
                screenlog("calculated DPI: %s x %s (from w: %s / %s, h: %s / %s)",
                          xdpi, ydpi, client_w, wmm, client_h, hmm)
        self.set_dpi(xdpi, ydpi)

        #try to find the best screen size to resize to:
        w, h = self.get_best_screen_size(desired_w, desired_h, bigger)

        #fakeXinerama:
        ui_clients = [s for s in self._server_sources.values() if s.ui_client]
        source = None
        screen_sizes = []
        if len(ui_clients)==1:
            source = ui_clients[0]
            screen_sizes = source.screen_sizes
        else:
            screenlog("fakeXinerama can only be enabled for a single client (found %s)" % len(ui_clients))
        xinerama_changed = save_fakeXinerama_config(self.fake_xinerama and len(ui_clients)==1, source, screen_sizes)
        #we can only keep things unchanged if xinerama was also unchanged
        #(many apps will only query xinerama again if they get a randr notification)
        if (w==root_w and h==root_h) and not xinerama_changed:
            screenlog.info("best resolution matching %sx%s is unchanged: %sx%s", desired_w, desired_h, w, h)
            return root_w, root_h
        try:
            if (w==root_w and h==root_h) and xinerama_changed:
                #xinerama was changed, but the RandR resolution will not be...
                #and we need a RandR change to force applications to re-query it
                #so we temporarily switch to another resolution to force
                #the change! (ugly! but this works)
                with xsync:
                    temp = {}
                    for tw,th in self.get_all_screen_sizes():
                        if tw!=w or th!=h:
                            #use the number of extra pixels as key:
                            #(so we can choose the closest resolution)
                            temp[abs((tw*th) - (w*h))] = (tw, th)
                if not temp:
                    screenlog.warn("cannot find a temporary resolution for Xinerama workaround!")
                else:
                    k = sorted(temp.keys())[0]
                    tw, th = temp[k]
                    screenlog.info("temporarily switching to %sx%s as a Xinerama workaround", tw, th)
                    with xsync:
                        RandR.set_screen_size(tw, th)
            with xsync:
                RandR.get_screen_size()
            #Xdummy with randr 1.2:
            screenlog("using XRRSetScreenConfigAndRate with %ix%i", w, h)
            with xsync:
                RandR.set_screen_size(w, h)
            if self.randr_exact_size:
                #Xvfb with randr > 1.2: the resolution has been added
                #we can use XRRSetScreenSize:
                try:
                    with xsync:
                        RandR.xrr_set_screen_size(w, h, self.xdpi or self.dpi or 96, self.ydpi or self.dpi or 96)
                except XError:
                    screenlog("XRRSetScreenSize failed", exc_info=True)
            screenlog("calling RandR.get_screen_size()")
            with xsync:
                root_w, root_h = RandR.get_screen_size()
            screenlog("RandR.get_screen_size()=%s,%s", root_w, root_h)
            screenlog("RandR.get_vrefresh()=%s", RandR.get_vrefresh())
            if root_w!=w or root_h!=h:
                screenlog.warn("Warning: tried to set resolution to %ix%i", w, h)
                screenlog.warn(" and ended up with %ix%i", root_w, root_h)
            else:
                msg = "server virtual display now set to %sx%s" % (root_w, root_h)
                if desired_w!=root_w or desired_h!=root_h:
                    msg += " (best match for %sx%s)" % (desired_w, desired_h)
                screenlog.info(msg)
            def show_dpi():
                wmm, hmm = RandR.get_screen_size_mm()      #ie: (1280, 1024)
                screenlog("RandR.get_screen_size_mm=%s,%s", wmm, hmm)
                actual_xdpi = iround(root_w * 25.4 / wmm)
                actual_ydpi = iround(root_h * 25.4 / hmm)
                if abs(actual_xdpi-xdpi)<=1 and abs(actual_ydpi-ydpi)<=1:
                    screenlog.info("DPI set to %s x %s", actual_xdpi, actual_ydpi)
                    screenlog("wanted: %s x %s", xdpi, ydpi)
                else:
                    #should this be a warning:
                    l = screenlog.info
                    maxdelta = max(abs(actual_xdpi-xdpi), abs(actual_ydpi-ydpi))
                    if maxdelta>=10:
                        l = log.warn
                    messages = [
                        "DPI set to %s x %s (wanted %s x %s)" % (actual_xdpi, actual_ydpi, xdpi, ydpi),
                        ]
                    if maxdelta>=10:
                        messages.append("you may experience scaling problems, such as huge or small fonts, etc")
                        messages.append("to fix this issue, try the dpi switch, or use a patched Xorg dummy driver")
                        self.notify_dpi_warning("\n".join(messages))
                    for i,message in enumerate(messages):
                        l("%s%s", ["", " "][i>0], message)
            #show dpi via idle_add so server has time to change the screen size (mm)
            self.idle_add(show_dpi)
        except Exception as e:
            screenlog.error("ouch, failed to set new resolution: %s", e, exc_info=True)
        return root_w, root_h
Beispiel #26
0
def get_screen_sizes(xscale=1, yscale=1):
    from xpra.platform.gui import get_workarea, get_workareas

    def xs(v):
        return iround(v / xscale)

    def ys(v):
        return iround(v / yscale)

    def swork(*workarea):
        return xs(workarea[0]), ys(workarea[1]), xs(workarea[2]), ys(
            workarea[3])

    display = Gdk.Display.get_default()
    if not display:
        return ()
    MIN_DPI = envint("XPRA_MIN_DPI", 10)
    MAX_DPI = envint("XPRA_MIN_DPI", 500)

    def dpi(size_pixels, size_mm):
        if size_mm == 0:
            return 0
        return iround(size_pixels * 254 / size_mm / 10)

    n_screens = display.get_n_screens()
    get_n_monitors = getattr(display, "get_n_monitors", None)
    if get_n_monitors:
        #GTK 3.22: always just one screen
        n_monitors = get_n_monitors()
        workareas = get_workareas()
        if workareas and len(workareas) != n_monitors:
            screenlog(" workareas: %s", workareas)
            screenlog(
                " number of monitors does not match number of workareas!")
            workareas = []
        monitors = []
        for j in range(n_monitors):
            monitor = display.get_monitor(j)
            geom = monitor.get_geometry()
            manufacturer, model = monitor.get_manufacturer(
            ), monitor.get_model()
            if manufacturer and model:
                plug_name = "%s %s" % (manufacturer, model)
            elif manufacturer:
                plug_name = manufacturer
            elif model:
                plug_name = model
            else:
                plug_name = "%i" % j
            wmm, hmm = monitor.get_width_mm(), monitor.get_height_mm()
            monitor_info = [
                plug_name,
                xs(geom.x),
                ys(geom.y),
                xs(geom.width),
                ys(geom.height), wmm, hmm
            ]
            screenlog(" monitor %s: %s", j, monitor)
            if GTK_WORKAREA and hasattr(monitor, "get_workarea"):
                rect = monitor.get_workarea()
                monitor_info += list(
                    swork(rect.x, rect.y, rect.width, rect.height))
            elif workareas:
                w = workareas[j]
                monitor_info += list(swork(*w))
            monitors.append(tuple(monitor_info))
        screen = display.get_default_screen()
        sw, sh = screen.get_width(), screen.get_height()
        work_x, work_y, work_width, work_height = swork(0, 0, sw, sh)
        workarea = get_workarea()  #pylint: disable=assignment-from-none
        if workarea:
            work_x, work_y, work_width, work_height = swork(*workarea)  #pylint: disable=not-an-iterable
        screenlog(" workarea=%s", workarea)
        wmm = screen.get_width_mm()
        hmm = screen.get_height_mm()
        xdpi = dpi(sw, wmm)
        ydpi = dpi(sh, hmm)
        if xdpi < MIN_DPI or xdpi > MAX_DPI or ydpi < MIN_DPI or ydpi > MAX_DPI:
            log("ignoring invalid screen size %ix%imm", wmm, hmm)
            if os.environ.get("WAYLAND_DISPLAY"):
                log(" (wayland display?)")
            if n_monitors > 0:
                wmm = sum(
                    display.get_monitor(i).get_width_mm()
                    for i in range(n_monitors))
                hmm = sum(
                    display.get_monitor(i).get_height_mm()
                    for i in range(n_monitors))
                xdpi = dpi(sw, wmm)
                ydpi = dpi(sh, hmm)
            if xdpi < MIN_DPI or xdpi > MAX_DPI or ydpi < MIN_DPI or ydpi > MAX_DPI:
                #still invalid, generate one from DPI=96
                wmm = iround(sw * 25.4 / 96)
                hmm = iround(sh * 25.4 / 96)
            log(" using %ix%i mm", wmm, hmm)
        item = (screen.make_display_name(), xs(sw), ys(sh), wmm, hmm, monitors,
                work_x, work_y, work_width, work_height)
        screenlog(" screen: %s", item)
        screen_sizes = [item]
    else:
        i = 0
        screen_sizes = []
        #GTK2 or GTK3<3.22:
        screenlog("get_screen_sizes(%f, %f) found %s screens", xscale, yscale,
                  n_screens)
        while i < n_screens:
            screen = display.get_screen(i)
            j = 0
            monitors = []
            workareas = []
            #native "get_workareas()" is only valid for a single screen (but describes all the monitors)
            #and it is only implemented on win32 right now
            #other platforms only implement "get_workarea()" instead, which is reported against the screen
            n_monitors = screen.get_n_monitors()
            screenlog(" screen %s has %s monitors", i, n_monitors)
            if n_screens == 1:
                workareas = get_workareas()
                if workareas and len(workareas) != n_monitors:
                    screenlog(" workareas: %s", workareas)
                    screenlog(
                        " number of monitors does not match number of workareas!"
                    )
                    workareas = []
            while j < screen.get_n_monitors():
                geom = screen.get_monitor_geometry(j)
                plug_name = ""
                if hasattr(screen, "get_monitor_plug_name"):
                    plug_name = screen.get_monitor_plug_name(j) or ""
                wmm = -1
                if hasattr(screen, "get_monitor_width_mm"):
                    wmm = screen.get_monitor_width_mm(j)
                hmm = -1
                if hasattr(screen, "get_monitor_height_mm"):
                    hmm = screen.get_monitor_height_mm(j)
                monitor = [
                    plug_name,
                    xs(geom.x),
                    ys(geom.y),
                    xs(geom.width),
                    ys(geom.height), wmm, hmm
                ]
                screenlog(" monitor %s: %s", j, monitor)
                if workareas:
                    w = workareas[j]
                    monitor += list(swork(*w))
                monitors.append(tuple(monitor))
                j += 1
            work_x, work_y, work_width, work_height = swork(
                0, 0, screen.get_width(), screen.get_height())
            workarea = get_workarea()  #pylint: disable=assignment-from-none
            if workarea:
                work_x, work_y, work_width, work_height = swork(*workarea)  #pylint: disable=not-an-iterable
            screenlog(" workarea=%s", workarea)
            item = (screen.make_display_name(), xs(screen.get_width()),
                    ys(screen.get_height()), screen.get_width_mm(),
                    screen.get_height_mm(), monitors, work_x, work_y,
                    work_width, work_height)
            screenlog(" screen %s: %s", i, item)
            screen_sizes.append(item)
            i += 1
    return screen_sizes
Beispiel #27
0
 def cy(self, v):
     """ convert Y coordinate from client to server """
     return iround(v / self.yscale)
Beispiel #28
0
    def test_calculate_timesize_weighted_average(self):
        #event_time, size, elapsed_time
        now = monotonic()
        sample_size = 1000
        data = []
        ts = now - sample_size
        for _ in range(sample_size):
            s = random.randint(1000, 10000)
            v = random.random()
            data.append((ts, s, v))
            ts += 1
        a, ra = cystats.calculate_timesize_weighted_average(data)
        assert a > 0 and ra > 0
        #the calculations use the ratio of the size divided by the elapsed time,
        #so check that a predictable ratio gives the expected value:
        for x in (5, 1000):
            v = [(now, i * x, x) for i in range(1, 1000)]
            a, ra = cystats.calculate_size_weighted_average(v)
            #but we need to round to an int to compare
            self.assertEqual(x, iround(a),
                             "average should be %i, got %i" % (x, a))
            self.assertEqual(x, iround(ra),
                             "recent average should be %i, got %i" % (x, ra))

        def t(v, ea, era):
            a, ra = cystats.calculate_size_weighted_average(v)
            self.assertEqual(
                iround(a), iround(ea),
                "average should be %s, got %s" % (iround(ea), iround(a)))
            self.assertEqual(
                iround(ra), iround(era),
                "recent average should be %s, got %s" %
                (iround(era), iround(ra)))

        #an old record won't make any difference
        #compared with one that was taken just now:
        for v in (1, 10, 1000):
            #1 day ago:
            if now > 60 * 60 * 24:
                t([(now - 60 * 60 * 24, 1000, 1000), (now, 1000, v)], v, v)
                t([(now - 60 * 60 * 24, 2 * 1000, 1000), (now, 1000, v)], v, v)
            #1 hour ago:
            if now > 60 * 60:
                t([(now - 60 * 60, 1000, 10), (now, 1000, v)], v, v)
        #but 100s ago starts to make a difference:
        t([(now - 100, 1000, 1), (now, 1000, 100)], 99, 100)
        #with only 10s:
        t([(now - 10, 1000, 1), (now, 1000, 100)], 92, 100)
        #1 second:
        t([(now - 1, 1000, 1), (now, 1000, 100)], 67, 92)
        #if using the same time, then size matters more:
        v = [(now, 100 * 1000, 1000), (now, 50 * 1000, 1000)]
        a, ra = cystats.calculate_size_weighted_average(v)
        #recent is the same as "normal" average:
        self.assertEqual(iround(a), iround(ra))
        self.assertGreater(a, 75)
        #real data:
        T = monotonic()
        v = [(T - 21.557095, 157684, 9110), (T - 22.23345, 3744, 1279),
             (T - 22.376621, 3744, 706), (T - 22.515456, 3744, 1302),
             (T - 23.013887, 78, 1342), (T - 43.707768, 78, 920),
             (T - 44.043399, 78, 1558), (T - 44.046686, 78, 1119),
             (T - 44.048169, 78, 1007), (T - 44.049807, 1716, 626),
             (T - 44.053967, 78, 2841), (T - 44.23714, 78, 1393),
             (T - 44.238555, 78, 2903), (T - 44.242623, 78, 1167),
             (T - 44.244426, 1716, 1032), (T - 44.245675, 78, 720),
             (T - 44.392009, 78, 784), (T - 44.392771, 78, 737),
             (T - 44.396293, 78, 911), (T - 44.397466, 1716, 772),
             (T - 44.398027, 78, 1234), (T - 44.538323, 78, 1200),
             (T - 44.539683, 78, 586), (T - 44.542575, 78, 1203),
             (T - 44.544646, 1716, 1129), (T - 44.546205, 78, 979),
             (T - 44.701881, 78, 901), (T - 44.703987, 78, 448),
             (T - 44.708965, 78, 474), (T - 44.711481, 1716, 1444),
             (T - 44.713157, 78, 1033), (T - 44.848487, 78, 860),
             (T - 44.850604, 78, 1172), (T - 44.857039, 78, 1367),
             (T - 44.858723, 1716, 1078), (T - 44.859743, 78, 1876),
             (T - 44.993883, 78, 824), (T - 44.99714, 78, 796),
             (T - 45.001942, 78, 714), (T - 45.002884, 1716, 744),
             (T - 45.004841, 78, 652), (T - 45.772856, 78, 652)]
        raw_v = [x[2] for x in v]
        min_v = min(raw_v)
        max_v = max(raw_v)
        a, ra = cystats.calculate_size_weighted_average(v)
        self.assertLess(a, max_v)
        self.assertLess(ra, max_v)
        self.assertGreater(a, min_v)
        self.assertGreater(ra, min_v)
Beispiel #29
0
    def set_screen_size(self, desired_w, desired_h):
        root_w, root_h = self.root_window.get_size()
        if not self.randr:
            return root_w,root_h
        if desired_w==root_w and desired_h==root_h and not self.fake_xinerama:
            return root_w,root_h    #unlikely: perfect match already!
        #clients may supply "xdpi" and "ydpi" (v0.15 onwards), or just "dpi", or nothing...
        xdpi = self.xdpi or self.dpi
        ydpi = self.ydpi or self.dpi
        screenlog("set_screen_size(%s, %s) xdpi=%s, ydpi=%s", desired_w, desired_h, xdpi, ydpi)
        if xdpi<=0 or ydpi<=0:
            #use some sane defaults: either the command line option, or fallback to 96
            #(96 is better than nothing, because we do want to set the dpi
            # to avoid Xdummy setting a crazy dpi from the virtual screen dimensions)
            xdpi = self.default_dpi or 96
            ydpi = self.default_dpi or 96
            #find the "physical" screen dimensions, so we can calculate the required dpi
            #(and do this before changing the resolution)
            wmm, hmm = 0, 0
            client_w, client_h = 0, 0
            sss = self._server_sources.values()
            for ss in sss:
                for s in ss.screen_sizes:
                    if len(s)>=10:
                        #display_name, width, height, width_mm, height_mm, monitors, work_x, work_y, work_width, work_height
                        client_w = max(client_w, s[1])
                        client_h = max(client_h, s[2])
                        wmm = max(wmm, s[3])
                        hmm = max(hmm, s[4])
            if wmm>0 and hmm>0 and client_w>0 and client_h>0:
                #calculate "real" dpi:
                xdpi = iround(client_w * 25.4 / wmm)
                ydpi = iround(client_h * 25.4 / hmm)
                screenlog("calculated DPI: %s x %s (from w: %s / %s, h: %s / %s)", xdpi, ydpi, client_w, wmm, client_h, hmm)
        self.set_dpi(xdpi, ydpi)

        #try to find the best screen size to resize to:
        new_size = None
        closest = {}
        for w,h in RandR.get_screen_sizes():
            if w<desired_w or h<desired_h:
                distance = abs(w-desired_w)*abs(h-desired_h)
                closest[distance] = (w, h)
                continue            #size is too small for client
            if new_size:
                ew,eh = new_size
                if ew*eh<w*h:
                    continue        #we found a better (smaller) candidate already
            new_size = w,h
        if not new_size:
            screenlog.warn("Warning: no matching resolution found for %sx%s", desired_w, desired_h)
            if len(closest)>0:
                new_size = sorted(closest.items())[0]
                screenlog.warn(" using %sx%s instead", *new_size)
            else:
                return  root_w, root_h
        screenlog("best resolution for client(%sx%s) is: %s", desired_w, desired_h, new_size)
        #now actually apply the new settings:
        w, h = new_size
        #fakeXinerama:
        ui_clients = [s for s in self._server_sources.values() if s.ui_client]
        source = None
        screen_sizes = []
        if len(ui_clients)==1:
            source = ui_clients[0]
            screen_sizes = source.screen_sizes
        else:
            screenlog("fakeXinerama can only be enabled for a single client (found %s)" % len(ui_clients))
        xinerama_changed = save_fakeXinerama_config(self.fake_xinerama and len(ui_clients)==1, source, screen_sizes)
        #we can only keep things unchanged if xinerama was also unchanged
        #(many apps will only query xinerama again if they get a randr notification)
        if (w==root_w and h==root_h) and not xinerama_changed:
            screenlog.info("best resolution matching %sx%s is unchanged: %sx%s", desired_w, desired_h, w, h)
            return  root_w, root_h
        try:
            if (w==root_w and h==root_h) and xinerama_changed:
                #xinerama was changed, but the RandR resolution will not be...
                #and we need a RandR change to force applications to re-query it
                #so we temporarily switch to another resolution to force
                #the change! (ugly! but this works)
                temp = {}
                for tw,th in RandR.get_screen_sizes():
                    if tw!=w or th!=h:
                        #use the number of extra pixels as key:
                        #(so we can choose the closest resolution)
                        temp[abs((tw*th) - (w*h))] = (tw, th)
                if len(temp)==0:
                    screenlog.warn("cannot find a temporary resolution for Xinerama workaround!")
                else:
                    k = sorted(temp.keys())[0]
                    tw, th = temp[k]
                    screenlog.info("temporarily switching to %sx%s as a Xinerama workaround", tw, th)
                    RandR.set_screen_size(tw, th)
            screenlog("calling RandR.set_screen_size(%s, %s)", w, h)
            with xsync:
                RandR.set_screen_size(w, h)
            screenlog("calling RandR.get_screen_size()")
            root_w, root_h = RandR.get_screen_size()
            screenlog("RandR.get_screen_size()=%s,%s", root_w, root_h)
            screenlog("RandR.get_vrefresh()=%s", RandR.get_vrefresh())
            if root_w!=w or root_h!=h:
                screenlog.error("odd, failed to set the new resolution, "
                                "tried to set it to %sx%s and ended up with %sx%s", w, h, root_w, root_h)
            else:
                msg = "server virtual display now set to %sx%s" % (root_w, root_h)
                if desired_w!=root_w or desired_h!=root_h:
                    msg += " (best match for %sx%s)" % (desired_w, desired_h)
                screenlog.info(msg)
            def show_dpi():
                wmm, hmm = RandR.get_screen_size_mm()      #ie: (1280, 1024)
                screenlog("RandR.get_screen_size_mm=%s,%s", wmm, hmm)
                actual_xdpi = iround(root_w * 25.4 / wmm)
                actual_ydpi = iround(root_h * 25.4 / hmm)
                if abs(actual_xdpi-xdpi)<=1 and abs(actual_ydpi-ydpi)<=1:
                    screenlog.info("DPI set to %s x %s", xdpi, ydpi)
                else:
                    #should this be a warning:
                    l = screenlog.info
                    maxdelta = max(abs(actual_xdpi-xdpi), abs(actual_ydpi-ydpi))
                    if maxdelta>=10:
                        l = log.warn
                    l("DPI set to %s x %s (wanted %s x %s)", actual_xdpi, actual_ydpi, xdpi, ydpi)
                    if maxdelta>=10:
                        l(" you may experience scaling problems, such as huge or small fonts, etc")
                        l(" to fix this issue, try the dpi switch, or use a patched Xorg dummy driver")
            #show dpi via idle_add so server has time to change the screen size (mm)
            self.idle_add(show_dpi)
        except Exception as e:
            screenlog.error("ouch, failed to set new resolution: %s", e, exc_info=True)
        return  root_w, root_h
Beispiel #30
0
 def make_cursor(self, cursor_data):
     #if present, try cursor ny name:
     display = display_get_default()
     cursorlog(
         "make_cursor: has-name=%s, has-cursor-types=%s, xscale=%s, yscale=%s, USE_LOCAL_CURSORS=%s",
         len(cursor_data) >= 9, bool(cursor_types), self.xscale,
         self.yscale, USE_LOCAL_CURSORS)
     #named cursors cannot be scaled (round to 10 to compare so 0.95 and 1.05 are considered the same as 1.0, no scaling):
     if len(cursor_data) >= 9 and cursor_types and iround(
             self.xscale * 10) == 10 and iround(self.yscale * 10) == 10:
         cursor_name = bytestostr(cursor_data[8])
         if cursor_name and USE_LOCAL_CURSORS:
             gdk_cursor = cursor_types.get(cursor_name.upper())
             if gdk_cursor is not None:
                 cursorlog("setting new cursor by name: %s=%s", cursor_name,
                           gdk_cursor)
                 return new_Cursor_for_display(display, gdk_cursor)
             else:
                 global missing_cursor_names
                 if cursor_name not in missing_cursor_names:
                     cursorlog("cursor name '%s' not found", cursor_name)
                     missing_cursor_names.add(cursor_name)
     #create cursor from the pixel data:
     w, h, xhot, yhot, serial, pixels = cursor_data[2:8]
     if len(pixels) < w * h * 4:
         import binascii
         cursorlog.warn(
             "not enough pixels provided in cursor data: %s needed and only %s bytes found (%s)",
             w * h * 4, len(pixels),
             binascii.hexlify(pixels)[:100])
         return
     pixbuf = get_pixbuf_from_data(pixels, True, w, h, w * 4)
     x = max(0, min(xhot, w - 1))
     y = max(0, min(yhot, h - 1))
     csize = display.get_default_cursor_size()
     cmaxw, cmaxh = display.get_maximal_cursor_size()
     if len(cursor_data) >= 11:
         ssize = cursor_data[9]
         smax = cursor_data[10]
         cursorlog("server cursor sizes: default=%s, max=%s", ssize, smax)
     cursorlog(
         "new cursor at %s,%s with serial=%s, dimensions: %sx%s, len(pixels)=%s, default cursor size is %s, maximum=%s",
         xhot, yhot, serial, w, h, len(pixels), csize, (cmaxw, cmaxh))
     fw, fh = get_fixed_cursor_size()
     if fw > 0 and fh > 0 and (w != fw or h != fh):
         #OS wants a fixed cursor size! (win32 does, and GTK doesn't do this for us)
         if w <= fw and h <= fh:
             cursorlog(
                 "pasting cursor of size %ix%i onto clear pixbuf of size %ix%i",
                 w, h, fw, fh)
             cursor_pixbuf = get_pixbuf_from_data("\0" * fw * fh * 4, True,
                                                  fw, fh, fw * 4)
             pixbuf.copy_area(0, 0, w, h, cursor_pixbuf, 0, 0)
         else:
             cursorlog("scaling cursor from %ix%i to fixed OS size %ix%i",
                       w, h, fw, fh)
             cursor_pixbuf = pixbuf.scale_simple(fw, fh, INTERP_BILINEAR)
             xratio, yratio = float(w) / fw, float(h) / fh
             x, y = iround(x / xratio), iround(y / yratio)
     else:
         sx, sy, sw, sh = x, y, w, h
         #scale the cursors:
         if self.xscale != 1 or self.yscale != 1:
             sx, sy, sw, sh = self.srect(x, y, w, h)
         sw = max(1, sw)
         sh = max(1, sh)
         #ensure we honour the max size if there is one:
         if (cmaxw > 0 and sw > cmaxw) or (cmaxh > 0 and sh > cmaxh):
             ratio = 1.0
             if cmaxw > 0:
                 ratio = max(ratio, float(w) / cmaxw)
             if cmaxh > 0:
                 ratio = max(ratio, float(h) / cmaxh)
             cursorlog("clamping cursor size to %ix%i using ratio=%s",
                       cmaxw, cmaxh, ratio)
             sx, sy, sw, sh = iround(x / ratio), iround(y / ratio), min(
                 cmaxw, iround(w / ratio)), min(cmaxh, iround(h / ratio))
         if sw != w or sh != h:
             cursorlog(
                 "scaling cursor from %ix%i hotspot at %ix%i to %ix%i hotspot at %ix%i",
                 w, h, x, y, sw, sh, sx, sy)
             cursor_pixbuf = pixbuf.scale_simple(sw, sh, INTERP_BILINEAR)
             x, y = sx, sy
         else:
             cursor_pixbuf = pixbuf
     #clamp to pixbuf size:
     w = cursor_pixbuf.get_width()
     h = cursor_pixbuf.get_height()
     x = max(0, min(x, w - 1))
     y = max(0, min(y, h - 1))
     try:
         c = new_Cursor_from_pixbuf(display, cursor_pixbuf, x, y)
     except RuntimeError as e:
         log.error("Error: failed to create cursor:")
         log.error(" %s", e)
         log.error(" using %s of size %ix%i with hotspot at %ix%i",
                   cursor_pixbuf, w, h, x, y)
         c = None
     return c
Beispiel #31
0
 def xs(v):
     return iround(v / xscale)
Beispiel #32
0
def r4cmp(
        v,
        rounding=1000.0):  #ignore small differences in floats for scale values
    return iround(v * rounding)
Beispiel #33
0
 def mint(v):
     #prefer int over float,
     #and even tolerate a 0.1% difference to get it:
     if iround(v) * 1000 == iround(v * 1000):
         return int(v)
     return v
Beispiel #34
0
 def ys(v):
     return iround(v / yscale)
Beispiel #35
0
 def sy(self, v):
     """ convert Y coordinate from server to client """
     return iround(v * self.yscale)
Beispiel #36
0
 def cx(self, v):
     """ convert X coordinate from client to server """
     return iround(v / self.xscale)
Beispiel #37
0
 def ys(v):
     return iround(v/yscale)