riverctl: add -focused-output for option commands
This is more convenient for interactive usage and makes using the same bindings across multiple outputs easy.
This commit is contained in:
parent
96d460c477
commit
a8a70a3b04
4 changed files with 75 additions and 13 deletions
|
@ -284,19 +284,20 @@ A complete list may be found in _/usr/include/linux/input-event-codes.h_
|
|||
|
||||
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
|
||||
scoped either globally or per-output if the -output flag is passed with the
|
||||
name of the output as obtained from the xdg-output protocol.
|
||||
scoped either globally or per-output if the *-output* flag is passed with the
|
||||
name of the output as obtained from the xdg-output protocol. Alternatively,
|
||||
the currently focused output may be targeted with the *-focused-output* flag.
|
||||
|
||||
*declare-option* [-output _output_name_] _name_ _type_ _value_
|
||||
*declare-option* [*-output* _output_name_|*-focused-output*] _name_ _type_ _value_
|
||||
Declare a new option with the given _type_ and inital _value_. If
|
||||
the option already exists with the given _type_, it is still set
|
||||
to _value_. If the option already exists with a different type,
|
||||
nothing happens.
|
||||
|
||||
*get-option* [-output _output_name_] _name_
|
||||
*get-option* [*-output* _output_name_|*-focused-output*] _name_
|
||||
Print the current value of the given option to stdout.
|
||||
|
||||
*set-option* [-output _output_name_] _name_ _value_
|
||||
*set-option* [*-output* _output_name_|*-focused-output*] _name_ _value_
|
||||
Set the value of the specified option to _value_.
|
||||
|
||||
River declares certain default options for all outputs.
|
||||
|
|
|
@ -60,6 +60,7 @@ pub fn Args(comptime num_positionals: comptime_int, comptime flag_defs: []const
|
|||
var arg_idx: usize = 0;
|
||||
var positional_idx: usize = 0;
|
||||
outer: while (arg_idx < argv.len) : (arg_idx += 1) {
|
||||
var should_continue = false;
|
||||
inline for (flag_defs) |flag_def, flag_idx| {
|
||||
if (cstr.cmp(flag_def.name, argv[arg_idx]) == 0) {
|
||||
switch (flag_def.kind) {
|
||||
|
@ -73,9 +74,12 @@ pub fn Args(comptime num_positionals: comptime_int, comptime flag_defs: []const
|
|||
"' requires an argument but none was provided!", .{});
|
||||
},
|
||||
}
|
||||
continue :outer;
|
||||
// TODO: this variable exists as a workaround for the fact that
|
||||
// using continue :outer here crashes the stage1 compiler.
|
||||
should_continue = true;
|
||||
}
|
||||
}
|
||||
if (should_continue) continue;
|
||||
|
||||
if (positional_idx == num_positionals) {
|
||||
root.printErrorExit(
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const wayland = @import("wayland");
|
||||
const wl = wayland.client.wl;
|
||||
|
@ -36,6 +37,7 @@ pub const Output = struct {
|
|||
pub const Globals = struct {
|
||||
control: ?*zriver.ControlV1 = null,
|
||||
options_manager: ?*zriver.OptionsManagerV1 = null,
|
||||
status_manager: ?*zriver.StatusManagerV1 = null,
|
||||
seat: ?*wl.Seat = null,
|
||||
output_manager: ?*zxdg.OutputManagerV1 = null,
|
||||
outputs: std.ArrayList(Output) = std.ArrayList(Output).init(gpa),
|
||||
|
@ -77,12 +79,15 @@ pub fn main() !void {
|
|||
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *Globals) void {
|
||||
switch (event) {
|
||||
.global => |global| {
|
||||
if (globals.seat == null and std.cstr.cmp(global.interface, wl.Seat.getInterface().name) == 0) {
|
||||
if (std.cstr.cmp(global.interface, wl.Seat.getInterface().name) == 0) {
|
||||
assert(globals.seat == null); // TODO: support multiple seats
|
||||
globals.seat = registry.bind(global.name, wl.Seat, 1) catch @panic("out of memory");
|
||||
} else if (std.cstr.cmp(global.interface, zriver.ControlV1.getInterface().name) == 0) {
|
||||
globals.control = registry.bind(global.name, zriver.ControlV1, 1) catch @panic("out of memory");
|
||||
} else if (std.cstr.cmp(global.interface, zriver.OptionsManagerV1.getInterface().name) == 0) {
|
||||
globals.options_manager = registry.bind(global.name, zriver.OptionsManagerV1, 1) catch @panic("out of memory");
|
||||
} else if (std.cstr.cmp(global.interface, zriver.StatusManagerV1.getInterface().name) == 0) {
|
||||
globals.status_manager = registry.bind(global.name, zriver.StatusManagerV1, 1) catch @panic("out of memory");
|
||||
} else if (std.cstr.cmp(global.interface, zxdg.OutputManagerV1.getInterface().name) == 0 and global.version >= 2) {
|
||||
globals.output_manager = registry.bind(global.name, zxdg.OutputManagerV1, 2) catch @panic("out of memory");
|
||||
} else if (std.cstr.cmp(global.interface, wl.Output.getInterface().name) == 0) {
|
||||
|
|
|
@ -49,12 +49,22 @@ const Context = struct {
|
|||
pub fn declareOption(display: *wl.Display, globals: *Globals) !void {
|
||||
// https://github.com/ziglang/zig/issues/7807
|
||||
const argv: [][*:0]const u8 = os.argv;
|
||||
const args = Args(3, &[_]FlagDef{.{ .name = "-output", .kind = .arg }}).parse(argv[2..]);
|
||||
const args = Args(3, &[_]FlagDef{
|
||||
.{ .name = "-output", .kind = .arg },
|
||||
.{ .name = "-focused-output", .kind = .boolean },
|
||||
}).parse(argv[2..]);
|
||||
|
||||
const key = args.positionals[0];
|
||||
const value_type = std.meta.stringToEnum(ValueType, mem.span(args.positionals[1])) orelse
|
||||
root.printErrorExit("'{}' is not a valid type, must be int, uint, fixed, or string", .{args.positionals[1]});
|
||||
const raw_value = args.positionals[2];
|
||||
const output = if (args.argFlag("-output")) |o| try parseOutputName(display, globals, o) else null;
|
||||
|
||||
const output = if (args.argFlag("-output")) |o|
|
||||
try parseOutputName(display, globals, o)
|
||||
else if (args.boolFlag("-focused-output"))
|
||||
try getFocusedOutput(display, globals)
|
||||
else
|
||||
null;
|
||||
|
||||
const options_manager = globals.options_manager orelse return error.RiverOptionsManagerNotAdvertised;
|
||||
const handle = try options_manager.getOptionHandle(key, if (output) |o| o.wl_output else null);
|
||||
|
@ -86,12 +96,23 @@ fn setFixedValueRaw(handle: *zriver.OptionHandleV1, raw_value: [*:0]const u8) vo
|
|||
pub fn getOption(display: *wl.Display, globals: *Globals) !void {
|
||||
// https://github.com/ziglang/zig/issues/7807
|
||||
const argv: [][*:0]const u8 = os.argv;
|
||||
const args = Args(1, &[_]FlagDef{.{ .name = "-output", .kind = .arg }}).parse(argv[2..]);
|
||||
const args = Args(1, &[_]FlagDef{
|
||||
.{ .name = "-output", .kind = .arg },
|
||||
.{ .name = "-focused-output", .kind = .boolean },
|
||||
}).parse(argv[2..]);
|
||||
|
||||
const output = if (args.argFlag("-output")) |o|
|
||||
try parseOutputName(display, globals, o)
|
||||
else if (args.boolFlag("-focused-output"))
|
||||
try getFocusedOutput(display, globals)
|
||||
else
|
||||
null;
|
||||
|
||||
const ctx = Context{
|
||||
.display = display,
|
||||
.key = args.positionals[0],
|
||||
.raw_value = undefined,
|
||||
.output = if (args.argFlag("-output")) |o| try parseOutputName(display, globals, o) else null,
|
||||
.output = output,
|
||||
};
|
||||
|
||||
const options_manager = globals.options_manager orelse return error.RiverOptionsManagerNotAdvertised;
|
||||
|
@ -105,12 +126,23 @@ pub fn getOption(display: *wl.Display, globals: *Globals) !void {
|
|||
pub fn setOption(display: *wl.Display, globals: *Globals) !void {
|
||||
// https://github.com/ziglang/zig/issues/7807
|
||||
const argv: [][*:0]const u8 = os.argv;
|
||||
const args = Args(2, &[_]FlagDef{.{ .name = "-output", .kind = .arg }}).parse(argv[2..]);
|
||||
const args = Args(2, &[_]FlagDef{
|
||||
.{ .name = "-output", .kind = .arg },
|
||||
.{ .name = "-focused-output", .kind = .boolean },
|
||||
}).parse(argv[2..]);
|
||||
|
||||
const output = if (args.argFlag("-output")) |o|
|
||||
try parseOutputName(display, globals, o)
|
||||
else if (args.boolFlag("-focused-output"))
|
||||
try getFocusedOutput(display, globals)
|
||||
else
|
||||
null;
|
||||
|
||||
const ctx = Context{
|
||||
.display = display,
|
||||
.key = args.positionals[0],
|
||||
.raw_value = args.positionals[1],
|
||||
.output = if (args.argFlag("-output")) |o| try parseOutputName(display, globals, o) else null,
|
||||
.output = output,
|
||||
};
|
||||
|
||||
const options_manager = globals.options_manager orelse return error.RiverOptionsManagerNotAdvertised;
|
||||
|
@ -142,6 +174,26 @@ fn xdgOutputListener(xdg_output: *zxdg.OutputV1, event: zxdg.OutputV1.Event, out
|
|||
}
|
||||
}
|
||||
|
||||
fn getFocusedOutput(display: *wl.Display, globals: *Globals) !*Output {
|
||||
const status_manager = globals.status_manager orelse return error.RiverStatusManagerNotAdvertised;
|
||||
const seat = globals.seat orelse return error.SeatNotAdverstised;
|
||||
const seat_status = try status_manager.getRiverSeatStatus(seat);
|
||||
var result: ?*wl.Output = null;
|
||||
seat_status.setListener(*?*wl.Output, seatStatusListener, &result) catch unreachable;
|
||||
_ = try display.roundtrip();
|
||||
const wl_output = if (result) |output| output else return error.NoOutputFocused;
|
||||
for (globals.outputs.items) |*output| {
|
||||
if (output.wl_output == wl_output) return output;
|
||||
} else unreachable;
|
||||
}
|
||||
|
||||
fn seatStatusListener(seat_status: *zriver.SeatStatusV1, event: zriver.SeatStatusV1.Event, result: *?*wl.Output) void {
|
||||
switch (event) {
|
||||
.focused_output => |ev| result.* = ev.output,
|
||||
.unfocused_output, .focused_view => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn getOptionListener(
|
||||
handle: *zriver.OptionHandleV1,
|
||||
event: zriver.OptionHandleV1.Event,
|
||||
|
|
Loading…
Reference in a new issue