Cursor: keep focus_follows_cursor_target updated
This goes as close as possible to the behavior before this state was introduced (keeping the improvement which needed it,931405ab
), fixing various mis-interactions of keyboard and focus_follows_cursor focus changes. The following text is irrelevant to restoring correct basic FFC behavior and talks about less common scenarios with regards to FFC clashing with views' input region beyond their geometry, continuing the work done in931405ab
. Scenario 1: the cursor traveling along a view's border in a "dead zone", never initiating a focus change. If the focused view has an extended input region, that area has some functionality (such as client-initiated resizing); therefore it should be respected and even if another view's geometry is also under the cursor, focus shouldn't change. In case of unfocused views, it is a matter of consistency with the focused-view case. This outcome is also easier to implement, as it doesn't require any additional code. Scenario 2: *clicking* such a dead zone, i.e. extended input region (of an unfocused view). In question is not whether to focus the view (yes), but whether the focus_follows_cursor_target should be set to the view as well. Only one case seems relevant to me here, which is when ffc_target is another view whose geometry is under the cursor, but covered by this newly-focused view's input region. The most likely action following the click is resizing the newly-focused view, where a touchpad or faulty mouse could make the cursor move a bit farther after the button has been released. I believe that ffc_target shouldn't have been updated, in order to now prevent focus from skipping away. (Another variant is me, wondering why the wrong view got focused and trying to focus the right one using FFC. In that case, however, one could ask if it's river that misbehaves and whether the application is really well-integrated into the user's desktop when it provides a feature they don't desire.)
This commit is contained in:
parent
0cc930b738
commit
7f30c655c7
@ -157,7 +157,8 @@ may_need_warp: bool = false,
|
||||
/// has been moved inside the constraint region.
|
||||
constraint: ?*PointerConstraint = null,
|
||||
|
||||
last_focus_follows_cursor_target: ?*View = null,
|
||||
/// View under the cursor, defined by view geometry rather than input region
|
||||
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.
|
||||
@ -917,34 +918,48 @@ pub fn checkFocusFollowsCursor(self: *Self) void {
|
||||
// change can't occur.
|
||||
if (self.seat.drag == .pointer) return;
|
||||
if (server.config.focus_follows_cursor == .disabled) return;
|
||||
|
||||
const last_target = self.focus_follows_cursor_target;
|
||||
self.updateFocusFollowsCursorTarget();
|
||||
if (self.focus_follows_cursor_target) |view| {
|
||||
// In .normal mode, only entering a view changes focus
|
||||
if (server.config.focus_follows_cursor == .normal and
|
||||
last_target == view) return;
|
||||
if (self.seat.focused != .view or self.seat.focused.view != view) {
|
||||
self.seat.focusOutput(view.current.output.?);
|
||||
self.seat.focus(view);
|
||||
server.root.applyPending();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn updateFocusFollowsCursorTarget(self: *Self) void {
|
||||
if (server.root.at(self.wlr_cursor.x, self.wlr_cursor.y)) |result| {
|
||||
switch (result.data) {
|
||||
.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
|
||||
// Some windows have an input region bigger than their window
|
||||
// geometry, we only want to update this when the cursor
|
||||
// properly enters the window (the box that we draw borders around)
|
||||
// in order to avoid clashes with cursor warping on focus change.
|
||||
var output_layout_box: wlr.Box = undefined;
|
||||
server.root.output_layout.getBox(view.current.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.current.output.?);
|
||||
self.seat.focus(view);
|
||||
self.last_focus_follows_cursor_target = view;
|
||||
server.root.applyPending();
|
||||
if (view.current.box.containsPoint(cursor_ox, cursor_oy)) {
|
||||
self.focus_follows_cursor_target = view;
|
||||
}
|
||||
},
|
||||
.layer_surface, .lock_surface => {},
|
||||
.xwayland_override_redirect => assert(build_options.xwayland),
|
||||
.layer_surface, .lock_surface => {
|
||||
self.focus_follows_cursor_target = null;
|
||||
},
|
||||
.xwayland_override_redirect => {
|
||||
assert(build_options.xwayland);
|
||||
self.focus_follows_cursor_target = null;
|
||||
},
|
||||
}
|
||||
} else {
|
||||
// The cursor is not above any view, so clear the last followed check
|
||||
self.last_focus_follows_cursor_target = null;
|
||||
// The cursor is not above any view
|
||||
self.focus_follows_cursor_target = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -962,6 +977,7 @@ pub fn updateState(self: *Self) void {
|
||||
|
||||
switch (self.mode) {
|
||||
.passthrough => {
|
||||
self.updateFocusFollowsCursorTarget();
|
||||
if (!self.hidden) {
|
||||
var now: os.timespec = undefined;
|
||||
os.clock_gettime(os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
|
||||
|
Loading…
Reference in New Issue
Block a user