diff options
| author | Marten Ringwelski <maringuu@posteo.de> | 2020-09-15 00:38:50 +0200 |
|---|---|---|
| committer | Isaac Freund <ifreund@ifreund.xyz> | 2020-09-15 15:15:55 +0200 |
| commit | 7e02fb679cc5cddb0f8584471576f89ae981acea (patch) | |
| tree | 414a360495c6ed08c103f9020c1fe5b91bc3c0cb | |
| parent | f597e7da63ed88b3e6156cd05867252b952d2094 (diff) | |
| download | river-7e02fb679cc5cddb0f8584471576f89ae981acea.tar.gz river-7e02fb679cc5cddb0f8584471576f89ae981acea.tar.xz | |
Implement focus-follows-cursor
| -rw-r--r-- | doc/riverctl.1.scd | 7 | ||||
| -rw-r--r-- | river/Config.zig | 11 | ||||
| -rw-r--r-- | river/Cursor.zig | 25 | ||||
| -rw-r--r-- | river/command.zig | 1 | ||||
| -rw-r--r-- | river/command/focus_follows_cursor.zig | 39 |
5 files changed, 83 insertions, 0 deletions
diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd index 3632827..f233ad1 100644 --- a/doc/riverctl.1.scd +++ b/doc/riverctl.1.scd @@ -116,6 +116,13 @@ that tag 1 through 9 are visible. *enter-mode* _name_ Switch to given mode if it exits. +*focus-follows-cursor* _disabled_|_normal_|_strict_ + When _disabled_ moving the cursor will not influence the focus. This is the default setting. + If set to _normal_ moving the cursor over a window will focus that window. + The focus still can be changed and moving the cursor within the (now unfocused) window will not change the focus to that window + but let the currently focused window in focus. + When set to _strict_ this is not the case. The focus will be updated on every cursor movement. + *map* _mode_ _modifiers_ _key_ _command_ _mode_ is either “normal” (the default mode) or a mode created with *declare-mode*. _modifiers_ is a list of one or more of the following diff --git a/river/Config.zig b/river/Config.zig index 900dabc..334c21d 100644 --- a/river/Config.zig +++ b/river/Config.zig @@ -25,6 +25,14 @@ const util = @import("util.zig"); const Server = @import("Server.zig"); const Mode = @import("Mode.zig"); +pub const FocusFollowsCursorMode = enum { + disabled, + /// Only change focus on entering a surface + normal, + /// On cursor movement the focus will be updated to the surface below the cursor + strict, +}; + /// Color of background in RGBA (alpha should only affect nested sessions) background_color: [4]f32 = [_]f32{ 0.0, 0.16862745, 0.21176471, 1.0 }, // Solarized base03 @@ -55,6 +63,9 @@ float_filter: std.ArrayList([]const u8), /// List of app_ids which are allowed to use client side decorations csd_filter: std.ArrayList([]const u8), +/// The selected focus_follows_cursor mode +focus_follows_cursor: FocusFollowsCursorMode = .disabled, + pub fn init() !Self { var self = Self{ .mode_to_id = std.StringHashMap(usize).init(util.gpa), diff --git a/river/Cursor.zig b/river/Cursor.zig index 045d08a..d102f53 100644 --- a/river/Cursor.zig +++ b/river/Cursor.zig @@ -185,6 +185,9 @@ const Mode = union(enum) { /// Pass an event on to the surface under the cursor, if any. fn passthrough(self: *Self, time: u32) void { + const root = &self.seat.input_manager.server.root; + const config = self.seat.input_manager.server.config; + var sx: f64 = undefined; var sy: f64 = undefined; if (self.surfaceAt(self.wlr_cursor.x, self.wlr_cursor.y, &sx, &sy)) |wlr_surface| { @@ -192,8 +195,30 @@ const Mode = union(enum) { // events. Note that wlroots won't actually send an enter event if // the surface has already been entered. if (self.seat.input_manager.inputAllowed(wlr_surface)) { + // The focus change must be checked before sending enter events + const focus_change = self.seat.wlr_seat.pointer_state.focused_surface != wlr_surface; + c.wlr_seat_pointer_notify_enter(self.seat.wlr_seat, wlr_surface, sx, sy); c.wlr_seat_pointer_notify_motion(self.seat.wlr_seat, time, sx, sy); + if (View.fromWlrSurface(wlr_surface)) |view| { + // Change focus according to config + switch (config.focus_follows_cursor) { + .disabled => {}, + .normal => { + // Only refocus when the cursor entered a new surface + if (focus_change) { + self.seat.focus(view); + root.startTransaction(); + } + }, + .strict => { + self.seat.focus(view); + root.startTransaction(); + }, + } + } + + return; } } else { // There is either no surface under the cursor or input is disallowed diff --git a/river/command.zig b/river/command.zig index cd9489c..bfe0727 100644 --- a/river/command.zig +++ b/river/command.zig @@ -42,6 +42,7 @@ const str_to_impl_fn = [_]struct { .{ .name = "exit", .impl = @import("command/exit.zig").exit }, .{ .name = "float-filter-add", .impl = @import("command/filter.zig").floatFilterAdd }, .{ .name = "focus-output", .impl = @import("command/focus_output.zig").focusOutput }, + .{ .name = "focus-follows-cursor", .impl = @import("command/focus_follows_cursor.zig").focusFollowsCursor }, .{ .name = "focus-view", .impl = @import("command/focus_view.zig").focusView }, .{ .name = "layout", .impl = @import("command/layout.zig").layout }, .{ .name = "map", .impl = @import("command/map.zig").map }, diff --git a/river/command/focus_follows_cursor.zig b/river/command/focus_follows_cursor.zig new file mode 100644 index 0000000..392e69f --- /dev/null +++ b/river/command/focus_follows_cursor.zig @@ -0,0 +1,39 @@ +// This file is part of river, a dynamic tiling wayland compositor. +// +// Copyright 2020 Marten Ringwelski +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +const std = @import("std"); + +const util = @import("../util.zig"); + +const Config = @import("../Config.zig"); +const Error = @import("../command.zig").Error; +const Seat = @import("../Seat.zig"); + +pub fn focusFollowsCursor( + allocator: *std.mem.Allocator, + seat: *Seat, + args: []const []const u8, + out: *?[]const u8, +) Error!void { + if (args.len < 2) return Error.NotEnoughArguments; + if (args.len > 2) return Error.TooManyArguments; + + const server = seat.input_manager.server; + + server.config.focus_follows_cursor = + std.meta.stringToEnum(Config.FocusFollowsCursorMode, args[1]) orelse return Error.UnknownOption; +} |
