mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-21 16:05:02 +02:00
Refactor visual window select infrastructure to make it reuseable
This commit is contained in:
104
kitty/boss.py
104
kitty/boss.py
@@ -158,6 +158,7 @@ class Boss:
|
|||||||
self.update_check_process: Optional[PopenType] = None
|
self.update_check_process: Optional[PopenType] = None
|
||||||
self.window_id_map: WeakValueDictionary[int, Window] = WeakValueDictionary()
|
self.window_id_map: WeakValueDictionary[int, Window] = WeakValueDictionary()
|
||||||
self.startup_colors = {k: opts[k] for k in opts if isinstance(opts[k], Color)}
|
self.startup_colors = {k: opts[k] for k in opts if isinstance(opts[k], Color)}
|
||||||
|
self.visual_window_select_callback: Optional[Callable[[Tab, Window], None]] = None
|
||||||
self.startup_cursor_text_color = opts.cursor_text_color
|
self.startup_cursor_text_color = opts.cursor_text_color
|
||||||
self.pending_sequences: Optional[SubSequenceMap] = None
|
self.pending_sequences: Optional[SubSequenceMap] = None
|
||||||
self.default_pending_action: Optional[KeyAction] = None
|
self.default_pending_action: Optional[KeyAction] = None
|
||||||
@@ -807,60 +808,58 @@ class Boss:
|
|||||||
if matched_action is not None:
|
if matched_action is not None:
|
||||||
self.dispatch_action(matched_action)
|
self.dispatch_action(matched_action)
|
||||||
|
|
||||||
@ac('win', '''
|
def visual_window_select_action(self, tab: Tab, callback: Callable[[Tab, Window], None], choose_msg: str) -> None:
|
||||||
Focus a visible window by pressing the number of the window. Window numbers are displayed
|
self.visual_window_select_callback = callback
|
||||||
over the windows for easy selection in this mode.
|
if tab.current_layout.only_active_window_visible:
|
||||||
''')
|
self.select_window_in_tab_using_overlay(tab, choose_msg)
|
||||||
def focus_visible_window(self) -> None:
|
return
|
||||||
tab = self.active_tab
|
pending_sequences: SubSequenceMap = {}
|
||||||
if tab is not None:
|
count = 0
|
||||||
if tab.current_layout.only_active_window_visible:
|
fmap = get_name_to_functional_number_map()
|
||||||
self.select_window_in_tab()
|
for idx, window in tab.windows.iter_windows_with_number(only_visible=True):
|
||||||
return
|
if idx > 9:
|
||||||
pending_sequences: SubSequenceMap = {}
|
break
|
||||||
count = 0
|
count += 1
|
||||||
fmap = get_name_to_functional_number_map()
|
num = idx + 1
|
||||||
for idx, window in tab.windows.iter_windows_with_number(only_visible=True):
|
ac = KeyAction('visual_window_select_action_trigger', (tab.id, window.id))
|
||||||
if idx > 9:
|
if num == 10:
|
||||||
break
|
num = 0
|
||||||
count += 1
|
window.screen.set_window_number(num)
|
||||||
num = idx + 1
|
for mods in (0, GLFW_MOD_CONTROL, GLFW_MOD_CONTROL | GLFW_MOD_SHIFT, GLFW_MOD_SUPER, GLFW_MOD_ALT, GLFW_MOD_SHIFT):
|
||||||
ac = KeyAction('focus_visible_window_trigger', (idx,))
|
pending_sequences[(SingleKey(mods=mods, key=ord(str(num))),)] = ac
|
||||||
if num == 10:
|
pending_sequences[(SingleKey(mods=mods, key=fmap[f'KP_{num}']),)] = ac
|
||||||
num = 0
|
if count > 1:
|
||||||
window.screen.set_window_number(num)
|
self.set_pending_sequences(pending_sequences, default_pending_action=KeyAction('visual_window_select_action_trigger', (tab.id,)))
|
||||||
for mods in (0, GLFW_MOD_CONTROL, GLFW_MOD_CONTROL | GLFW_MOD_SHIFT, GLFW_MOD_SUPER, GLFW_MOD_ALT, GLFW_MOD_SHIFT):
|
redirect_mouse_handling(True)
|
||||||
pending_sequences[(SingleKey(mods=mods, key=ord(str(num))),)] = ac
|
self.mouse_handler = self.focus_visible_window_mouse_handler
|
||||||
pending_sequences[(SingleKey(mods=mods, key=fmap[f'KP_{num}']),)] = ac
|
else:
|
||||||
if count > 1:
|
self.visual_window_select_action_trigger(tab.id)
|
||||||
self.set_pending_sequences(pending_sequences, default_pending_action=KeyAction('focus_visible_window_trigger'))
|
if get_options().enable_audio_bell:
|
||||||
redirect_mouse_handling(True)
|
ring_bell()
|
||||||
self.mouse_handler = self.focus_visible_window_mouse_handler
|
|
||||||
else:
|
|
||||||
self.focus_visible_window_trigger()
|
|
||||||
if get_options().enable_audio_bell:
|
|
||||||
ring_bell()
|
|
||||||
|
|
||||||
def focus_visible_window_trigger(self, idx: int = -1) -> None:
|
def visual_window_select_action_trigger(self, tab_id: int, window_id: int = 0) -> None:
|
||||||
tab = self.active_tab
|
|
||||||
redirect_mouse_handling(False)
|
redirect_mouse_handling(False)
|
||||||
self.clear_pending_sequences()
|
self.clear_pending_sequences()
|
||||||
if tab is not None:
|
for tab in self.all_tabs:
|
||||||
for window in tab:
|
if tab.id == tab_id:
|
||||||
window.screen.set_window_number()
|
for window in tab:
|
||||||
if idx > -1:
|
window.screen.set_window_number()
|
||||||
tab.nth_window(idx)
|
if window.id == window_id:
|
||||||
|
if self.visual_window_select_callback:
|
||||||
|
self.visual_window_select_callback(tab, window)
|
||||||
|
break
|
||||||
|
self.visual_window_select_callback = None
|
||||||
|
|
||||||
def focus_visible_window_mouse_handler(self, ev: WindowSystemMouseEvent) -> None:
|
def focus_visible_window_mouse_handler(self, ev: WindowSystemMouseEvent) -> None:
|
||||||
|
tab = self.active_tab
|
||||||
if ev.button == GLFW_MOUSE_BUTTON_LEFT and ev.action == GLFW_PRESS and ev.window_id:
|
if ev.button == GLFW_MOUSE_BUTTON_LEFT and ev.action == GLFW_PRESS and ev.window_id:
|
||||||
w = self.window_id_map.get(ev.window_id)
|
w = self.window_id_map.get(ev.window_id)
|
||||||
tab = self.active_tab
|
|
||||||
if w is not None and tab is not None and w in tab:
|
if w is not None and tab is not None and w in tab:
|
||||||
tab.set_active_window(w)
|
tab.set_active_window(w)
|
||||||
self.focus_visible_window_trigger()
|
self.visual_window_select_action_trigger(tab.id)
|
||||||
return
|
return
|
||||||
if ev.button > -1:
|
if ev.button > -1 and tab is not None:
|
||||||
self.focus_visible_window_trigger()
|
self.visual_window_select_action_trigger(tab.id)
|
||||||
|
|
||||||
def mouse_event(
|
def mouse_event(
|
||||||
self, in_tab_bar: bool, window_id: int, action: int, modifiers: int, button: int,
|
self, in_tab_bar: bool, window_id: int, action: int, modifiers: int, button: int,
|
||||||
@@ -870,12 +869,8 @@ class Boss:
|
|||||||
ev = WindowSystemMouseEvent(in_tab_bar, window_id, action, modifiers, button, currently_pressed_button, x, y)
|
ev = WindowSystemMouseEvent(in_tab_bar, window_id, action, modifiers, button, currently_pressed_button, x, y)
|
||||||
self.mouse_handler(ev)
|
self.mouse_handler(ev)
|
||||||
|
|
||||||
@ac('win', 'Interactively select a window in the current tab')
|
def select_window_in_tab_using_overlay(self, tab: Tab, msg: str) -> None:
|
||||||
def select_window_in_tab(self) -> None:
|
aw = tab.active_window
|
||||||
tab = self.active_tab
|
|
||||||
if tab is None:
|
|
||||||
return
|
|
||||||
aw = self.active_window
|
|
||||||
windows = tuple((w.id, w.title) for i, w in tab.windows.iter_windows_with_number(only_visible=False) if w is not aw)
|
windows = tuple((w.id, w.title) for i, w in tab.windows.iter_windows_with_number(only_visible=False) if w is not aw)
|
||||||
tab_id = tab.id
|
tab_id = tab.id
|
||||||
if len(windows) < 1:
|
if len(windows) < 1:
|
||||||
@@ -886,10 +881,13 @@ class Boss:
|
|||||||
def chosen(ans: Union[None, int, str]) -> None:
|
def chosen(ans: Union[None, int, str]) -> None:
|
||||||
if isinstance(ans, int):
|
if isinstance(ans, int):
|
||||||
for tab in self.all_tabs:
|
for tab in self.all_tabs:
|
||||||
if tab.id == tab_id:
|
if tab.id == tab_id and self.visual_window_select_callback:
|
||||||
tab.set_active_window(ans)
|
w = self.window_id_map.get(ans)
|
||||||
|
if w is not None:
|
||||||
|
self.visual_window_select_callback(tab, w)
|
||||||
break
|
break
|
||||||
self.choose_entry('Choose window to switch to', windows, chosen)
|
self.visual_window_select_callback = None
|
||||||
|
self.choose_entry(msg, windows, chosen)
|
||||||
|
|
||||||
@ac('win', '''
|
@ac('win', '''
|
||||||
Resize the active window interactively
|
Resize the active window interactively
|
||||||
|
|||||||
@@ -574,6 +574,16 @@ class Tab: # {{{
|
|||||||
if w is not None and w.id != window_id:
|
if w is not None and w.id != window_id:
|
||||||
self.current_layout.move_window_to_group(self.windows, group.id)
|
self.current_layout.move_window_to_group(self.windows, group.id)
|
||||||
|
|
||||||
|
@ac('win', '''
|
||||||
|
Focus a visible window by pressing the number of the window. Window numbers are displayed
|
||||||
|
over the windows for easy selection in this mode.
|
||||||
|
''')
|
||||||
|
def focus_visible_window(self) -> None:
|
||||||
|
def callback(tab: Tab, window: Window) -> None:
|
||||||
|
tab.set_active_window(window)
|
||||||
|
|
||||||
|
get_boss().visual_window_select_action(self, callback, 'Choose window to switch to')
|
||||||
|
|
||||||
@ac('win', 'Move active window to the top (make it the first window)')
|
@ac('win', 'Move active window to the top (make it the first window)')
|
||||||
def move_window_to_top(self) -> None:
|
def move_window_to_top(self) -> None:
|
||||||
n = self.windows.active_group_idx
|
n = self.windows.active_group_idx
|
||||||
|
|||||||
Reference in New Issue
Block a user