Add draggable window title bars

Implements drag-to-reorder for window title bars, following up on the
merged window title bar feature (#9450) and the design discussion in #9619.

- Drag a title bar and drop on another title bar to swap positions
- Drop on a window body quadrant (left/right/top/bottom) to insert as
  a directional split; Splits layout uses insert_window_next_to(), other
  layouts fall back to move_window_to_group()
- Drop on a tab bar tab to move the window into that tab
- Drop on another OS window to move into its active tab
- Drop outside kitty to detach into a new OS window
- Tab bar highlights the hovered tab during a window drag, mirroring
  how the destination window title bar is highlighted
- toggle_window_title_bars action temporarily force-shows title bars
  for drag-to-reorder when they are normally hidden, auto-hiding after
  the drag completes
- window_title_bar_drag_threshold option (default 5px) controls how far
  the mouse must move before a drag is initiated; 0 disables dragging

MIME type follows the same convention as tab dragging:
application/net.kovidgoyal.kitty-window-{PID}

Ref: #9619
This commit is contained in:
mcrmck
2026-03-08 20:56:38 -04:00
parent db5453c291
commit 59c963c481
15 changed files with 391 additions and 29 deletions

View File

@@ -909,14 +909,15 @@ static void update_titlebar_button_visibility_after_fullscreen_transition(_GLFWw
self.identifier = @"kitty-content-view";
[self updateTrackingAreas];
char tab_mime[64];
char tab_mime[64], window_mime[64];
snprintf(tab_mime, sizeof(tab_mime), "application/net.kovidgoyal.kitty-tab-%d", getpid());
snprintf(window_mime, sizeof(window_mime), "application/net.kovidgoyal.kitty-window-%d", getpid());
NSMutableArray *types = [NSMutableArray arrayWithObjects:
NSPasteboardTypeFileURL, NSPasteboardTypeString, NSPasteboardTypeURL, NSPasteboardTypeColor,
NSPasteboardTypeFont, NSPasteboardTypeHTML, NSPasteboardTypePDF, NSPasteboardTypePNG,
NSPasteboardTypeRTF, NSPasteboardTypeSound, NSPasteboardTypeTIFF,
UTTypeData.identifier, UTTypeItem.identifier, UTTypeContent.identifier,
mime_to_uti(tab_mime),
mime_to_uti(tab_mime), mime_to_uti(window_mime),
nil];
// Add file promise types
[types addObjectsFromArray:[NSFilePromiseReceiver readableDraggedTypes]];
@@ -1591,6 +1592,10 @@ update_drop_state(_GLFWwindow *window, size_t mime_count) {
for (size_t i = 0; i < d->mimes_count; i++)
_glfwPlatformRequestDropData(window, d->mimes[i]);
}
// Restore first-responder status after native DnD; the drag operation can
// displace the content view from first responder, silently breaking keyboard
// input even though osw->is_focused remains true.
[window->ns.object makeFirstResponder:window->ns.view];
return YES;
}