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;
|
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
|
static inline void
|
||||||
update_window_title(id_type os_window_id, id_type tab_id, id_type window_id, PyObject *title) {
|
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);
|
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;
|
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
|
static inline void
|
||||||
destroy_tab(Tab *tab) {
|
destroy_tab(Tab *tab) {
|
||||||
for (size_t i = tab->num_windows; i > 0; i--) remove_window_inner(tab, tab->windows[i - 1].id);
|
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_OBJ(update_window_title)
|
||||||
THREE_ID(remove_window)
|
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(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_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(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); }
|
PYWRAP0(current_os_window) { OSWindow *w = current_os_window(); if (!w) Py_RETURN_NONE; return PyLong_FromUnsignedLongLong(w->id); }
|
||||||
TWO_ID(remove_tab)
|
TWO_ID(remove_tab)
|
||||||
KI(set_active_tab)
|
KI(set_active_tab)
|
||||||
@ -803,10 +825,11 @@ static PyMethodDef module_methods[] = {
|
|||||||
MW(pt_to_px, METH_VARARGS),
|
MW(pt_to_px, METH_VARARGS),
|
||||||
MW(add_tab, METH_O),
|
MW(add_tab, METH_O),
|
||||||
MW(add_window, METH_VARARGS),
|
MW(add_window, METH_VARARGS),
|
||||||
MW(change_window_tab, METH_VARARGS),
|
|
||||||
MW(update_window_title, METH_VARARGS),
|
MW(update_window_title, METH_VARARGS),
|
||||||
MW(remove_tab, METH_VARARGS),
|
MW(remove_tab, METH_VARARGS),
|
||||||
MW(remove_window, 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_tab, METH_VARARGS),
|
||||||
MW(set_active_window, METH_VARARGS),
|
MW(set_active_window, METH_VARARGS),
|
||||||
MW(swap_tabs, METH_VARARGS),
|
MW(swap_tabs, METH_VARARGS),
|
||||||
@ -832,6 +855,15 @@ static PyMethodDef module_methods[] = {
|
|||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{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
|
bool
|
||||||
init_state(PyObject *module) {
|
init_state(PyObject *module) {
|
||||||
global_state.font_sz_in_pts = 11.0;
|
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;
|
if (PyStructSequence_InitType2(&RegionType, ®ion_desc) != 0) return false;
|
||||||
Py_INCREF((PyObject *) &RegionType);
|
Py_INCREF((PyObject *) &RegionType);
|
||||||
PyModule_AddObject(module, "Region", (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;
|
return true;
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|||||||
@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
import weakref
|
import weakref
|
||||||
from collections import deque, namedtuple
|
from collections import deque, namedtuple
|
||||||
from functools import partial
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from .borders import Borders
|
from .borders import Borders
|
||||||
from .child import Child
|
from .child import Child
|
||||||
from .constants import appname, get_boss, is_macos, is_wayland
|
from .constants import appname, get_boss, is_macos, is_wayland
|
||||||
from .fast_data_types import (
|
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,
|
pt_to_px, remove_tab, remove_window, ring_bell, set_active_tab, swap_tabs,
|
||||||
x11_window_id
|
x11_window_id
|
||||||
)
|
)
|
||||||
@ -232,6 +232,10 @@ class Tab: # {{{
|
|||||||
ans.fork()
|
ans.fork()
|
||||||
return ans
|
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(
|
def new_window(
|
||||||
self, use_shell=True, cmd=None, stdin=None, override_title=None,
|
self, use_shell=True, cmd=None, stdin=None, override_title=None,
|
||||||
cwd_from=None, cwd=None, overlay_for=None, env=None, location=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
|
overlaid.overlay_window_id = window.id
|
||||||
# Must add child before laying out so that resize_pty succeeds
|
# Must add child before laying out so that resize_pty succeeds
|
||||||
get_boss().add_child(window)
|
get_boss().add_child(window)
|
||||||
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx, location)
|
self._add_window(window, location=location)
|
||||||
self.relayout_borders()
|
|
||||||
return window
|
return window
|
||||||
|
|
||||||
def new_special_window(self, special_window, location=None, copy_colors_from=None):
|
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:
|
if w.id == old_window_id:
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
def remove_window(self, window):
|
def remove_window(self, window, destroy=True):
|
||||||
idx = self.previous_active_window_idx(1)
|
idx = self.previous_active_window_idx(1)
|
||||||
next_window_id = None
|
next_window_id = None
|
||||||
if idx is not None:
|
if idx is not None:
|
||||||
next_window_id = self.windows[idx].id
|
next_window_id = self.windows[idx].id
|
||||||
active_window_idx = self.current_layout.remove_window(self.windows, window, self.active_window_idx)
|
active_window_idx = self.current_layout.remove_window(self.windows, window, self.active_window_idx)
|
||||||
remove_window(self.os_window_id, self.id, window.id)
|
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:
|
if window.overlay_for is not None:
|
||||||
for idx, q in enumerate(self.windows):
|
for idx, q in enumerate(self.windows):
|
||||||
if q.id == window.overlay_for:
|
if q.id == window.overlay_for:
|
||||||
@ -294,6 +300,33 @@ class Tab: # {{{
|
|||||||
if active_window:
|
if active_window:
|
||||||
self.title_changed(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):
|
def set_active_window_idx(self, idx):
|
||||||
if idx != self.active_window_idx:
|
if idx != self.active_window_idx:
|
||||||
self.active_window_idx = self.current_layout.set_active_window(self.windows, idx)
|
self.active_window_idx = self.current_layout.set_active_window(self.windows, idx)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user