diff --git a/build.zig b/build.zig index 4d0017c..fb3a21e 100644 --- a/build.zig +++ b/build.zig @@ -112,7 +112,7 @@ pub fn build(b: *zbs.Builder) !void { scanner.generate("zwp_pointer_constraints_v1", 1); scanner.generate("zriver_control_v1", 1); - scanner.generate("zriver_status_manager_v1", 2); + scanner.generate("zriver_status_manager_v1", 3); scanner.generate("river_layout_manager_v3", 1); scanner.generate("zwlr_layer_shell_v1", 4); diff --git a/protocol/river-status-unstable-v1.xml b/protocol/river-status-unstable-v1.xml index 13affaa..6a74256 100644 --- a/protocol/river-status-unstable-v1.xml +++ b/protocol/river-status-unstable-v1.xml @@ -16,7 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - + A global factory for objects that receive status information specific to river. It could be used to implement, for example, a status bar. @@ -85,7 +85,7 @@ - + This interface allows clients to receive information about the current focus of a seat. Note that (un)focused_output events will only be sent @@ -121,5 +121,13 @@ + + + + Sent once on binding the interface and again whenever a new mode + is entered (e.g. with riverctl enter-mode foobar). + + + diff --git a/river/Config.zig b/river/Config.zig index 2da717c..9d0fa4c 100644 --- a/river/Config.zig +++ b/river/Config.zig @@ -57,7 +57,8 @@ border_color_unfocused: [4]f32 = [_]f32{ 0.34509804, 0.43137255, 0.45882353, 1.0 border_color_urgent: [4]f32 = [_]f32{ 0.86274510, 0.19607843, 0.18431373, 1.0 }, // Solarized red /// Map of keymap mode name to mode id -mode_to_id: std.StringHashMap(usize), +/// Does not own the string keys. They are owned by the corresponding Mode struct. +mode_to_id: std.StringHashMap(u32), /// All user-defined keymap modes, indexed by mode id modes: std.ArrayListUnmanaged(Mode), @@ -98,7 +99,7 @@ cursor_hide_when_typing: HideCursorWhenTypingMode = .disabled, pub fn init() !Self { var self = Self{ - .mode_to_id = std.StringHashMap(usize).init(util.gpa), + .mode_to_id = std.StringHashMap(u32).init(util.gpa), .modes = try std.ArrayListUnmanaged(Mode).initCapacity(util.gpa, 2), }; errdefer self.deinit(); @@ -106,27 +107,22 @@ pub fn init() !Self { // Start with two empty modes, "normal" and "locked" { // Normal mode, id 0 - const owned_slice = try util.gpa.dupe(u8, "normal"); + const owned_slice = try util.gpa.dupeZ(u8, "normal"); try self.mode_to_id.putNoClobber(owned_slice, 0); - self.modes.appendAssumeCapacity(.{}); + self.modes.appendAssumeCapacity(.{ .name = owned_slice }); } { // Locked mode, id 1 - const owned_slice = try util.gpa.dupe(u8, "locked"); + const owned_slice = try util.gpa.dupeZ(u8, "locked"); try self.mode_to_id.putNoClobber(owned_slice, 1); - self.modes.appendAssumeCapacity(.{}); + self.modes.appendAssumeCapacity(.{ .name = owned_slice }); } return self; } pub fn deinit(self: *Self) void { - { - var it = self.mode_to_id.keyIterator(); - while (it.next()) |key| util.gpa.free(key.*); - self.mode_to_id.deinit(); - } - + self.mode_to_id.deinit(); for (self.modes.items) |*mode| mode.deinit(); self.modes.deinit(util.gpa); diff --git a/river/InputManager.zig b/river/InputManager.zig index cc159f3..3bcef06 100644 --- a/river/InputManager.zig +++ b/river/InputManager.zig @@ -188,7 +188,7 @@ fn handleInhibitActivate( // Enter locked mode seat_node.data.prev_mode_id = seat_node.data.mode_id; - seat_node.data.mode_id = 1; + seat_node.data.enterMode(1); } self.exclusive_client = self.input_inhibit_manager.active_client; @@ -215,8 +215,9 @@ fn handleInhibitDeactivate( // have each Seat handle focus and enter their previous mode. var seat_it = self.seats.first; while (seat_it) |seat_node| : (seat_it = seat_node.next) { - seat_node.data.focus(null); - seat_node.data.mode_id = seat_node.data.prev_mode_id; + const seat = &seat_node.data; + seat.enterMode(seat.prev_mode_id); + seat.focus(null); } server.root.startTransaction(); diff --git a/river/Mode.zig b/river/Mode.zig index 5793c50..cd0c1ab 100644 --- a/river/Mode.zig +++ b/river/Mode.zig @@ -23,11 +23,13 @@ const Mapping = @import("Mapping.zig"); const PointerMapping = @import("PointerMapping.zig"); const SwitchMapping = @import("SwitchMapping.zig"); +name: [:0]const u8, mappings: std.ArrayListUnmanaged(Mapping) = .{}, pointer_mappings: std.ArrayListUnmanaged(PointerMapping) = .{}, switch_mappings: std.ArrayListUnmanaged(SwitchMapping) = .{}, pub fn deinit(self: *Self) void { + util.gpa.free(self.name); for (self.mappings.items) |m| m.deinit(); self.mappings.deinit(util.gpa); self.pointer_mappings.deinit(util.gpa); diff --git a/river/Seat.zig b/river/Seat.zig index 7fd16d3..9582313 100644 --- a/river/Seat.zig +++ b/river/Seat.zig @@ -63,10 +63,10 @@ keyboards: std.TailQueue(Keyboard) = .{}, switches: std.TailQueue(Switch) = .{}, /// ID of the current keymap mode -mode_id: usize = 0, +mode_id: u32 = 0, /// ID of previous keymap mode, used when returning from "locked" mode -prev_mode_id: usize = 0, +prev_mode_id: u32 = 0, /// Timer for repeating keyboard mappings mapping_repeat_timer: *wl.EventSource, @@ -358,6 +358,16 @@ pub fn handleViewUnmap(self: *Self, view: *View) void { if (self.focused == .view and self.focused.view == view) self.focus(null); } +pub fn enterMode(self: *Self, mode_id: u32) void { + self.mode_id = mode_id; + + var it = self.status_trackers.first; + while (it) |node| : (it = node.next) { + const seat_status = node.data.seat_status; + seat_status.sendMode(server.config.modes.items[mode_id].name); + } +} + /// Is there a user-defined mapping for passed keycode, modifiers and keyboard state? pub fn hasMapping( self: *Self, diff --git a/river/SeatStatus.zig b/river/SeatStatus.zig index a4adf99..d06c7dd 100644 --- a/river/SeatStatus.zig +++ b/river/SeatStatus.zig @@ -21,6 +21,7 @@ const wayland = @import("wayland"); const wl = wayland.server.wl; const zriver = wayland.server.zriver; +const server = &@import("main.zig").server; const util = @import("util.zig"); const Seat = @import("Seat.zig"); @@ -35,7 +36,8 @@ pub fn init(self: *Self, seat: *Seat, seat_status: *zriver.SeatStatusV1) void { seat_status.setHandler(*Self, handleRequest, handleDestroy, self); - // Send focused output/view once on bind + // Send all info once on bind + seat_status.sendMode(server.config.modes.items[seat.mode_id].name); self.sendOutput(.focused); self.sendFocusedView(); } diff --git a/river/StatusManager.zig b/river/StatusManager.zig index 1cf75eb..8239587 100644 --- a/river/StatusManager.zig +++ b/river/StatusManager.zig @@ -39,7 +39,7 @@ server_destroy: wl.Listener(*wl.Server) = wl.Listener(*wl.Server).init(handleSer pub fn init(self: *Self) !void { self.* = .{ - .global = try wl.Global.create(server.wl_server, zriver.StatusManagerV1, 2, ?*anyopaque, null, bind), + .global = try wl.Global.create(server.wl_server, zriver.StatusManagerV1, 3, ?*anyopaque, null, bind), }; server.wl_server.addDestroyListener(&self.server_destroy); diff --git a/river/command/declare_mode.zig b/river/command/declare_mode.zig index 8b0d7a6..5b50b77 100644 --- a/river/command/declare_mode.zig +++ b/river/command/declare_mode.zig @@ -38,9 +38,12 @@ pub fn declareMode( if (config.mode_to_id.get(new_mode_name) != null) return; + try config.mode_to_id.ensureUnusedCapacity(1); try config.modes.ensureUnusedCapacity(util.gpa, 1); - const owned_name = try util.gpa.dupe(u8, new_mode_name); - errdefer util.gpa.free(owned_name); - try config.mode_to_id.putNoClobber(owned_name, config.modes.items.len); - config.modes.appendAssumeCapacity(.{}); + + const owned_name = try util.gpa.dupeZ(u8, new_mode_name); + + const id = @intCast(u32, config.modes.items.len); + config.mode_to_id.putAssumeCapacityNoClobber(owned_name, id); + config.modes.appendAssumeCapacity(.{ .name = owned_name }); } diff --git a/river/command/enter_mode.zig b/river/command/enter_mode.zig index f5ae8e1..c982e60 100644 --- a/river/command/enter_mode.zig +++ b/river/command/enter_mode.zig @@ -59,5 +59,5 @@ pub fn enterMode( return Error.Other; } - seat.mode_id = mode_id; + seat.enterMode(mode_id); }