Implement sending command from riverctl
These commands are successfully received by the server, but not yet executed.
This commit is contained in:
		
							
								
								
									
										84
									
								
								build.zig
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								build.zig
									
									
									
									
									
								
							@ -19,39 +19,53 @@ pub fn build(b: *std.build.Builder) !void {
 | 
			
		||||
 | 
			
		||||
    const scan_protocols = ScanProtocolsStep.create(b);
 | 
			
		||||
 | 
			
		||||
    const river = b.addExecutable("river", "src/river.zig");
 | 
			
		||||
    river.setTarget(target);
 | 
			
		||||
    river.setBuildMode(mode);
 | 
			
		||||
    river.addBuildOption(bool, "xwayland", xwayland);
 | 
			
		||||
    addServerDeps(river, &scan_protocols.step);
 | 
			
		||||
    river.install();
 | 
			
		||||
    {
 | 
			
		||||
        const river = b.addExecutable("river", "src/river.zig");
 | 
			
		||||
        river.setTarget(target);
 | 
			
		||||
        river.setBuildMode(mode);
 | 
			
		||||
        river.addBuildOption(bool, "xwayland", xwayland);
 | 
			
		||||
 | 
			
		||||
    const run_cmd = river.run();
 | 
			
		||||
    run_cmd.step.dependOn(b.getInstallStep());
 | 
			
		||||
        addProtocolDeps(river, &scan_protocols.step);
 | 
			
		||||
        addServerDeps(river);
 | 
			
		||||
 | 
			
		||||
    const run_step = b.step("run", "Run the compositor");
 | 
			
		||||
    run_step.dependOn(&run_cmd.step);
 | 
			
		||||
        river.install();
 | 
			
		||||
 | 
			
		||||
    const riverctl = b.addExecutable("riverctl", "src/riverctl.zig");
 | 
			
		||||
    riverctl.setTarget(target);
 | 
			
		||||
    riverctl.setBuildMode(mode);
 | 
			
		||||
    riverctl.install();
 | 
			
		||||
        const run_cmd = river.run();
 | 
			
		||||
        run_cmd.step.dependOn(b.getInstallStep());
 | 
			
		||||
 | 
			
		||||
    const river_test = b.addTest("src/test_main.zig");
 | 
			
		||||
    river_test.setTarget(target);
 | 
			
		||||
    river_test.setBuildMode(mode);
 | 
			
		||||
    river_test.addBuildOption(bool, "xwayland", xwayland);
 | 
			
		||||
    addServerDeps(river_test, &scan_protocols.step);
 | 
			
		||||
        const run_step = b.step("run", "Run the compositor");
 | 
			
		||||
        run_step.dependOn(&run_cmd.step);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const test_step = b.step("test", "Run the tests");
 | 
			
		||||
    test_step.dependOn(&river_test.step);
 | 
			
		||||
    {
 | 
			
		||||
        const riverctl = b.addExecutable("riverctl", "src/riverctl.zig");
 | 
			
		||||
        riverctl.setTarget(target);
 | 
			
		||||
        riverctl.setBuildMode(mode);
 | 
			
		||||
 | 
			
		||||
        addProtocolDeps(riverctl, &scan_protocols.step);
 | 
			
		||||
 | 
			
		||||
        riverctl.linkLibC();
 | 
			
		||||
 | 
			
		||||
        riverctl.linkSystemLibrary("wayland-client");
 | 
			
		||||
 | 
			
		||||
        riverctl.install();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        const river_test = b.addTest("src/test_main.zig");
 | 
			
		||||
        river_test.setTarget(target);
 | 
			
		||||
        river_test.setBuildMode(mode);
 | 
			
		||||
        river_test.addBuildOption(bool, "xwayland", xwayland);
 | 
			
		||||
 | 
			
		||||
        addProtocolDeps(river_test, &scan_protocols.step);
 | 
			
		||||
        addServerDeps(river_test);
 | 
			
		||||
 | 
			
		||||
        const test_step = b.step("test", "Run the tests");
 | 
			
		||||
        test_step.dependOn(&river_test.step);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn addServerDeps(exe: *std.build.LibExeObjStep, protocol_step: *std.build.Step) void {
 | 
			
		||||
    exe.step.dependOn(protocol_step);
 | 
			
		||||
    exe.addIncludeDir("protocol");
 | 
			
		||||
    exe.addCSourceFile("protocol/river-window-management-unstable-v1-protocol.c", &[_][]const u8{"-std=c99"});
 | 
			
		||||
 | 
			
		||||
fn addServerDeps(exe: *std.build.LibExeObjStep) void {
 | 
			
		||||
    exe.addCSourceFile("include/bindings.c", &[_][]const u8{"-std=c99"});
 | 
			
		||||
    exe.addIncludeDir(".");
 | 
			
		||||
 | 
			
		||||
@ -62,6 +76,12 @@ fn addServerDeps(exe: *std.build.LibExeObjStep, protocol_step: *std.build.Step)
 | 
			
		||||
    exe.linkSystemLibrary("xkbcommon");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn addProtocolDeps(exe: *std.build.LibExeObjStep, protocol_step: *std.build.Step) void {
 | 
			
		||||
    exe.step.dependOn(protocol_step);
 | 
			
		||||
    exe.addIncludeDir("protocol");
 | 
			
		||||
    exe.addCSourceFile("protocol/river-window-management-unstable-v1-protocol.c", &[_][]const u8{"-std=c99"});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ScanProtocolsStep = struct {
 | 
			
		||||
    builder: *std.build.Builder,
 | 
			
		||||
    step: std.build.Step,
 | 
			
		||||
@ -116,6 +136,18 @@ const ScanProtocolsStep = struct {
 | 
			
		||||
            _ = try self.builder.exec(
 | 
			
		||||
                &[_][]const u8{ "wayland-scanner", "private-code", xml_in_path, code_out_path },
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // We need the client header as well for river-window-management
 | 
			
		||||
            if (std.mem.eql(u8, basename_no_ext, "river-window-management-unstable-v1")) {
 | 
			
		||||
                const client_header_out_path = try std.mem.concat(
 | 
			
		||||
                    self.builder.allocator,
 | 
			
		||||
                    u8,
 | 
			
		||||
                    &[_][]const u8{ "protocol/", basename_no_ext, "-client-protocol.h" },
 | 
			
		||||
                );
 | 
			
		||||
                _ = try self.builder.exec(
 | 
			
		||||
                    &[_][]const u8{ "wayland-scanner", "client-header", xml_in_path, client_header_out_path },
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,8 @@
 | 
			
		||||
        A complete list of commands will be found in the man page.
 | 
			
		||||
        TODO: write the man page.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="command" type="string" summary="the command to run"/>
 | 
			
		||||
      <arg name="command" type="array" summary="the command to run as a series
 | 
			
		||||
        of null-terminated strings"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <enum name="error">
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,7 @@ wl_global: *c.wl_global,
 | 
			
		||||
listen_display_destroy: c.wl_listener,
 | 
			
		||||
 | 
			
		||||
pub fn init(self: *Self, server: *Server) !void {
 | 
			
		||||
    self.server = server;
 | 
			
		||||
    self.wl_global = c.wl_global_create(
 | 
			
		||||
        server.wl_display,
 | 
			
		||||
        &c.zriver_window_manager_v1_interface,
 | 
			
		||||
@ -72,6 +73,22 @@ fn resourceDestroy(wl_resource: ?*c.wl_resource) callconv(.C) void {
 | 
			
		||||
    // TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn runCommand(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource, command: ?[*:0]const u8) callconv(.C) void {
 | 
			
		||||
    Log.Debug.log("command: {}", .{command});
 | 
			
		||||
fn runCommand(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource, command: ?*c.wl_array) callconv(.C) void {
 | 
			
		||||
    const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), c.wl_resource_get_user_data(wl_resource)));
 | 
			
		||||
    const allocator = self.server.allocator;
 | 
			
		||||
 | 
			
		||||
    var args = std.ArrayList([]const u8).init(allocator);
 | 
			
		||||
 | 
			
		||||
    var i: usize = 0;
 | 
			
		||||
    const data = @ptrCast([*]const u8, command.?.data);
 | 
			
		||||
    while (i < command.?.size) {
 | 
			
		||||
        const slice = std.mem.spanZ(@ptrCast([*:0]const u8, &data[i]));
 | 
			
		||||
        args.append(std.mem.dupe(allocator, u8, slice) catch unreachable) catch unreachable;
 | 
			
		||||
 | 
			
		||||
        i += slice.len + 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (args.items) |x| {
 | 
			
		||||
        std.debug.warn("{}\n", .{x});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,9 +18,62 @@
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
 | 
			
		||||
const c = @cImport({
 | 
			
		||||
    @cInclude();
 | 
			
		||||
    @cInclude("wayland-client.h");
 | 
			
		||||
    @cInclude("river-window-management-unstable-v1-client-protocol.h");
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
pub fn main() void {
 | 
			
		||||
    std.debug.warn("hello world\n", .{});
 | 
			
		||||
const wl_registry_listener = c.wl_registry_listener{
 | 
			
		||||
    .global = handleGlobal,
 | 
			
		||||
    .global_remove = handleGlobalRemove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var river_window_manager: ?*c.zriver_window_manager_v1 = null;
 | 
			
		||||
 | 
			
		||||
pub fn main() !void {
 | 
			
		||||
    const wl_display = c.wl_display_connect(null) orelse return error.CantConnectToDisplay;
 | 
			
		||||
    const wl_registry = c.wl_display_get_registry(wl_display);
 | 
			
		||||
 | 
			
		||||
    _ = c.wl_registry_add_listener(wl_registry, &wl_registry_listener, null);
 | 
			
		||||
    if (c.wl_display_roundtrip(wl_display) == -1) return error.RoundtripFailed;
 | 
			
		||||
 | 
			
		||||
    const wm = river_window_manager orelse return error.RiverWMNotAdvertised;
 | 
			
		||||
 | 
			
		||||
    var command: c.wl_array = undefined;
 | 
			
		||||
    c.wl_array_init(&command);
 | 
			
		||||
    var it = std.process.args();
 | 
			
		||||
    // Skip our name
 | 
			
		||||
    _ = it.nextPosix();
 | 
			
		||||
    while (it.nextPosix()) |arg| {
 | 
			
		||||
        // Add one as we need to copy the null terminators as well
 | 
			
		||||
        var ptr = @ptrCast([*]u8, c.wl_array_add(&command, arg.len + 1) orelse
 | 
			
		||||
            return error.OutOfMemory);
 | 
			
		||||
        for (arg) |ch, i| ptr[i] = ch;
 | 
			
		||||
        ptr[arg.len] = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c.zriver_window_manager_v1_run_command(wm, &command);
 | 
			
		||||
    if (c.wl_display_roundtrip(wl_display) == -1) return error.RoundtripFailed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn handleGlobal(
 | 
			
		||||
    data: ?*c_void,
 | 
			
		||||
    wl_registry: ?*c.wl_registry,
 | 
			
		||||
    name: u32,
 | 
			
		||||
    interface: ?[*:0]const u8,
 | 
			
		||||
    version: u32,
 | 
			
		||||
) callconv(.C) void {
 | 
			
		||||
    // We only care about the river_window_manager global
 | 
			
		||||
    if (std.mem.eql(
 | 
			
		||||
        u8,
 | 
			
		||||
        std.mem.spanZ(interface.?),
 | 
			
		||||
        std.mem.spanZ(@ptrCast([*:0]const u8, c.zriver_window_manager_v1_interface.name.?)),
 | 
			
		||||
    )) {
 | 
			
		||||
        river_window_manager = @ptrCast(
 | 
			
		||||
            *c.zriver_window_manager_v1,
 | 
			
		||||
            c.wl_registry_bind(wl_registry, name, &c.zriver_window_manager_v1_interface, 1),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Ignore the event
 | 
			
		||||
fn handleGlobalRemove(data: ?*c_void, wl_registry: ?*c.wl_registry, name: u32) callconv(.C) void {}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user