diff --git a/build.zig b/build.zig index 0b75789..58116dd 100644 --- a/build.zig +++ b/build.zig @@ -68,6 +68,13 @@ pub fn build(b: *std.build.Builder) !void { riverctl.install(); } + { + const rivertile = b.addExecutable("rivertile", "rivertile/main.zig"); + rivertile.setTarget(target); + rivertile.setBuildMode(mode); + rivertile.install(); + } + if (man_pages) { const scdoc_step = ScdocStep.create(b); try scdoc_step.install(); diff --git a/rivertile/main.zig b/rivertile/main.zig new file mode 100644 index 0000000..8171dcc --- /dev/null +++ b/rivertile/main.zig @@ -0,0 +1,128 @@ +// This file is part of river, a dynamic tiling wayland compositor. +// +// Copyright 2020 Isaac Freund +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +const std = @import("std"); + +const Orientation = enum { + left, + right, + top, + bottom, +}; + +/// This is an implementation of the default "tiled" layout of dwm and the +/// 3 other orientations thereof. This code is written with the left +/// orientation in mind and then the input/output values are adjusted to apply +/// the necessary transformations to derive the other 3. +/// +/// With 4 views and one master, the left layout looks something like this: +/// +/// +-----------------------+------------+ +/// | | | +/// | | | +/// | | | +/// | +------------+ +/// | | | +/// | | | +/// | | | +/// | +------------+ +/// | | | +/// | | | +/// | | | +/// +-----------------------+------------+ +pub fn main() !void { + // first arg must be left, right, top, or bottom + const master_location = std.meta.stringToEnum(Orientation, std.mem.spanZ(std.os.argv[1])).?; + + // the other 5 are passed by river and described in river-layouts(7) + const num_views = try std.fmt.parseInt(u32, std.mem.spanZ(std.os.argv[2]), 10); + const master_count = try std.fmt.parseInt(u32, std.mem.spanZ(std.os.argv[3]), 10); + const master_factor = try std.fmt.parseFloat(f64, std.mem.spanZ(std.os.argv[4])); + + const width_arg: u32 = switch (master_location) { + .left, .right => 5, + .top, .bottom => 6, + }; + const height_arg: u32 = if (width_arg == 5) 6 else 5; + + const output_width = try std.fmt.parseInt(u32, std.mem.spanZ(std.os.argv[width_arg]), 10); + const output_height = try std.fmt.parseInt(u32, std.mem.spanZ(std.os.argv[height_arg]), 10); + + const secondary_count = num_views - master_count; + + // to make things pixel-perfect, we make the first master and first secondary + // view slightly larger if the height is not evenly divisible + var master_width: u32 = undefined; + var master_height: u32 = undefined; + var master_height_rem: u32 = undefined; + + var secondary_width: u32 = undefined; + var secondary_height: u32 = undefined; + var secondary_height_rem: u32 = undefined; + + if (master_count > 0 and secondary_count > 0) { + master_width = @floatToInt(u32, master_factor * @intToFloat(f64, output_width)); + master_height = output_height / master_count; + master_height_rem = output_height % master_count; + + secondary_width = output_width - master_width; + secondary_height = output_height / secondary_count; + secondary_height_rem = output_height % secondary_count; + } else if (master_count > 0) { + master_width = output_width; + master_height = output_height / master_count; + master_height_rem = output_height % master_count; + } else if (secondary_width > 0) { + master_width = 0; + secondary_width = output_width; + secondary_height = output_height / secondary_count; + secondary_height_rem = output_height % secondary_count; + } + + // Buffering the output makes things faster + var stdout_buf = std.io.bufferedOutStream(std.io.getStdOut().outStream()); + const stdout = stdout_buf.outStream(); + + var i: u32 = 0; + while (i < num_views) : (i += 1) { + var x: u32 = undefined; + var y: u32 = undefined; + var width: u32 = undefined; + var height: u32 = undefined; + + if (i < master_count) { + x = 0; + y = i * master_height + if (i > 0) master_height_rem else 0; + width = master_width; + height = master_height + if (i == 0) master_height_rem else 0; + } else { + x = master_width; + y = (i - master_count) * secondary_height + if (i > master_count) secondary_height_rem else 0; + width = secondary_width; + height = secondary_height + if (i == master_count) secondary_height_rem else 0; + } + + switch (master_location) { + .left => try stdout.print("{} {} {} {}\n", .{ x, y, width, height }), + .right => try stdout.print("{} {} {} {}\n", .{ output_width - x - width, y, width, height }), + .top => try stdout.print("{} {} {} {}\n", .{ y, x, height, width }), + .bottom => try stdout.print("{} {} {} {}\n", .{ y, output_width - x - width, height, width }), + } + } + + try stdout_buf.flush(); +}