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:
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user