Output: Add layoutExternal()
This commit is contained in:
parent
754e24a710
commit
2fce8c7108
123
river/Output.zig
123
river/Output.zig
@ -165,7 +165,7 @@ fn layoutFull(self: *Self, visible_count: u32, output_tags: u32) void {
|
|||||||
const border_width = self.root.server.config.border_width;
|
const border_width = self.root.server.config.border_width;
|
||||||
const view_padding = self.root.server.config.view_padding;
|
const view_padding = self.root.server.config.view_padding;
|
||||||
const outer_padding = self.root.server.config.outer_padding;
|
const outer_padding = self.root.server.config.outer_padding;
|
||||||
const xy_offset = @intCast(i32, outer_padding + border_width + view_padding);
|
const xy_offset = outer_padding + border_width + view_padding;
|
||||||
|
|
||||||
var full_box: Box = .{
|
var full_box: Box = .{
|
||||||
.x = self.usable_box.x + @intCast(i32, xy_offset),
|
.x = self.usable_box.x + @intCast(i32, xy_offset),
|
||||||
@ -190,31 +190,116 @@ fn layoutFull(self: *Self, visible_count: u32, output_tags: u32) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LayoutError = error{
|
||||||
|
BadExitCode,
|
||||||
|
BadWindowConfiguration,
|
||||||
|
ConfigurationMismatch,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Parse a window configuration string and write values to the box
|
||||||
|
fn parseWindowConfig(buffer: []const u8) LayoutError!Box {
|
||||||
|
var i: u32 = 0;
|
||||||
|
var box: Box = undefined;
|
||||||
|
var it = std.mem.split(buffer, " ");
|
||||||
|
while (it.next()) |token| : (i += 1) {
|
||||||
|
switch (i) {
|
||||||
|
0 => box.x = std.fmt.parseInt(i32, token, 10) catch return LayoutError.BadWindowConfiguration,
|
||||||
|
1 => box.y = std.fmt.parseInt(i32, token, 10) catch return LayoutError.BadWindowConfiguration,
|
||||||
|
2 => box.width = std.fmt.parseInt(u32, token, 10) catch return LayoutError.BadWindowConfiguration,
|
||||||
|
3 => box.height = std.fmt.parseInt(u32, token, 10) catch return LayoutError.BadWindowConfiguration,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i != 4) return LayoutError.BadWindowConfiguration;
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parse window configuration" {
|
||||||
|
const testing = @import("std").testing;
|
||||||
|
var box = try parseWindowConfig("5 10 100 200");
|
||||||
|
testing.expect(box.x == 5);
|
||||||
|
testing.expect(box.y == 10);
|
||||||
|
testing.expect(box.width == 100);
|
||||||
|
testing.expect(box.height == 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute an external layout function, parse its output and apply the layout
|
||||||
|
/// to the output.
|
||||||
|
fn layoutExternal(self: *Self, visible_count: u32, output_tags: u32) !void {
|
||||||
|
const allocator = self.root.server.allocator;
|
||||||
|
|
||||||
const border_width = self.root.server.config.border_width;
|
const border_width = self.root.server.config.border_width;
|
||||||
const view_padding = self.root.server.config.view_padding;
|
const view_padding = self.root.server.config.view_padding;
|
||||||
const outer_padding = self.root.server.config.outer_padding;
|
const outer_padding = self.root.server.config.outer_padding;
|
||||||
|
const xy_offset = @intCast(i32, border_width + outer_padding + view_padding);
|
||||||
|
const delta_size = (border_width + view_padding) * 2;
|
||||||
|
const layout_width = @intCast(u32, self.usable_box.width) - outer_padding * 2;
|
||||||
|
const layout_height = @intCast(u32, self.usable_box.height) - outer_padding * 2;
|
||||||
|
|
||||||
|
// Assemble command
|
||||||
var i: u32 = 0;
|
const parameters = std.fmt.allocPrint(allocator, "{} {} {d} {} {}", .{ visible_count, self.master_count, self.master_factor, layout_width, layout_height }) catch @panic("Out of memory.");
|
||||||
var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
|
defer allocator.free(parameters);
|
||||||
while (it.next()) |node| {
|
const layout_command = try std.mem.join(allocator, " ", &[_][]const u8{
|
||||||
const view = &node.view;
|
self.layout,
|
||||||
|
parameters,
|
||||||
if (view.floating) {
|
});
|
||||||
continue;
|
defer allocator.free(layout_command);
|
||||||
}
|
const cmd = [_][]const u8{
|
||||||
|
"/bin/sh",
|
||||||
var new_box: Box = undefined;
|
"-c",
|
||||||
new_box = .{
|
layout_command,
|
||||||
.x = x_offset,
|
|
||||||
.y = y_offset,
|
|
||||||
.width = layout_width,
|
|
||||||
.height = layout_height,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
view.pending_box = new_box;
|
// Execute layout executable
|
||||||
|
// TODO abort after 1 second
|
||||||
|
const child = try std.ChildProcess.init(&cmd, allocator);
|
||||||
|
defer child.deinit();
|
||||||
|
child.stdin_behavior = .Ignore;
|
||||||
|
child.stdout_behavior = .Pipe;
|
||||||
|
try std.ChildProcess.spawn(child);
|
||||||
|
const max_output_size = 400 * 1024;
|
||||||
|
const buffer = try child.stdout.?.inStream().readAllAlloc(allocator, max_output_size);
|
||||||
|
defer allocator.free(buffer);
|
||||||
|
const term = try child.wait();
|
||||||
|
switch (term) {
|
||||||
|
.Exited, .Signal, .Stopped, .Unknown => |code| {
|
||||||
|
if (code != 0) {
|
||||||
|
return LayoutError.BadExitCode;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
i += 1;
|
// Parse layout command output
|
||||||
|
var view_boxen = std.ArrayList(Box).init(self.root.server.allocator);
|
||||||
|
defer view_boxen.deinit();
|
||||||
|
var parse_it = std.mem.split(buffer, "\n");
|
||||||
|
while (parse_it.next()) |token| {
|
||||||
|
if (std.mem.eql(u8, token, "")) break;
|
||||||
|
var box = try parseWindowConfig(token);
|
||||||
|
box.x += self.usable_box.x + xy_offset;
|
||||||
|
box.y += self.usable_box.y + xy_offset;
|
||||||
|
box.width -= delta_size;
|
||||||
|
box.height -= delta_size;
|
||||||
|
if (box.width < minimum_size) {
|
||||||
|
box.width = minimum_size;
|
||||||
|
Log.Info.log("Window configuration hits minimum view width.", .{});
|
||||||
|
}
|
||||||
|
if (box.height < minimum_size) {
|
||||||
|
box.height = minimum_size;
|
||||||
|
Log.Info.log("Window configuration hits minimum view height.", .{});
|
||||||
|
}
|
||||||
|
try view_boxen.append(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view_boxen.items.len != visible_count) return LayoutError.ConfigurationMismatch;
|
||||||
|
|
||||||
|
// Apply window configuration to views
|
||||||
|
var i: u32 = 0;
|
||||||
|
var view_it = ViewStack(View).pendingIterator(self.views.first, output_tags);
|
||||||
|
while (view_it.next()) |node| : (i += 1) {
|
||||||
|
const view = &node.view;
|
||||||
|
if (view.floating) continue;
|
||||||
|
view.pending_box = view_boxen.items[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user