add river-control-unstable-v1 support

This commit is contained in:
Leon Henrik Plickat
2024-01-08 11:47:00 +01:00
parent 153b5e0858
commit 4ae3654e35
6 changed files with 214 additions and 9 deletions

View File

@@ -8,6 +8,8 @@
#include "output.h"
#include "seat.h"
#include "river-control-unstable-v1.h"
/**
* ISO C forbids casting a function pointer to a void pointer because on some
* architectures they have different sizes. However scm_c_define_gsubr() wants
@@ -155,6 +157,72 @@ static SCM install_handler (SCM key, SCM proc)
return SCM_BOOL_T;
}
static SCM riverctl (SCM first, SCM rest)
{
if ( context.river_control == NULL )
{
fputs("ERROR: User script attempts to send river command but river-control-unstable-v1 not available.\n", stderr);
fputs("INFO: This error is not fatal, however riverguile will not be able to send any commands to river.\n", stderr);
return SCM_BOOL_F;
}
if ( wl_list_length(&context.seats) == 0 )
{
fputs("ERROR: User script attempts to send river command but server did not advertise any seats.\n", stderr);
fputs("INFO: This error is not fatal, however riverguile will not be able to send any commands to river.\n", stderr);
return SCM_BOOL_F;
}
if ( scm_is_string(first) != 1 )
goto error;
assert(scm_is_true(scm_list_p(rest)) == 1);
const uint32_t rest_len = scm_to_uint32(scm_length(rest));
for (uint32_t i = 0; i < rest_len; i++)
if ( scm_is_string(scm_list_ref(rest, scm_from_uint32(i))) != 1 )
goto error;
char *first_owned = scm_to_utf8_stringn(first, 0);
zriver_control_v1_add_argument(context.river_control, first_owned);
free(first_owned);
for (uint32_t i = 0; i < rest_len; i++)
{
char *owned = scm_to_utf8_stringn(scm_list_ref(rest, scm_from_uint32(i)), 0);
zriver_control_v1_add_argument(context.river_control, owned);
free(owned);
}
/* Just use the first seat. River only supports a single one anyway. */
struct Seat *seat;
wl_list_for_each(seat, &context.seats, link)
break;
/* While river does tell us about the status of the command, I do not
* want to make use of that in riverguile for multiple reasons.
* For one, the reporting is of course async, meaning we could not raise
* a guile error in response to failed commands, even if we wanted to.
* Riverguile could allow to install a handler for the callback, however
* I do not sett the use. There are two riverctl commands that return
* useful data as a string, however using that for scripting would be
* very hacky and I prefer dedicated well designed interfaces. So we
* just destroy the callback before it even fires.
*/
zriver_command_callback_v1_destroy(
zriver_control_v1_run_command(context.river_control, seat->wl_seat)
);
return SCM_BOOL_T;
error:
scm_error_scm(
scm_from_utf8_symbol("wrong-type-arg"),
scm_from_utf8_string("riverctl"),
scm_from_utf8_string("All arguments must be strings."),
SCM_BOOL_F,
SCM_BOOL_F
);
return SCM_UNSPECIFIED;
}
static void *load_script_inner (void *data)
{
const char *path = (char *)data;
@@ -172,6 +240,7 @@ void *load_script (void *data)
/* Note: All guile objects are garbage collected. */
scm_c_define_gsubr_fix("install-handler", 2, 0, 0, install_handler);
scm_c_define_gsubr_fix("riverctl", 1, 0, 1, riverctl);
/* Continuation barrier causes stack unwind on exceptions to stop here.
* Otherwise the entire stack created by scm_with_guile() would be