Repository: qtile/qtile

Issue:
[wayland] qtile crashes (segfaults) on chrome tab drag n drop
### The issue:

When I start dragging a tab qtile immediately crashes. (newest qtile and chrome versions). No log output, direct segfault in qtile (dmesg). I would expect - even if this is a chrome issue - qtile to not crash :D)

I expected this to be a common wayland bug, since chrome (and electectron) is notoriously annoying there :P However after scouring the internet for potential fixes all bug reports I found have been fixed (for e.g. swaywm). Also the qtile issues relating this never describe this particular bug and are solved for the most part (#408 #1257).

How is drag-n-drop with other programs:
firefox: works, but only shows drag hints, does not actually drag the tab, same for vscode

Possibly related: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/46

Thus: did I miss some magic setting or is this a kown bug? (I get the behavior with the default config as well)
The way I start chrome:  `google-chrome --ozone-platform-hint=auto --enable-features=WebRTCPipeWireCapturer`

Chrome: Version 106.0.5249.119 (Official Build) (64-bit)
Qtile: 0.22.2.dev9+g946908b9

### Required:

- [X] I have searched past issues to see if this bug has already been reported.


Discussion:
```dmesg
[ 1557.257405] qtile[914]: segfault at 18 ip 00007fa8ca809abe sp 00007fff881e94e0 error 4 in _ffi.abi3.so[7fa8ca800000+10000]
[ 1557.257420] Code: 48 8d 65 e0 31 c0 5b 41 5c 41 5d 41 5e 5d c3 0f 1f 44 00 00 e8 23 ab ff ff 49 89 c4 ff 15 f2 92 20 00 48 8b 45 c0 48 8b 75 c8 <48> 8b 38 e8 8a ab ff ff ff 15 e4 92 20 00 4c 89 e7 e8 bc a6 ff ff
```
Sometimes I see in my log this:
```
Traceback (most recent call last):
File "...site-packages/pywayland/server/listener.py", line 40, in notify_func callback(listener, data)
File "...site-packages/libqtile/backend/wayland/output.py", line 113, in _on_frame with self.wlr_output as wlr_output:
File "...site-packages/wlroots/wlr_types/output.py", line 162, in __exit__ self.commit()
File "...site-packages/wlroots/wlr_types/output.py", line 199, in commit raise RuntimeError("Unable to commit output")
RuntimeError: Unable to commit output
```
Hope this helps...

This bug is driving me nuts :P
Ok I am at a loss here with debugging. I tried python's faulthandler, but the trace only shows that the ffi call was made from a thread, no idea where from though. `WAYLAND_DEBUG=1` did **NOT** produce any output other than the normal logs I get, which seems weird to me, but is thus also a dead end. I tried it with a fresh chrome install - still broken. Chromes debug log shows no error either.
@m-col , @elParaguayo do you have any suggestions as to how I can debug this further? Or where qtile is involved here? Also, can you replicate the issue (on wayland), I am very confused why I am not finding anything about this bug online.
Thank you for your help!
Hey, thanks for the detailed debugging :)

Do you also get the issue with chromium? I don't get any crashes with that, will install chrome and take a look at that too.
OK sad news, I installed chrome and it works just fine for me. I don't get an icon when dragging but I don't know if there is meant to be one. I can drag a tab to a new window, drag tabs to re-order them in the same window, or drag a tab between windows - all work as expected. Are you using the latest wlroots release, 0.15.1?
Scratch that - I was running chrome directly without the flags, so it was probably using XWayland. Running with those flags causes a crash, which does not happen on sway. Will investigate! :)

Resolving patch:
diff --git a/libqtile/backend/wayland/output.py b/libqtile/backend/wayland/output.py
--- a/libqtile/backend/wayland/output.py
+++ b/libqtile/backend/wayland/output.py
@@ -227,8 +227,8 @@ def _render_dnd_icon(
         self, dnd: Dnd, now: Timespec, scale: float, transform_matrix: Matrix
     ) -> None:
         """Render the drag-n-drop icon if there is one."""
-        icon = dnd.wlr_drag.icon
-        if icon.mapped:
+        icon = dnd.icon
+        if icon is not None and icon.mapped:
             texture = icon.surface.get_texture()
             if texture:
                 box = Box(
diff --git a/libqtile/backend/wayland/wlrq.py b/libqtile/backend/wayland/wlrq.py
--- a/libqtile/backend/wayland/wlrq.py
+++ b/libqtile/backend/wayland/wlrq.py
@@ -191,10 +191,12 @@ def __init__(self, core: Core, wlr_drag: data_device_manager.Drag):
         self.height: int = 0
 
         self.add_listener(wlr_drag.destroy_event, self._on_destroy)
-        self.add_listener(wlr_drag.icon.map_event, self._on_icon_map)
-        self.add_listener(wlr_drag.icon.unmap_event, self._on_icon_unmap)
-        self.add_listener(wlr_drag.icon.destroy_event, self._on_icon_destroy)
-        self.add_listener(wlr_drag.icon.surface.commit_event, self._on_icon_commit)
+        self.icon = icon = wlr_drag.icon
+        if icon is not None:
+            self.add_listener(icon.map_event, self._on_icon_map)
+            self.add_listener(icon.unmap_event, self._on_icon_unmap)
+            self.add_listener(icon.destroy_event, self._on_icon_destroy)
+            self.add_listener(icon.surface.commit_event, self._on_icon_commit)
 
     def finalize(self) -> None:
         self.finalize_listeners()
@@ -218,9 +220,10 @@ def _on_icon_destroy(self, _listener: Listener, _event: Any) -> None:
         logger.debug("Signal: wlr_drag_icon destroy")
 
     def _on_icon_commit(self, _listener: Listener, _event: Any) -> None:
-        self.width = self.wlr_drag.icon.surface.current.width
-        self.height = self.wlr_drag.icon.surface.current.height
-        self.position(self.core.cursor.x, self.core.cursor.y)
+        if self.icon is not None:
+            self.width = self.icon.surface.current.width
+            self.height = self.icon.surface.current.height
+            self.position(self.core.cursor.x, self.core.cursor.y)
 
     def position(self, cx: float, cy: float) -> None:
         self.x = cx


Test patch: