mirror of
https://github.com/MezzalunaWM/Whetstone.git
synced 2026-03-07 19:49:53 -05:00
initial commit
This commit is contained in:
commit
86177a190e
9 changed files with 420 additions and 0 deletions
94
src/main.zig
Normal file
94
src/main.zig
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
const std = @import("std");
|
||||
const argsParser = @import("args");
|
||||
|
||||
const util = @import("util.zig");
|
||||
const Remote = @import("remote.zig");
|
||||
|
||||
const gpa = std.heap.c_allocator;
|
||||
|
||||
var remote: Remote = undefined;
|
||||
|
||||
fn loop(input: bool) !void {
|
||||
var pollfds: [2]std.posix.pollfd = undefined;
|
||||
|
||||
pollfds[0] = .{ // wayland fd
|
||||
.fd = remote.display.getFd(),
|
||||
.events = std.posix.POLL.IN,
|
||||
.revents = 0,
|
||||
};
|
||||
if (input) {
|
||||
pollfds[1] = .{ // stdin
|
||||
.fd = std.posix.STDIN_FILENO,
|
||||
.events = std.posix.POLL.IN,
|
||||
.revents = 0,
|
||||
};
|
||||
}
|
||||
|
||||
var buf: [2]u8 = undefined;
|
||||
var stdout_writer = std.fs.File.stdout().writer(&buf);
|
||||
const stdout = &stdout_writer.interface;
|
||||
while (true) {
|
||||
if (input) {
|
||||
try stdout.print("> ", .{});
|
||||
try stdout.flush();
|
||||
}
|
||||
|
||||
_ = std.posix.poll(&pollfds, -1) catch |err| {
|
||||
util.fatal("poll() failed: {s}", .{@errorName(err)});
|
||||
};
|
||||
|
||||
for (pollfds) |fd| {
|
||||
if (fd.revents & std.posix.POLL.IN == 1) {
|
||||
if (fd.fd == std.posix.STDIN_FILENO) {
|
||||
var in_buf: [1024]u8 = undefined;
|
||||
const len = std.posix.read(fd.fd, &in_buf) catch 0;
|
||||
|
||||
if (len == 0) {
|
||||
try stdout.print("\n", .{});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_buf[len - 1] == '\n') in_buf[len - 1] = 0 else in_buf[len] = 0;
|
||||
if (remote.remote_lua) |rl| rl.pushLua(@ptrCast(in_buf[0..len].ptr));
|
||||
}
|
||||
|
||||
// FIXME: we really shouldn't be reading from the socket
|
||||
if (fd.fd == remote.display.getFd()) {
|
||||
var in_buf: [1024]u8 = undefined;
|
||||
const len = std.posix.read(fd.fd, &in_buf) catch 0;
|
||||
std.debug.print("\n{s}", .{in_buf[0..len]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try remote.flush();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
const options = argsParser.parseForCurrentProcess(struct {
|
||||
// long options
|
||||
code: ?[]const u8 = null,
|
||||
@"follow-log": bool = false,
|
||||
|
||||
// short-hand options
|
||||
pub const shorthands = .{
|
||||
.c = "code",
|
||||
.f = "follow-log",
|
||||
};
|
||||
}, gpa, .print) catch return;
|
||||
defer options.deinit();
|
||||
|
||||
// connect to the compositor
|
||||
remote = Remote.init();
|
||||
defer remote.deinit();
|
||||
|
||||
// handle options
|
||||
if (options.options.code) |c| {
|
||||
remote.remote_lua.?.pushLua(@ptrCast(c[0..].ptr));
|
||||
} else if (options.options.@"follow-log") {
|
||||
try loop(false);
|
||||
} else {
|
||||
try loop(true);
|
||||
}
|
||||
}
|
||||
121
src/remote.zig
Normal file
121
src/remote.zig
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
const Remote = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const posix = std.posix;
|
||||
const wayland = @import("wayland");
|
||||
const wl = wayland.client.wl;
|
||||
const mez = wayland.client.zmez;
|
||||
|
||||
const util = @import("util.zig");
|
||||
|
||||
display: *wl.Display,
|
||||
registry: *wl.Registry,
|
||||
compositor: ?*wl.Compositor,
|
||||
remote_lua_manager: ?*mez.RemoteLuaManagerV1,
|
||||
remote_lua: ?*mez.RemoteLuaV1,
|
||||
|
||||
pub fn init() Remote {
|
||||
var self: Remote = .{
|
||||
.registry = undefined,
|
||||
.compositor = null,
|
||||
.remote_lua = null,
|
||||
.remote_lua_manager = null,
|
||||
.display = wl.Display.connect(null) catch |err| {
|
||||
util.fatal("failed to connect to a wayland compositor: {s}", .{@errorName(err)});
|
||||
},
|
||||
};
|
||||
|
||||
self.registry = self.display.getRegistry() catch unreachable;
|
||||
errdefer self.registry.destroy();
|
||||
self.registry.setListener(*Remote, registry_listener, &self);
|
||||
|
||||
const errno = self.display.roundtrip();
|
||||
if (errno != .SUCCESS) {
|
||||
util.fatal("initial roundtrip failed: {s}", .{@tagName(errno)});
|
||||
}
|
||||
|
||||
if (self.compositor == null) util.not_advertised(wl.Compositor);
|
||||
if (self.remote_lua_manager == null) util.not_advertised(mez.RemoteLuaManagerV1);
|
||||
|
||||
self.remote_lua = self.remote_lua_manager.?.getRemote() catch util.oom();
|
||||
if (self.remote_lua) |rl| {
|
||||
std.log.info("yayayy", .{});
|
||||
rl.setListener(?*anyopaque, handleRemote, null);
|
||||
} else {
|
||||
std.log.err("no luck", .{});
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn flush(self: *Remote) !void {
|
||||
while (true) {
|
||||
while (!self.display.prepareRead()) {
|
||||
const errno = self.display.dispatchPending();
|
||||
if (errno != .SUCCESS) {
|
||||
util.fatal("failed to dispatch pending wayland events: E{s}", .{@tagName(errno)});
|
||||
}
|
||||
}
|
||||
|
||||
const errno = self.display.flush();
|
||||
switch (errno) {
|
||||
.SUCCESS => return,
|
||||
.PIPE => {
|
||||
// libwayland uses this error to indicate that the wayland server
|
||||
// closed its side of the wayland socket. We want to continue to
|
||||
// read any buffered messages from the server though as there is
|
||||
// likely a protocol error message we'd like libwayland to log.
|
||||
_ = self.display.readEvents();
|
||||
util.fatal("connection to wayland server unexpectedly terminated", .{});
|
||||
},
|
||||
else => {
|
||||
util.fatal("failed to flush wayland requests: E{s}", .{@tagName(errno)});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Remote) void {
|
||||
self.registry.destroy();
|
||||
}
|
||||
|
||||
fn registry_listener(
|
||||
registry: *wl.Registry,
|
||||
event: wl.Registry.Event,
|
||||
remote: *Remote,
|
||||
) void {
|
||||
registry_event(registry, event, remote) catch |err| switch (err) {
|
||||
error.OutOfMemory => util.oom(),
|
||||
};
|
||||
}
|
||||
|
||||
fn registry_event(registry: *wl.Registry, event: wl.Registry.Event, remote: *Remote) !void {
|
||||
switch (event) {
|
||||
.global => |ev| {
|
||||
if (std.mem.orderZ(u8, ev.interface, wl.Compositor.interface.name) == .eq) {
|
||||
const ver = 1;
|
||||
if (ev.version < 1) {
|
||||
util.fatal("advertised wl_compositor version too old, version {} required", .{ver});
|
||||
}
|
||||
remote.compositor = try registry.bind(ev.name, wl.Compositor, ver);
|
||||
} else if (std.mem.orderZ(u8, ev.interface, mez.RemoteLuaManagerV1.interface.name) == .eq) {
|
||||
const ver = 1;
|
||||
if (ev.version < ver) {
|
||||
util.fatal("advertised remote_lua_manager version too old, version {} required", .{ver});
|
||||
}
|
||||
remote.remote_lua_manager = try registry.bind(ev.name, mez.RemoteLuaManagerV1, ver);
|
||||
}
|
||||
},
|
||||
.global_remove => {},
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: this doesn't actually handle events for some reason and we currently
|
||||
// just read from the socket directly
|
||||
fn handleRemote(_: *mez.RemoteLuaV1, event: mez.RemoteLuaV1.Event, _: ?*anyopaque) void {
|
||||
switch (event) {
|
||||
.new_log_entry => |e| {
|
||||
std.log.info("{s}", .{e.text});
|
||||
},
|
||||
}
|
||||
}
|
||||
14
src/util.zig
Normal file
14
src/util.zig
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn fatal(comptime str: []const u8, opts: anytype) noreturn {
|
||||
std.log.err(str, opts);
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
pub fn oom() noreturn {
|
||||
fatal("out of memory", .{});
|
||||
}
|
||||
|
||||
pub fn not_advertised(comptime Global: type) noreturn {
|
||||
fatal("{s} not advertised", .{Global.interface.name});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue