#1310 move windows into separate tabs

This commit is contained in:
Manuel Herrmann
2019-10-10 16:59:53 +02:00
parent eb9fe06d10
commit 497e2c9163
4 changed files with 82 additions and 10 deletions

View File

@@ -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 = ()

View File

@@ -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::

View File

@@ -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),

View File

@@ -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]