From 42b383703538e379a0bd89db89618f54494bda9a Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Mon, 12 Sep 2016 09:00:32 +0000 Subject: [PATCH] #1284: clamp OR windows to the monitors we have git-svn-id: https://xpra.org/svn/Xpra/trunk@13669 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- .../client/gtk_base/gtk_client_window_base.py | 67 ++++++++++++++++++- src/xpra/client/ui_client_base.py | 3 + 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/xpra/client/gtk_base/gtk_client_window_base.py b/src/xpra/client/gtk_base/gtk_client_window_base.py index 52deb08b95..cae62fa328 100644 --- a/src/xpra/client/gtk_base/gtk_client_window_base.py +++ b/src/xpra/client/gtk_base/gtk_client_window_base.py @@ -145,6 +145,7 @@ def init_window(self, metadata): self._current_frame_extents = None self._screen = -1 self._frozen = False + self.OR_offset = None #add platform hooks self.on_realize_cb = {} self.connect_after("realize", self.on_realize) @@ -275,8 +276,16 @@ def focus_out(*args): #try to honour the initial position geomlog("setup_window() position=%s, set_initial_position=%s, OR=%s, decorated=%s", self._pos, self._set_initial_position, self.is_OR(), self.get_decorated()) - if self._pos!=(0, 0) or self._set_initial_position: + if self._pos!=(0, 0) or self._set_initial_position or self.is_OR(): x,y = self._pos + if self.is_OR(): + #make sure OR windows are mapped on screen + if self._client._current_screen_sizes: + w, h = self._size + self.OR_offset = self.calculate_OR_offset(x, y, w, h) + if self.OR_offset: + x += self.OR_offset[0] + y += self.OR_offset[1] if not self.is_OR() and self.get_decorated(): #try to adjust for window frame size if we can figure it out: #Note: we cannot just call self.get_window_frame_size() here because @@ -296,6 +305,51 @@ def focus_out(*args): self.move(x, y) self.set_default_size(*self._size) + def calculate_OR_offset(self, wx, wy, ww, wh): + ss = self._client._current_screen_sizes + if not ss: + return None + if len(ss)!=1: + geomlog("cannot handle one more than one screen for OR offset: %s", ) + return None + screen0 = ss[0] + monitors = screen0[5] + if not monitors: + geomlog("screen %s lacks monitors information: %s", screen0) + return None + distances = {} + for i, monitor in enumerate(monitors): + plug_name, x, y, w, h = monitor[:5] + if wx>=x and wx+ww<=x+w and wy+wh<=y+h: + geomlog("window fits in monitor %i: %s", i, plug_name) + return None + xdists = (wx-x, wx+ww-x, wx-(x+w), wx+ww-(x+w)) + ydists = (wy-y, wy+wh-y, wy-(y+h), wy+wh-(y+h)) + distance = min((abs(v) for v in xdists))+min((abs(v) for v in ydists)) + distances[distance] = i + #so it doesn't fit... choose the closest monitor and make it fit + geomlog("OR window distances: %s", distances) + closest = min(distances.keys()) + i = distances[closest] + monitor = monitors[i] + plug_name, x, y, w, h = monitor[:5] + geomlog("calculating OR offset for monitor %i: %s", i, plug_name) + if ww>w or wh>=h: + geomlog("window %ix%i is bigger than the monitor %i: %s %ix%i, not adjusting it", ww, wh, i, plug_name, w, h) + return None + dx = 0 + dy = 0 + if wxx+w: + dx = (x+w) - (wx+ww) + if wyy+h: + dy = (y+h) - (wy+wh) + assert dx!=0 or dy!=0 + geomlog("calculate_OR_offset%s=%s", (wx, wy, ww, wh), (dx, dy)) + return dx, dy def when_realized(self, identifier, callback, *args): if self.is_realized(): @@ -1040,6 +1094,10 @@ def move_resize(self, x, y, w, h, resize_counter=0): geomlog("window %i move_resize%s", self._id, (x, y, w, h, resize_counter)) w = max(1, w) h = max(1, h) + if self.OR_offset: + x += self.OR_offset[0] + y += self.OR_offset[1] + #TODO: check this doesn't move it off-screen! self._resize_counter = resize_counter window = self.get_window() if window.get_position()==(x, y): @@ -1110,7 +1168,12 @@ def do_delete_event(self, event): def _pointer_modifiers(self, event): - pointer = self._client.cp(event.x_root, event.y_root) + x = event.x_root + y = event.y_root + if self.OR_offset: + x -= self.OR_offset[0] + y -= self.OR_offset[1] + pointer = self._client.cp(x, y) modifiers = self._client.mask_to_names(event.state) buttons = [] for mask, button in self.BUTTON_MASK.items(): diff --git a/src/xpra/client/ui_client_base.py b/src/xpra/client/ui_client_base.py index b2c277d6c9..ca31d92992 100644 --- a/src/xpra/client/ui_client_base.py +++ b/src/xpra/client/ui_client_base.py @@ -303,6 +303,7 @@ def __init__(self): self._suspended_at = 0 self._button_state = {} self._on_handshake = [] + self._current_screen_sizes = None self.init_aliases() @@ -987,6 +988,7 @@ def update_screen_size(self): self.screen_size_change_pending = False u_root_w, u_root_h = self.get_root_size() root_w, root_h = self.cp(u_root_w, u_root_h) + self._current_screen_sizes = self.get_screen_sizes() sss = self.get_screen_sizes(self.xscale, self.yscale) ndesktops = get_number_of_desktops() desktop_names = get_desktop_names() @@ -1330,6 +1332,7 @@ def make_hello(self): desktop_names = get_desktop_names() capabilities["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: