Skip to content

Commit

Permalink
#790: fix bug in computation of state updates dict (was always using …
Browse files Browse the repository at this point in the history
…a boolean value as key..) and add support for more states client side by watching the _NET_WM_STATE changes, server-side now also forwards most of these updates to the window model (and therefor to the application via the _NET_WM_STATE property changes

git-svn-id: https://xpra.org/svn/Xpra/trunk@8802 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Mar 19, 2015
1 parent 5e99a52 commit c291c05
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
13 changes: 11 additions & 2 deletions src/xpra/client/client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ def __init__(self, client, group_leader, wid, x, y, w, h, metadata, override_red
self._below = False
self._shaded = False
self._sticky = False
self._skip_pager = False
self._skip_taskbar = False
self._sticky = False
self._iconified = False
self.border = border
self.max_window_size = max_window_size
Expand Down Expand Up @@ -269,10 +272,16 @@ def metadata_replace(match):
self.unstick()

if b"skip-taskbar" in metadata:
self.set_skip_taskbar_hint(metadata.boolget("skip-taskbar"))
skip_taskbar = metadata.boolget("skip-taskbar")
if self._skip_taskbar!=skip_taskbar:
self._skip_taskbar = skip_taskbar
self.set_skip_taskbar_hint(skip_taskbar)

if b"skip-pager" in metadata:
self.set_skip_pager_hint(metadata.boolget("skip-pager"))
skip_pager = metadata.boolget("skip-pager")
if self._skip_pager!=skip_pager:
self._skip_pager = skip_pager
self.set_skip_taskbar_hint(skip_pager)

if b"workspace" in metadata:
self.set_workspace(metadata.intget("workspace"))
Expand Down
45 changes: 38 additions & 7 deletions src/xpra/client/gtk_base/gtk_client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,25 +237,31 @@ def window_state_updated(self, widget, event):
state_updates["below"] = bool(event.new_window_state & self.WINDOW_STATE_BELOW)
if event.changed_mask & self.WINDOW_STATE_STICKY:
state_updates["sticky"] = bool(event.new_window_state & self.WINDOW_STATE_STICKY)
if event.changed_mask & self.WINDOW_STATE_ICONIFIED:
state_updates["iconified"] = bool(event.new_window_state & self.WINDOW_STATE_ICONIFIED)
if event.changed_mask & self.WINDOW_STATE_MAXIMIZED:
#this may get sent now as part of map_event code below (and it is irrelevant for the unmap case),
#or when we get the configure event - which should come straight after
#if we're changing the maximized state
state_updates["maximized"] = bool(event.new_window_state & self.WINDOW_STATE_MAXIMIZED)
self.update_window_state(state_updates)

def update_window_state(self, state_updates):
#decide if this is really an update by comparing with our local state vars:
#(could just be a notification of a state change we already know about)
actual_updates = {}
for var,value in state_updates.items():
cur = getattr(self, "_%s" % var) #ie: self._maximized
for state,value in state_updates.items():
var = "_" + state.replace("-", "_") #ie: "skip-pager" -> "_skip_pager"
cur = getattr(self, var) #ie: self._maximized
if cur!=value:
setattr(self, "_%s" % var, value) #ie: self._maximized = True
actual_updates[cur] = value
setattr(self, var, value) #ie: self._maximized = True
actual_updates[state] = value
statelog("%s=%s (was %s)", var, value, cur)
statelog("window_state_updated(..) state updates: %s, actual updates: %s", state_updates, actual_updates)
self._window_state.update(actual_updates)
#iconification is handled a bit differently...
if event.changed_mask & self.WINDOW_STATE_ICONIFIED:
iconified = bool(event.new_window_state & self.WINDOW_STATE_ICONIFIED)
if "iconified" in actual_updates:
iconified = actual_updates.get("iconified")
statelog("iconified=%s (was %s)", iconified, self._iconified)
if iconified!=self._iconified:
self._iconified = iconified
Expand Down Expand Up @@ -399,7 +405,32 @@ def property_changed(self, widget, event):
#unused for now, but log it:
xklavier_state = prop_get(self.get_window(), "XKLAVIER_STATE", ["integer"], ignore_errors=False)
keylog("XKLAVIER_STATE=%s", [hex(x) for x in (xklavier_state or [])])

elif event.atom=="_NET_WM_STATE":
wm_state_atoms = prop_get(self.get_window(), "_NET_WM_STATE", ["atom"], ignore_errors=False)
#code mostly duplicated from gtk_x11/window.py:
WM_STATE_NAME = {
"fullscreen" : ("_NET_WM_STATE_FULLSCREEN", ),
"maximized" : ("_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ"),
"shaded" : ("_NET_WM_STATE_SHADED", ),
"sticky" : ("_NET_WM_STATE_STICKY", ),
"skip-pager" : ("_NET_WM_STATE_SKIP_PAGER", ),
"skip-taskbar" : ("_NET_WM_STATE_SKIP_TASKBAR", ),
"above" : ("_NET_WM_STATE_ABOVE", ),
"below" : ("_NET_WM_STATE_BELOW", ),
}
state_atoms = set(wm_state_atoms)
state_updates = {}
for state, atoms in WM_STATE_NAME.items():
var = "_" + state.replace("-", "_") #ie: "skip-pager" -> "_skip_pager"
cur_state = getattr(self, var)
wm_state_is_set = set(atoms).issubset(state_atoms)
if wm_state_is_set and not cur_state:
state_updates[state] = True
elif cur_state and not wm_state_is_set:
state_updates[state] = False
log("_NET_WM_STATE=%s, state_updates=%s", wm_state_atoms, state_updates)
if state_updates:
self.update_window_state(state_updates)

def workspace_changed(self):
#on X11 clients, this fires from the root window property watcher
Expand Down
14 changes: 7 additions & 7 deletions src/xpra/x11/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,13 +697,13 @@ def _raised_window(self, window, event):


def _set_window_state(self, proto, wid, window, new_window_state):
#only used for setting maximized state:
if "maximized" in new_window_state:
new_state = bool(new_window_state.get("maximized", False))
cur_state = bool(window.get_property("maximized"))
if cur_state!=new_state:
window.set_property("maximized", new_state)
#TODO: also sync "above", "below", "sticky" and "fullscreen"
for k in ("maximized", "above", "below", "fullscreen", "sticky", "shaded", "skip-pager", "skip-taskbar"):
if k in new_window_state:
new_state = bool(new_window_state.get(k, False))
cur_state = bool(window.get_property(k))
log("set window state for '%s': current state=%s, new state=%s", k, cur_state, new_state)
if cur_state!=new_state:
window.set_property(k, new_state)

def _process_map_window(self, proto, packet):
wid, x, y, width, height = packet[1:6]
Expand Down

0 comments on commit c291c05

Please sign in to comment.