added commandline options
This commit is contained in:
parent
6742491be6
commit
855577e9dd
81
box.zig
81
box.zig
|
@ -199,6 +199,41 @@ pub const Box = struct {
|
||||||
pub fn size(self: *Self) usize {
|
pub fn size(self: *Self) usize {
|
||||||
return self.extents.size();
|
return self.extents.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parseFromStr(str: [:0]const u8) !struct {
|
||||||
|
box: Box,
|
||||||
|
label: ?[]u8,
|
||||||
|
|
||||||
|
pub fn destroy(self: @This()) void {
|
||||||
|
if (self.label) |label| {
|
||||||
|
std.c.free(label.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
var box: Box = undefined;
|
||||||
|
var label: ?[*] u8 = null;
|
||||||
|
|
||||||
|
const Stdio = @cImport({@cInclude("stdio.h");@cInclude("string.h");});
|
||||||
|
if (Stdio.sscanf(
|
||||||
|
str.ptr,
|
||||||
|
"%d,%d %dx%d %m[^\n]",
|
||||||
|
&box.position.x,
|
||||||
|
&box.position.y,
|
||||||
|
&box.extents.width,
|
||||||
|
&box.extents.height,
|
||||||
|
&label,
|
||||||
|
) < 4) {
|
||||||
|
return error.ScanFFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lbl = if (label == null) null else
|
||||||
|
label.?[0..Stdio.strlen(label)];
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.box = box,
|
||||||
|
.label = lbl,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Boxes = struct {
|
pub const Boxes = struct {
|
||||||
|
@ -244,11 +279,11 @@ pub const Boxes = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: Self) void {
|
||||||
self.boxes.deinit();
|
self.boxes.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(self: *Self) Iterator {
|
pub fn iter(self: *const Self) Iterator {
|
||||||
return .{
|
return .{
|
||||||
.items = self.boxes.items,
|
.items = self.boxes.items,
|
||||||
};
|
};
|
||||||
|
@ -339,7 +374,49 @@ test "boxes" {
|
||||||
try boxes.boxes.append(a4);
|
try boxes.boxes.append(a4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "parse box" {
|
||||||
|
std.testing.refAllDecls(Box);
|
||||||
|
|
||||||
|
{
|
||||||
|
const expected = Box{
|
||||||
|
.position = .{.x = 10, .y = 10,},
|
||||||
|
.extents = .{.width = 100, .height = 100,},
|
||||||
|
};
|
||||||
|
|
||||||
|
const box = try Box.parseFromStr("10,10 100x100 cool_box");
|
||||||
|
defer box.destroy();
|
||||||
|
std.debug.assert(box.box.eq(expected));
|
||||||
|
std.debug.assert(std.mem.eql(u8, box.label.?, "cool_box"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const expected = Box{
|
||||||
|
.position = .{.x = 10, .y = -10,},
|
||||||
|
.extents = .{.width = 100, .height = 100,},
|
||||||
|
};
|
||||||
|
|
||||||
|
const box = try Box.parseFromStr("10,-10 100x100 cool_\nbox");
|
||||||
|
defer box.destroy();
|
||||||
|
std.debug.assert(box.box.eq(expected));
|
||||||
|
std.debug.assert(std.mem.eql(u8, box.label.?, "cool_"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const expected = Box{
|
||||||
|
.position = .{.x = 10, .y = 10,},
|
||||||
|
.extents = .{.width = 100, .height = 100,},
|
||||||
|
};
|
||||||
|
|
||||||
|
const box = try Box.parseFromStr("10,10 100x100 \n");
|
||||||
|
defer box.destroy();
|
||||||
|
std.debug.assert(box.box.eq(expected));
|
||||||
|
std.debug.assert(box.label == null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "box" {
|
test "box" {
|
||||||
|
std.testing.refAllDecls(Box);
|
||||||
|
|
||||||
const a = Box.default();
|
const a = Box.default();
|
||||||
const a2 = Box{.extents = .{.width = 1, .height = 1,}};
|
const a2 = Box{.extents = .{.width = 1, .height = 1,}};
|
||||||
const b = Box.default();
|
const b = Box.default();
|
||||||
|
|
10
build.zig
10
build.zig
|
@ -72,6 +72,16 @@ pub fn build(b: *std.build.Builder) void {
|
||||||
exe_tests.setBuildMode(mode);
|
exe_tests.setBuildMode(mode);
|
||||||
exe_tests.linkLibC();
|
exe_tests.linkLibC();
|
||||||
|
|
||||||
|
exe_tests.step.dependOn(&scanner.step);
|
||||||
|
exe_tests.addPackage(wayland);
|
||||||
|
exe_tests.addPackage(zig_args);
|
||||||
|
|
||||||
|
exe_tests.linkSystemLibrary("wayland-client");
|
||||||
|
exe_tests.linkSystemLibrary("xkbcommon");
|
||||||
|
exe_tests.linkSystemLibrary("cairo");
|
||||||
|
|
||||||
|
scanner.addCSource(exe_tests);
|
||||||
|
|
||||||
const test_step = b.step("test", "Run unit tests");
|
const test_step = b.step("test", "Run unit tests");
|
||||||
test_step.dependOn(&exe_tests.step);
|
test_step.dependOn(&exe_tests.step);
|
||||||
}
|
}
|
||||||
|
|
188
main.zig
188
main.zig
|
@ -10,6 +10,7 @@ const list = wayland.server.wl.list;
|
||||||
const Utils = @import("box.zig");
|
const Utils = @import("box.zig");
|
||||||
const Point = Utils.Point;
|
const Point = Utils.Point;
|
||||||
const Box = Utils.Box;
|
const Box = Utils.Box;
|
||||||
|
const Boxes = Utils.Boxes;
|
||||||
const Size = Utils.Size;
|
const Size = Utils.Size;
|
||||||
const Selection = Utils.Selection;
|
const Selection = Utils.Selection;
|
||||||
|
|
||||||
|
@ -222,49 +223,6 @@ fn ListItem(comptime T: type) type {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Options = struct {
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
help: bool = false,
|
|
||||||
@"display-dimensions": bool = false,
|
|
||||||
background: ?u32 = null,
|
|
||||||
border: ?u32 = null,
|
|
||||||
selection: ?u32 = null,
|
|
||||||
choice: ?u32 = null,
|
|
||||||
format: ?[]const u8 = null,
|
|
||||||
@"font-family": ?[]const u8 = null,
|
|
||||||
@"border-weight": ?u32 = null,
|
|
||||||
@"single-point": bool = false,
|
|
||||||
@"output-boxes": bool = false,
|
|
||||||
@"restrict-selection": bool = false,
|
|
||||||
// TODO: parse this in the format of W:H instead of a fraction
|
|
||||||
@"aspect-ratio": ?f64 = null,
|
|
||||||
|
|
||||||
pub const shorthands = .{
|
|
||||||
.h = "help",
|
|
||||||
.b = "background",
|
|
||||||
.c = "border",
|
|
||||||
.s = "selection",
|
|
||||||
.B = "choice",
|
|
||||||
.f = "format",
|
|
||||||
.F = "font-family",
|
|
||||||
.w = "border-weight",
|
|
||||||
.p = "single-point",
|
|
||||||
.o = "output-boxes",
|
|
||||||
.r = "restrict-selection",
|
|
||||||
.a = "aspect-ratio",
|
|
||||||
};
|
|
||||||
|
|
||||||
const usage = @embedFile("usage");
|
|
||||||
|
|
||||||
fn parse() !zig_args.ParseArgsResult(Self, null) {
|
|
||||||
const self = try zig_args.parseForCurrentProcess(Self, std.heap.page_allocator, .print);
|
|
||||||
// TODO: print help
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Output = struct {
|
const Output = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
@ -343,10 +301,29 @@ const Output = struct {
|
||||||
|
|
||||||
fn render(self: *Self, buffer: *Buffer) void {
|
fn render(self: *Self, buffer: *Buffer) void {
|
||||||
const cairo = &buffer.cairo;
|
const cairo = &buffer.cairo;
|
||||||
|
const opts = self.state.getOptions();
|
||||||
|
|
||||||
|
// clear screen
|
||||||
Cairo.cairo_set_operator(cairo.ctx, Cairo.CAIRO_OPERATOR_SOURCE);
|
Cairo.cairo_set_operator(cairo.ctx, Cairo.CAIRO_OPERATOR_SOURCE);
|
||||||
setSourceU32(cairo.ctx, 0xFFFFFF40);
|
setSourceU32(cairo.ctx, opts.background);
|
||||||
Cairo.cairo_paint(cairo.ctx);
|
Cairo.cairo_paint(cairo.ctx);
|
||||||
|
|
||||||
|
// draw in_boxes
|
||||||
|
if (self.state.config.in_boxes) |boxes| {
|
||||||
|
std.debug.print("in_boxes: {}\n", .{boxes});
|
||||||
|
var iter = boxes.iter();
|
||||||
|
while (iter.next()) |box| {
|
||||||
|
if (box.intersects(&self.logical_geometry)) {
|
||||||
|
const corrected_box = box.translated(self.logical_geometry.position.inverted());
|
||||||
|
|
||||||
|
drawRect(buffer, corrected_box, opts.choice);
|
||||||
|
Cairo.cairo_fill(cairo.ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// draw selection for each seat
|
||||||
var seat_iter = self.state.seats.iterator(.forward);
|
var seat_iter = self.state.seats.iterator(.forward);
|
||||||
while (seat_iter.next()) |link| {
|
while (seat_iter.next()) |link| {
|
||||||
const seat = link.get();
|
const seat = link.get();
|
||||||
|
@ -359,11 +336,11 @@ const Output = struct {
|
||||||
const corrected_box = box.translated(self.logical_geometry.position.inverted());
|
const corrected_box = box.translated(self.logical_geometry.position.inverted());
|
||||||
std.debug.print("selection: {}\n", .{corrected_box});
|
std.debug.print("selection: {}\n", .{corrected_box});
|
||||||
|
|
||||||
drawRect(buffer, corrected_box, 0x0);
|
drawRect(buffer, corrected_box, opts.selection);
|
||||||
Cairo.cairo_fill(cairo.ctx);
|
Cairo.cairo_fill(cairo.ctx);
|
||||||
|
|
||||||
Cairo.cairo_set_line_width(cairo.ctx, 2.0);
|
Cairo.cairo_set_line_width(cairo.ctx, @intToFloat(f64, opts.@"border-weight"));
|
||||||
drawRect(buffer, corrected_box, 0x000000FF);
|
drawRect(buffer, corrected_box, opts.border);
|
||||||
Cairo.cairo_stroke(cairo.ctx);
|
Cairo.cairo_stroke(cairo.ctx);
|
||||||
|
|
||||||
// TODO: draw dimensions
|
// TODO: draw dimensions
|
||||||
|
@ -897,8 +874,7 @@ const State = struct {
|
||||||
seats: *ListItem(Seat).Head() = undefined,
|
seats: *ListItem(Seat).Head() = undefined,
|
||||||
outputs: *ListItem(Output).Head() = undefined,
|
outputs: *ListItem(Output).Head() = undefined,
|
||||||
|
|
||||||
fn create() !*Self {
|
fn create(ally: std.mem.Allocator) !*Self {
|
||||||
const ally = std.heap.c_allocator;
|
|
||||||
|
|
||||||
const dpy = try wl.Display.connect(null);
|
const dpy = try wl.Display.connect(null);
|
||||||
const registry = try dpy.getRegistry();
|
const registry = try dpy.getRegistry();
|
||||||
|
@ -1020,7 +996,7 @@ const State = struct {
|
||||||
const Init = struct {
|
const Init = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
ally: std.mem.Allocator = std.heap.c_allocator,
|
ally: std.mem.Allocator = undefined,
|
||||||
|
|
||||||
running: bool = true,
|
running: bool = true,
|
||||||
|
|
||||||
|
@ -1042,6 +1018,8 @@ const State = struct {
|
||||||
seats: *ListItem(Seat).Head() = undefined,
|
seats: *ListItem(Seat).Head() = undefined,
|
||||||
outputs: *ListItem(Output).Head() = undefined,
|
outputs: *ListItem(Output).Head() = undefined,
|
||||||
|
|
||||||
|
config: Input = undefined,
|
||||||
|
|
||||||
fn init(self: *Self, uninit: *Uninit) !void {
|
fn init(self: *Self, uninit: *Uninit) !void {
|
||||||
const xkb_context = xkb.xkb_context_new(xkb.XKB_CONTEXT_NO_FLAGS) orelse
|
const xkb_context = xkb.xkb_context_new(xkb.XKB_CONTEXT_NO_FLAGS) orelse
|
||||||
return error.NoXkbContext;
|
return error.NoXkbContext;
|
||||||
|
@ -1076,6 +1054,8 @@ const State = struct {
|
||||||
|
|
||||||
.seats = uninit.seats,
|
.seats = uninit.seats,
|
||||||
.outputs = uninit.outputs,
|
.outputs = uninit.outputs,
|
||||||
|
|
||||||
|
.config = try Input.init(uninit.ally),
|
||||||
};
|
};
|
||||||
|
|
||||||
// i hope this is fine but appears to be requried to reset the listener on the registry
|
// i hope this is fine but appears to be requried to reset the listener on the registry
|
||||||
|
@ -1110,6 +1090,10 @@ const State = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn getOptions(self: *Self) *Args {
|
||||||
|
return &self.config.args.options;
|
||||||
|
}
|
||||||
|
|
||||||
fn stuff(self: *Self) !void {
|
fn stuff(self: *Self) !void {
|
||||||
while (self.running) {
|
while (self.running) {
|
||||||
if (self.dpy.dispatch() != .SUCCESS) return error.DispatchFailed;
|
if (self.dpy.dispatch() != .SUCCESS) return error.DispatchFailed;
|
||||||
|
@ -1165,18 +1149,118 @@ const State = struct {
|
||||||
self.registry.destroy();
|
self.registry.destroy();
|
||||||
self.ally.destroy(self.registry_listener);
|
self.ally.destroy(self.registry_listener);
|
||||||
|
|
||||||
|
self.config.deinit();
|
||||||
|
|
||||||
self.ally.free(self.cursor_theme);
|
self.ally.free(self.cursor_theme);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() !void {
|
const Args = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
help: bool = false,
|
||||||
|
@"display-dimensions": bool = false,
|
||||||
|
background: u32 = 0xFFFFFF40,
|
||||||
|
border: u32 = 0x000000FF,
|
||||||
|
selection: u32 = 0x00000000,
|
||||||
|
choice: u32 = 0xFFFFFF40,
|
||||||
|
format: ?[]const u8 = null,
|
||||||
|
@"font-family": ?[]const u8 = null,
|
||||||
|
@"border-weight": u32 = 2,
|
||||||
|
@"single-point": bool = false,
|
||||||
|
@"output-boxes": bool = false,
|
||||||
|
@"restrict-selection": bool = false,
|
||||||
|
// TODO: parse this in the format of W:H instead of a fraction
|
||||||
|
@"aspect-ratio": ?f64 = null,
|
||||||
|
|
||||||
|
pub const shorthands = .{
|
||||||
|
.h = "help",
|
||||||
|
.b = "background",
|
||||||
|
.c = "border",
|
||||||
|
.s = "selection",
|
||||||
|
.B = "choice",
|
||||||
|
.f = "format",
|
||||||
|
.F = "font-family",
|
||||||
|
.w = "border-weight",
|
||||||
|
.p = "single-point",
|
||||||
|
.o = "output-boxes",
|
||||||
|
.r = "restrict-selection",
|
||||||
|
.a = "aspect-ratio",
|
||||||
|
};
|
||||||
|
|
||||||
|
const usage = @embedFile("usage");
|
||||||
|
|
||||||
|
const ResultType = zig_args.ParseArgsResult(Self, null);
|
||||||
|
|
||||||
|
fn parse(ally: std.mem.Allocator) !ResultType {
|
||||||
|
const self = try zig_args.parseForCurrentProcess(Self, ally, .print);
|
||||||
|
// TODO: print help
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Input = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
args: Args.ResultType,
|
||||||
|
in_boxes: ?Boxes = null,
|
||||||
|
|
||||||
|
fn init(ally: std.mem.Allocator) !Self {
|
||||||
|
const args = try Args.parse(ally);
|
||||||
|
const in_boxes = try readInBoxes(ally);
|
||||||
|
|
||||||
|
return Self {
|
||||||
|
.in_boxes = in_boxes,
|
||||||
|
.args = args,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: Self) void {
|
||||||
|
self.args.deinit();
|
||||||
|
if (self.in_boxes) |boxes| {
|
||||||
|
boxes.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readInBoxes(alloc: std.mem.Allocator) !?Boxes {
|
||||||
|
var buf = [_]u8{0} ** 256;
|
||||||
|
if (!std.io.getStdIn().isTty()) {
|
||||||
|
var in_boxes = Boxes.init(alloc);
|
||||||
|
errdefer in_boxes.deinit();
|
||||||
|
|
||||||
|
var reader = std.io.getStdIn().reader();
|
||||||
|
while (try reader.readUntilDelimiterOrEof(&buf, '\n')) |line| {
|
||||||
|
if (line.len == 0) continue;
|
||||||
|
|
||||||
|
buf[line.len + 1] = 0;
|
||||||
|
const sentineld = buf[0..line.len + 1:0];
|
||||||
|
|
||||||
|
const result = try Box.parseFromStr(sentineld);
|
||||||
|
defer result.destroy();
|
||||||
|
|
||||||
|
try in_boxes.boxes.append(result.box);
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_boxes;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn run(ally: std.mem.Allocator) !void {
|
||||||
// Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
|
// Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
|
||||||
std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
|
std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
|
||||||
|
|
||||||
const state = try State.Uninit.create();
|
const state = try State.Uninit.create(ally);
|
||||||
const init = try state.intoInit();
|
const init = try state.intoInit();
|
||||||
defer init.deinit();
|
defer init.deinit();
|
||||||
|
|
||||||
try init.stuff();
|
try init.stuff();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
try run(std.heap.c_allocator);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue