Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
river: remove various config options
river/Config.zig | 49 ---------------
river/Cursor.zig | 179 ++---------------------------------------------------
river/Keyboard.zig | 11 ----
river/Output.zig | 6 --
river/Seat.zig | 9 ---
river/View.zig | 64 +------------------
6 files changed, 8 insertions(+), 310 deletions(-)
diff --git a/river/Config.zig b/river/Config.zig
index 0b54f77..66a284a 100644
--- a/river/Config.zig
+++ b/river/Config.zig
@@ -31,33 +31,6 @@ const Mode = @import("Mode.zig");
const RuleList = @import("rule_list.zig").RuleList;
const View = @import("View.zig");
-pub const AttachMode = union(enum) {
- top,
- bottom,
- after: u32,
- above,
- below,
-};
-
-pub const FocusFollowsCursorMode = enum {
- disabled,
- /// Only change focus on entering a surface
- normal,
- /// Change focus on any cursor movement
- always,
-};
-
-pub const WarpCursorMode = enum {
- disabled,
- @"on-output-change",
- @"on-focus-change",
-};
-
-pub const HideCursorWhenTypingMode = enum {
- disabled,
- enabled,
-};
-
pub const Position = struct {
x: u31,
y: u31,
@@ -100,35 +73,15 @@ rules: struct {
fullscreen: RuleList(bool) = .{},
} = .{},
-/// The selected focus_follows_cursor mode
-focus_follows_cursor: FocusFollowsCursorMode = .disabled,
-
-/// If true, the cursor warps to the center of the focused output
-warp_cursor: WarpCursorMode = .disabled,
-
-/// The default layout namespace for outputs which have never had a per-output
-/// value set. Call Output.handleLayoutNamespaceChange() on setting this if
-/// Output.layout_namespace is null.
-default_layout_namespace: []const u8 = &[0]u8{},
-
/// Bitmask restricting the tags of newly created views.
spawn_tagmask: u32 = std.math.maxInt(u32),
-/// Determines where new views will be attached to the view stack.
-default_attach_mode: AttachMode = .top,
-
/// Keyboard repeat rate in characters per second
repeat_rate: u31 = 25,
/// Keyboard repeat delay in milliseconds
repeat_delay: u31 = 600,
-/// Cursor hide timeout in milliseconds
-cursor_hide_timeout: u31 = 0,
-
-/// Hide the cursor while typing
-cursor_hide_when_typing: HideCursorWhenTypingMode = .disabled,
-
xkb_context: *xkb.Context,
/// The xkb keymap used for all keyboards
keymap: *xkb.Keymap,
@@ -183,8 +136,6 @@ pub fn deinit(config: *Config) void {
config.rules.dimensions.deinit();
config.rules.fullscreen.deinit();
- util.gpa.free(config.default_layout_namespace);
-
config.keymap.unref();
config.xkb_context.unref();
}
diff --git a/river/Cursor.zig b/river/Cursor.zig
index c873936..95b6acb 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -131,19 +131,11 @@ xcursor_name: ?[*:0]const u8 = null,
/// Number of distinct buttons currently pressed
pressed_count: u32 = 0,
-hide_cursor_timer: *wl.EventSource,
-
-hidden: bool = false,
-may_need_warp: bool = false,
-
/// The pointer constraint for the surface that currently has keyboard focus, if any.
/// This constraint is not necessarily active, activation only occurs once the cursor
/// has been moved inside the constraint region.
constraint: ?*PointerConstraint = 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.
touch_points: std.AutoHashMapUnmanaged(i32, LayoutPoint) = .{},
@@ -201,15 +193,11 @@ pub fn init(cursor: *Cursor, seat: *Seat) !void {
const xcursor_manager = try wlr.XcursorManager.create(null, default_size);
errdefer xcursor_manager.destroy();
- const event_loop = server.wl_server.getEventLoop();
cursor.* = .{
.seat = seat,
.wlr_cursor = wlr_cursor,
.xcursor_manager = xcursor_manager,
- .hide_cursor_timer = try event_loop.addTimer(*Cursor, handleHideCursorTimeout, cursor),
};
- errdefer cursor.hide_cursor_timer.remove();
- try cursor.hide_cursor_timer.timerUpdate(server.config.cursor_hide_timeout);
try cursor.setTheme(null, null);
// wlr_cursor *only* displays an image on screen. It does not move around
@@ -243,7 +231,6 @@ pub fn init(cursor: *Cursor, seat: *Seat) !void {
}
pub fn deinit(cursor: *Cursor) void {
- cursor.hide_cursor_timer.remove();
cursor.xcursor_manager.destroy();
cursor.wlr_cursor.destroy();
}
@@ -307,7 +294,6 @@ fn handleAxis(listener: *wl.Listener(*wlr.Pointer.event.Axis), event: *wlr.Point
const device: *InputDevice = @ptrFromInt(event.device.data);
cursor.seat.handleActivity();
- cursor.unhide();
// Notify the client with pointer focus of the axis event.
cursor.seat.wlr_seat.pointerNotifyAxis(
@@ -332,7 +318,6 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
const cursor: *Cursor = @fieldParentPtr("button", listener);
cursor.seat.handleActivity();
- cursor.unhide();
if (event.state == .released) {
assert(cursor.pressed_count > 0);
@@ -744,40 +729,6 @@ fn handleRequestSetCursor(
}
}
-pub fn hide(cursor: *Cursor) void {
- if (cursor.pressed_count > 0) return;
-
- // Hiding the cursor and sending wl_pointer.leave whlie a pointer constraint
- // is active does not make much sense. In particular, doing so seems to interact
- // poorly with Xwayland's pointer constraints implementation.
- if (cursor.constraint) |constraint| {
- if (constraint.state == .active) return;
- }
-
- cursor.hidden = true;
- cursor.wlr_cursor.unsetImage();
- cursor.xcursor_name = null;
- cursor.seat.wlr_seat.pointerNotifyClearFocus();
- cursor.hide_cursor_timer.timerUpdate(0) catch {
- log.err("failed to update cursor hide timeout", .{});
- };
-}
-
-pub fn unhide(cursor: *Cursor) void {
- cursor.hide_cursor_timer.timerUpdate(server.config.cursor_hide_timeout) catch {
- log.err("failed to update cursor hide timeout", .{});
- };
- if (!cursor.hidden) return;
- cursor.hidden = false;
- cursor.updateState();
-}
-
-fn handleHideCursorTimeout(cursor: *Cursor) c_int {
- log.debug("hide cursor timeout", .{});
- cursor.hide();
- return 0;
-}
-
pub fn startMove(cursor: *Cursor, view: *View) void {
// Guard against assertion in enterMode()
if (view.current.output == null) return;
@@ -884,8 +835,6 @@ fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor_name: [*:0]const
}
fn processMotion(cursor: *Cursor, device: *wlr.InputDevice, time: u32, delta_x: f64, delta_y: f64, unaccel_dx: f64, unaccel_dy: f64) void {
- cursor.unhide();
-
server.input_manager.relative_pointer_manager.sendRelativeMotion(
cursor.seat.wlr_seat,
@as(u64, time) * 1000,
@@ -913,7 +862,6 @@ fn processMotion(cursor: *Cursor, device: *wlr.InputDevice, time: u32, delta_x:
switch (cursor.mode) {
.passthrough => {
- cursor.checkFocusFollowsCursor();
cursor.passthrough(time);
},
.down => |data| {
@@ -1008,90 +956,24 @@ fn processMotion(cursor: *Cursor, device: *wlr.InputDevice, time: u32, delta_x:
}
}
-pub fn checkFocusFollowsCursor(cursor: *Cursor) void {
- // Don't do focus-follows-cursor if a pointer drag is in progress as focus
- // change can't occur.
- if (cursor.seat.drag == .pointer) return;
- if (server.config.focus_follows_cursor == .disabled) return;
-
- const last_target = cursor.focus_follows_cursor_target;
- cursor.updateFocusFollowsCursorTarget();
- if (cursor.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 (cursor.seat.focused != .view or cursor.seat.focused.view != view) {
- if (view.current.output) |output| {
- cursor.seat.focusOutput(output);
- cursor.seat.focus(view);
- server.root.applyPending();
- }
- }
- } else {
- // The output doesn't contain any views, just focus the output.
- cursor.updateOutputFocus(cursor.wlr_cursor.x, cursor.wlr_cursor.y);
- }
-}
-
-fn updateFocusFollowsCursorTarget(cursor: *Cursor) void {
- if (server.root.at(cursor.wlr_cursor.x, cursor.wlr_cursor.y)) |result| {
- switch (result.data) {
- .view => |view| {
- // 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.
- if (view.current.output) |output| {
- var output_layout_box: wlr.Box = undefined;
- server.root.output_layout.getBox(output.wlr_output, &output_layout_box);
-
- const cursor_ox = cursor.wlr_cursor.x - @as(f64, @floatFromInt(output_layout_box.x));
- const cursor_oy = cursor.wlr_cursor.y - @as(f64, @floatFromInt(output_layout_box.y));
- if (view.current.box.containsPoint(cursor_ox, cursor_oy)) {
- cursor.focus_follows_cursor_target = view;
- }
- }
- },
- .layer_surface, .lock_surface => {
- cursor.focus_follows_cursor_target = null;
- },
- .override_redirect => {
- assert(build_options.xwayland);
- assert(server.xwayland != null);
- cursor.focus_follows_cursor_target = null;
- },
- }
- } else {
- // The cursor is not above any view
- cursor.focus_follows_cursor_target = null;
- }
-}
-
/// Handle potential change in location of views on the output, as well as
/// the target view of a cursor operation potentially being moved to a non-visible tag,
/// becoming fullscreen, etc.
pub fn updateState(cursor: *Cursor) void {
- if (cursor.may_need_warp) {
- cursor.warp();
- }
-
if (cursor.constraint) |constraint| {
constraint.updateState();
}
switch (cursor.mode) {
.passthrough => {
- cursor.updateFocusFollowsCursorTarget();
- if (!cursor.hidden) {
- var now: posix.timespec = undefined;
- posix.clock_gettime(posix.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
- const msec: u32 = @intCast(now.tv_sec * std.time.ms_per_s +
- @divTrunc(now.tv_nsec, std.time.ns_per_ms));
- cursor.passthrough(msec);
- }
+ var now: posix.timespec = undefined;
+ posix.clock_gettime(posix.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
+ const msec: u32 = @intCast(now.tv_sec * std.time.ms_per_s +
+ @divTrunc(now.tv_nsec, std.time.ns_per_ms));
+ cursor.passthrough(msec);
},
// TODO: Leave down mode if the target surface is no longer visible.
- .down => assert(!cursor.hidden),
+ .down => {},
.move, .resize => {
// Moving and resizing of views is handled through the transaction system. Therefore,
// we must inspect the inflight_mode instead if a move or a resize is in progress.
@@ -1110,7 +992,6 @@ pub fn updateState(cursor: *Cursor) void {
switch (cursor.inflight_mode) {
.passthrough, .down => {},
inline .move, .resize => |data, mode| {
- assert(!cursor.hidden);
// These conditions are checked in Root.applyPending()
const output = data.view.current.output orelse return;
@@ -1166,54 +1047,6 @@ fn passthrough(cursor: *Cursor, time: u32) void {
cursor.clearFocus();
}
-fn warp(cursor: *Cursor) void {
- cursor.may_need_warp = false;
-
- const focused_output = cursor.seat.focused_output orelse return;
-
- // Warp pointer to center of the focused view/output (In layout coordinates) if enabled.
- var output_layout_box: wlr.Box = undefined;
- server.root.output_layout.getBox(focused_output.wlr_output, &output_layout_box);
- const target_box = switch (server.config.warp_cursor) {
- .disabled => return,
- .@"on-output-change" => output_layout_box,
- .@"on-focus-change" => switch (cursor.seat.focused) {
- .layer, .lock_surface, .none => output_layout_box,
- .view => |view| wlr.Box{
- .x = output_layout_box.x + view.current.box.x,
- .y = output_layout_box.y + view.current.box.y,
- .width = view.current.box.width,
- .height = view.current.box.height,
- },
- .override_redirect => |override_redirect| wlr.Box{
- .x = override_redirect.xwayland_surface.x,
- .y = override_redirect.xwayland_surface.y,
- .width = override_redirect.xwayland_surface.width,
- .height = override_redirect.xwayland_surface.height,
- },
- },
- };
- // Checking against the usable box here gives much better UX when, for example,
- // a status bar allows using the pointer to change tag/view focus.
- const usable_box = focused_output.usable_box;
- const usable_layout_box = wlr.Box{
- .x = output_layout_box.x + usable_box.x,
- .y = output_layout_box.y + usable_box.y,
- .width = usable_box.width,
- .height = usable_box.height,
- };
- if (!output_layout_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y) or
- (usable_layout_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y) and
- !target_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y)))
- {
- const lx: f64 = @floatFromInt(target_box.x + @divTrunc(target_box.width, 2));
- const ly: f64 = @floatFromInt(target_box.y + @divTrunc(target_box.height, 2));
- if (!cursor.wlr_cursor.warp(null, lx, ly)) {
- log.err("failed to warp cursor on focus change", .{});
- }
- }
-}
-
fn updateDragIcons(cursor: *Cursor) void {
var it = server.root.drag_icons.children.iterator(.forward);
while (it.next()) |node| {
diff --git a/river/Keyboard.zig b/river/Keyboard.zig
index 3c659d8..b0479d3 100644
--- a/river/Keyboard.zig
+++ b/river/Keyboard.zig
@@ -168,17 +168,6 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
const keysyms = xkb_state.keyGetSyms(keycode);
- // Hide cursor when typing
- for (keysyms) |sym| {
- if (server.config.cursor_hide_when_typing == .enabled and
- !released and
- !isModifier(sym))
- {
- keyboard.device.seat.cursor.hide();
- break;
- }
- }
-
for (keysyms) |sym| {
if (!released and handleBuiltinMapping(sym)) return;
}
diff --git a/river/Output.zig b/river/Output.zig
index e1382ca..daaa20d 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -164,8 +164,6 @@ current: struct {
/// Remembered version of tags (from last run)
previous_tags: u32 = 1 << 0,
-attach_mode: ?Config.AttachMode = null,
-
destroy: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleDestroy),
request_state: wl.Listener(*wlr.Output.event.RequestState) = wl.Listener(*wlr.Output.event.RequestState).init(handleRequestState),
frame: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleFrame),
@@ -597,7 +595,3 @@ fn setTitle(output: Output) void {
output.wlr_output.x11SetTitle(title);
}
}
-
-pub fn attachMode(output: Output) Config.AttachMode {
- return output.attach_mode orelse server.config.default_attach_mode;
-}
diff --git a/river/Seat.zig b/river/Seat.zig
index 0e5638e..b5c160f 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -284,10 +284,6 @@ pub fn setFocusRaw(seat: *Seat, new_focus: FocusTarget) void {
}
}
}
-
- // Depending on configuration and cursor position, changing keyboard focus
- // may cause the cursor to be warped.
- seat.cursor.may_need_warp = true;
}
/// Send keyboard enter/leave events and handle pointer constraints
@@ -325,10 +321,6 @@ pub fn focusOutput(seat: *Seat, output: ?*Output) void {
if (seat.focused_output == output) return;
seat.focused_output = output;
-
- // Depending on configuration and cursor position, changing output focus
- // may cause the cursor to be warped.
- seat.cursor.may_need_warp = true;
}
pub fn handleActivity(seat: Seat) void {
@@ -563,7 +555,6 @@ fn handleDragDestroy(listener: *wl.Listener(*wlr.Drag), _: *wlr.Drag) void {
switch (seat.drag) {
.none => unreachable,
.pointer => {
- seat.cursor.checkFocusFollowsCursor();
seat.cursor.updateState();
},
.touch => {},
diff --git a/river/View.zig b/river/View.zig
index e6654c2..7d10c12 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -54,11 +54,6 @@ const Impl = union(enum) {
none,
};
-const AttachRelativeMode = enum {
- above,
- below,
-};
-
pub const State = struct {
/// The output the view is currently assigned to.
/// May be null if there are no outputs or for newly created views.
@@ -519,13 +514,7 @@ pub fn setPendingOutput(view: *View, output: *Output) void {
view.pending_wm_stack_link.remove();
view.pending_focus_stack_link.remove();
- switch (output.attachMode()) {
- .top => output.pending.wm_stack.prepend(view),
- .bottom => output.pending.wm_stack.append(view),
- .after => |n| view.attachAfter(&output.pending, n),
- .above => view.attachRelative(&output.pending, .above),
- .below => view.attachRelative(&output.pending, .below),
- }
+ output.pending.wm_stack.prepend(view);
output.pending.focus_stack.prepend(view);
if (view.pending.fullscreen) {
@@ -578,49 +567,6 @@ pub fn applyConstraints(view: *View, box: *wlr.Box) void {
box.height = math.clamp(box.height, view.constraints.min_height, view.constraints.max_height);
}
-/// Attach after n visible, not-floating views in the pending wm_stack
-pub fn attachAfter(view: *View, output_pending: *Output.PendingState, n: usize) void {
- var visible: u32 = 0;
- var it = output_pending.wm_stack.iterator(.forward);
-
- while (it.next()) |other| {
- if (visible >= n) break;
- if (!other.pending.float and other.pending.tags & output_pending.tags != 0) {
- visible += 1;
- }
- }
-
- it.current.prev.?.insert(&view.pending_wm_stack_link);
-}
-
-/// Attach above or below the currently focused view
-pub fn attachRelative(view: *View, output_pending: *Output.PendingState, mode: AttachRelativeMode) void {
- const focus_stack_head = output_pending.focus_stack.first() orelse {
- output_pending.wm_stack.append(view);
- return;
- };
-
- // There are two cases to consider here:
- //
- // 1. The first view in the focus stack is visible given the currently focused tags.
- // In this case, inserting directly before/after that view in the wm_stack is correct.
- //
- // 2. There are no views visible given the currently focused tags. In this case it
- // doesn't matter where in the wm_stack the new view is inserted as it will be the only
- // view visible.
-
- var it = output_pending.wm_stack.iterator(.forward);
- while (it.next()) |other| {
- if (other == focus_stack_head) {
- switch (mode) {
- .above => other.pending_wm_stack_link.prev.?.insert(&view.pending_wm_stack_link),
- .below => other.pending_wm_stack_link.insert(&view.pending_wm_stack_link),
- }
- return;
- }
- }
-}
-
/// Called by the impl when the surface is ready to be displayed
pub fn map(view: *View) !void {
log.debug("view '{?s}' mapped", .{view.getTitle()});
@@ -675,13 +621,7 @@ pub fn map(view: *View) !void {
view.pending_wm_stack_link.remove();
view.pending_focus_stack_link.remove();
- switch (server.config.default_attach_mode) {
- .top => server.root.fallback_pending.wm_stack.prepend(view),
- .bottom => server.root.fallback_pending.wm_stack.append(view),
- .after => |n| view.attachAfter(&server.root.fallback_pending, n),
- .above => view.attachRelative(&server.root.fallback_pending, .above),
- .below => view.attachRelative(&server.root.fallback_pending, .below),
- }
+ server.root.fallback_pending.wm_stack.prepend(view);
server.root.fallback_pending.focus_stack.prepend(view);
view.inflight_wm_stack_link.remove();