Skip to content

Commit

Permalink
#56:
Browse files Browse the repository at this point in the history
* allow desktop windows to be resized without restrictions (when the Xvfb supports this
* keep track of the exact resize flag in an X11 environment variable to survive server upgrades and crashes
* add support for this in HTML5 client

git-svn-id: https://xpra.org/svn/Xpra/trunk@16996 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Sep 30, 2017
1 parent 66ad8ec commit 514285a
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 113 deletions.
2 changes: 2 additions & 0 deletions src/html5/js/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ XpraClient.prototype.init_state = function(container) {
this.dQ_interval_id = null;
this.process_interval = 4;

this.server_resize_exact = false;
this.server_screen_sizes = [];
this.server_is_desktop = false;

Expand Down Expand Up @@ -1663,6 +1664,7 @@ XpraClient.prototype._process_hello = function(packet, ctx) {
if (ctx.server_is_desktop) {
jQuery("body").addClass("desktop");
}
ctx.server_resize_exact = hello["resize_exact"] || false;
ctx.server_screen_sizes = hello["screen-sizes"] || [];
console.log("server screen sizes:", ctx.server_screen_sizes)

Expand Down
54 changes: 31 additions & 23 deletions src/html5/js/Window.js
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ XpraWindow.prototype.handle_moved = function(e) {
* if it is fullscreen or maximized.
*/
XpraWindow.prototype.screen_resized = function() {
console.log("screen resized");
if (this.client.server_is_desktop) {
this.match_screen_size();
this.handle_resized();
Expand All @@ -792,43 +793,50 @@ XpraWindow.prototype.screen_resized = function() {
};

XpraWindow.prototype.match_screen_size = function() {
if (this.client.server_screen_sizes.length==0) {
return;
}
//try to find the best screen size to use,
//cannot be larger than the browser area
var maxw = this.client.desktop_width;
var maxh = this.client.desktop_height;
var best = 0;
var neww = 0, newh = 0;
var w = 0, h = 0;
var screen_sizes = this.client.server_screen_sizes;
var screen_size;
for (var i = 0; i < screen_sizes.length; i++) {
screen_size = screen_sizes[i];
w = screen_size[0];
h = screen_size[1];
if (w<=maxw && h<=maxh && w*h>best) {
best = w*h;
neww = w;
newh = h;
}
if (this.client.server_resize_exact) {
neww = maxw;
newh = maxh;
console.log("resizing to exact size:", neww, newh);
}
if (neww==0 && newh==0) {
//not found, try to fine the smallest one:
best = 0;
else {
if (this.client.server_screen_sizes.length==0) {
return;
}
//try to find the best screen size to use,
//cannot be larger than the browser area
var best = 0;
var w = 0, h = 0;
var screen_sizes = this.client.server_screen_sizes;
var screen_size;
for (var i = 0; i < screen_sizes.length; i++) {
screen_size = screen_sizes[i];
w = screen_size[0];
h = screen_size[1];
if (best==0 || w*h<best) {
if (w<=maxw && h<=maxh && w*h>best) {
best = w*h;
neww = w;
newh = h;
}
}
if (neww==0 && newh==0) {
//not found, try to fine the smallest one:
best = 0;
for (var i = 0; i < screen_sizes.length; i++) {
screen_size = screen_sizes[i];
w = screen_size[0];
h = screen_size[1];
if (best==0 || w*h<best) {
best = w*h;
neww = w;
newh = h;
}
}
}
console.log("best screen size:", neww, newh);
}
console.log("best screen size:", neww, newh);
this.resize(neww, newh);
};

Expand Down
135 changes: 60 additions & 75 deletions src/xpra/x11/desktop_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import gobject
import socket

from xpra.util import updict, log_screen_sizes, envbool
from xpra.util import updict, log_screen_sizes
from xpra.os_util import get_generic_os_name
from xpra.platform.paths import get_icon
from xpra.platform.gui import get_wm_name
Expand Down Expand Up @@ -49,8 +49,6 @@

glib = import_glib()

FORCE_SCREEN_MISMATCH = envbool("XPRA_FORCE_SCREEN_MISMATCH", False)


class DesktopModel(WindowModelStub, WindowDamageHandler):
__gsignals__ = {}
Expand Down Expand Up @@ -84,14 +82,13 @@ class DesktopModel(WindowModelStub, WindowDamageHandler):
_property_names = ["xid", "client-machine", "window-type", "shadow", "size-hints", "class-instance", "focused", "title", "depth", "icon"]
_dynamic_property_names = ["size-hints", "title", "icon"]

def __init__(self, root):
def __init__(self, root, resize_exact=False):
WindowDamageHandler.__init__(self, root)
WindowModelStub.__init__(self)
self.root_prop_watcher = XRootPropWatcher(["WINDOW_MANAGER", "_NET_SUPPORTING_WM_CHECK"], root)
self.root_prop_watcher.connect("root-prop-changed", self.root_prop_changed)
self.update_icon()
self.resize_timer = None
self.resize_value = None
self.resize_exact = resize_exact

def __repr__(self):
return "DesktopModel(%#x)" % (self.client_window.xid)
Expand All @@ -114,10 +111,6 @@ def unmanage(self, exiting=False):
if rpw:
self.root_prop_watcher = None
rpw.cleanup()
rt = self.resize_timer
if rt:
self.resize_timer = None
glib.source_remove(rt)

def root_prop_changed(self, watcher, prop):
iconlog("root_prop_changed(%s, %s)", watcher, prop)
Expand Down Expand Up @@ -177,59 +170,6 @@ def get_property(self, prop):
else:
return gobject.GObject.get_property(self, prop)

def resize(self, w, h):
geomlog("resize(%i, %i)", w, h)
if not RandR.has_randr():
geomlog.error("Error: cannot honour resize request,")
geomlog.error(" not RandR support on display")
return
#FIXME: small race if the user resizes with randr,
#at the same time as he resizes the window..
self.resize_value = (w, h)
if not self.resize_timer:
self.resize_timer = glib.timeout_add(250, self.do_resize)

def do_resize(self):
self.resize_timer = None
try:
w, h = self.resize_value
with xsync:
screen_sizes = RandR.get_screen_sizes()
#hack: force mistmatch
if FORCE_SCREEN_MISMATCH:
screen_sizes = [(sw,sh) for sw,sh in screen_sizes if (sw!=w and sh!=h)]
geomlog("screen sizes=%s", screen_sizes)
if (w,h) not in screen_sizes:
geomlog.warn("Warning: invalid screen size %ix%i", w, h)
#find the nearest:
distances = {}
lower_distances = {} #for sizes lower than requested
for sw, sh in screen_sizes:
distance = abs(sw*sh - w*h)
distances.setdefault(distance, []).append((sw, sh))
if sw<=w and sh<=h:
lower_distances.setdefault(distance, []).append((sw, sh))
geomlog("lower distances=%s", distances)
if lower_distances:
nearest = lower_distances[sorted(lower_distances.keys())[0]]
else:
geomlog("distances=%s", distances)
nearest = distances[sorted(distances.keys())[0]]
geomlog("nearest matches: %s", nearest)
w, h = nearest[0]
geomlog.warn(" using %ix%i instead", w, h)
if RandR.get_screen_size()==(w,h):
#this is already the resolution we have,
#but the client has other ideas,
#so tell the client we ain't budging:
self.emit("resized")
return
RandR.set_screen_size(w, h)
except Exception as e:
geomlog("resize(%i, %i)", w, h, exc_info=True)
geomlog.error("Error: failed to resize desktop display to %ix%i:", w, h)
geomlog.error(" %s", e)

def _screen_size_changed(self, screen):
w, h = screen.get_width(), screen.get_height()
screenlog("screen size changed: new size %ix%i", w, h)
Expand All @@ -242,16 +182,21 @@ def update_size_hints(self, screen):
w, h = screen.get_width(), screen.get_height()
screenlog("screen dimensions: %ix%i", w, h)
if RandR.has_randr():
#TODO: get all of this from randr:
#screen_sizes = RandR.get_screen_sizes()
size_hints = {
"maximum-size" : (8192, 4096),
"minimum-size" : (640, 640),
"base-size" : (640, 640),
"increment" : (128, 128),
"minimum-aspect-ratio" : (1, 3),
"maximum-aspect-ratio" : (3, 1),
}
if self.resize_exact:
#assume resize_excact is enabled
#no size restrictions
size_hints = {}
else:
#TODO: get all of this from randr:
#screen_sizes = RandR.get_screen_sizes()
size_hints = {
"maximum-size" : (8192, 4096),
"minimum-size" : (640, 640),
"base-size" : (640, 640),
"increment" : (128, 128),
"minimum-aspect-ratio" : (1, 3),
"maximum-aspect-ratio" : (3, 1),
}
else:
size = w, h
size_hints = {
Expand Down Expand Up @@ -283,6 +228,8 @@ def __init__(self):
gobject.GObject.__init__(self)
X11ServerBase.__init__(self)
self.session_type = "desktop"
self.resize_timer = None
self.resize_value = None

def init(self, opts):
X11ServerBase.init(self, opts)
Expand All @@ -303,6 +250,7 @@ def x11_init(self):
X11Keyboard.selectBellNotification(True)

def do_cleanup(self):
self.cancel_resize_timer()
X11ServerBase.do_cleanup(self)
remove_catchall_receiver("xpra-motion-event", self)
cleanup_x11_filter()
Expand Down Expand Up @@ -347,6 +295,43 @@ def configure_best_screen_size(self):
return root_w, root_h
return self.set_screen_size(w, h)

def cancel_resize_timer(self):
rt = self.resize_timer
if rt:
self.resize_timer = None
glib.source_remove(rt)

def resize(self, w, h):
geomlog("resize(%i, %i)", w, h)
if not RandR.has_randr():
geomlog.error("Error: cannot honour resize request,")
geomlog.error(" no RandR support on this display")
return
#FIXME: small race if the user resizes with randr,
#at the same time as he resizes the window..
self.resize_value = (w, h)
if not self.resize_timer:
self.resize_timer = glib.timeout_add(250, self.do_resize)

def do_resize(self):
self.resize_timer = None
rw, rh = self.resize_value
try:
with xsync:
ow, oh = RandR.get_screen_size()
w, h = self.set_screen_size(rw, rh)
if (ow, oh) == (w, h):
#this is already the resolution we have,
#but the client has other ideas,
#so tell the client we ain't budging:
for win in self._window_to_id.keys():
win.emit("resized")
except Exception as e:
geomlog("do_resize() %ix%i", rw, rh, exc_info=True)
geomlog.error("Error: failed to resize desktop display to %ix%i:", rw, rh)
geomlog.error(" %s", e)


def set_desktop_geometry_attributes(self, w, h):
#geometry is not synced with the client's for desktop servers
pass
Expand Down Expand Up @@ -380,7 +365,7 @@ def load_existing_windows(self):
for n in range(screens):
screen = display.get_screen(n)
root = screen.get_root_window()
model = DesktopModel(root)
model = DesktopModel(root, self.randr_exact_size)
model.setup()
windowlog("adding root window model %s", model)
X11ServerBase._add_new_window_common(self, model)
Expand Down Expand Up @@ -498,7 +483,7 @@ def _process_configure_window(self, proto, packet):
if not skip_geometry:
owx, owy, oww, owh = window.get_geometry()
geomlog("_process_configure_window(%s) old window geometry: %s", packet[1:], (owx, owy, oww, owh))
window.resize(w, h)
self.resize(w, h)
if len(packet)>=7:
cprops = packet[6]
if cprops:
Expand Down
Loading

0 comments on commit 514285a

Please sign in to comment.