Consolidate visual select cleanup in one place

Also ensure callback is called even when only a single window is present
and when selecting in stack
This commit is contained in:
Kovid Goyal 2021-10-31 10:36:23 +05:30
parent d160db1bcd
commit da7fa53b1a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -27,16 +27,17 @@ from .constants import (
from .fast_data_types import (
CLOSE_BEING_CONFIRMED, GLFW_MOD_ALT, GLFW_MOD_CONTROL, GLFW_MOD_SHIFT,
GLFW_MOD_SUPER, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS,
IMPERATIVE_CLOSE_REQUESTED, NO_CLOSE_REQUESTED, ChildMonitor, KeyEvent,
add_timer, apply_options_update, background_opacity_of,
IMPERATIVE_CLOSE_REQUESTED, NO_CLOSE_REQUESTED, ChildMonitor, Color,
KeyEvent, add_timer, apply_options_update, background_opacity_of,
change_background_opacity, change_os_window_state, cocoa_set_menubar_title,
create_os_window, current_application_quit_request, current_os_window,
destroy_global_data, focus_os_window, get_clipboard_string, get_options,
get_os_window_size, global_font_size, mark_os_window_for_close,
os_window_font_size, patch_global_colors, redirect_mouse_handling,
ring_bell, safe_pipe, set_application_quit_request, set_background_image,
set_boss, set_clipboard_string, set_in_sequence_mode, set_options,
set_os_window_size, thread_write, toggle_fullscreen, toggle_maximized, Color
destroy_global_data, focus_os_window, get_boss, get_clipboard_string,
get_options, get_os_window_size, global_font_size,
mark_os_window_for_close, os_window_font_size, patch_global_colors,
redirect_mouse_handling, ring_bell, safe_pipe,
set_application_quit_request, set_background_image, set_boss,
set_clipboard_string, set_in_sequence_mode, set_options,
set_os_window_size, thread_write, toggle_fullscreen, toggle_maximized
)
from .key_encoding import get_name_to_functional_number_map
from .keys import get_shortcut, shortcut_matches
@ -148,6 +149,32 @@ class VisualSelect:
self.callback = callback
self.window_ids: List[int] = []
def cancel(self) -> None:
self.clear_global_state()
self.callback(None, None)
def trigger(self, window_id: int) -> None:
boss = self.clear_global_state()
w = boss.window_id_map.get(window_id)
if w is None:
self.callback(None, None)
else:
tab = w.tabref()
if tab is None:
self.callback(None, None)
else:
self.callback(tab, w)
def clear_global_state(self) -> 'Boss':
boss = get_boss()
redirect_mouse_handling(False)
boss.clear_pending_sequences()
for wid in self.window_ids:
w = boss.window_id_map.get(wid)
if w is not None:
w.screen.set_window_number()
return boss
class Boss:
@ -825,7 +852,8 @@ class Boss:
def cancel_current_visual_select(self) -> None:
if self.current_visual_select:
self.visual_window_select_action_trigger(self.current_visual_select.tab_id)
self.current_visual_select.cancel()
self.current_visual_select = None
def visual_window_select_action(self, tab: Tab, callback: Callable[[Optional[Tab], Optional[Window]], None], choose_msg: str) -> None:
self.cancel_current_visual_select()
@ -834,14 +862,12 @@ class Boss:
return
self.current_visual_select = VisualSelect(tab.id, callback)
pending_sequences: SubSequenceMap = {}
count = 0
fmap = get_name_to_functional_number_map()
for idx, window in tab.windows.iter_windows_with_number(only_visible=True):
if idx > 9:
break
count += 1
num = idx + 1
ac = KeyAction('visual_window_select_action_trigger', (tab.id, window.id))
ac = KeyAction('visual_window_select_action_trigger', (window.id,))
if num == 10:
num = 0
window.screen.set_window_number(num)
@ -849,44 +875,29 @@ class Boss:
for mods in (0, GLFW_MOD_CONTROL, GLFW_MOD_CONTROL | GLFW_MOD_SHIFT, GLFW_MOD_SUPER, GLFW_MOD_ALT, GLFW_MOD_SHIFT):
pending_sequences[(SingleKey(mods=mods, key=ord(str(num))),)] = ac
pending_sequences[(SingleKey(mods=mods, key=fmap[f'KP_{num}']),)] = ac
if count > 1:
self.set_pending_sequences(pending_sequences, default_pending_action=KeyAction('visual_window_select_action_trigger', (tab.id,)))
if len(self.current_visual_select.window_ids) > 1:
self.set_pending_sequences(pending_sequences, default_pending_action=KeyAction('visual_window_select_action_trigger', (0,)))
redirect_mouse_handling(True)
self.mouse_handler = self.focus_visible_window_mouse_handler
else:
self.visual_window_select_action_trigger(tab.id)
self.visual_window_select_action_trigger(self.current_visual_select.window_ids[0] if self.current_visual_select.window_ids else 0)
if get_options().enable_audio_bell:
ring_bell()
def visual_window_select_action_trigger(self, tab_id: int, window_id: int = 0) -> None:
redirect_mouse_handling(False)
self.clear_pending_sequences()
cv = self.current_visual_select
def visual_window_select_action_trigger(self, window_id: int = 0) -> None:
if self.current_visual_select:
self.current_visual_select.trigger(window_id)
self.current_visual_select = None
if cv is not None:
called = False
for wid in cv.window_ids:
w = self.window_id_map.get(wid)
if w is not None:
w.screen.set_window_number()
if wid == window_id:
tab = w.tabref()
if tab is not None:
cv.callback(tab, w)
called = True
if not called:
cv.callback(None, 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:
w = self.window_id_map.get(ev.window_id)
if w is not None and tab is not None and w in tab:
tab.set_active_window(w)
self.visual_window_select_action_trigger(tab.id)
self.visual_window_select_action_trigger(w.id)
return
if ev.button > -1 and tab is not None:
self.visual_window_select_action_trigger(tab.id)
self.visual_window_select_action_trigger()
def mouse_event(
self, in_tab_bar: bool, window_id: int, action: int, modifiers: int, button: int,
@ -899,9 +910,8 @@ class Boss:
def select_window_in_tab_using_overlay(self, tab: Tab, msg: str) -> None:
aw = tab.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)
tab_id = tab.id
if len(windows) < 1:
self.visual_window_select_action_trigger(tab.id)
self.visual_window_select_action_trigger(windows[0][0] if windows else 0)
if get_options().enable_audio_bell:
ring_bell()
return
@ -911,12 +921,7 @@ class Boss:
q = self.current_visual_select
self.current_visual_select = None
if cvs and q is cvs and isinstance(ans, int):
for tab in self.all_tabs:
if tab.id == tab_id:
w = self.window_id_map.get(ans)
if w is not None:
cvs.callback(tab, w)
break
q.trigger(ans)
self.choose_entry(msg, windows, chosen)
@ac('win', '''