goto cleanup;
}
break;
+ case ACTION_TYPE_IF:
+ if (!strcmp(argument, "message.prompt")) {
+ action_arg_add_str(action, "message.prompt", content);
+ }
+ goto cleanup;
}
wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s'",
}
}
+struct action_prompt {
+ /* Set when created */
+ struct server *server;
+ struct action *action;
+ struct view *view;
+
+ /* Set when executed */
+ pid_t pid;
+
+ struct {
+ struct wl_listener destroy;
+ } on_view;
+ struct wl_list link;
+};
+
+static struct wl_list prompts = WL_LIST_INIT(&prompts);
+
+static void
+action_prompt_destroy(struct action_prompt *prompt)
+{
+ wl_list_remove(&prompt->on_view.destroy.link);
+ wl_list_remove(&prompt->link);
+ free(prompt);
+}
+
+static void
+handle_view_destroy(struct wl_listener *listener, void *data)
+{
+ struct action_prompt *prompt = wl_container_of(listener, prompt, on_view.destroy);
+ wl_list_remove(&prompt->on_view.destroy.link);
+ wl_list_init(&prompt->on_view.destroy.link);
+ prompt->view = NULL;
+}
+
+static void
+action_prompt_create(struct view *view, struct server *server, struct action *action)
+{
+ char *command = strdup_printf("labnag -m \"%s\" -Z \"%s\" : -Z \"%s\" :",
+ action_get_str(action, "message.prompt", "Choose wisely"),
+ _("Yes"), _("No"));
+
+ int pipe_fd;
+ pid_t prompt_pid = spawn_piped(command, &pipe_fd);
+ if (prompt_pid < 0) {
+ wlr_log(WLR_ERROR, "Failed to create action prompt");
+ goto cleanup;
+ }
+ /* FIXME: closing stdout might confuse clients */
+ close(pipe_fd);
+
+ struct action_prompt *prompt = znew(*prompt);
+ prompt->server = server;
+ prompt->action = action;
+ prompt->view = view;
+ prompt->pid = prompt_pid;
+ if (view) {
+ prompt->on_view.destroy.notify = handle_view_destroy;
+ wl_signal_add(&view->events.destroy, &prompt->on_view.destroy);
+ } else {
+ /* Allows removing during destroy */
+ wl_list_init(&prompt->on_view.destroy.link);
+ }
+
+ wl_list_insert(&prompts, &prompt->link);
+
+cleanup:
+ free(command);
+}
+
+bool
+action_check_prompt_result(pid_t pid, int exit_code)
+{
+ struct action_prompt *prompt, *tmp;
+ wl_list_for_each_safe(prompt, tmp, &prompts, link) {
+ if (prompt->pid != pid) {
+ continue;
+ }
+
+ wlr_log(WLR_INFO, "Found pending prompt for exit code %d", exit_code);
+ struct wl_list *actions = NULL;
+ if (exit_code == 0) {
+ wlr_log(WLR_INFO, "Selected the 'then' branch");
+ actions = action_get_actionlist(prompt->action, "then");
+ } else {
+ wlr_log(WLR_INFO, "Selected the 'else' branch");
+ actions = action_get_actionlist(prompt->action, "else");
+ }
+ if (actions) {
+ wlr_log(WLR_INFO, "Running actions");
+ actions_run(prompt->view, prompt->server,
+ actions, /*cursor_ctx*/ NULL);
+ } else {
+ wlr_log(WLR_INFO, "No actions for selected branch");
+ }
+ action_prompt_destroy(prompt);
+ return true;
+ }
+ return false;
+}
+
static bool
match_queries(struct view *view, struct action *action)
{
+ assert(view);
+
struct wl_list *queries = action_get_querylist(action, "query");
if (!queries) {
return true;
}
- if (!view) {
- return false;
- }
/* All queries are OR'ed */
struct view_query *query;
break;
}
case ACTION_TYPE_IF: {
- struct wl_list *actions;
- if (match_queries(view, action)) {
- actions = action_get_actionlist(action, "then");
- } else {
- actions = action_get_actionlist(action, "else");
- }
- if (actions) {
- actions_run(view, server, actions, ctx);
+ /* At least one of the queries was matched or there was no query */
+ if (action_get_str(action, "message.prompt", NULL)) {
+ /*
+ * We delay the selection and execution of the
+ * branch until we get a response from the user.
+ */
+ action_prompt_create(view, server, action);
+ } else if (view) {
+ struct wl_list *actions;
+ if (match_queries(view, action)) {
+ actions = action_get_actionlist(action, "then");
+ } else {
+ actions = action_get_actionlist(action, "else");
+ }
+ if (actions) {
+ actions_run(view, server, actions, ctx);
+ }
}
break;
}
#endif
#include "drm-lease-v1-protocol.h"
+#include "action.h"
#include "common/macros.h"
#include "common/scaled-scene-buffer.h"
#include "config/rcxml.h"
const char *signame;
switch (info.si_code) {
case CLD_EXITED:
- wlr_log(info.si_status == 0 ? WLR_DEBUG : WLR_ERROR,
- "spawned child %ld exited with %d",
- (long)info.si_pid, info.si_status);
+ if (!action_check_prompt_result(info.si_pid, info.si_status)) {
+ wlr_log(info.si_status == 0 ? WLR_DEBUG : WLR_ERROR,
+ "spawned child %ld exited with %d",
+ (long)info.si_pid, info.si_status);
+ }
break;
case CLD_KILLED:
case CLD_DUMPED:
"spawned child %ld terminated with signal %d (%s)",
(long)info.si_pid, info.si_status,
signame ? signame : "unknown");
+ /* Allow cleanup of killed prompt */
+ action_check_prompt_result(info.si_pid, -info.si_status);
break;
default:
wlr_log(WLR_ERROR,