From 49f6c926e04fca95213c5d7cb5f480aa18d70f71 Mon Sep 17 00:00:00 2001 From: mcrmck Date: Tue, 17 Mar 2026 23:26:55 -0400 Subject: [PATCH] Fix window drag-drop: force-show title bars and add new-tab drop target - 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. --- kitty/tabs.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/kitty/tabs.py b/kitty/tabs.py index 0be40ddbe..8384b62d1 100644 --- a/kitty/tabs.py +++ b/kitty/tabs.py @@ -1828,6 +1828,14 @@ def start_window_drag(self, window_id: int) -> None: set_window_being_dragged() return opts = get_options() + if opts.window_title_bar != 'none': + min_w = opts.window_title_bar_min_windows + for tm in boss.all_tab_managers: + for t in tm: + visible = sum(1 for _ in t.windows.iter_all_layoutable_groups(only_visible=True)) + if not (min_w > 0 and visible >= min_w): + t.force_show_title_bars = True + t.relayout() title = str(w.title or '') fg = color_as_int(opts.window_title_bar_active_foreground or opts.active_tab_foreground) bg = color_as_int(opts.window_title_bar_active_background or opts.active_tab_background) @@ -1905,7 +1913,20 @@ def on_window_drop_move(self, window_id: int = 0, is_dest: bool = False, x: int return self._set_drag_target_tab(0) dest_window = self._find_window_at(x, y) - target_id = dest_window.id if (dest_window and dest_window.id != window_id) else 0 + if dest_window and dest_window.id != window_id and dest_window.show_title_bar: + from .fast_data_types import cell_size_for_window + _, ch = cell_size_for_window(self.os_window_id) + g = dest_window.geometry + opts = get_options() + tb_top = g.top if opts.window_title_bar == 'top' else g.bottom - ch + tb_bottom = tb_top + ch + from .fast_data_types import viewport_for_window + central = viewport_for_window(self.os_window_id)[0] + rel_y = y - central.top + in_title_bar = tb_top <= rel_y < tb_bottom + target_id = dest_window.id if in_title_bar else 0 + else: + target_id = 0 self._set_drag_target_window(target_id) def on_window_drop(self, x: int, y: int, window_id: int) -> None: @@ -1923,6 +1944,8 @@ def on_window_drop(self, x: int, y: int, window_id: int) -> None: if in_tab_bar: if (tab_id := self.tab_bar.tab_id_at(x)) and (dest_tab := self.tab_for_id(tab_id)): boss._move_window_to(w, target_tab_id=dest_tab.id) + else: + boss._move_window_to(w, target_tab_id='new') return # Case 2: Drop in central area