Add an API to attach and detach windows from tabs
This commit is contained in:
parent
bf0ffa80be
commit
d1aa59080f
@ -116,31 +116,6 @@ add_window(id_type os_window_id, id_type tab_id, PyObject *title) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline id_type
|
||||
change_window_tab(id_type window_id, id_type old_tab_os_window_id, id_type old_tab_id, id_type new_tab_os_window_id, id_type new_tab_id) {
|
||||
// move the window description from one tab to another
|
||||
Window* new_window_description = 0;
|
||||
WITH_TAB(new_tab_os_window_id, new_tab_id);
|
||||
ensure_space_for(tab, windows, Window, tab->num_windows + 1, capacity, 1, true);
|
||||
make_os_window_context_current(osw);
|
||||
zero_at_i(tab->windows, tab->num_windows);
|
||||
new_window_description = &tab->windows[tab->num_windows];
|
||||
++tab->num_windows;
|
||||
END_WITH_TAB;
|
||||
if (new_window_description == 0) return 0; // could not find the window inside the old tab
|
||||
WITH_TAB(old_tab_os_window_id, old_tab_id);
|
||||
for (size_t i = 0; i < tab->num_windows; i++) {
|
||||
if (tab->windows[i].id == window_id) {
|
||||
memcpy(new_window_description, &tab->windows[i], sizeof(Window));
|
||||
zero_at_i(tab->windows, i);
|
||||
remove_i_from_array(tab->windows, i, tab->num_windows);
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_WITH_TAB;
|
||||
return new_window_description->id;
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_window_title(id_type os_window_id, id_type tab_id, id_type window_id, PyObject *title) {
|
||||
WITH_TAB(os_window_id, tab_id);
|
||||
@ -174,6 +149,52 @@ remove_window(id_type os_window_id, id_type tab_id, id_type id) {
|
||||
END_WITH_TAB;
|
||||
}
|
||||
|
||||
static inline void
|
||||
no_op_on_window(Window *w UNUSED) {}
|
||||
|
||||
typedef struct {
|
||||
unsigned int num_windows, capacity;
|
||||
Window *windows;
|
||||
} DetachedWindows;
|
||||
|
||||
static DetachedWindows detached_windows = {0};
|
||||
|
||||
|
||||
static void
|
||||
add_detached_window(Window *w) {
|
||||
ensure_space_for(&detached_windows, windows, Window, detached_windows.num_windows + 1, capacity, 8, true);
|
||||
memcpy(detached_windows.windows + detached_windows.num_windows++, w, sizeof(Window));
|
||||
}
|
||||
|
||||
static inline void
|
||||
detach_window(id_type os_window_id, id_type tab_id, id_type id) {
|
||||
WITH_TAB(os_window_id, tab_id);
|
||||
for (size_t i = 0; i < tab->num_windows; i++) {
|
||||
if (tab->windows[i].id == id) {
|
||||
add_detached_window(tab->windows + i);
|
||||
zero_at_i(tab->windows, i);
|
||||
remove_i_from_array(tab->windows, i, tab->num_windows);
|
||||
}
|
||||
}
|
||||
END_WITH_TAB;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
attach_window(id_type os_window_id, id_type tab_id, id_type id) {
|
||||
WITH_TAB(os_window_id, tab_id);
|
||||
for (size_t i = 0; i < detached_windows.num_windows; i++) {
|
||||
if (detached_windows.windows[i].id == id) {
|
||||
ensure_space_for(tab, windows, Window, tab->num_windows + 1, capacity, 1, true);
|
||||
memcpy(tab->windows + tab->num_windows++, detached_windows.windows + i, sizeof(Window));
|
||||
zero_at_i(detached_windows.windows, i);
|
||||
remove_i_from_array(detached_windows.windows, i, detached_windows.num_windows);
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_WITH_TAB;
|
||||
}
|
||||
|
||||
static inline void
|
||||
destroy_tab(Tab *tab) {
|
||||
for (size_t i = tab->num_windows; i > 0; i--) remove_window_inner(tab, tab->windows[i - 1].id);
|
||||
@ -778,10 +799,11 @@ PYWRAP0(destroy_global_data) {
|
||||
|
||||
THREE_ID_OBJ(update_window_title)
|
||||
THREE_ID(remove_window)
|
||||
THREE_ID(detach_window)
|
||||
THREE_ID(attach_window)
|
||||
PYWRAP1(resolve_key_mods) { int mods; PA("ii", &kitty_mod, &mods); return PyLong_FromLong(resolve_mods(mods)); }
|
||||
PYWRAP1(add_tab) { return PyLong_FromUnsignedLongLong(add_tab(PyLong_AsUnsignedLongLong(args))); }
|
||||
PYWRAP1(add_window) { PyObject *title; id_type a, b; PA("KKO", &a, &b, &title); return PyLong_FromUnsignedLongLong(add_window(a, b, title)); }
|
||||
PYWRAP1(change_window_tab) { id_type a, b, c, d, e; PA("KKKKK", &a, &b, &c, &d, &e); return PyLong_FromUnsignedLongLong(change_window_tab(a, b, c, d, e)); }
|
||||
PYWRAP0(current_os_window) { OSWindow *w = current_os_window(); if (!w) Py_RETURN_NONE; return PyLong_FromUnsignedLongLong(w->id); }
|
||||
TWO_ID(remove_tab)
|
||||
KI(set_active_tab)
|
||||
@ -803,10 +825,11 @@ static PyMethodDef module_methods[] = {
|
||||
MW(pt_to_px, METH_VARARGS),
|
||||
MW(add_tab, METH_O),
|
||||
MW(add_window, METH_VARARGS),
|
||||
MW(change_window_tab, METH_VARARGS),
|
||||
MW(update_window_title, METH_VARARGS),
|
||||
MW(remove_tab, METH_VARARGS),
|
||||
MW(remove_window, METH_VARARGS),
|
||||
MW(detach_window, METH_VARARGS),
|
||||
MW(attach_window, METH_VARARGS),
|
||||
MW(set_active_tab, METH_VARARGS),
|
||||
MW(set_active_window, METH_VARARGS),
|
||||
MW(swap_tabs, METH_VARARGS),
|
||||
@ -832,6 +855,15 @@ static PyMethodDef module_methods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static void
|
||||
finalize(void) {
|
||||
while(detached_windows.num_windows--) {
|
||||
destroy_window(&detached_windows.windows[detached_windows.num_windows]);
|
||||
}
|
||||
if (detached_windows.windows) free(detached_windows.windows);
|
||||
detached_windows.capacity = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
init_state(PyObject *module) {
|
||||
global_state.font_sz_in_pts = 11.0;
|
||||
@ -845,6 +877,10 @@ init_state(PyObject *module) {
|
||||
if (PyStructSequence_InitType2(&RegionType, ®ion_desc) != 0) return false;
|
||||
Py_INCREF((PyObject *) &RegionType);
|
||||
PyModule_AddObject(module, "Region", (PyObject *) &RegionType);
|
||||
if (Py_AtExit(finalize) != 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to register the state at exit handler");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// }}}
|
||||
|
||||
@ -4,14 +4,14 @@
|
||||
|
||||
import weakref
|
||||
from collections import deque, namedtuple
|
||||
from functools import partial
|
||||
from contextlib import suppress
|
||||
from functools import partial
|
||||
|
||||
from .borders import Borders
|
||||
from .child import Child
|
||||
from .constants import appname, get_boss, is_macos, is_wayland
|
||||
from .fast_data_types import (
|
||||
add_tab, mark_tab_bar_dirty, next_window_id,
|
||||
add_tab, attach_window, detach_window, mark_tab_bar_dirty, next_window_id,
|
||||
pt_to_px, remove_tab, remove_window, ring_bell, set_active_tab, swap_tabs,
|
||||
x11_window_id
|
||||
)
|
||||
@ -232,6 +232,10 @@ class Tab: # {{{
|
||||
ans.fork()
|
||||
return ans
|
||||
|
||||
def _add_window(self, window, location=None):
|
||||
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx, location)
|
||||
self.relayout_borders()
|
||||
|
||||
def new_window(
|
||||
self, use_shell=True, cmd=None, stdin=None, override_title=None,
|
||||
cwd_from=None, cwd=None, overlay_for=None, env=None, location=None,
|
||||
@ -245,8 +249,7 @@ class Tab: # {{{
|
||||
overlaid.overlay_window_id = window.id
|
||||
# Must add child before laying out so that resize_pty succeeds
|
||||
get_boss().add_child(window)
|
||||
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx, location)
|
||||
self.relayout_borders()
|
||||
self._add_window(window, location=location)
|
||||
return window
|
||||
|
||||
def new_special_window(self, special_window, location=None, copy_colors_from=None):
|
||||
@ -265,13 +268,16 @@ class Tab: # {{{
|
||||
if w.id == old_window_id:
|
||||
return idx
|
||||
|
||||
def remove_window(self, window):
|
||||
def remove_window(self, window, destroy=True):
|
||||
idx = self.previous_active_window_idx(1)
|
||||
next_window_id = None
|
||||
if idx is not None:
|
||||
next_window_id = self.windows[idx].id
|
||||
active_window_idx = self.current_layout.remove_window(self.windows, window, self.active_window_idx)
|
||||
if destroy:
|
||||
remove_window(self.os_window_id, self.id, window.id)
|
||||
else:
|
||||
detach_window(self.os_window_id, self.id, window.id)
|
||||
if window.overlay_for is not None:
|
||||
for idx, q in enumerate(self.windows):
|
||||
if q.id == window.overlay_for:
|
||||
@ -294,6 +300,33 @@ class Tab: # {{{
|
||||
if active_window:
|
||||
self.title_changed(active_window)
|
||||
|
||||
def detach_window(self, window):
|
||||
underlaid_window = None
|
||||
overlaid_window = window
|
||||
if window.overlay_for:
|
||||
for x in self.windows:
|
||||
if x.id == window.overlay_for:
|
||||
underlaid_window = x
|
||||
break
|
||||
elif window.overlay_window_id:
|
||||
underlaid_window = window
|
||||
overlaid_window = None
|
||||
for x in self.windows:
|
||||
if x.id == window.overlay_window_id:
|
||||
overlaid_window = x
|
||||
break
|
||||
if overlaid_window is not None:
|
||||
self.remove_window(overlaid_window, destroy=False)
|
||||
if underlaid_window is not None:
|
||||
self.remove_window(underlaid_window, destroy=False)
|
||||
return underlaid_window, overlaid_window
|
||||
|
||||
def attach_window(self, window):
|
||||
window.tab_id = self.id
|
||||
window.os_window_id = self.os_window_id
|
||||
attach_window(self.os_window_id, self.id, window.id)
|
||||
self._add_window(window)
|
||||
|
||||
def set_active_window_idx(self, idx):
|
||||
if idx != self.active_window_idx:
|
||||
self.active_window_idx = self.current_layout.set_active_window(self.windows, idx)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user