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
@ -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
|
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
|
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
|
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.
|
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
|
Declare a new option with the given _type_ and inital _value_. If
|
||||||
the option already exists with the given _type_, it is still set
|
the option already exists with the given _type_, it is still set
|
||||||
to _value_. If the option already exists with a different type,
|
to _value_. If the option already exists with a different type,
|
||||||
nothing happens.
|
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.
|
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_.
|
Set the value of the specified option to _value_.
|
||||||
|
|
||||||
River declares certain default options for all outputs.
|
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 arg_idx: usize = 0;
|
||||||
var positional_idx: usize = 0;
|
var positional_idx: usize = 0;
|
||||||
outer: while (arg_idx < argv.len) : (arg_idx += 1) {
|
outer: while (arg_idx < argv.len) : (arg_idx += 1) {
|
||||||
|
var should_continue = false;
|
||||||
inline for (flag_defs) |flag_def, flag_idx| {
|
inline for (flag_defs) |flag_def, flag_idx| {
|
||||||
if (cstr.cmp(flag_def.name, argv[arg_idx]) == 0) {
|
if (cstr.cmp(flag_def.name, argv[arg_idx]) == 0) {
|
||||||
switch (flag_def.kind) {
|
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!", .{});
|
"' 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) {
|
if (positional_idx == num_positionals) {
|
||||||
root.printErrorExit(
|
root.printErrorExit(
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
const os = std.os;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const wayland = @import("wayland");
|
const wayland = @import("wayland");
|
||||||
const wl = wayland.client.wl;
|
const wl = wayland.client.wl;
|
||||||
@ -36,6 +37,7 @@ pub const Output = struct {
|
|||||||
pub const Globals = struct {
|
pub const Globals = struct {
|
||||||
control: ?*zriver.ControlV1 = null,
|
control: ?*zriver.ControlV1 = null,
|
||||||
options_manager: ?*zriver.OptionsManagerV1 = null,
|
options_manager: ?*zriver.OptionsManagerV1 = null,
|
||||||
|
status_manager: ?*zriver.StatusManagerV1 = null,
|
||||||
seat: ?*wl.Seat = null,
|
seat: ?*wl.Seat = null,
|
||||||
output_manager: ?*zxdg.OutputManagerV1 = null,
|
output_manager: ?*zxdg.OutputManagerV1 = null,
|
||||||
outputs: std.ArrayList(Output) = std.ArrayList(Output).init(gpa),
|
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 {
|
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *Globals) void {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.global => |global| {
|
.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");
|
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) {
|
} 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");
|
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) {
|
} 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");
|
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) {
|
} 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");
|
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) {
|
} 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 {
|
pub fn declareOption(display: *wl.Display, globals: *Globals) !void {
|
||||||
// https://github.com/ziglang/zig/issues/7807
|
// https://github.com/ziglang/zig/issues/7807
|
||||||
const argv: [][*:0]const u8 = os.argv;
|
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 key = args.positionals[0];
|
||||||
const value_type = std.meta.stringToEnum(ValueType, mem.span(args.positionals[1])) orelse
|
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]});
|
root.printErrorExit("'{}' is not a valid type, must be int, uint, fixed, or string", .{args.positionals[1]});
|
||||||
const raw_value = args.positionals[2];
|
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 options_manager = globals.options_manager orelse return error.RiverOptionsManagerNotAdvertised;
|
||||||
const handle = try options_manager.getOptionHandle(key, if (output) |o| o.wl_output else null);
|
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 {
|
pub fn getOption(display: *wl.Display, globals: *Globals) !void {
|
||||||
// https://github.com/ziglang/zig/issues/7807
|
// https://github.com/ziglang/zig/issues/7807
|
||||||
const argv: [][*:0]const u8 = os.argv;
|
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{
|
const ctx = Context{
|
||||||
.display = display,
|
.display = display,
|
||||||
.key = args.positionals[0],
|
.key = args.positionals[0],
|
||||||
.raw_value = undefined,
|
.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;
|
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 {
|
pub fn setOption(display: *wl.Display, globals: *Globals) !void {
|
||||||
// https://github.com/ziglang/zig/issues/7807
|
// https://github.com/ziglang/zig/issues/7807
|
||||||
const argv: [][*:0]const u8 = os.argv;
|
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{
|
const ctx = Context{
|
||||||
.display = display,
|
.display = display,
|
||||||
.key = args.positionals[0],
|
.key = args.positionals[0],
|
||||||
.raw_value = args.positionals[1],
|
.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;
|
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(
|
fn getOptionListener(
|
||||||
handle: *zriver.OptionHandleV1,
|
handle: *zriver.OptionHandleV1,
|
||||||
event: zriver.OptionHandleV1.Event,
|
event: zriver.OptionHandleV1.Event,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user