When a USB HID device (keyboard/mouse) is disconnected, X11 fires an
XI_HierarchyChanged event, which triggers read_xi_scroll_devices().
That function calls XIGetProperty() on devices from XIQueryDevice().
There is a race condition: if a device is removed between these calls,
X11 generates an XI_BadDevice error. Without a custom error handler, the
default X11 handler calls exit(), killing kitty.
Fix: wrap the device query loop in read_xi_scroll_devices() with
_glfwGrabErrorHandlerX11() / _glfwReleaseErrorHandlerX11() so that any
XI_BadDevice error is captured by kitty's own handler rather than the
default fatal one.
Fixes#9723Fixes#9724
Appends a synthetic TabBarData(tab_id=-1, title='+') to tab_bar_data
while a window drag is active. The existing tab highlight machinery
(_set_drag_target_tab / mark_tab_bar_dirty) handles hover highlighting
with no extra state. Dropping on it falls through the existing new-tab
branch in on_window_drop (tab_for_id(-1) returns None). Mark tab bar
dirty at drag start so the indicator appears immediately, and again
after set_window_being_dragged() on drop so it clears right away.
splits.py: insert_window_next_to called split_and_add on self.pairs_root
instead of on the pair found by pair_for_window. split_and_add only handles
direct children, so nested dest windows fell to 'else: self.two = pair',
silently replacing an entire subtree. Lost windows were re-added by
do_layout, producing phantom panes.
tabs.py: on_window_drop returned early (window not found) before calling
_clear_force_show_title_bars, leaving the drag overlay stuck on screen.
quadrant=5: title bar hover — full window overlay + title bar highlight
quadrant=6: body hover (non-Splits) — full window overlay only
quadrant=1-4: Splits body hover — directional half-window overlay
Previously quadrant=5 was used for all full-window cases, causing
is_drag_target=True to fire on body hover which incorrectly lit up
the title bar highlight whenever hovering any window body.
The regression was introduced by commit b277a016b which added an early
`return` in handle_button_event that prevented kitty's internal text
selection from starting on focus-transfer clicks to unfocused splits.
Changes:
- In handle_button_event: replace the early return with a local
suppress_child_forwarding flag that prevents PRESS from being forwarded
to child processes in mouse-tracking mode, while still allowing
dispatch_mouse_event to run (which starts text selection)
- In mouse_event's active_drag_in_window release path: clear
suppress_left_mouse_release to prevent stale flags after drags
Fixes#9713Fixes#9715
This ensures that Ctrl+H behaves like Backspace and correctly clears
the pre-edit state, preventing uncommitted characters from remaining
on the screen when using IMEs like the Japanese one on macOS.
When kitty loses focus and the user scrolls in another
application, X11 XI scroll valuators accumulate position values. When the
user returns to kitty and scrolls, delta (value - v->value) uses the stale
pre-focus-loss value, causing a massive unexpected scroll jump.
Fix: reset scroll valuators (mark them uninitialized) on FocusOut so the
first scroll event after focus is regained sets the baseline without firing
a scroll event.
Fixes#9703Fixes#9707
On 32-bit platforms Py_ssize_t is int (signed 32-bit), while
os_window->num_tabs is unsigned int. Direct comparison triggers
-Werror=sign-compare. Cast the unsigned side to Py_ssize_t to
silence the warning. The value can never overflow Py_ssize_t
since num_tabs is bounded by the number of open tabs.