Repository: qtile/qtile

Issue:
Systray icon disappears with restart
As reported on IRC:
```
[08:11] <    elcaven> this morning I updated qtile from the qtile-git package from the AUR and since then it seems that my systray widget resets every time qtile restarts, so after a qtile restart the systray
                      is empty until a program spawns there again
[08:12] <    elcaven> there don't seem to be any related errors in the logfile, only one I see is "AttributeError: 'Screen' object has 
[20:53] < elParaguayo> | elcaven - interesting. That may be a side-effect of the config reloading code that was recently committed.
[21:09] <       mcol> What does it mean for the systray to reset? Can it persist state across restarts?
[21:14] < elParaguayo> | I'm guessing that the app is still open but the icon has disappeared from the tray
[21:22] < elParaguayo> | I wonder if SNI has that issue too...
[21:25] < elParaguayo> | No, SNI looks ok.
[21:25] < elParaguayo> | Tested with "restart" and "reload_config"
[21:27] < elParaguayo> | Confirmed, Systray icon disappears on reload_config even though app is open.
[21:28] < elParaguayo> | Icon doesn't disappear with "restart"
```

Tested on latest: 66ce6c28


Discussion:
Same error.
.xsession-errord output
```
(nm-applet:3612600): Gdk-WARNING **: 13:34:48.974: GdkWindow 0x120000b unexpectedly destroyed
Exception in callback ThreadPoolText.timer_setup.<locals>.on_done(<Future cancelled>) at /usr/lib/python3.9/site-packages/libqtile/widget/base.py:551
handle: <Handle ThreadPoolText.timer_setup.<locals>.on_done(<Future cancelled>) at /usr/lib/python3.9/site-packages/libqtile/widget/base.py:551>
Traceback (most recent call last):
  File "/usr/lib/python3.9/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/lib/python3.9/site-packages/libqtile/widget/base.py", line 553, in on_done
    result = future.result()
asyncio.exceptions.CancelledError

(nm-applet:3612600): Gdk-WARNING **: 13:34:48.975: The program 'nm-applet' received an X Window System error.
This probably reflects a bug in the program.
The error was 'RenderBadPicture (invalid Picture parameter)'.
  (Details: serial 357 error_code 143 request_code 139 (RENDER) minor_code 7)
  (Note to programmers: normally, X errors are reported asynchronously;
   that is, you will receive the error a while after causing it.
   To debug your program, run it with the GDK_SYNCHRONIZE environment
   variable to change this behavior. You can then get a meaningful
   backtrace from your debugger if you break on the gdk_x_error() function.)
```
There are two issues: 
* `reload_config` makes any systray icon disappear; 
* both `reload_config` and `restart` kill nm-applet.

On that second issue, dmesg says:
```
traps: nm-applet[6163] trap int3 ip:7f2181b0bdc5 sp:7ffe09593370 error:0 in libglib-2.0.so.0.6600.8[7f2181ad1000+86000]
```
That nm-applet message doesn't make much sense to me but I assume the issue is that the tray is killed and so any apps that only provide a tray icon die. That doesn't seem to be too unreasonable and could be something that's fixed with a hook to respawn the app.
Adding a hook? Restarts used to keep the systray icons alive, so why not just try to revert what broke that? I did the bisect and it seems that the problem was introduced in b7cf35ed4572818d0c40c40499c97ed5030872a6.
Sorry, I misunderstood. I thought you were saying that restart always killed nm-applet. If that's not the case then, yes, let's fix the problem!
My guess is that this will be caused by widgets having `finalize` called on them which was done to stop an issue with timers.
It's because the `Bar` now kills its own window when finalizing. Commenting out this one line fixes it: https://github.com/qtile/qtile/commit/b7cf35ed4572818d0c40c40499c97ed5030872a6#diff-effdc1f9379ed88ce401e42f5852cc8db7444a9b885995477d68709069ca4977R314

Doing so locally might be quick workaround. Will investigate later if not doing that is the best thing or not, but I think the bar window does need finalizing in some way if it is being replaced by a new `Bar` instance. This also happens when restarting though so that makes me window if bar windows just always hang around after restarts? 
Interesting. SysTray provides its own window too so I'd have thought killing that would be more problematic but clearly I'm wrong!
The systray window is embedded within the bar window, so it needs to un-embed itself before the bar finalises, and re-embed itself with the new window.

Resolving patch:
diff --git a/libqtile/widget/systray.py b/libqtile/widget/systray.py
--- a/libqtile/widget/systray.py
+++ b/libqtile/widget/systray.py
@@ -247,3 +247,11 @@ def finalize(self):
             xcffib.CurrentTime,
         )
         self.hide()
+
+        root = self.qtile.core._root.wid
+        for wid in self.icons:
+            self.conn.conn.core.ReparentWindow(wid, root, 0, 0)
+        self.conn.conn.flush()
+
+        del self.qtile.windows_map[self.wid]
+        self.conn.conn.core.DestroyWindow(self.wid)


Test patch: