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()
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
def test_config(self): from xpra.x11.fakeXinerama import save_fakeXinerama_config, cleanup_fakeXinerama ss = () save_fakeXinerama_config(True, "", ss) cleanup_fakeXinerama()
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
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