Skip to content

Commit

Permalink
#1656: detect if vfb cannot be resized via randr (no sizes available,…
Browse files Browse the repository at this point in the history
… ie: Xwayland) and turn off desktop window resizing

git-svn-id: https://xpra.org/svn/Xpra/trunk@17140 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Oct 10, 2017
1 parent 1d0a1fe commit 6d5ce09
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 70 deletions.
26 changes: 21 additions & 5 deletions src/xpra/x11/bindings/randr_bindings.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ cdef extern from "X11/extensions/Xrandr.h":
int XScreenCount(Display *display)
int XDisplayWidthMM(Display *display, int screen_number)
int XDisplayHeightMM(Display *display, int screen_number)
int XDisplayWidth(Display *display, int screen_number)
int XDisplayHeight(Display *display, int screen_number)

short XRRConfigCurrentRate(XRRScreenConfiguration *config)

Expand Down Expand Up @@ -156,7 +158,7 @@ cdef class _RandRBindings(_X11CoreBindings):
def has_randr(self):
return bool(self._has_randr)

cdef _get_screen_sizes(self):
cdef _get_xrr_screen_sizes(self):
cdef int num_sizes = 0
cdef XRRScreenSize * xrrs
cdef XRRScreenSize xrr
Expand All @@ -169,9 +171,9 @@ cdef class _RandRBindings(_X11CoreBindings):
sizes.append((xrr.width, xrr.height))
return sizes

def get_screen_sizes(self):
v = self._get_screen_sizes()
log("get_screen_sizes()=%s", v)
def get_xrr_screen_sizes(self):
v = self._get_xrr_screen_sizes()
log("get_xrr_screen_sizes()=%s", v)
return v

cdef _set_screen_size(self, width, height):
Expand Down Expand Up @@ -242,6 +244,16 @@ cdef class _RandRBindings(_X11CoreBindings):
sizes.append((w, h))
return sizes

def get_screen_sizes(self):
cdef unsigned int n = XScreenCount(self.display)
cdef unsigned int i, w, h
cdef object sizes = []
for i in range(n):
w = XDisplayWidth(self.display, i)
h = XDisplayHeight(self.display, i)
sizes.append((w, h))
return sizes

def get_screen_size(self):
return self._get_screen_size()

Expand All @@ -259,13 +271,17 @@ cdef class _RandRBindings(_X11CoreBindings):
if config==NULL:
raise Exception("failed to get screen info")
xrrs = XRRConfigSizes(config, &num_sizes)
if num_sizes==0:
#on Xwayland, we get no sizes...
#so fallback to DisplayWidth / DisplayHeight:
return XDisplayWidth(self.display, 0), XDisplayHeight(self.display, 0)
if xrrs==NULL:
raise Exception("failed to get screen sizes")
size_id = XRRConfigCurrentConfiguration(config, &original_rotation)
if size_id<0:
raise Exception("failed to get current configuration")
if size_id>=num_sizes:
raise Exception("invalid size ID")
raise Exception("invalid XRR size ID %i (num sizes=%i)" % (size_id, num_sizes))

