Skip to content

Conversation

@seijikohara
Copy link

@seijikohara seijikohara commented Dec 17, 2025

Summary

This pull request implements mouse-based tab dragging functionality, enabling users to reorder tabs by dragging them within the tab bar and to detach tabs into new OS windows by dragging them outside the tab bar region.

Refs #7410

Features

Tab Reordering

  • Drag tabs horizontally within the tab bar to change their order
  • Drop position is determined by the midpoint of each tab extent
  • Tab order updates immediately upon release

Tab Detachment

  • Drag a tab outside the tab bar boundaries to detach it into a new OS window
  • Requires at least two tabs (the last tab cannot be detached)
  • Detachment threshold includes a 20-pixel margin for improved usability

Visual Feedback

  • Dragged tab is rendered with reduced opacity (dimmed appearance)
  • A green vertical indicator shows the prospective drop position
  • Indicator updates in real-time as the cursor moves

Performance Optimization

  • Motion events are throttled at 16ms intervals to prevent excessive processing
  • Drag state is tracked using an immutable NamedTuple for efficient updates

Configuration Options

Three new options have been added to kitty.conf:

Option Type Default Description
enable_tab_drag bool yes Enable or disable tab dragging
tab_drag_threshold int 5 Minimum pixel distance before drag initiates
enable_tab_drag_detach bool yes Allow detaching tabs to new windows

Implementation Details

Modified Files

  • kitty/tabs.py: Core drag logic including TabDragState, event handling, and reordering
  • kitty/tab_bar.py: Visual feedback rendering (dimming, drop indicator)
  • kitty/mouse.c: Motion event reporting during tab bar drag operations
  • kitty/boss.py: Tab transfer coordination via existing _move_tab_to method
  • kitty/state.h, kitty/state.c: C-level drag state flag and option fields
  • kitty/options/definition.py: New configuration option definitions

New Test File

  • kitty_tests/tab_drag.py: Unit tests for _move_tab_to_index and _calculate_drop_index

Testing

  • Manual testing performed on macOS
  • Unit tests added for core logic functions (12 test cases)
  • All existing tests continue to pass

Limitations

Cross-window tab merging (dragging a tab from one window into another) is not included in this implementation due to fundamental constraints in mouse event routing, where events are always dispatched to the window where the mouse button was initially pressed.

Implement tab dragging with the following features:

- Tab reordering: Drag tabs within the tab bar to change their order
- Tab detachment: Drag a tab outside the tab bar to detach it into a new OS window
- Visual feedback: Dragged tab is dimmed, green vertical indicator shows drop position
- Motion throttling: 16ms interval to optimize performance

New configuration options:
- enable_tab_drag: Enable/disable tab dragging (default: yes)
- tab_drag_threshold: Pixel threshold before drag starts (default: 5)
- enable_tab_drag_detach: Allow detaching tabs to new windows (default: yes)

Implementation details:
- TabDragState NamedTuple tracks drag state including position and timing
- handle_click_on_tab() extended to handle PRESS/MOTION/RELEASE events
- Mouse motion events reported during tab bar drag via C-level flag
- Drop position calculated based on tab extent midpoints

Includes unit tests for _move_tab_to_index and _calculate_drop_index.
@kovidgoyal
Copy link
Owner

Before reviewing the code, some initial feedback:

  1. Make a single config option for this, taking two numbers

enable_tab_drag x y

Where x is the drag threshold with negative numbers disabling tab dragging.
y is the threshold distance for how far out of the tab bar the tab should be
dragged to detach it. y should be optional defaulting to some small positive
number, negative disables detach.

  1. The issue with dragging to another OS Window should be easily fixable at least on
    macOS/X11 where you can get OS Window positions. So if a drag is in process, and
    the mouse co-ords are over another OS window it can be routed to that OS
    window. On Wayland its a bit more involved thanks to Wayland's boneheaded
    design. You would need to actually start a drag event and listen for a drag and
    drop events in the target window. Since I am guessing you are on macOS, you can
    leave that off for now. Maybe I will get to it someday, or as usual Wayland
    users will suffer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants