From c776aff855cc491f350fff076614eb55b8033a7c Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Sat, 27 Jun 2015 11:46:15 +0000 Subject: [PATCH] #794: support _NET_WM_STATE_FOCUSED forwarding from X11 clients to server git-svn-id: https://xpra.org/svn/Xpra/trunk@9733 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- src/xpra/client/client_window_base.py | 1 + .../client/gtk_base/gtk_client_window_base.py | 3 +- src/xpra/x11/gtk2/window.py | 60 ++++++++++++------- src/xpra/x11/server.py | 18 ++++-- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/xpra/client/client_window_base.py b/src/xpra/client/client_window_base.py index 97b5e92cc0..5333d207c9 100644 --- a/src/xpra/client/client_window_base.py +++ b/src/xpra/client/client_window_base.py @@ -42,6 +42,7 @@ def __init__(self, client, group_leader, wid, x, y, w, h, metadata, override_red self._skip_taskbar = False self._sticky = False self._iconified = False + self._focused = False self.border = border self.max_window_size = max_window_size self.button_state = {} 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 48f58bfede..3d2413e4d2 100644 --- a/src/xpra/client/gtk_base/gtk_client_window_base.py +++ b/src/xpra/client/gtk_base/gtk_client_window_base.py @@ -328,7 +328,7 @@ def tell_server(): #if we have state updates, send them back to the server using a configure window packet: if self.is_OR() and not self._client.window_configure_skip_geometry: #we can't do it: the server can't handle configure packets for OR windows! - log("not sending updated window state %s to a server which is missing the configure skip-geometry feature", self._window_state) + statelog("not sending updated window state %s to a server which is missing the configure skip-geometry feature", self._window_state) return def send_updated_window_state(): if self._window_state and self.get_window(): @@ -517,6 +517,7 @@ def property_changed(self, widget, event): "skip-taskbar" : ("_NET_WM_STATE_SKIP_TASKBAR", ), "above" : ("_NET_WM_STATE_ABOVE", ), "below" : ("_NET_WM_STATE_BELOW", ), + "focused" : ("_NET_WM_STATE_FOCUSED", ), } state_atoms = set(wm_state_atoms) state_updates = {} diff --git a/src/xpra/x11/gtk2/window.py b/src/xpra/x11/gtk2/window.py index 188ea5d67c..80ffac9983 100644 --- a/src/xpra/x11/gtk2/window.py +++ b/src/xpra/x11/gtk2/window.py @@ -314,13 +314,17 @@ class BaseWindowModel(AutoPropGObjectMixin, gobject.GObject): "hint that the window would benefit from running uncomposited ", "", 0, 2, 0, gobject.PARAM_READABLE), + "fullscreen-monitors": (gobject.TYPE_PYOBJECT, + "List of 4 monitor indices indicating the top, bottom, left, and right edges of the window when the fullscreen state is enabled", "", + gobject.PARAM_READABLE), "fullscreen": (gobject.TYPE_BOOLEAN, "Fullscreen-ness of window", "", False, gobject.PARAM_READWRITE), - "fullscreen-monitors": (gobject.TYPE_PYOBJECT, - "List of 4 monitor indices indicating the top, bottom, left, and right edges of the window when the fullscreen state is enabled", "", - gobject.PARAM_READABLE), + "focused": (gobject.TYPE_BOOLEAN, + "Is the window focused", "", + False, + gobject.PARAM_READWRITE), "maximized": (gobject.TYPE_BOOLEAN, "Is the window maximized", "", False, @@ -1729,6 +1733,7 @@ def get_default_window_icon(self): "skip-taskbar" : ("_NET_WM_STATE_SKIP_TASKBAR", ), "skip-pager" : ("_NET_WM_STATE_SKIP_PAGER", ), "modal" : ("_NET_WM_STATE_MODAL", ), + "focused" : ("_NET_WM_STATE_FOCUSED", ), } _state_properties_reversed = {} @@ -1768,8 +1773,9 @@ def _state_isset(self, state_name): def _handle_state_changed(self, *args): # Sync changes to "state" property out to X property. with xswallow: - prop_set(self.client_window, "_NET_WM_STATE", - ["atom"], self.get_property("state")) + wm_state = list(self.get_property("state")) + prop_set(self.client_window, "_NET_WM_STATE", ["atom"], wm_state) + log("_handle_state_changed: _NET_WM_STATE=%s", wm_state) def _handle_frame_changed(self, *args): v = self.get_property("frame") @@ -1783,16 +1789,22 @@ def _handle_frame_changed(self, *args): with xswallow: prop_set(self.client_window, "_NET_FRAME_EXTENTS", ["u32"], v) - def do_set_property(self, pspec, value): if pspec.name in self._state_properties: - state_names = self._state_properties[pspec.name] - if value: - self._state_add(*state_names) - else: - self._state_remove(*state_names) + #virtual property for WM_STATE: + self.update_state(pspec.name, value) + return + AutoPropGObjectMixin.do_set_property(self, pspec, value) + + def update_wm_state(self, prop, b): + state_names = self._state_properties.get(prop) + assert state_names, "invalid window state %s" % prop + log("update_wm_state(%s, %s) state_names=%s", prop, b, state_names) + if b: + self._state_add(*state_names) else: - AutoPropGObjectMixin.do_set_property(self, pspec, value) + self._state_remove(*state_names) + def do_get_property_can_focus(self, name): assert name == "can-focus" @@ -1800,14 +1812,20 @@ def do_get_property_can_focus(self, name): def do_get_property(self, pspec): if pspec.name in self._state_properties: - #return True if any is set (only relevant for maximized) - state_names = self._state_properties[pspec.name] - for x in state_names: - if self._state_isset(x): - return True - return False - else: - return AutoPropGObjectMixin.do_get_property(self, pspec) + #virtual property for WM_STATE: + return self.get_wm_state(pspec.name) + return AutoPropGObjectMixin.do_get_property(self, pspec) + + def get_wm_state(self, prop): + state_names = self._state_properties.get(prop) + assert state_names, "invalid window state %s" % prop + log("get_wm_state(%s) state_names=%s", prop, state_names) + #this is a virtual property for WM_STATE: + #return True if any is set (only relevant for maximized) + for x in state_names: + if self._state_isset(x): + return True + return False def unmap(self): @@ -1851,7 +1869,7 @@ def _write_initial_properties_and_setup(self): ################################ def give_client_focus(self): - """The focus manager has decided that our client should recieve X + """The focus manager has decided that our client should receive X focus. See world_window.py for details.""" if self.corral_window: with xswallow: diff --git a/src/xpra/x11/server.py b/src/xpra/x11/server.py index 245faaa6a3..a871f42533 100644 --- a/src/xpra/x11/server.py +++ b/src/xpra/x11/server.py @@ -714,15 +714,21 @@ def _set_window_state(self, proto, wid, window, new_window_state): #the size of the window frame may have changed frame = new_window_state.get("frame") or (0, 0, 0, 0) window.set_property("frame", frame) - for k in ("maximized", "above", "below", "fullscreen", "sticky", "shaded", "skip-pager", "skip-taskbar", "iconified"): + #boolean: but not a wm_state and renamed in the model... (iconic vs inconified!) + iconified = new_window_state.get("iconified") + if iconified is not None: + if window.get_property("iconic")!=bool(iconified): + window.set_property("iconic", iconified) + changes.append("iconified") + #handle wm_state virtual booleans: + for k in ("maximized", "above", "below", "fullscreen", "sticky", "shaded", "skip-pager", "skip-taskbar", "focused"): if k in new_window_state: - #stupid naming conflict (should have used the same at both ends): - wpropname = {"iconified" : "iconic"}.get(k, k) + #metadatalog.info("window.get_property=%s", window.get_property) new_state = bool(new_window_state.get(k, False)) - cur_state = bool(window.get_property(wpropname)) - metadatalog("set window state for '%s': current state=%s, new state=%s", k, cur_state, new_state) + cur_state = bool(window.get_property(k)) + #metadatalog.info("set window state for '%s': current state=%s, new state=%s", k, cur_state, new_state) if cur_state!=new_state: - window.set_property(wpropname, new_state) + window.update_wm_state(k, new_state) changes.append(k) metadatalog("set_window_state: changes=%s", changes) return changes