Repository: qtile/qtile

Issue:
Floating window always shows in the desktop whare they are opened first time
Floating window, albert or kcalc, in this case, always open in the desktop where they was opened first.
For example if I open a float in desktop 1 and then switch to desktop 4 and try to reopen that float it doesn't display but if I switch back to desktop 1 I can see that floating window.


Discussion:
I can confirm.
I don't know about floats, but when I launch albert for the first time after start up it will always show up on the same workspace afterwards.
Reproduce:
Step 1 : launch albert with hotkey on workspace 1
Step 2 : launch program with albert
Step 3 : change to workspace 2
Step 4 : launch albert with hotkey, nothings appears to happen on workspace 2
Step 5 : change to workspace 1, notice albert.
Yeah! It's annoying.
Any progress on this?

Workaround: For ulauncher, you can set the toggle binding from it's settings. Works properly for me this way.

Resolving patch:
diff --git a/libqtile/backend/x11/core.py b/libqtile/backend/x11/core.py
--- a/libqtile/backend/x11/core.py
+++ b/libqtile/backend/x11/core.py
@@ -106,16 +106,15 @@ def __init__(self, display_name: str = None) -> None:
                 logger.error("not starting; existing window manager {}".format(existing_wmname))
                 raise ExistingWMException(existing_wmname)
 
-        self._root.set_attribute(
-            eventmask=(
-                EventMask.StructureNotify
-                | EventMask.SubstructureNotify
-                | EventMask.SubstructureRedirect
-                | EventMask.EnterWindow
-                | EventMask.LeaveWindow
-                | EventMask.ButtonPress
-            )
+        self.eventmask = (
+            EventMask.StructureNotify
+            | EventMask.SubstructureNotify
+            | EventMask.SubstructureRedirect
+            | EventMask.EnterWindow
+            | EventMask.LeaveWindow
+            | EventMask.ButtonPress
         )
+        self._root.set_attribute(eventmask=self.eventmask)
 
         self._root.set_property(
             "_NET_SUPPORTED", [self.conn.atoms[x] for x in xcbq.SUPPORTED_ATOMS]
@@ -692,26 +691,42 @@ def handle_DestroyNotify(self, event) -> None:  # noqa: N802
     def handle_UnmapNotify(self, event) -> None:  # noqa: N802
         assert self.qtile is not None
 
-        if event.event != self._root.wid:
-            win = self.qtile.windows_map.get(event.window)
-            if win and getattr(win, "group", None):
-                try:
-                    win.hide()
-                    assert isinstance(win, window._Window)
-                    win.state = window.WithdrawnState
-                except xcffib.xproto.WindowError:
-                    # This means that the window has probably been destroyed,
-                    # but we haven't yet seen the DestroyNotify (it is likely
-                    # next in the queue). So, we just let these errors pass
-                    # since the window is dead.
-                    pass
-            self.qtile.unmanage(event.window)
-            if self.qtile.current_window is None:
-                self.conn.fixup_focus()
+        win = self.qtile.windows_map.get(event.window)
+        assert isinstance(win, (window.Window, window.Static))
+
+        if win and getattr(win, "group", None):
+            try:
+                win.hide()
+                assert isinstance(win, window._Window)
+                win.state = window.WithdrawnState
+            except xcffib.xproto.WindowError:
+                # This means that the window has probably been destroyed,
+                # but we haven't yet seen the DestroyNotify (it is likely
+                # next in the queue). So, we just let these errors pass
+                # since the window is dead.
+                pass
+            # Clear these atoms as per spec
+            win.window.conn.conn.core.DeleteProperty(
+                win.wid, win.window.conn.atoms["_NET_WM_STATE"]
+            )
+            win.window.conn.conn.core.DeleteProperty(
+                win.wid, win.window.conn.atoms["_NET_WM_DESKTOP"]
+            )
+        self.qtile.unmanage(event.window)
+        if self.qtile.current_window is None:
+            self.conn.fixup_focus()
 
     def handle_ScreenChangeNotify(self, event) -> None:  # noqa: N802
         hook.fire("screen_change", event)
 
+    @contextlib.contextmanager
+    def disable_unmap_events(self):
+        self._root.set_attribute(
+            eventmask=self.eventmask & (~EventMask.SubstructureNotify)
+        )
+        yield
+        self._root.set_attribute(eventmask=self.eventmask)
+
     @property
     def painter(self):
         if self._painter is None:
diff --git a/libqtile/backend/x11/window.py b/libqtile/backend/x11/window.py
--- a/libqtile/backend/x11/window.py
+++ b/libqtile/backend/x11/window.py
@@ -740,7 +740,8 @@ def kill(self):
     def hide(self):
         # We don't want to get the UnmapNotify for this unmap
         with self.disable_mask(EventMask.StructureNotify):
-            self.window.unmap()
+            with self.qtile.core.disable_unmap_events():
+                self.window.unmap()
         self.hidden = True
 
     def unhide(self):


Test patch: