Add callback to command request for error handling
This commit is contained in:
		@ -29,12 +29,10 @@
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="command" type="array" summary="the command to run as a series
 | 
			
		||||
        of null-terminated strings"/>
 | 
			
		||||
      <arg name="callback" type="new_id" interface="zriver_command_callback_v1"
 | 
			
		||||
        summary="callback object to recieve success/error events"/>
 | 
			
		||||
    </request>
 | 
			
		||||
 | 
			
		||||
    <enum name="error">
 | 
			
		||||
      <entry name="invalid_command" value="0" summary="the command is invalid"/>
 | 
			
		||||
    </enum>
 | 
			
		||||
 | 
			
		||||
    <event name="focus">
 | 
			
		||||
      <description summary="sent when a view gains focus">
 | 
			
		||||
      </description>
 | 
			
		||||
@ -56,4 +54,27 @@
 | 
			
		||||
        summary="the current tags of each view on the output"/>
 | 
			
		||||
    </event>
 | 
			
		||||
  </interface>
 | 
			
		||||
 | 
			
		||||
  <interface name="zriver_command_callback_v1" version="1">
 | 
			
		||||
    <description summary="callback object">
 | 
			
		||||
      Exactly one of the success or failure events will be sent.
 | 
			
		||||
    </description>
 | 
			
		||||
 | 
			
		||||
    <event name="success">
 | 
			
		||||
      <description summary="command successful">
 | 
			
		||||
        Send when the command has been successfully received and validated by
 | 
			
		||||
        the server and will be carried out.
 | 
			
		||||
      </description>
 | 
			
		||||
    </event>
 | 
			
		||||
 | 
			
		||||
    <event name="failure">
 | 
			
		||||
      <description summary="command failed">
 | 
			
		||||
        Sent when the command could not be carried out. This could be due to
 | 
			
		||||
        sending a non-existent command, no command, not enough arguments, too
 | 
			
		||||
        many arguments, invalid arguments, etc.
 | 
			
		||||
      </description>
 | 
			
		||||
      <arg name="failure_message" type="string"
 | 
			
		||||
        summary="a message explaining why failure occurred"/>
 | 
			
		||||
    </event>
 | 
			
		||||
  </interface>
 | 
			
		||||
</protocol>
 | 
			
		||||
 | 
			
		||||
@ -117,10 +117,21 @@ const str_to_read_fn = [_]Definition{
 | 
			
		||||
};
 | 
			
		||||
// zig fmt: on
 | 
			
		||||
 | 
			
		||||
