Skip to content

Commit

Permalink
#976: better and cleaner workspace code
Browse files Browse the repository at this point in the history
* better debug logging
* don't use on-realize
* always wait for map event to send the window manager message
* never modify _NET_WM_DESKTOP ourselves

git-svn-id: https://xpra.org/svn/Xpra/trunk@10972 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Oct 22, 2015
1 parent 44eda91 commit a2468b8
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 46 deletions.
13 changes: 8 additions & 5 deletions src/xpra/client/gtk2/gtk2_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@

from xpra.client.gtk_base.gtk_client_window_base import GTKClientWindowBase, HAS_X11_BINDINGS
from xpra.gtk_common.gtk_util import WINDOW_NAME_TO_HINT, WINDOW_EVENT_MASK, BUTTON_MASK
from xpra.util import WORKSPACE_UNSET
from xpra.util import WORKSPACE_UNSET, WORKSPACE_NAMES

def wn(w):
return WORKSPACE_NAMES.get(w, w)


GTK2_OR_TYPE_HINTS = (gdk.WINDOW_TYPE_HINT_DIALOG,
Expand Down Expand Up @@ -126,16 +129,16 @@ def get_window_workspace(self):

def do_get_workspace(self, target, prop, default_value=None):
if not self._can_set_workspace:
workspacelog("do_get_workspace: not supported, returning %s", default_value)
workspacelog("do_get_workspace: not supported, returning %s", wn(default_value))
return default_value #windows and OSX do not have workspaces
if target is None:
workspacelog("do_get_workspace: target is None, returning %s", default_value)
workspacelog("do_get_workspace: target is None, returning %s", wn(default_value))
return default_value #window is not realized yet
value = self.xget_u32_property(target, prop)
if value is not None:
workspacelog("do_get_workspace %s=%s on window %#x", prop, value, target.xid)
workspacelog("do_get_workspace %s=%s on window %#x", prop, wn(value), target.xid)
return value
workspacelog("do_get_workspace %s unset on window %#x, returning default value=%s", prop, target.xid, default_value)
workspacelog("do_get_workspace %s unset on window %#x, returning default value=%s", prop, target.xid, wn(default_value))
return default_value


Expand Down
82 changes: 41 additions & 41 deletions src/xpra/client/gtk_base/gtk_client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
from xpra.x11.gtk_x11.prop import prop_get, prop_set
from xpra.x11.bindings.window_bindings import constants, X11WindowBindings, SHAPE_KIND #@UnresolvedImport
from xpra.x11.bindings.core_bindings import X11CoreBindings
from xpra.gtk_common.error import xsync, xswallow
from xpra.gtk_common.error import xsync
from xpra.x11.gtk_x11.send_wm import send_wm_workspace
X11Window = X11WindowBindings()
X11Core = X11CoreBindings()
Expand Down Expand Up @@ -272,7 +272,7 @@ def when_realized(self, identifier, callback, *args):
self.on_realize_cb[identifier] = callback, args

def on_realize(self, widget):
eventslog("on_realize(%s) gdk window=%s", widget, self.get_window())
eventslog("on_realize(%s) gdk window=%#x", widget, get_xid(self.get_window()))
add_window_hooks(self)
cb = self.on_realize_cb
self.on_realize_cb = {}
Expand Down Expand Up @@ -694,48 +694,44 @@ def do_workspace_changed(self, info):

def get_workspace_count(self):
if not HAS_X11_BINDINGS:
return 1
return None
return self.xget_u32_property(root, "_NET_NUMBER_OF_DESKTOPS")


def set_workspace(self, workspace):
if not self._can_set_workspace:
return None
workspacelog("set_workspace(%s)", workspace)
if not self._been_mapped:
#will be dealt with in the map event handler
#which will look at the window metadata again
workspacelog("workspace=%s will be set when the window is mapped", wn(workspace))
return
desktop = self.get_desktop_workspace()
if self._been_mapped and (workspace==desktop or desktop is None):
ndesktops = self.get_workspace_count()
current = self.get_window_workspace()
workspacelog("set_workspace(%s) realized=%s, current workspace=%s, detected=%s, desktop workspace=%s, ndesktops=%s",
wn(workspace), self.is_realized(), wn(self._window_workspace), wn(current), wn(desktop), ndesktops)
if not self._can_set_workspace or ndesktops is None:
return None
if workspace==desktop or workspace==WORKSPACE_ALL or desktop is None:
#window is back in view
self._client.control_refresh(self._id, False, False)
if workspace<0:
#this should not happen, workspace is unsigned! (CARDINAL)
workspacelog.warn("invalid workspace number: %s", wn(workspace))
if (workspace<0 or workspace>=ndesktops) and workspace not in(WORKSPACE_UNSET, WORKSPACE_ALL):
#this should not happen, workspace is unsigned (CARDINAL)
#and the server should have the same list of desktops that we have here
workspacelog.warn("Warning: invalid workspace number: %s", wn(workspace))
workspace = WORKSPACE_UNSET
self.when_realized("workspace", self.do_set_workspace, workspace)

def do_set_workspace(self, workspace):
#we will need the gdk window:
gdkwin = self.get_window()
ndesktops = self.get_workspace_count()
if ndesktops is None or ndesktops<=1:
workspacelog("number of desktops not defined, cannot set workspace")
return None
if workspace==WORKSPACE_UNSET:
#we want to remove the setting, so access the window property directly:
self._window_workspace = WORKSPACE_UNSET
xid = get_xid(gdkwin)
with xswallow:
X11Window.XDeleteProperty(xid, "_NET_WM_DESKTOP")
#we cannot unset via send_wm_workspace, so we have to choose one:
workspace = self.get_desktop_workspace()
if workspace in (None, WORKSPACE_UNSET):
workspacelog.warn("workspace=%s (doing nothing)", wn(workspace))
return
#clamp to number of workspaces just in case we have a mismatch:
if workspace==WORKSPACE_ALL:
workspace = WORKSPACE_ALL
else:
workspace = max(0, min(ndesktops-1, workspace))
workspacelog("%s.set_workspace() ndesktops=%i, clamped workspace=%s", self, ndesktops, wn(self._window_workspace))
if not gdkwin.is_visible():
#window is unmapped so we can set the window property directly:
prop_set(gdkwin, "_NET_WM_DESKTOP", "u32", workspace)
self._window_workspace = workspace
#we will need the gdk window:
if current==workspace:
workspacelog("window workspace unchanged: %s", wn(workspace))
return
#the window is visible, so we have to ask the window manager politely
gdkwin = self.get_window()
workspacelog("do_set_workspace: gdkwindow: %#x, mapped=%s, visible=%s", gdkwin.xid, self.is_mapped(), gdkwin.is_visible())
with xsync:
send_wm_workspace(root, gdkwin, workspace)

Expand Down Expand Up @@ -828,25 +824,29 @@ def do_map_event(self, event):
gtk.Window.do_map_event(self, event)
if not self._override_redirect:
self.process_map_event()
self._been_mapped = True

def process_map_event(self):
x, y, w, h = self.get_window_geometry()
state = self._window_state
props = self._client_properties
self._client_properties = {}
self._window_state = {}
workspace = None
workspace = self.get_window_workspace()
workspacelog("process_map_event() workspace=%s, been_mapped=%s", workspace, self._been_mapped)
if self._been_mapped:
props["screen"] = self.get_screen().get_number()
workspace = self.get_window_workspace()
if workspace is None:
#not set, so assume it is on the current workspace:
workspace = self.get_desktop_workspace()
if self._window_workspace!=workspace and workspace is not None:
workspacelog("map event: been_mapped=%s, changed workspace from %s to %s", self._been_mapped, wn(self._window_workspace), wn(workspace))
self._window_workspace = workspace
props["workspace"] = workspace
else:
self._been_mapped = True
workspace = self._metadata.intget("workspace", -1)
self.set_workspace(workspace)
if self._window_workspace!=workspace and workspace is not None:
workspacelog("map event: been_mapped=%s, changed workspace from %s to %s", self._been_mapped, wn(self._window_workspace), wn(workspace))
self._window_workspace = workspace
if workspace is not None:
props["workspace"] = workspace
if self._client.server_window_frame_extents and "frame" not in state:
wfs = self.get_window_frame_size()
if wfs:
Expand Down

0 comments on commit a2468b8

Please sign in to comment.