Ejemplo n.º 1
0
    def test_config(self):
        from xpra.x11.fakeXinerama import save_fakeXinerama_config, cleanup_fakeXinerama, log
        #silence warnings during tests:
        log.warn = log.debug

        def get_display_info(*monitors):
            #display_name, width, height, width_mm, height_mm, \
            #monitors, work_x, work_y, work_width, work_height = s[:11]
            return (
                "fake-display",
                1920,
                1080,
                400,
                300,
                monitors,
                0,
                60,
                1920,
                1020,
            )

        monitor0 = ("plug0", 0, 0, 1920, 1080, 400, 300)
        monitor1 = ("plug1", 1920, 0, 1920, 1080, 300, 200)
        for ss in (
                get_display_info(),
                get_display_info((0, 0)),
                get_display_info(monitor0),
                get_display_info(monitor0, monitor1),
            (800, 600),
            (1, 2, 3, 4, 5),
        ):
            save_fakeXinerama_config(True, "", (ss, ))
            cleanup_fakeXinerama()
Ejemplo n.º 2
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
Ejemplo n.º 3
0
 def test_config(self):
     from xpra.x11.fakeXinerama import save_fakeXinerama_config, cleanup_fakeXinerama
     ss = ()
     save_fakeXinerama_config(True, "", ss)
     cleanup_fakeXinerama()
Ejemplo n.º 4
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 = {}
        with xsync:
            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)
                    with xsync:
                        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()")
            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.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():
                with xsync:
                    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
Ejemplo n.º 5
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