From 931405abe46e12485f2439135bd0fa20ea7fc984 Mon Sep 17 00:00:00 2001 From: shironeko Date: Sat, 31 Dec 2022 13:51:42 -0500 Subject: Rework focus-follows-cursor to work with warp When focus-follows-cursor is used with cursor-warp, some windows will get focus before the cursor properly "enters" the window since they have a larger input-region than their window geometry, this causes the cursor to be yanked to the middle unexpectedly. This fix makes it so the focus is only given when the cursor enters the window geometry. --- river/Cursor.zig | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/river/Cursor.zig b/river/Cursor.zig index d73c376..24aa5a1 100644 --- a/river/Cursor.zig +++ b/river/Cursor.zig @@ -112,6 +112,8 @@ hide_cursor_timer: *wl.EventSource, hidden: bool = false, may_need_warp: bool = false, +last_focus_follows_cursor_target: ?*View = null, + /// Keeps track of the last known location of all touch points in layout coordinates. /// This information is necessary for proper touch dnd support if there are multiple touch points. touch_points: std.AutoHashMapUnmanaged(i32, LayoutPoint) = .{}, @@ -1049,21 +1051,33 @@ pub fn checkFocusFollowsCursor(self: *Self) void { if (self.seat.drag == .pointer) return; if (server.config.focus_follows_cursor == .disabled) return; if (self.surfaceAt()) |result| { - if (server.config.focus_follows_cursor == .always or - self.seat.wlr_seat.pointer_state.focused_surface != result.surface) - { - switch (result.parent) { - .view => |view| { - if (self.seat.focused != .view or self.seat.focused.view != view) { - self.seat.focusOutput(view.output); - self.seat.focus(view); - server.root.startTransaction(); - } - }, - .layer_surface, .lock_surface => {}, - .xwayland_override_redirect => assert(build_options.xwayland), - } + switch (result.parent) { + .view => |view| { + // Don't re-focus the last focused view when the mode is .normal + if (server.config.focus_follows_cursor == .normal and + self.last_focus_follows_cursor_target == view) return; + // Some windows have a input region bigger than their window + // geometry, we only want to move focus when the cursor + // properly enters the window (the box that we draw borders around) + var output_layout_box: wlr.Box = undefined; + server.root.output_layout.getBox(view.output.wlr_output, &output_layout_box); + const cursor_ox = self.wlr_cursor.x - @intToFloat(f64, output_layout_box.x); + const cursor_oy = self.wlr_cursor.y - @intToFloat(f64, output_layout_box.y); + if ((self.seat.focused != .view or self.seat.focused.view != view) and + view.current.box.containsPoint(cursor_ox, cursor_oy)) + { + self.seat.focusOutput(view.output); + self.seat.focus(view); + self.last_focus_follows_cursor_target = view; + server.root.startTransaction(); + } + }, + .layer_surface, .lock_surface => {}, + .xwayland_override_redirect => assert(build_options.xwayland), } + } else { + // The cursor is not above any view, so clear the last followed check + self.last_focus_follows_cursor_target = null; } } -- cgit v1.2.3