output: add output_title default option
Outputs now have a default option, "output_title". If this changes, the outputs title is set to the option value. This title is currently only relevant when run nested in a wayland/X11 session. Co-authored-by: Isaac Freund <ifreund@ifreund.xyz>
This commit is contained in:
		
				
					committed by
					
						 Isaac Freund
						Isaac Freund
					
				
			
			
				
	
			
			
			
						parent
						
							5e09b853f7
						
					
				
				
					commit
					7029a5cd3e
				
			
							
								
								
									
										2
									
								
								deps/zig-wlroots
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								deps/zig-wlroots
									
									
									
									
										vendored
									
									
								
							 Submodule deps/zig-wlroots updated: 4db6b92146...5bc7fcf94e
									
								
							| @ -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: | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user