river-status: add mode event to seat status

This allows clients such as a status bar to display the currently active
mode.
This commit is contained in:
Isaac Freund 2022-05-31 18:09:03 +02:00
parent 03e8da669c
commit d657dc791b
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
10 changed files with 49 additions and 27 deletions

View File

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

View File

@ -16,7 +16,7 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</copyright>
<interface name="zriver_status_manager_v1" version="2">
<interface name="zriver_status_manager_v1" version="3">
<description summary="manage river status objects">
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 @@
</event>
</interface>
<interface name="zriver_seat_status_v1" version="1">
<interface name="zriver_seat_status_v1" version="3">
<description summary="track seat focus">
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 @@
</description>
<arg name="title" type="string" summary="title of the focused view"/>
</event>
<event name="mode" since="3">
<description summary="the active mode changed">
Sent once on binding the interface and again whenever a new mode
is entered (e.g. with riverctl enter-mode foobar).
</description>
<arg name="name" type="string" summary="name of the mode"/>
</event>
</interface>
</protocol>

View File

@ -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();
}
for (self.modes.items) |*mode| mode.deinit();
self.modes.deinit(util.gpa);

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -59,5 +59,5 @@ pub fn enterMode(
return Error.Other;
}
seat.mode_id = mode_id;
seat.enterMode(mode_id);
}