river-layout: update to v3

- Remove advertise_view and advertise_done events. Using the information
provided by these for any purpose would make the layout far less
predictable. Futhermore, in the months this has been available for use,
to my knowledge nobody has actually used it for anything useful.

- Replace the set/mod layout value events with a single user_command
event. This simplifies the protocol and is more flexible for clients.

- Add a layout_name argument to the commit request. This name is an
arbitrary, user-facing string that might, for example, be displayed by a
status bar. This was present in early drafts of the protocol, but was
removed in favor of river-options. Since river-options itself has since
been removed and this feature is nice to have, re-add it.

- Rename main factor to main ratio in rivertile. The "factor" name was
just legacy from dwm, "ratio" is much more accurate.
This commit is contained in:
Isaac Freund
2021-07-15 13:22:37 +02:00
parent 96e1082156
commit 2635f3299a
11 changed files with 322 additions and 437 deletions

View File

@ -36,12 +36,12 @@ const LayoutDemand = @import("LayoutDemand.zig");
const log = std.log.scoped(.layout);
layout: *river.LayoutV2,
layout: *river.LayoutV3,
namespace: []const u8,
output: *Output,
pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namespace: []const u8) !void {
const layout = try river.LayoutV2.create(client, version, id);
const layout = try river.LayoutV3.create(client, version, id);
if (namespaceInUse(namespace, output, client)) {
layout.sendNamespaceInUse();
@ -92,7 +92,7 @@ fn namespaceInUse(namespace: []const u8, output: *Output, client: *wl.Client) bo
/// This exists to handle layouts that have been rendered inert (due to the
/// namespace already being in use) until the client destroys them.
fn handleRequestInert(layout: *river.LayoutV2, request: river.LayoutV2.Request, _: ?*c_void) void {
fn handleRequestInert(layout: *river.LayoutV3, request: river.LayoutV3.Request, _: ?*c_void) void {
if (request == .destroy) layout.destroy();
}
@ -108,28 +108,19 @@ pub fn startLayoutDemand(self: *Self, views: u32) void {
log.err("failed starting layout demand", .{});
return;
};
const serial = self.output.layout_demand.?.serial;
// Then we let the client know that we require a layout
self.layout.sendLayoutDemand(
views,
self.output.usable_box.width,
self.output.usable_box.height,
self.output.pending.tags,
serial,
self.output.layout_demand.?.serial,
);
// And finally we advertise all visible views
var it = ViewStack(View).iter(self.output.views.first, .forward, self.output.pending.tags, Output.arrangeFilter);
while (it.next()) |view| {
self.layout.sendAdvertiseView(view.pending.tags, view.getAppId(), serial);
}
self.layout.sendAdvertiseDone(serial);
server.root.trackLayoutDemands();
}
fn handleRequest(layout: *river.LayoutV2, request: river.LayoutV2.Request, self: *Self) void {
fn handleRequest(layout: *river.LayoutV3, request: river.LayoutV3.Request, self: *Self) void {
switch (request) {
.destroy => layout.destroy(),
@ -168,7 +159,7 @@ fn handleRequest(layout: *river.LayoutV2, request: river.LayoutV2.Request, self:
}
}
fn handleDestroy(layout: *river.LayoutV2, self: *Self) void {
fn handleDestroy(layout: *river.LayoutV3, self: *Self) void {
self.destroy();
}

View File

@ -38,7 +38,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, river.LayoutManagerV2, 1, *Self, self, bind),
.global = try wl.Global.create(server.wl_server, river.LayoutManagerV3, 1, *Self, self, bind),
};
server.wl_server.addDestroyListener(&self.server_destroy);
@ -50,7 +50,7 @@ fn handleServerDestroy(listener: *wl.Listener(*wl.Server), wl_server: *wl.Server
}
fn bind(client: *wl.Client, self: *Self, version: u32, id: u32) callconv(.C) void {
const layout_manager = river.LayoutManagerV2.create(client, 1, id) catch {
const layout_manager = river.LayoutManagerV3.create(client, 1, id) catch {
client.postNoMemory();
log.crit("out of memory", .{});
return;
@ -58,7 +58,7 @@ fn bind(client: *wl.Client, self: *Self, version: u32, id: u32) callconv(.C) voi
layout_manager.setHandler(*Self, handleRequest, null, self);
}
fn handleRequest(layout_manager: *river.LayoutManagerV2, request: river.LayoutManagerV2.Request, self: *Self) void {
fn handleRequest(layout_manager: *river.LayoutManagerV3, request: river.LayoutManagerV3.Request, self: *Self) void {
switch (request) {
.destroy => layout_manager.destroy(),

View File

@ -64,14 +64,13 @@ const str_to_impl_fn = [_]struct {
.{ .name = "list-inputs", .impl = @import("command/input.zig").listInputs },
.{ .name = "map", .impl = @import("command/map.zig").map },
.{ .name = "map-pointer", .impl = @import("command/map.zig").mapPointer },
.{ .name = "mod-layout-value", .impl = @import("command/layout.zig").modLayoutValue },
.{ .name = "move", .impl = @import("command/move.zig").move },
.{ .name = "output-layout", .impl = @import("command/layout.zig").outputLayout },
.{ .name = "resize", .impl = @import("command/move.zig").resize },
.{ .name = "send-layout-cmd", .impl = @import("command/layout.zig").sendLayoutCmd },
.{ .name = "send-to-output", .impl = @import("command/output.zig").sendToOutput },
.{ .name = "set-cursor-warp", .impl = @import("command/config.zig").setCursorWarp },
.{ .name = "set-focused-tags", .impl = @import("command/tags.zig").setFocusedTags },
.{ .name = "set-layout-value", .impl = @import("command/layout.zig").setLayoutValue },
.{ .name = "set-repeat", .impl = @import("command/set_repeat.zig").setRepeat },
.{ .name = "set-view-tags", .impl = @import("command/tags.zig").setViewTags },
.{ .name = "snap", .impl = @import("command/move.zig").snap },
@ -99,7 +98,6 @@ pub const Error = error{
InvalidButton,
InvalidCharacter,
InvalidDirection,
InvalidType,
InvalidPhysicalDirection,
InvalidOrientation,
InvalidRgba,
@ -144,7 +142,6 @@ pub fn errToMsg(err: Error) [:0]const u8 {
Error.InvalidButton => "invalid button",
Error.InvalidCharacter => "invalid character in argument",
Error.InvalidDirection => "invalid direction. Must be 'next' or 'previous'",
Error.InvalidType => "invalid type",
Error.InvalidPhysicalDirection => "invalid direction. Must be 'up', 'down', 'left' or 'right'",
Error.InvalidOrientation => "invalid orientation. Must be 'horizontal', or 'vertical'",
Error.InvalidRgba => "invalid color format, must be #RRGGBB or #RRGGBBAA",

View File

@ -56,28 +56,20 @@ pub fn defaultLayout(
}
}
const SetType = enum {
int,
fixed,
string,
};
/// riverctl set-layout-value rivertile int main_count 42
/// riverctl set-layout-value rivertile fixed main_factor 42.0
/// riverctl set-layout-value rivertile string main_location top
pub fn setLayoutValue(
/// riverctl send-layout-cmd rivertile "mod-main-count 1"
/// riverctl send-layout-cmd rivertile "mod-main-factor -0.1"
/// riverctl send-layout-cmd rivertile "main-location top"
pub fn sendLayoutCmd(
allocator: *std.mem.Allocator,
seat: *Seat,
args: []const [:0]const u8,
out: *?[]const u8,
) Error!void {
if (args.len < 5) return Error.NotEnoughArguments;
if (args.len > 5) return Error.TooManyArguments;
const target_namespace = args[1];
const kind = std.meta.stringToEnum(SetType, args[2]) orelse return Error.InvalidType;
if (args.len < 3) return Error.NotEnoughArguments;
if (args.len > 3) return Error.TooManyArguments;
const output = seat.focused_output;
const target_namespace = args[1];
var it = output.layouts.first;
const layout = while (it) |node| : (it = node.next) {
@ -85,68 +77,7 @@ pub fn setLayoutValue(
if (mem.eql(u8, layout.namespace, target_namespace)) break layout;
} else return;
const null_terminated_name = try util.gpa.dupeZ(u8, args[3]);
defer util.gpa.free(null_terminated_name);
switch (kind) {
.int => {
const value = try std.fmt.parseInt(i32, args[4], 10);
layout.layout.sendSetIntValue(null_terminated_name, value);
},
.fixed => {
const value = try std.fmt.parseFloat(f64, args[4]);
layout.layout.sendSetFixedValue(null_terminated_name, wl.Fixed.fromDouble(value));
},
.string => {
const null_terminated_value = try util.gpa.dupeZ(u8, args[4]);
defer util.gpa.free(null_terminated_value);
layout.layout.sendSetStringValue(null_terminated_name, null_terminated_value);
},
}
output.arrangeViews();
}
const ModType = enum {
int,
fixed,
};
/// riverctl mode-layout-value rivertile int main_count 42
/// riverctl set-layout-value rivertile fixed main_factor 42.0
pub fn modLayoutValue(
allocator: *std.mem.Allocator,
seat: *Seat,
args: []const [:0]const u8,
out: *?[]const u8,
) Error!void {
if (args.len < 5) return Error.NotEnoughArguments;
if (args.len > 5) return Error.TooManyArguments;
const target_namespace = args[1];
const kind = std.meta.stringToEnum(ModType, args[2]) orelse return Error.InvalidType;
const output = seat.focused_output;
var it = output.layouts.first;
const layout = while (it) |node| : (it = node.next) {
const layout = &node.data;
if (mem.eql(u8, layout.namespace, target_namespace)) break layout;
} else return;
const null_terminated_name = try util.gpa.dupeZ(u8, args[3]);
defer util.gpa.free(null_terminated_name);
switch (kind) {
.int => {
const value = try std.fmt.parseInt(i32, args[4], 10);
layout.layout.sendModIntValue(null_terminated_name, value);
},
.fixed => {
const value = try std.fmt.parseFloat(f64, args[4]);
layout.layout.sendModFixedValue(null_terminated_name, wl.Fixed.fromDouble(value));
},
}
layout.layout.sendUserCommand(args[2]);
output.arrangeViews();
}