diff --git a/src/tests/xpra/test_apps/test_window_maximize.py b/src/tests/xpra/test_apps/test_window_maximize.py index 715f02e7e7..a2d2bce5d0 100755 --- a/src/tests/xpra/test_apps/test_window_maximize.py +++ b/src/tests/xpra/test_apps/test_window_maximize.py @@ -4,46 +4,52 @@ def main(): window = gtk.Window(gtk.WINDOW_TOPLEVEL) - window.set_size_request(200, 300) + window.set_size_request(200, 600) window.connect("delete_event", gtk.mainquit) vbox = gtk.VBox(False, 0) - maximize_btn = gtk.Button("maximize me") - def maximize(*args): - window.maximize() - maximize_btn.connect('clicked', maximize) - vbox.pack_start(maximize_btn, expand=False, fill=False, padding=10) + def add_buttons(t1, cb1, t2, cb2): + hbox = gtk.HBox(True, 10) + b1 = gtk.Button(t1) + def vcb1(*args): + cb1() + b1.connect('clicked', vcb1) + hbox.pack_start(b1, expand=True, fill=False, padding=5) + b2 = gtk.Button(t2) + def vcb2(*args): + cb2() + b2.connect('clicked', vcb2) + hbox.pack_start(b2, expand=True, fill=False, padding=5) + vbox.pack_start(hbox, expand=False, fill=False, padding=2) - unmaximize_btn = gtk.Button("unmaximize me") - def unmaximize(*args): - window.unmaximize() - unmaximize_btn.connect('clicked', unmaximize) - vbox.pack_start(unmaximize_btn, expand=False, fill=False, padding=10) - - fullscreen_btn = gtk.Button("fullscreen me") - def fullscreen(*args): - window.fullscreen() - fullscreen_btn.connect('clicked', fullscreen) - vbox.pack_start(fullscreen_btn, expand=False, fill=False, padding=10) - - unfullscreen_btn = gtk.Button("unfullscreen me") - def unfullscreen(*args): - window.unfullscreen() - unfullscreen_btn.connect('clicked', unfullscreen) - vbox.pack_start(unfullscreen_btn, expand=False, fill=False, padding=10) - - decorate_btn = gtk.Button("decorate me") - def decorate(*args): + add_buttons("maximize", window.maximize, "unmaximize", window.unmaximize) + add_buttons("fullscreen", window.fullscreen, "unfullscreen", window.unfullscreen) + def decorate(): window.set_decorated(True) - decorate_btn.connect('clicked', decorate) - vbox.pack_start(decorate_btn, expand=False, fill=False, padding=10) - - undecorate_btn = gtk.Button("undecorate me") - def undecorate(*args): + def undecorate(): window.set_decorated(False) - undecorate_btn.connect('clicked', undecorate) - vbox.pack_start(undecorate_btn, expand=False, fill=False, padding=10) - + add_buttons("decorate", decorate, "undecorate", undecorate) + def above(): + window.set_keep_above(True) + def notabove(): + window.set_keep_above(False) + add_buttons("keep above", above, "not above", notabove) + def below(): + window.set_keep_below(True) + def notbelow(): + window.set_keep_below(False) + add_buttons("keep below", below, "not below", notbelow) + add_buttons("stick", window.stick, "unstick", window.unstick) + def skip_pager(): + window.set_skip_pager_hint(True) + def notskip_pager(): + window.set_skip_pager_hint(False) + add_buttons("skip pager", skip_pager, "not skip pager", notskip_pager) + def skip_taskbar(): + window.set_skip_taskbar_hint(True) + def notskip_taskbar(): + window.set_skip_taskbar_hint(False) + add_buttons("skip taskbar", skip_taskbar, "not skip taskbar", notskip_taskbar) def window_state(widget, event): STATES = { diff --git a/src/xpra/client/client_window_base.py b/src/xpra/client/client_window_base.py index f6b5846e00..63844293ce 100644 --- a/src/xpra/client/client_window_base.py +++ b/src/xpra/client/client_window_base.py @@ -219,6 +219,12 @@ def metadata_replace(match): else: self.unstick() + if b"skip-taskbar" in metadata: + self.set_skip_taskbar_hint(metadata.boolget("skip-taskbar")) + + if b"skip-pager" in metadata: + self.set_skip_pager_hint(metadata.boolget("skip-pager")) + def set_size_constraints(self, size_constraints, max_window_size): self._set_initial_position = size_constraints.get("set-initial-position") diff --git a/src/xpra/client/gtk_base/gtk_client_base.py b/src/xpra/client/gtk_base/gtk_client_base.py index 5da4458ebb..bce7066627 100644 --- a/src/xpra/client/gtk_base/gtk_client_base.py +++ b/src/xpra/client/gtk_base/gtk_client_base.py @@ -227,7 +227,7 @@ def make_hello(self): icons += it.list_icons(context) log("icons: %s", icons) capabilities["theme.default.icons"] = list(set(icons)) - capabilities["window.states"] = ["fullscreen", "maximized", "sticky", "above", "below", "iconified"] + capabilities["window.states"] = ["fullscreen", "maximized", "sticky", "above", "below", "iconified", "skip-taskbar", "skip-pager"] #window icon bits capabilities["encoding.icons.greedy"] = True #we don't set a default window icon any more capabilities["encoding.icons.size"] = 64, 64 #size we want diff --git a/src/xpra/server/source.py b/src/xpra/server/source.py index d3b61157e3..ffa2aa7f3e 100644 --- a/src/xpra/server/source.py +++ b/src/xpra/server/source.py @@ -77,7 +77,7 @@ def make_window_metadata(window, propname, get_transient_for=None, get_window_id return {} elif propname == "window-type": return {"window-type" : window.get_property("window-type")} - elif propname in ("iconic", "fullscreen", "maximized", "decorations", "above", "below", "sticky"): + elif propname in ("iconic", "fullscreen", "maximized", "decorations", "above", "below", "sticky", "skip-taskbar", "skip-pager"): #always send these when requested return {propname : bool(window.get_property(propname))} elif propname in ("has-alpha", "override-redirect", "tray", "modal"): diff --git a/src/xpra/x11/gtk_x11/window.py b/src/xpra/x11/gtk_x11/window.py index 8a4869b4e9..eac603a234 100644 --- a/src/xpra/x11/gtk_x11/window.py +++ b/src/xpra/x11/gtk_x11/window.py @@ -291,6 +291,14 @@ class BaseWindowModel(AutoPropGObjectMixin, gobject.GObject): "Is the window below most windows", "", False, gobject.PARAM_READWRITE), + "skip-taskbar": (gobject.TYPE_BOOLEAN, + "Should the window be included on a taskbar", "", + False, + gobject.PARAM_READWRITE), + "skip-pager": (gobject.TYPE_BOOLEAN, + "Should the window be included on a pager", "", + False, + gobject.PARAM_READWRITE), "sticky": (gobject.TYPE_BOOLEAN, "Is the window's position fixed on the screen", "", False, @@ -620,7 +628,7 @@ def get_image(self, x, y, width, height, logger=log.debug): return None def do_xpra_client_message_event(self, event): - log.info("do_xpra_client_message_event(%s)", event) + log("do_xpra_client_message_event(%s)", event) # FIXME # Need to listen for: # _NET_CLOSE_WINDOW @@ -657,6 +665,10 @@ def update_wm_state(prop): update_wm_state("below") elif atom1=="_NET_WM_STATE_STICKY": update_wm_state("sticky") + elif atom1=="_NET_WM_STATE_SKIP_TASKBAR": + update_wm_state("skip-taskbar") + elif atom1=="_NET_WM_STATE_SKIP_PAGER": + update_wm_state("skip-pager") elif atom1 in ("_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ"): #we only have one state for both, so we require both to be set: atom2 = get_pyatom(event.window, event.data[2]) @@ -902,7 +914,7 @@ def __init__(self, parking_window, client_window): self.connect("notify::iconic", self._handle_iconic_update) self.property_names += ["title", "icon-title", "size-hints", "class-instance", "icon", "client-machine", "modal", "decorations", - "above", "below", "sticky"] + "above", "below", "sticky", "skip-taskbar", "skip-pager"] self.call_setup() def setup(self): @@ -964,7 +976,8 @@ def setup(self): self._internal_set_property("actual-size", (nw, nh)) def get_dynamic_property_names(self): - return list(BaseWindowModel.get_dynamic_property_names(self))+["icon", "icon-title", "size-hints", "iconic", "decorations", "above", "below", "sticky"] + return list(BaseWindowModel.get_dynamic_property_names(self))+["icon", "icon-title", "size-hints", "iconic", "decorations", + "above", "below", "sticky", "skip-taskbar", "skip-pager"] def is_OR(self): @@ -1505,6 +1518,8 @@ def get_default_window_icon(self): "above" : ("_NET_WM_STATE_ABOVE", ), "below" : ("_NET_WM_STATE_BELOW", ), "sticky" : ("_NET_WM_STATE_STICKY", ), + "skip-taskbar" : ("_NET_WM_STATE_SKIP_TASKBAR", ), + "skip-pager" : ("_NET_WM_STATE_SKIP_PAGER", ), } _state_properties_reversed = {}