width = xrrs[size_id].width;
height = xrrs[size_id].height;
Expand Down
88 changes: 46 additions & 42 deletions src/xpra/x11/desktop_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,60 +181,64 @@ def _screen_size_changed(self, screen):
def update_size_hints(self, screen):
w, h = screen.get_width(), screen.get_height()
screenlog("screen dimensions: %ix%i", w, h)
size_hints = {}
def use_fixed_size():
size = w, h
size_hints.update({
"maximum-size" : size,
"minimum-size" : size,
"base-size" : size,
})
if RandR.has_randr():
if self.resize_exact:
#assume resize_excact is enabled
#assume resize_exact is enabled
#no size restrictions
size_hints = {}
else:
size_hints = {
"minimum-aspect-ratio" : (1, 3),
"maximum-aspect-ratio" : (3, 1),
}
try:
with xsync:
screen_sizes = RandR.get_screen_sizes()
screen_sizes = RandR.get_xrr_screen_sizes()
except:
screenlog("failed to query screen sizes", exc_info=True)
else:
#find the maximum size supported:
max_size = {}
for tw, th in screen_sizes:
max_size[tw*th] = (tw, th)
max_pixels = sorted(max_size.keys())[-1]
size_hints["maximum-size"] = max_size[max_pixels]
#find the best increment we can use:
inc_hits = {}
#we should also figure out what the potential increments are,
#rather than hardcoding them here:
INC_VALUES = (16, 32, 64, 128, 256)
for inc in INC_VALUES:
hits = 0
for tsize in screen_sizes:
tw, th = tsize
if (tw+inc, th+inc) in screen_sizes:
hits += 1
inc_hits[inc] = hits
screenlog("size increment hits: %s", inc_hits)
max_hits = max(inc_hits.values())
if max_hits>16:
#find the first increment value matching the max hits
if len(screen_sizes)==0:
use_fixed_size()
else:
#find the maximum size supported:
max_size = {}
for tw, th in screen_sizes:
max_size[tw*th] = (tw, th)
max_pixels = sorted(max_size.keys())[-1]
size_hints["maximum-size"] = max_size[max_pixels]
#find the best increment we can use:
inc_hits = {}
#we should also figure out what the potential increments are,
#rather than hardcoding them here:
INC_VALUES = (16, 32, 64, 128, 256)
for inc in INC_VALUES:
if inc_hits[inc]==max_hits:
break
#TODO: also get these values from the screen sizes:
size_hints.update({
"base-size" : (640, 640),
"minimum-size" : (640, 640),
"increment" : (128, 128),
})
hits = 0
for tsize in screen_sizes:
tw, th = tsize
if (tw+inc, th+inc) in screen_sizes:
hits += 1
inc_hits[inc] = hits
screenlog("size increment hits: %s", inc_hits)
max_hits = max(inc_hits.values())
if max_hits>16:
#find the first increment value matching the max hits
for inc in INC_VALUES:
if inc_hits[inc]==max_hits:
break
#TODO: also get these values from the screen sizes:
size_hints.update({
"base-size" : (640, 640),
"minimum-size" : (640, 640),
"increment" : (128, 128),
"minimum-aspect-ratio" : (1, 3),
"maximum-aspect-ratio" : (3, 1),
})
else:
size = w, h
size_hints = {
"maximum-size" : size,
"minimum-size" : size,
"base-size" : size,
}
use_fixed_size()
screenlog("size-hints=%s", size_hints)
self._updateprop("size-hints", size_hints)

Expand Down
2 changes: 1 addition & 1 deletion src/xpra/x11/vfb_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def set_initial_resolution(desktop=False):
l("Warning: no RandR support,")
l(" default virtual display size unchanged")
return
sizes = randr.get_screen_sizes()
sizes = randr.get_xrr_screen_sizes()
size = randr.get_screen_size()
log("RandR available, current size=%s, sizes available=%s", size, sizes)
if res in sizes:
Expand Down
53 changes: 31 additions & 22 deletions src/xpra/x11/x11_server_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,29 +112,34 @@ def x11_init(self):

def init_randr(self):
self.randr = RandR.has_randr()
log("randr=%s", self.randr)
screenlog("randr=%s", self.randr)
#check the property first,
#because we may be inheriting this display,
#in which case the screen sizes list may be longer than 1
self.randr_exact_size = prop_get(self.root_window, "_XPRA_RANDR_EXACT_SIZE", "u32", ignore_errors=True, raise_xerrors=False)==1
eprop = prop_get(self.root_window, "_XPRA_RANDR_EXACT_SIZE", "u32", ignore_errors=True, raise_xerrors=False)
screenlog("_XPRA_RANDR_EXACT_SIZE=%s", eprop)
self.randr_exact_size = eprop==1
if not self.randr_exact_size:
#ugly hackish way of detecting Xvfb with randr,
#assume that it has only one resolution pre-defined:
sizes = RandR.get_screen_sizes()
sizes = RandR.get_xrr_screen_sizes()
if len(sizes)==1:
self.randr_exact_size = True
prop_set(self.root_window, "_XPRA_RANDR_EXACT_SIZE", "u32", 1)
log("randr exact size=%s", self.randr_exact_size)
if self.randr:
display = display_get_default()
i=0
while i<display.get_n_screens():
screen = display.get_screen(i)
screen.connect("size-changed", self._screen_size_changed)
i += 1
log("randr enabled: %s", self.randr)
else:
log.warn("Warning: no X11 RandR support on %s", os.environ.get("DISPLAY"))
elif len(sizes)==0:
#xwayland?
self.randr = False
self.randr_exact_size = False
screenlog("randr=%s, exact size=%s", self.randr, self.randr_exact_size)
display = display_get_default()
i=0
while i<display.get_n_screens():
screen = display.get_screen(i)
screen.connect("size-changed", self._screen_size_changed)
i += 1
screenlog("randr enabled: %s", self.randr)
if not self.randr:
screenlog.warn("Warning: no X11 RandR support on %s", os.environ.get("DISPLAY"))

