Handle mouse clicks when displaying focus window overlay

This commit is contained in:
Kovid Goyal
2021-10-15 09:55:15 +05:30
parent 3c2e521dd7
commit a16ffcdde2
6 changed files with 75 additions and 9 deletions

View File

@@ -31,14 +31,14 @@ from .fast_data_types import (
GLFW_MOD_SUPER, IMPERATIVE_CLOSE_REQUESTED, NO_CLOSE_REQUESTED, GLFW_MOD_SUPER, IMPERATIVE_CLOSE_REQUESTED, NO_CLOSE_REQUESTED,
ChildMonitor, KeyEvent, add_timer, apply_options_update, ChildMonitor, KeyEvent, add_timer, apply_options_update,
background_opacity_of, change_background_opacity, change_os_window_state, background_opacity_of, change_background_opacity, change_os_window_state,
cocoa_set_menubar_title, create_os_window, cocoa_set_menubar_title, create_os_window, GLFW_PRESS, GLFW_MOUSE_BUTTON_LEFT,
current_application_quit_request, current_os_window, destroy_global_data, current_application_quit_request, current_os_window, destroy_global_data,
focus_os_window, get_clipboard_string, get_options, get_os_window_size, focus_os_window, get_clipboard_string, get_options, get_os_window_size,
global_font_size, mark_os_window_for_close, os_window_font_size, global_font_size, mark_os_window_for_close, os_window_font_size,
patch_global_colors, ring_bell, safe_pipe, set_application_quit_request, patch_global_colors, redirect_mouse_handling, ring_bell, safe_pipe,
set_background_image, set_boss, set_clipboard_string, set_in_sequence_mode, set_application_quit_request, set_background_image, set_boss,
set_options, set_os_window_size, thread_write, toggle_fullscreen, set_clipboard_string, set_in_sequence_mode, set_options,
toggle_maximized set_os_window_size, thread_write, toggle_fullscreen, toggle_maximized
) )
from .key_encoding import get_name_to_functional_number_map from .key_encoding import get_name_to_functional_number_map
from .keys import get_shortcut, shortcut_matches from .keys import get_shortcut, shortcut_matches
@@ -52,7 +52,7 @@ from .session import Session, create_sessions, get_os_window_sizing_data
from .tabs import ( from .tabs import (
SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager
) )
from .types import _T, SingleKey, ac from .types import _T, SingleKey, WindowSystemMouseEvent, ac
from .typing import PopenType, TypedDict from .typing import PopenType, TypedDict
from .utils import ( from .utils import (
func_name, get_editor, get_new_os_window_size, get_primary_selection, func_name, get_editor, get_new_os_window_size, get_primary_selection,
@@ -183,6 +183,7 @@ class Boss:
self.args = args self.args = args
self.global_shortcuts_map = {v: KeyAction(k) for k, v in global_shortcuts.items()} self.global_shortcuts_map = {v: KeyAction(k) for k, v in global_shortcuts.items()}
self.global_shortcuts = global_shortcuts self.global_shortcuts = global_shortcuts
self.mouse_handler: Optional[Callable[[WindowSystemMouseEvent], None]] = None
self.update_keymap() self.update_keymap()
if is_macos: if is_macos:
from .fast_data_types import ( from .fast_data_types import (
@@ -779,6 +780,10 @@ class Boss:
elif isinstance(key_action, KeyAction): elif isinstance(key_action, KeyAction):
return self.dispatch_action(key_action) return self.dispatch_action(key_action)
def clear_pending_sequences(self) -> None:
self.pending_sequences = self.default_pending_action = None
set_in_sequence_mode(False)
def process_sequence(self, ev: KeyEvent) -> None: def process_sequence(self, ev: KeyEvent) -> None:
if not self.pending_sequences: if not self.pending_sequences:
set_in_sequence_mode(False) set_in_sequence_mode(False)
@@ -798,8 +803,7 @@ class Boss:
self.pending_sequences = remaining self.pending_sequences = remaining
else: else:
matched_action = matched_action or self.default_pending_action matched_action = matched_action or self.default_pending_action
self.pending_sequences = self.default_pending_action = None self.clear_pending_sequences()
set_in_sequence_mode(False)
if matched_action is not None: if matched_action is not None:
self.dispatch_action(matched_action) self.dispatch_action(matched_action)
@@ -825,6 +829,8 @@ class Boss:
pending_sequences[(SingleKey(mods=mods, key=fmap[f'KP_{idx+1}']),)] = ac pending_sequences[(SingleKey(mods=mods, key=fmap[f'KP_{idx+1}']),)] = ac
if count > 1: if count > 1:
self.set_pending_sequences(pending_sequences, default_pending_action=KeyAction('focus_visible_window_trigger')) self.set_pending_sequences(pending_sequences, default_pending_action=KeyAction('focus_visible_window_trigger'))
redirect_mouse_handling(True)
self.mouse_handler = self.focus_visible_window_mouse_handler
else: else:
self.focus_visible_window_trigger() self.focus_visible_window_trigger()
if get_options().enable_audio_bell: if get_options().enable_audio_bell:
@@ -832,12 +838,34 @@ class Boss:
def focus_visible_window_trigger(self, idx: int = -1) -> None: def focus_visible_window_trigger(self, idx: int = -1) -> None:
tab = self.active_tab tab = self.active_tab
redirect_mouse_handling(False)
if tab is not None: if tab is not None:
for window in tab: for window in tab:
window.screen.set_window_number() window.screen.set_window_number()
if idx > -1: if idx > -1:
tab.nth_window(idx) tab.nth_window(idx)
def focus_visible_window_mouse_handler(self, ev: WindowSystemMouseEvent) -> None:
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)
tab = self.active_tab
if w is not None and tab is not None and w in tab:
tab.set_active_window(w)
self.clear_pending_sequences()
self.focus_visible_window_trigger()
return
if ev.button > -1:
self.clear_pending_sequences()
self.focus_visible_window_trigger()
def mouse_event(
self, in_tab_bar: bool, window_id: int, action: int, modifiers: int, button: int,
currently_pressed_button: int, x: float, y: float
) -> None:
if self.mouse_handler is not None:
ev = WindowSystemMouseEvent(in_tab_bar, window_id, action, modifiers, button, currently_pressed_button, x, y)
self.mouse_handler(ev)
@ac('win', 'Interactively select a window in the current tab') @ac('win', 'Interactively select a window in the current tab')
def select_window_in_tab(self) -> None: def select_window_in_tab(self) -> None:
tab = self.active_tab tab = self.active_tab

View File

@@ -1246,3 +1246,7 @@ def get_all_processes() -> Tuple[int, ...]:
def num_users() -> int: def num_users() -> int:
pass pass
def redirect_mouse_handling(yes: bool) -> None:
pass

View File

@@ -669,6 +669,16 @@ mouse_event(const int button, int modifiers, int action) {
unsigned int window_idx = 0; unsigned int window_idx = 0;
Window *w = NULL; Window *w = NULL;
debug("%s mouse_button: %d %s", action == GLFW_RELEASE ? "\x1b[32mRelease\x1b[m" : (button < 0 ? "\x1b[36mMove\x1b[m" : "\x1b[31mPress\x1b[m"), button, format_mods(modifiers)); debug("%s mouse_button: %d %s", action == GLFW_RELEASE ? "\x1b[32mRelease\x1b[m" : (button < 0 ? "\x1b[36mMove\x1b[m" : "\x1b[31mPress\x1b[m"), button, format_mods(modifiers));
if (global_state.redirect_mouse_handling) {
w = window_for_event(&window_idx, &in_tab_bar);
call_boss(mouse_event, "OK iiii dd",
(in_tab_bar ? Py_True : Py_False), (w ? w->id : 0),
action, modifiers, button, currently_pressed_button(),
global_state.callback_os_window->mouse_x, global_state.callback_os_window->mouse_y
);
debug("mouse handling redirected\n");
return;
}
if (global_state.active_drag_in_window) { if (global_state.active_drag_in_window) {
if (button == -1) { // drag move if (button == -1) { // drag move
w = window_for_id(global_state.active_drag_in_window); w = window_for_id(global_state.active_drag_in_window);

View File

@@ -1055,7 +1055,18 @@ PYWRAP1(click_mouse_url) {
if (click_mouse_url(a, b, c)) { Py_RETURN_TRUE; } if (click_mouse_url(a, b, c)) { Py_RETURN_TRUE; }
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
PYWRAP1(move_cursor_to_mouse_if_in_prompt) { id_type a, b, c; PA("KKK", &a, &b, &c); if (move_cursor_to_mouse_if_in_prompt(a, b, c)) Py_RETURN_TRUE; Py_RETURN_FALSE; }
PYWRAP1(move_cursor_to_mouse_if_in_prompt) {
id_type a, b, c; PA("KKK", &a, &b, &c);
if (move_cursor_to_mouse_if_in_prompt(a, b, c)) Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
PYWRAP1(redirect_mouse_handling) {
global_state.redirect_mouse_handling = PyObject_IsTrue(args) ? true : false;
Py_RETURN_NONE;
}
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(detach_window)
@@ -1080,6 +1091,7 @@ static PyMethodDef module_methods[] = {
MW(get_options, METH_NOARGS), MW(get_options, METH_NOARGS),
MW(click_mouse_url, METH_VARARGS), MW(click_mouse_url, METH_VARARGS),
MW(move_cursor_to_mouse_if_in_prompt, METH_VARARGS), MW(move_cursor_to_mouse_if_in_prompt, METH_VARARGS),
MW(redirect_mouse_handling, METH_O),
MW(mouse_selection, METH_VARARGS), MW(mouse_selection, METH_VARARGS),
MW(set_in_sequence_mode, METH_O), MW(set_in_sequence_mode, METH_O),
MW(resolve_key_mods, METH_VARARGS), MW(resolve_key_mods, METH_VARARGS),

View File

@@ -217,6 +217,7 @@ typedef struct {
id_type active_drag_in_window, tracked_drag_in_window; id_type active_drag_in_window, tracked_drag_in_window;
int active_drag_button; int active_drag_button;
CloseRequest quit_request; CloseRequest quit_request;
bool redirect_mouse_handling;
} GlobalState; } GlobalState;
extern GlobalState global_state; extern GlobalState global_state;

View File

@@ -61,6 +61,17 @@ class MouseEvent(NamedTuple):
grabbed: bool = False grabbed: bool = False
class WindowSystemMouseEvent(NamedTuple):
in_tab_bar: bool
window_id: int
action: int
modifiers: int
button: int
currently_pressed_button: int
x: float
y: float
ConvertibleToNumbers = Union[str, bytes, int, float] ConvertibleToNumbers = Union[str, bytes, int, float]