A quick click-and-flick on a tab could leave all of kitty with mouse
input permanently redirected to the tab bar, making every window
unclickable and text selection impossible.
Starting a tab drag is asynchronous: the drag thumbnail is rendered on
the next frame before glfwStartDrag is called. If the button is
released in that window, wl_data_device_start_drag is sent with a stale
serial that no longer matches an active pointer implicit grab, so the
compositor silently ignores it. The wl_data_source then never receives
any event, on_drag_source_finished never runs, and the
tab_being_dragged state is stuck forever, hijacking all mouse events.
Fix in layers:
- glfw/Wayland: track the implicit grab (serial of the first button
press and pressed-button count), use that serial for start_drag and
refuse with EAGAIN when there is no active implicit grab instead of
letting the compositor silently drop the request
- mouse.c: a left button release arriving while a tab drag is marked
started but no system DND is active means the drag never launched
(an active DND consumes the release on all platforms), so clear the
drag state instead of waiting for DND events that will never come
- tabs.py: handle OSError from start_drag_with_data for tab drags the
same way window drags already do; clear the potential-drag state when
the release lands on the new-tab button or empty tab bar area
- tabs.py/boss.py: clear drag state on drag finish/drop even when the
dragged tab has already been closed
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
inform_compositor_of_window_geometry() calls xdg_surface_set_window_geometry()
unconditionally, but layer-shell surfaces (e.g. those from `kitten panel`) have
no xdg_surface. With hide_window_decorations set to titlebar-only, the panel hits
this geometry call during creation and dereferences the NULL proxy, crashing in
wl_proxy_get_version() with SIGSEGV.
Guard on window->wl.xdg.surface: layer-shell surfaces manage geometry via the
layer surface, so the xdg call is skipped. Normal toplevels are unaffected.
Some window managers (e.g. kwin_x11) clear _NET_WM_STATE when a window
is unmapped/withdrawn. This caused layer shell windows to lose states like
_NET_WM_STATE_ABOVE, _NET_WM_STATE_SKIP_TASKBAR, etc. when hidden and
re-shown via toggle. The result was inconsistent behaviour between the
first show and subsequent shows.
Fix by calling update_wm_hints() before XMapWindow in
_glfwPlatformShowWindow() for layer shell windows, which re-applies all
WM state properties (_NET_WM_STATE, window type, strut, size hints)
before each map operation.