def init_cursor(self):
#cursor:
Expand Down Expand Up @@ -279,8 +284,10 @@ def make_hello(self, source):
"keyboard.fast-switching" : True,
"wheel.precise" : self.pointer_device.has_precise_wheel(),
})
if self.randr and len(RandR.get_screen_sizes())>1:
capabilities["screen-sizes"] = RandR.get_screen_sizes()
if self.randr:
sizes = RandR.get_xrr_screen_sizes()
if len(sizes)>1:
capabilities["screen-sizes"] = sizes
if self.default_cursor_data and source.wants_default_cursor:
capabilities["cursor.default"] = self.default_cursor_data
return capabilities
Expand Down Expand Up @@ -329,7 +336,7 @@ def get_ui_info(self, proto, wids=None, *args):
#randr:
try:
with xsync:
sizes = RandR.get_screen_sizes()
sizes = RandR.get_xrr_screen_sizes()
if self.randr and len(sizes)>=0:
sinfo["randr"] = {
"" : True,
Expand Down Expand Up @@ -441,7 +448,7 @@ def get_cursor_data(self):

def get_max_screen_size(self):
max_w, max_h = self.root_window.get_geometry()[2:4]
sizes = RandR.get_screen_sizes()
sizes = RandR.get_xrr_screen_sizes()
if self.randr and len(sizes)>=1:
for w,h in sizes:
max_w = max(max_w, w)
Expand Down Expand Up @@ -483,7 +490,7 @@ def get_best_screen_size(self, desired_w, desired_h, bigger=True):
return self.do_get_best_screen_size(desired_w, desired_h, bigger)

def do_get_best_screen_size(self, desired_w, desired_h, bigger=True):
screen_sizes = RandR.get_screen_sizes()
screen_sizes = RandR.get_xrr_screen_sizes()
if (desired_w, desired_h) in screen_sizes:
return desired_w, desired_h
if self.randr_exact_size:
Expand All @@ -500,10 +507,12 @@ def do_get_best_screen_size(self, desired_w, desired_h, bigger=True):
except Exception as e:
screenlog.warn("Warning: failed to add resolution %ix%i:", desired_w, desired_h)
screenlog.warn(" %s", e)
#re-query:
screen_sizes = RandR.get_xrr_screen_sizes()
#try to find the best screen size to resize to:
new_size = None
closest = {}
for w,h in RandR.get_screen_sizes():
for w,h in screen_sizes:
if (w<desired_w)==bigger or (h<desired_h)==bigger:
distance = abs(w-desired_w)*abs(h-desired_h)
closest[distance] = (w, h)
Expand Down Expand Up @@ -588,7 +597,7 @@ def set_screen_size(self, desired_w, desired_h, bigger=True):
#so we temporarily switch to another resolution to force
#the change! (ugly! but this works)
temp = {}
for tw,th in RandR.get_screen_sizes():
for tw,th in RandR.get_xrr_screen_sizes():
if tw!=w or th!=h:
#use the number of extra pixels as key:
#(so we can choose the closest resolution)
Expand Down Expand Up @@ -805,7 +814,7 @@ def do_process_button_action(self, proto, wid, button, pressed, pointer, modifie
self._process_mouse_common(proto, wid, pointer, deviceid)
self.button_action(pointer, button, pressed, deviceid)

def button_action(self, pointer, button, pressed, deviceid=-1, *args):
def button_action(self, _pointer, button, pressed, deviceid=-1, *args):
device = self.pointer_device
assert device, "pointer device %s not found" % deviceid
try:
Expand Down

0 comments on commit 6d5ce09

Please sign in to comment.