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 scan_protocols = ScanProtocolsStep.create(b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const river = b.addExecutable("river", "src/river.zig");
 | 
					    {
 | 
				
			||||||
    river.setTarget(target);
 | 
					        const river = b.addExecutable("river", "src/river.zig");
 | 
				
			||||||
    river.setBuildMode(mode);
 | 
					        river.setTarget(target);
 | 
				
			||||||
    river.addBuildOption(bool, "xwayland", xwayland);
 | 
					        river.setBuildMode(mode);
 | 
				
			||||||
    addServerDeps(river, &scan_protocols.step);
 | 
					        river.addBuildOption(bool, "xwayland", xwayland);
 | 
				
			||||||
    river.install();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const run_cmd = river.run();
 | 
					        addProtocolDeps(river, &scan_protocols.step);
 | 
				
			||||||
    run_cmd.step.dependOn(b.getInstallStep());
 | 
					        addServerDeps(river);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const run_step = b.step("run", "Run the compositor");
 | 
					        river.install();
 | 
				
			||||||
    run_step.dependOn(&run_cmd.step);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const riverctl = b.addExecutable("riverctl", "src/riverctl.zig");
 | 
					        const run_cmd = river.run();
 | 
				
			||||||
    riverctl.setTarget(target);
 | 
					        run_cmd.step.dependOn(b.getInstallStep());
 | 
				
			||||||
    riverctl.setBuildMode(mode);
 | 
					 | 
				
			||||||
    riverctl.install();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const river_test = b.addTest("src/test_main.zig");
 | 
					        const run_step = b.step("run", "Run the compositor");
 | 
				
			||||||
    river_test.setTarget(target);
 | 
					        run_step.dependOn(&run_cmd.step);
 | 
				
			||||||
    river_test.setBuildMode(mode);
 | 
					    }
 | 
				
			||||||
    river_test.addBuildOption(bool, "xwayland", xwayland);
 | 
					 | 
				
			||||||
    addServerDeps(river_test, &scan_protocols.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 {
 | 
					fn addServerDeps(exe: *std.build.LibExeObjStep) void {
 | 
				
			||||||
    exe.step.dependOn(protocol_step);
 | 
					 | 
				
			||||||
    exe.addIncludeDir("protocol");
 | 
					 | 
				
			||||||
    exe.addCSourceFile("protocol/river-window-management-unstable-v1-protocol.c", &[_][]const u8{"-std=c99"});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    exe.addCSourceFile("include/bindings.c", &[_][]const u8{"-std=c99"});
 | 
					    exe.addCSourceFile("include/bindings.c", &[_][]const u8{"-std=c99"});
 | 
				
			||||||
    exe.addIncludeDir(".");
 | 
					    exe.addIncludeDir(".");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -62,6 +76,12 @@ fn addServerDeps(exe: *std.build.LibExeObjStep, protocol_step: *std.build.Step)
 | 
				
			|||||||
    exe.linkSystemLibrary("xkbcommon");
 | 
					    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 {
 | 
					const ScanProtocolsStep = struct {
 | 
				
			||||||
    builder: *std.build.Builder,
 | 
					    builder: *std.build.Builder,
 | 
				
			||||||
    step: std.build.Step,
 | 
					    step: std.build.Step,
 | 
				
			||||||
@ -116,6 +136,18 @@ const ScanProtocolsStep = struct {
 | 
				
			|||||||
            _ = try self.builder.exec(
 | 
					            _ = try self.builder.exec(
 | 
				
			||||||
                &[_][]const u8{ "wayland-scanner", "private-code", xml_in_path, code_out_path },
 | 
					                &[_][]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.
 | 
					        A complete list of commands will be found in the man page.
 | 
				
			||||||
        TODO: write the man page.
 | 
					        TODO: write the man page.
 | 
				
			||||||
      </description>
 | 
					      </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>
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <enum name="error">
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ wl_global: *c.wl_global,
 | 
				
			|||||||
listen_display_destroy: c.wl_listener,
 | 
					listen_display_destroy: c.wl_listener,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn init(self: *Self, server: *Server) !void {
 | 
					pub fn init(self: *Self, server: *Server) !void {
 | 
				
			||||||
 | 
					    self.server = server;
 | 
				
			||||||
    self.wl_global = c.wl_global_create(
 | 
					    self.wl_global = c.wl_global_create(
 | 
				
			||||||
        server.wl_display,
 | 
					        server.wl_display,
 | 
				
			||||||
        &c.zriver_window_manager_v1_interface,
 | 
					        &c.zriver_window_manager_v1_interface,
 | 
				
			||||||
@ -72,6 +73,22 @@ fn resourceDestroy(wl_resource: ?*c.wl_resource) callconv(.C) void {
 | 
				
			|||||||
    // TODO
 | 
					    // TODO
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn runCommand(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource, command: ?[*:0]const u8) callconv(.C) void {
 | 
					fn runCommand(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource, command: ?*c.wl_array) callconv(.C) void {
 | 
				
			||||||
    Log.Debug.log("command: {}", .{command});
 | 
					    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 std = @import("std");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const c = @cImport({
 | 
					const c = @cImport({
 | 
				
			||||||
    @cInclude();
 | 
					    @cInclude("wayland-client.h");
 | 
				
			||||||
 | 
					    @cInclude("river-window-management-unstable-v1-client-protocol.h");
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn main() void {
 | 
					const wl_registry_listener = c.wl_registry_listener{
 | 
				
			||||||
    std.debug.warn("hello world\n", .{});
 | 
					    .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