Implement focus-follows-cursor

This commit is contained in:
Marten Ringwelski 2020-09-15 00:38:50 +02:00 committed by Isaac Freund
parent f597e7da63
commit 7e02fb679c
5 changed files with 83 additions and 0 deletions

View file

@ -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

View file

@ -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),

View file

@ -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

View file

@ -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 },

View file

@ -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;
}