#1310 move windows into separate tabs
This commit is contained in:
@@ -39,6 +39,7 @@ from .utils import (
|
||||
log_error, open_url, parse_address_spec, remove_socket_file, safe_print,
|
||||
set_primary_selection, single_instance, startup_notification_handler
|
||||
)
|
||||
from .window import Window
|
||||
|
||||
|
||||
def listen_on(spec):
|
||||
@@ -960,14 +961,20 @@ class Boss:
|
||||
|
||||
def _new_tab(self, args, cwd_from=None, as_neighbor=False):
|
||||
special_window = None
|
||||
existing_window = None
|
||||
if args:
|
||||
if isinstance(args, SpecialWindowInstance):
|
||||
special_window = args
|
||||
elif isinstance(args, Window):
|
||||
existing_window = args
|
||||
else:
|
||||
special_window = self.args_to_special_window(args, cwd_from=cwd_from)
|
||||
tm = self.active_tab_manager
|
||||
if tm is not None:
|
||||
return tm.new_tab(special_window=special_window, cwd_from=cwd_from, as_neighbor=as_neighbor)
|
||||
return tm.new_tab(special_window=special_window,
|
||||
existing_window=existing_window,
|
||||
cwd_from=cwd_from,
|
||||
as_neighbor=as_neighbor)
|
||||
|
||||
def _create_tab(self, args, cwd_from=None):
|
||||
as_neighbor = False
|
||||
@@ -1020,6 +1027,13 @@ class Boss:
|
||||
if tm is not None:
|
||||
tm.move_tab(-1)
|
||||
|
||||
def _move_window_to_tab(self, args, cmd_from=None):
|
||||
window = self.active_window
|
||||
self._new_tab(window)
|
||||
|
||||
def move_window_to_tab(self, *args):
|
||||
self._move_window_to_tab(args)
|
||||
|
||||
def disable_ligatures_in(self, where, strategy):
|
||||
if isinstance(where, str):
|
||||
windows = ()
|
||||
|
||||
@@ -1074,6 +1074,12 @@ see :doc:`pipe`.
|
||||
# }}}
|
||||
|
||||
g('shortcuts.window') # {{{
|
||||
k('move_window_to_tab', 'kitty_mod+x', 'move_window_to_tab', _(''), long_text=_('''
|
||||
You can move a window into a separate tab, for example::
|
||||
|
||||
map kitty_mod+x move_window_to_tab
|
||||
|
||||
'''))
|
||||
k('new_window', 'kitty_mod+enter', 'new_window', _(''), long_text=_('''
|
||||
You can open a new window running an arbitrary program, for example::
|
||||
|
||||
|
||||
@@ -116,6 +116,31 @@ 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);
|
||||
@@ -756,6 +781,7 @@ THREE_ID(remove_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)
|
||||
@@ -777,6 +803,7 @@ 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),
|
||||
|
||||
@@ -12,7 +12,7 @@ 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,
|
||||
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, change_window_tab,
|
||||
x11_window_id
|
||||
)
|
||||
from .layout import create_layout_object_for, evict_cached_layouts
|
||||
@@ -38,7 +38,7 @@ def add_active_id_to_history(items, item_id, maxlen=64):
|
||||
|
||||
class Tab: # {{{
|
||||
|
||||
def __init__(self, tab_manager, session_tab=None, special_window=None, cwd_from=None):
|
||||
def __init__(self, tab_manager, session_tab=None, special_window=None, existing_window=None, cwd_from=None):
|
||||
self._active_window_idx = 0
|
||||
self.tab_manager_ref = weakref.ref(tab_manager)
|
||||
self.os_window_id = tab_manager.os_window_id
|
||||
@@ -61,7 +61,9 @@ class Tab: # {{{
|
||||
self.cwd = self.args.directory
|
||||
sl = self.enabled_layouts[0]
|
||||
self._set_current_layout(sl)
|
||||
if special_window is None:
|
||||
if existing_window is not None:
|
||||
self.add_window(existing_window)
|
||||
elif special_window is None:
|
||||
self.new_window(cwd_from=cwd_from)
|
||||
else:
|
||||
self.new_special_window(special_window)
|
||||
@@ -232,6 +234,11 @@ 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()
|
||||
return window
|
||||
|
||||
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 +252,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 +271,14 @@ 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)
|
||||
remove_window(self.os_window_id, self.id, window.id)
|
||||
if destroy:
|
||||
remove_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:
|
||||
@@ -545,11 +552,29 @@ class TabManager: # {{{
|
||||
self._set_active_tab(nidx)
|
||||
self.mark_tab_bar_dirty()
|
||||
|
||||
def new_tab(self, special_window=None, cwd_from=None, as_neighbor=False):
|
||||
def new_tab(self, special_window=None, existing_window=None, cwd_from=None, as_neighbor=False):
|
||||
nidx = self.active_tab_idx + 1
|
||||
idx = len(self.tabs)
|
||||
self._add_tab(Tab(self, special_window=special_window, cwd_from=cwd_from))
|
||||
if existing_window is not None:
|
||||
for tab in self.tabs:
|
||||
if existing_window not in tab:
|
||||
continue
|
||||
if len(tab) == 1:
|
||||
return tab
|
||||
tab.remove_window(existing_window, destroy=False)
|
||||
old_tab = tab
|
||||
break
|
||||
self._add_tab(Tab(self, special_window=special_window, existing_window=existing_window, cwd_from=cwd_from))
|
||||
self._set_active_tab(idx)
|
||||
|
||||
if existing_window is not None:
|
||||
active_tab = self.active_tab
|
||||
change_window_tab(existing_window.id,
|
||||
old_tab.os_window_id, old_tab.id,
|
||||
active_tab.os_window_id, active_tab.id)
|
||||
existing_window.os_window_id = active_tab.os_window_id
|
||||
existing_window.tab_id = active_tab.id
|
||||
|
||||
if len(self.tabs) > 2 and as_neighbor and idx != nidx:
|
||||
for i in range(idx, nidx, -1):
|
||||
self.tabs[i], self.tabs[i-1] = self.tabs[i-1], self.tabs[i]
|
||||
|
||||
Reference in New Issue
Block a user