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.
During a window title-bar drag, render a semi-transparent tint over
the destination window to preview the drop outcome:
- Full-window tint (quadrant=5) when hovering any window in swap-based
layouts (Tall, Stack, Fat, etc.) or over a title bar — swap is the
result so the whole window is highlighted.
- Half-window directional tint (quadrant 1-4) when hovering in the
Splits layout — a real directional insert happens so only the target
half is highlighted.
- 150ms fade-in; clears immediately on drop or drag exit.
Implementation follows the visual_bell TINT_PROGRAM infrastructure:
two new Screen fields (start_drag_overlay_at, drag_overlay_quadrant),
draw_drag_preview_overlay() in shaders.c called from draw_cells() after
both render paths, set_window_drag_overlay() C→Python bridge in state.c,
and the same child-monitor.c needs_render + set_maximum_wait hooks that
visual_bell uses to keep frames firing during animation.
Layout detection uses hasattr(layout, 'insert_window_next_to') — the
same guard _insert_window_in_direction uses internally — so the overlay
always matches the actual drop behavior.
- start_window_drag now force-shows title bars on all tabs during a drag
so the user can actually drop onto them to trigger a swap. The cleanup
code to clear force_show_title_bars already existed but the corresponding
set was never written.
- on_window_drop_move now only highlights a destination window's title bar
when the cursor is actually within the title bar row, so the visual
feedback accurately reflects what will happen on drop (swap vs split).
- Dropping a window onto the empty space in the tab bar (past the last tab)
now creates a new tab and moves the window into it.
Position the window below the notch by reducing the frame height by
safeAreaInsets.top. Create a fullscreen child window behind it with a
colored subview covering just the notch strip, matching the terminal
background color and opacity.
Also fix background_opacity not triggering a chrome update on config
reload.
Wayland (glfw/wl_window.c):
- Fix out-of-bounds access in send_drag_data: look up item by MIME type
instead of using the data-request index i to index _glfw.drag.items[].
The compositor calls drag_source_send once per target window entered,
so _glfw.wl.drag.count grows independently of item_count, causing
_glfw.drag.items[i] to be out-of-bounds on the second drag, yielding a
garbage optional_data pointer that made write() fail with EFAULT.
- Fix protocol error "Drag has not ended": change on_fail and the
GLFW_DRAG_DATA_REQUEST error path to call finish_drag_write(i)+return
instead of cancel_drag(), which was calling wl_data_source_destroy()
before the compositor ended the drag, violating the Wayland protocol.
- Fix double-free of dr.pending_data: null the pointer after free and
add cleanup to finish_drag_write().
- Fix missing finish_drag_write() after a full write in data-request
mode, which left the pipe open causing the target to wait for EOF.
X11 (glfw/x11_window.c):
- Wrap XSendEvent() calls in send_xdnd_enter/position/leave/drop with
_glfwGrabErrorHandlerX11()/_glfwReleaseErrorHandlerX11(). A target
window destroyed between discovery and message delivery produced a
BadWindow error that hit the default X11 abort handler. Now handled
gracefully by clearing current_target or cancelling the drag."
Fixes#9677Fixes#9683
When tab_bar_filter is used (e.g. with sessions), move_tab() was using
self.active_tab_idx (index in the full tabs list) as an index into the
filtered tabs list, causing incorrect behavior.
Also fix the same bug in tab_at_location() for left/right locations.
Fixes#9672Fixes#9673
Fixes#9663: visible gray/black bars appear at the left and right
sides of the tab bar when background_opacity is set and the window width
is not a multiple of the cell width.
Three fixes in update_blank_rects:
1. Fix off-by-one: use g.right instead of g.right-1 for the right blank
rect start position. The old code caused a 1-pixel overlap with tab
content and spuriously added a right blank rect even for
perfectly-aligned windows.
2. Fix blank rect colors: only use tab_bar_left/right_edge_color when
tab_bar_margin_width > 0 (explicit configured margin). When
margin_width=0 (default), use default_bg which blends with the window
background instead of showing a solid tab-colored bar.
3. Fix inner margin BOTTOM_EDGE height: use tab_bar.top instead of vh
so the inner margin blank rect covers only the inner margin area.
Fixes#9664
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>