aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------deps/zig-wlroots0
-rw-r--r--doc/riverctl.1.scd8
-rw-r--r--river/Option.zig7
-rw-r--r--river/Output.zig36
-rw-r--r--river/Server.zig2
5 files changed, 51 insertions, 2 deletions
diff --git a/deps/zig-wlroots b/deps/zig-wlroots
-Subproject 4db6b92146f22054b9a9363d0999cf3fb359a4f
+Subproject 5bc7fcf94e1d488a8e2316ff7ebdd0ca193d030
diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd
index 05eafdf..3424ea4 100644
--- a/doc/riverctl.1.scd
+++ b/doc/riverctl.1.scd
@@ -280,7 +280,7 @@ A complete list may be found in _/usr/include/linux/input-event-codes.h_
and is made available through the _XCURSOR_THEME_ and _XCURSOR_SIZE_
environment variables.
-# OPTIONS
+## OPTIONS
River has various options that are saved in a typed key-value store. It also
allows users to store arbitrary custom options in the store. Options are
@@ -299,6 +299,12 @@ name of the output as obtained from the xdg-output protocol.
*set-option* [-output _output_name_] _name_ _value_
Set the value of the specified option to _value_.
+River declares certain default options for all outputs.
+
+*output_title* (string)
+ Changing this option changes the title of the wayland and X11 backend
+ outputs.
+
# EXAMPLES
Bind bemenu-run to Super+P in normal mode:
diff --git a/river/Option.zig b/river/Option.zig
index a6366bc..db9a731 100644
--- a/river/Option.zig
+++ b/river/Option.zig
@@ -45,6 +45,9 @@ output: ?*Output,
key: [*:0]const u8,
value: Value = .unset,
+/// Emitted whenever the value of the option changes.
+update: wl.Signal(*Self) = undefined,
+
handles: wl.list.Head(zriver.OptionHandleV1, null) = undefined,
pub fn create(options_manager: *OptionsManager, output: ?*Output, key: [*:0]const u8) !*Self {
@@ -57,6 +60,7 @@ pub fn create(options_manager: *OptionsManager, output: ?*Output, key: [*:0]cons
.key = try util.gpa.dupeZ(u8, mem.span(key)),
};
self.handles.init();
+ self.update.init();
options_manager.options.append(self);
@@ -101,6 +105,9 @@ pub fn set(self: *Self, value: Value) !void {
var it = self.handles.iterator(.forward);
while (it.next()) |handle| self.sendValue(handle);
+
+ // Call listeners, if any.
+ self.update.emit(self);
}
fn sendValue(self: Self, handle: *zriver.OptionHandleV1) void {
diff --git a/river/Output.zig b/river/Output.zig
index 1b599ef..bbedcc6 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -18,6 +18,8 @@
const Self = @This();
const std = @import("std");
+const mem = std.mem;
+const fmt = std.fmt;
const wlr = @import("wlroots");
const wayland = @import("wayland");
const wl = wayland.server.wl;
@@ -35,6 +37,7 @@ const View = @import("View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const AttachMode = @import("view_stack.zig").AttachMode;
const OutputStatus = @import("OutputStatus.zig");
+const Option = @import("Option.zig");
const State = struct {
/// A bit field of focused tags
@@ -84,6 +87,9 @@ enable: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleEnable),
frame: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleFrame),
mode: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleMode),
+// Listeners for options
+output_title: wl.Listener(*Option) = wl.Listener(*Option).init(handleTitleChange),
+
pub fn init(self: *Self, root: *Root, wlr_output: *wlr.Output) !void {
// Some backends don't have modes. DRM+KMS does, and we need to set a mode
// before we can use the output. The mode is a tuple of (width, height,
@@ -138,6 +144,10 @@ pub fn init(self: *Self, root: *Root, wlr_output: *wlr.Output) !void {
.height = effective_resolution.height,
};
}
+
+ var buf: ["river - ".len + wlr_output.name.len + 1]u8 = undefined;
+ const default_title = fmt.bufPrintZ(&buf, "river - {}", .{mem.spanZ(&wlr_output.name)}) catch unreachable;
+ try self.defaultOption("output_title", .{ .string = default_title.ptr }, &self.output_title);
}
pub fn getLayer(self: *Self, layer: zwlr.LayerShellV1.Layer) *std.TailQueue(LayerSurface) {
@@ -545,3 +555,29 @@ pub fn getEffectiveResolution(self: *Self) struct { width: u32, height: u32 } {
.height = @intCast(u32, height),
};
}
+
+pub fn setTitle(self: *Self, title: [*:0]const u8) void {
+ if (self.wlr_output.isWl()) {
+ self.wlr_output.wlSetTitle(title);
+ } else if (self.wlr_output.isX11()) {
+ self.wlr_output.x11SetTitle(title);
+ }
+}
+
+/// Create an option for this output, attach a listener which is called when
+/// the option changed and initialize with a default value. Note that the
+/// listener is called once through this function.
+fn defaultOption(
+ self: *Self,
+ key: [*:0]const u8,
+ value: Option.Value,
+ listener: *wl.Listener(*Option),
+) !void {
+ const option = try Option.create(&self.root.server.options_manager, self, key);
+ option.update.add(listener);
+ try option.set(value);
+}
+
+fn handleTitleChange(listener: *wl.Listener(*Option), option: *Option) void {
+ if (option.value.string) |title| option.output.?.setTitle(title);
+}
diff --git a/river/Server.zig b/river/Server.zig
index 7923065..5ea699b 100644
--- a/river/Server.zig
+++ b/river/Server.zig
@@ -112,12 +112,12 @@ pub fn init(self: *Self) !void {
self.config = try Config.init();
try self.decoration_manager.init(self);
+ try self.options_manager.init(self);
try self.root.init(self);
// Must be called after root is initialized
try self.input_manager.init(self);
try self.control.init(self);
try self.status_manager.init(self);
- try self.options_manager.init(self);
// These all free themselves when the wl_server is destroyed
_ = try wlr.DataDeviceManager.create(self.wl_server);