Closed ghost closed 1 year ago
Thanks for reporting this. I'm still trying to get my hobby time budget back on track, so I'm not sure if I'll be able to fix this quickly, but I'll see what I can do.
Definitely a tricky bug to identify in testing if you don't know what you're looking for. To be honest, I've been wondering if maybe, as part of the port to GTK+ 3.x, I should also rewrite QuickTile in Rust to get the monadic error handling which would have prevented this failure from being catastrophic by reminding me that the call is fallible.
Either way, I should really make some time to start writing integration tests for QuickTile. To be honest, the need to spin up something like Xnest, Xephyr, or Xvfb, a WM inside it, and then write a test harness which creates windows to be moved around has been a bit demotivating.
All callers of WindowManager.get_monitor will need to be changed to account for this.
I think it'd provide both greater robustness and a nicer API for command authors if I just wrapped the dispatching of commands in a try
/except
block.
I wasn't able to reproduce the specific error described, but, on one of the "hold the key combo while mpv exits" tests, I managed to trigger a new error handler that I thought was only reachable during QuickTile startup, followed by the underlying GTK killing QuickTile because it received an X11 BadDrawable error.
(I say "GTK killing QuickTile" because GTK is bypassing my exception handler and just exiting the program with its own error message.)
I'm looking into that now.
I added a generic "don't let exceptions in tiling commands kill things" handler for the error you described, which I can't test because I can't reproduce the bug, but I can't work around the bug I can reproduce on my end because GTK's "helpful" error handling prevents Python exceptions from firing and I can find no evidence of an option to opt out of it.
All I can suggest is to file a bug with the GTK developers and tell them that there's a race condition in GTK, reproducible by launching ./quicktile.sh -b
, focusing MPV, and holding down a tiling hotkey in QuickTile while the MPV window is in the process of going away of its own volition.
The relevant portion of the backtrace looks like this:
#6 0x00007ffff632635b in _XError () at /lib/x86_64-linux-gnu/libX11.so.6
#7 0x00007ffff63230c7 in () at /lib/x86_64-linux-gnu/libX11.so.6
#8 0x00007ffff63242d3 in _XReply () at /lib/x86_64-linux-gnu/libX11.so.6
#9 0x00007ffff63081cf in XGetGeometry () at /lib/x86_64-linux-gnu/libX11.so.6
#10 0x00007ffff5d3793f in () at /lib/x86_64-linux-gnu/libgdk-3.so.0
#11 0x00007ffff5d0687c in gdk_window_get_geometry () at /lib/x86_64-linux-gnu/libgdk-3.so.0
#12 0x00007ffff5cf0d22 in gdk_display_get_monitor_at_window () at /lib/x86_64-linux-gnu/libgdk-3.so.0
#13 0x00007ffff5cff542 in gdk_screen_get_monitor_at_window () at /lib/x86_64-linux-gnu/libgdk-3.so.0
#14 0x00007ffff7fbcff5 in () at /lib/x86_64-linux-gnu/libffi.so.7
(i.e. The race condition appears to be "GTK crashes if a window goes away in the middle of it being the subject of a gdk_screen_get_monitor_at_window
call.)
Since that particular bug kills QuickTile entirely, the only thing I can suggest to work around it would be to run QuickTile in a shell script that re-launches it every time it dies.
Something like this:
#!/bin/sh
while true; do
./quicktile -b
sleep 1
done
When this happened, I had two windows open: mpv in the foreground and caja in the background. My window manager is xfwm4 4.12.4 and I have one monitor. I was holding the right arrow key to fast forward through a video. I don't have a binding for
Right
configured in quicktile, but I do have bindings for<Ctrl><Alt>Right
and<Ctrl><Alt><Shift>Right
(which results in a binding forRight
being created via_vary_modmask
). I fast forwarded past the end of the video, which resulted in mpv exiting and the window focus changing back to caja. I was still holding the right arrow key at that point. Immediately after mpv exited, this error appeared:At that point, quicktile stopped responding to any of my keybindings, even though it was still running. After restarting quicktile, it began working again. Unfortunately, I only have the backtrace and not the debug log.
For reference, this is my quicktile config:
This line in quicktile/wm.py seems to be the problem:
Apparently
gtk.gdk.window_foreign_new
returnedNone
even thoughwin
was notNone
(awnck.Window
).Based on this information, I have a hypothesis as to what happened:
WindowManager.get_monitor
calledgtk.gdk.window_foreign_new
. Since the mpv window no longer existed, it returnedNone
.self.gdk_screen.get_monitor_at_window(win)
failed becausewin
isNone
.Basically it's a race between executing the quicktile command and closing the window. I believe what is needed to fix it is to check that the result of
gtk.gdk.window_foreign_new
is notNone
, and bail if it is. All callers ofWindowManager.get_monitor
will need to be changed to account for this.