// This file is part of river, a dynamic tiling wayland compositor. // // Copyright 2020 The River Developers // // 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 { const args = std.os.argv; if (args.len != 7) printUsageAndExit(); // first arg must be left, right, top, or bottom const master_location = std.meta.stringToEnum(Orientation, std.mem.spanZ(args[1])) orelse printUsageAndExit(); // the other 5 are passed by river and described in river-layouts(7) const num_views = try std.fmt.parseInt(u32, std.mem.spanZ(args[2]), 10); const master_count = try std.fmt.parseInt(u32, std.mem.spanZ(args[3]), 10); const master_factor = try std.fmt.parseFloat(f64, std.mem.spanZ(args[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(args[width_arg]), 10); const output_height = try std.fmt.parseInt(u32, std.mem.spanZ(args[height_arg]), 10); const secondary_count = if (num_views > master_count) num_views - master_count else 0; // 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(); } fn printUsageAndExit() noreturn { const usage: []const u8 = \\Usage: rivertile left|right|top|bottom [args passed by river] \\ ; std.debug.warn(usage, .{}); std.os.exit(1); }