Detach tab via drag and drop now implemented

This commit is contained in:
Kovid Goyal 2026-02-21 15:15:33 +05:30
parent e10451dbcb
commit 96c01b74d8
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 22 additions and 3 deletions

2
glfw/wl_window.c vendored
View file

@ -3227,7 +3227,7 @@ static void
drag_source_dnd_drop_performed(void *data UNUSED, struct wl_data_source *source UNUSED) {
_GLFWwindow *window = _glfwWindowForId(_glfw.drag.window_id);
if (window) {
GLFWDragEvent ev = {.type=GLFW_DRAG_ACTION_CHANGED};
GLFWDragEvent ev = {.type=GLFW_DRAG_DROPPED};
_glfwInputDragSourceRequest(window, &ev);
} else drag_source_cancelled(data, source);
}

View file

@ -1917,6 +1917,7 @@ class Boss:
set_tab_being_dragged()
for tm in self.all_tab_managers:
tm.on_tab_drop_move(0, False, 0, 0)
tm.layout_tab_bar() # ensure tab bar is fully updated
return
central, tab_bar = viewport_for_window(os_window_id)[:2]
if central.left <= x < central.right and central.top <= y < central.bottom:
@ -1932,6 +1933,18 @@ class Boss:
if (tab_id := tm.tab_bar.tab_id_at(x)) and (tab := self.tab_for_id(tab_id)) and (w := tab.active_window):
w.on_drop(drop)
def on_drag_source_finished(
self, was_dropped: bool, was_canceled: bool, accepted_mime_type: str, action: int, data: dict[str, bytes] | None
) -> None:
if data and (tidb := data.get(f'application/net.kovidgoyal.kitty-tab-{os.getpid()}')):
set_tab_being_dragged()
for tm in self.all_tab_managers:
tm.on_tab_drop_move(0, False, 0, 0)
if not was_dropped: # detach tab into new OS Window
tab_id = int(tidb.decode())
if (tab := self.tab_for_id(tab_id)):
self._move_tab_to(tab)
@ac('win', '''
Focus the nth OS window if positive or the previously active OS windows if negative. When the number is larger
than the number of OS windows focus the last OS window. A value of zero will refocus the currently focused OS window,

View file

@ -746,6 +746,7 @@ on_drop(GLFWwindow *window, GLFWDropEvent *ev) {
Py_CLEAR(global_state.drop_dest.data);
if (ev->from_self) {
if (global_state.drag_source.drag_data) {
global_state.drag_source.was_dropped = true;
WINDOW_CALLBACK(on_drop, "OOii", global_state.drag_source.drag_data, Py_True,
global_state.callback_os_window->last_drag_event.x, global_state.callback_os_window->last_drag_event.y);
} else log_error("Got a drop from self but drag_source.drag_data is NULL");
@ -804,12 +805,17 @@ drag_source_callback(GLFWwindow *window UNUSED, GLFWDragEvent *ev) {
ds.accepted_mime_type = ev->mime_type ? strdup(ev->mime_type) : NULL;
break;
case GLFW_DRAG_ACTION_CHANGED: ds.action = ev->action; break;
case GLFW_DRAG_DROPPED: ds.was_dropped = true; break;
case GLFW_DRAG_DROPPED:
ds.was_dropped = true;
break;
case GLFW_DRAG_CANCELLED:
ds.was_canceled = true;
/* fallthrough */
case GLFW_DRAG_FINSHED:
ds.is_active = false;
call_boss(on_drag_source_finished, "OOsiO",
ds.was_dropped ? Py_True : Py_False, ds.was_canceled ? Py_True: Py_False,
ds.accepted_mime_type ? ds.accepted_mime_type : "",
ds.action, ds.drag_data ? ds.drag_data : Py_None);
free_drag_source();
break;
}