pub const Error = error{
 | 
			
		||||
    NoCommand,
 | 
			
		||||
    UnknownCommand,
 | 
			
		||||
    NotEnoughArguments,
 | 
			
		||||
    TooManyArguments,
 | 
			
		||||
    Overflow,
 | 
			
		||||
    InvalidCharacter,
 | 
			
		||||
    InvalidDirection,
 | 
			
		||||
    OutOfMemory,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
impl: ImplFn,
 | 
			
		||||
arg: Arg,
 | 
			
		||||
 | 
			
		||||
pub fn init(args: []const []const u8, allocator: *std.mem.Allocator) !Self {
 | 
			
		||||
pub fn init(args: []const []const u8, allocator: *std.mem.Allocator) Error!Self {
 | 
			
		||||
    if (args.len == 0) return error.NoCommand;
 | 
			
		||||
    const name = args[0];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -74,7 +74,12 @@ fn resourceDestroy(wl_resource: ?*c.wl_resource) callconv(.C) void {
 | 
			
		||||
    // TODO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn runCommand(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource, wl_array: ?*c.wl_array) callconv(.C) void {
 | 
			
		||||
fn runCommand(
 | 
			
		||||
    wl_client: ?*c.wl_client,
 | 
			
		||||
    wl_resource: ?*c.wl_resource,
 | 
			
		||||
    wl_array: ?*c.wl_array,
 | 
			
		||||
    callback_id: u32,
 | 
			
		||||
) callconv(.C) void {
 | 
			
		||||
    const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), c.wl_resource_get_user_data(wl_resource)));
 | 
			
		||||
    const allocator = self.server.allocator;
 | 
			
		||||
 | 
			
		||||
@ -89,11 +94,34 @@ fn runCommand(wl_client: ?*c.wl_client, wl_resource: ?*c.wl_resource, wl_array:
 | 
			
		||||
        i += slice.len + 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (args.items) |x| {
 | 
			
		||||
        std.debug.warn("{}\n", .{x});
 | 
			
		||||
    }
 | 
			
		||||
    const callback_resource = c.wl_resource_create(
 | 
			
		||||
        wl_client,
 | 
			
		||||
        &c.zriver_command_callback_v1_interface,
 | 
			
		||||
        protocol_version,
 | 
			
		||||
        callback_id,
 | 
			
		||||
    ) orelse {
 | 
			
		||||
        c.wl_client_post_no_memory(wl_client);
 | 
			
		||||
        return;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // TODO: send the error event on failure instead of crashing
 | 
			
		||||
    const command = Command.init(args.items, allocator) catch unreachable;
 | 
			
		||||
    c.wl_resource_set_implementation(callback_resource, null, null, null);
 | 
			
		||||
 | 
			
		||||
    const command = Command.init(args.items, allocator) catch |err| {
 | 
			
		||||
        c.zriver_command_callback_v1_send_failure(
 | 
			
		||||
            callback_resource,
 | 
			
		||||
            switch (err) {
 | 
			
		||||
                Command.Error.NoCommand => "no command given",
 | 
			
		||||
                Command.Error.UnknownCommand => "unknown command",
 | 
			
		||||
                Command.Error.NotEnoughArguments => "not enough arguments",
 | 
			
		||||
                Command.Error.TooManyArguments => "too many arguments",
 | 
			
		||||
                Command.Error.Overflow => "value out of bounds",
 | 
			
		||||
                Command.Error.InvalidCharacter => "invalid character in argument",
 | 
			
		||||
                Command.Error.InvalidDirection => "invalid direction. Must be 'next' or 'previous'",
 | 
			
		||||
                Command.Error.OutOfMemory => unreachable,
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
        return;
 | 
			
		||||
    };
 | 
			
		||||
    c.zriver_command_callback_v1_send_success(callback_resource);
 | 
			
		||||
    command.run(self.server.input_manager.default_seat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -27,14 +27,20 @@ const wl_registry_listener = c.wl_registry_listener{
 | 
			
		||||
    .global_remove = handleGlobalRemove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const command_callback_listener = c.zriver_command_callback_v1_listener{
 | 
			
		||||
    .success = handleSuccess,
 | 
			
		||||
    .failure = handleFailure,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
    if (c.wl_registry_add_listener(wl_registry, &wl_registry_listener, null) < 0)
 | 
			
		||||
        return error.FailedToAddListener;
 | 
			
		||||
    if (c.wl_display_roundtrip(wl_display) < 0) return error.RoundtripFailed;
 | 
			
		||||
 | 
			
		||||
    const wm = river_window_manager orelse return error.RiverWMNotAdvertised;
 | 
			
		||||
 | 
			
		||||
@ -51,8 +57,15 @@ pub fn main() !void {
 | 
			
		||||
        ptr[arg.len] = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c.zriver_window_manager_v1_run_command(wm, &command);
 | 
			
		||||
    if (c.wl_display_roundtrip(wl_display) == -1) return error.RoundtripFailed;
 | 
			
		||||
    const command_callback = c.zriver_window_manager_v1_run_command(wm, &command);
 | 
			
		||||
    if (c.zriver_command_callback_v1_add_listener(
 | 
			
		||||
        command_callback,
 | 
			
		||||
        &command_callback_listener,
 | 
			
		||||
        null,
 | 
			
		||||
    ) < 0) return error.FailedToAddListener;
 | 
			
		||||
 | 
			
		||||
    // Loop until our callback is called and we exit.
 | 
			
		||||
    while (true) if (c.wl_display_dispatch(wl_display) < 0) return error.DispatchFailed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn handleGlobal(
 | 
			
		||||
@ -77,3 +90,20 @@ fn handleGlobal(
 | 
			
		||||
 | 
			
		||||
/// Ignore the event
 | 
			
		||||
fn handleGlobalRemove(data: ?*c_void, wl_registry: ?*c.wl_registry, name: u32) callconv(.C) void {}
 | 
			
		||||
 | 
			
		||||
/// On success we simply exit with a clean exit code
 | 
			
		||||
fn handleSuccess(data: ?*c_void, callback: ?*c.zriver_command_callback_v1) callconv(.C) void {
 | 
			
		||||
    std.os.exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Print the failure message and exit non-zero
 | 
			
		||||
fn handleFailure(
 | 
			
		||||
    data: ?*c_void,
 | 
			
		||||
    callback: ?*c.zriver_command_callback_v1,
 | 
			
		||||
    failure_message: ?[*:0]const u8,
 | 
			
		||||
) callconv(.C) void {
 | 
			
		||||
    if (failure_message) |message| {
 | 
			
		||||
        std.debug.warn("Error: {}\n", .{failure_message});
 | 
			
		||||
    }
 | 
			
		||||
    std.os.exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user