diff --git a/kitty/boss.py b/kitty/boss.py index bed9be9e9..d0e1e393f 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -2419,12 +2419,16 @@ class Boss: if tab: tab.set_active_window(window_id) - def drag_resize_start(self, x: float, y: float, cell_width: int, cell_height: int) -> None: + def drag_resize_start(self, x: float, y: float, cell_width: int, cell_height: int) -> bool: if tab := self.active_tab: horizontal, vertical = tab.current_layout.drag_resize_target_windows(x, y, tab.windows) + if horizontal is None or vertical is None: + return False self.drag_resize_of_window = WindowResizeDrag( is_active=True, horizontal_target_window_id=horizontal.id, vertical_target_window_id=vertical.id, cell_width=cell_width, cell_height=cell_height, initial_x=x, initial_y=y) + return True + return False def drag_resize_update(self, x: float, y: float) -> None: if not (r := self.drag_resize_of_window): diff --git a/kitty/layout/base.py b/kitty/layout/base.py index 92fdbb3b2..bd0e5e77b 100644 --- a/kitty/layout/base.py +++ b/kitty/layout/base.py @@ -452,10 +452,12 @@ class Layout: def set_layout_state(self, layout_state: dict[str, Any], map_group_id: WindowMapper) -> bool: return True - def drag_resize_target_windows(self, x: float, y: float, all_windows: WindowList) -> tuple[WindowType, WindowType]: + def drag_resize_target_windows( + self, x: float, y: float, all_windows: WindowList + ) -> tuple[WindowType | None, WindowType | None]: # Identify the window where the click occurred and which horizontal and # vertical half it was in - click_window, left_half_clicked, top_half_clicked = (None, False, False) + click_window, left_half_clicked, top_half_clicked = None, False, False for w in all_windows.all_windows: g = w.geometry if x >= g.left and x <= g.right and y >= g.top and y <= g.bottom: @@ -463,15 +465,13 @@ class Layout: left_half_clicked = g.left <= x and x <= g.left + (float(g.right - g.left) / 2.0) top_half_clicked = g.top <= y and y <= g.top + (float(g.bottom - g.top) / 2.0) break - if click_window is None: - raise Exception("Failed to determine click window") - + return None, None neighbors = self.neighbors_for_window(click_window, all_windows) - left = neighbors.get("left", []) - right = neighbors.get("right", []) - top = neighbors.get("top", []) - bottom = neighbors.get("bottom", []) + left = neighbors.get("left", ()) + right = neighbors.get("right", ()) + top = neighbors.get("top", ()) + bottom = neighbors.get("bottom", ()) # Infer which window should be horizontally resized based on click # position and layout state diff --git a/kitty/mouse.c b/kitty/mouse.c index 839c7b82f..6ec66ceb9 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -813,18 +813,32 @@ dispatch_possible_click(Window *w, int button, int modifiers) { HANDLER(handle_button_event) { modifiers &= ~GLFW_LOCK_MASK; - if (!global_state.callback_os_window) return; + OSWindow *osw = global_state.callback_os_window; + if (!osw) return; - Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab; - bool is_release = !global_state.callback_os_window->mouse_button_pressed[button]; + Tab *t = osw->tabs + osw->active_tab; + bool is_release = !osw->mouse_button_pressed[button]; if (handle_scrollbar_mouse(w, button, is_release ? RELEASE : PRESS, modifiers)) return; if (window_idx != t->active_window && !is_release) { call_boss(switch_focus_to_in_active_tab, "K", t->windows[window_idx].id); } + Screen *screen = w->render_data.screen; if (!screen) return; + if (!global_state.active_drag_resize && button == GLFW_MOUSE_BUTTON_LEFT && !is_release && modifiers == GLFW_MOD_CONTROL) { + RAII_PyObject(r, PyObject_CallMethod( + global_state.boss, "drag_resize_start", "ddII", osw->mouse_x, osw->mouse_y, screen->cell_size.width, screen->cell_size.height)); + if (r == NULL) { PyErr_Print(); return; } + if (PyObject_IsTrue(r)) { + global_state.active_drag_resize = w->id; + mouse_cursor_shape = NESW_RESIZE_POINTER; + set_mouse_cursor(mouse_cursor_shape); + return; + } + } + bool a, b; if (!set_mouse_position(w, &a, &b)) return; id_type wid = w->id; @@ -923,35 +937,6 @@ closest_window_for_event(unsigned int *window_idx) { return ans; } -static void -drag_resize_start(double mouse_x, double mouse_y, unsigned int cell_width, unsigned int cell_height) { - call_boss(drag_resize_start, "ddII", mouse_x, mouse_y, cell_width, cell_height); -} - -static void -drag_resize_update(double mouse_x, double mouse_y) { - call_boss(drag_resize_update, "dd", mouse_x, mouse_y); -} - -static void -drag_resize_end(void) { - call_boss(drag_resize_end, ""); -} - -static bool -is_in_window(double mouse_x, double mouse_y) { - Tab *active_tab = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab; - - for (unsigned int i = 0; i < active_tab->num_windows; ++i) { - WindowGeometry *g = &active_tab->windows[i].render_data.geometry; - if (g->left <= mouse_x && mouse_x <= g->right && g->top <= mouse_y && mouse_y <= g->bottom) { - return true; - } - } - - return false; -} - void focus_in_event(void) { // Ensure that no URL is highlighted and the mouse cursor is in default shape @@ -1092,28 +1077,6 @@ mouse_event(const int button, int modifiers, int action) { OSWindow *osw = global_state.callback_os_window; - // Handle mouse drag window resizing - if (!global_state.active_drag_resize && button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS && modifiers & GLFW_MOD_CONTROL) { - if (is_in_window(osw->mouse_x, osw->mouse_y)) { - drag_resize_start(osw->mouse_x, osw->mouse_y, osw->fonts_data->fcm.cell_width, osw->fonts_data->fcm.cell_height); - global_state.active_drag_resize = true; - mouse_cursor_shape = MOVE_POINTER; - set_mouse_cursor(mouse_cursor_shape); - return; - } - } else if (global_state.active_drag_resize) { - if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) { - drag_resize_end(); - global_state.active_drag_resize = false; - mouse_cursor_shape = DEFAULT_POINTER; - set_mouse_cursor(mouse_cursor_shape); - return; - } else if (button < 0) { - drag_resize_update(osw->mouse_x, osw->mouse_y); - return; - } - } - if (OPT(debug_keyboard)) { if (button < 0) { debug("%s x: %.1f y: %.1f ", "\x1b[36mMove\x1b[m", global_state.callback_os_window->mouse_x, global_state.callback_os_window->mouse_y); } else { debug("%s mouse_button: %d %s", action == GLFW_RELEASE ? "\x1b[32mRelease\x1b[m" : "\x1b[31mPress\x1b[m", button, format_mods(modifiers)); } @@ -1183,6 +1146,17 @@ mouse_event(const int button, int modifiers, int action) { } } } + if (global_state.active_drag_resize) { + if (button < 0) { + call_boss(drag_resize_update, "dd", osw->mouse_x, osw->mouse_y); + } else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) { + call_boss(drag_resize_end, ""); + global_state.active_drag_resize = 0; + mouse_cursor_shape = DEFAULT_POINTER; + set_mouse_cursor(mouse_cursor_shape); + } + return; + } w = window_for_event(&window_idx, &in_tab_bar); set_currently_hovered_window(w ? w->id : 0, modifiers);