Skip to content

Commit

Permalink
#794: support _NET_WM_STATE_FOCUSED forwarding from X11 clients to se…
Browse files Browse the repository at this point in the history
…rver

git-svn-id: https://xpra.org/svn/Xpra/trunk@9733 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jun 27, 2015
1 parent d072ff7 commit c776aff
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/xpra/client/client_window_base.py
Expand Up @@ -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 = {}
Expand Down
3 changes: 2 additions & 1 deletion src/xpra/client/gtk_base/gtk_client_window_base.py
Expand Up @@ -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():
Expand Down Expand Up @@ -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 = {}
Expand Down
60 changes: 39 additions & 21 deletions src/xpra/x11/gtk2/window.py
Expand Up @@ -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,
Expand Down Expand Up @@ -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 = {}
Expand Down Expand Up @@ -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")
Expand All @@ -1783,31 +1789,43 @@ 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"
return bool(self._input_field) or "WM_TAKE_FOCUS" in self.get_property("protocols")

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):
Expand Down Expand Up @@ -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:
Expand Down
18 changes: 12 additions & 6 deletions src/xpra/x11/server.py
Expand Up @@ -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
Expand Down

0 comments on commit c776aff

Please sign in to comment.