mirror of
https://github.com/labwc/labwc.git
synced 2026-03-22 05:33:57 -04:00
action: add support for <prompt> in 'If' actions
...and allow If Action without activator view.
For example:
<action name="If">
<prompt message="Toggle maximize?"/>
<then>
<action name="ToggleMaximize" />
</then>
</action>
Also revert the change in b9c84f9 that <else> branch is always taken when
no window is focused.
Co-Authored-by: johanmalm
Co-Authored-by: tokyo4j
This commit is contained in:
parent
32e308b5d5
commit
fba73a0036
3 changed files with 135 additions and 14 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
#define LABWC_ACTION_H
|
#define LABWC_ACTION_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <wayland-util.h>
|
#include <wayland-util.h>
|
||||||
|
|
||||||
struct view;
|
struct view;
|
||||||
|
|
@ -47,6 +48,8 @@ bool actions_contain_toggle_keybinds(struct wl_list *action_list);
|
||||||
void actions_run(struct view *activator, struct server *server,
|
void actions_run(struct view *activator, struct server *server,
|
||||||
struct wl_list *actions, struct cursor_context *ctx);
|
struct wl_list *actions, struct cursor_context *ctx);
|
||||||
|
|
||||||
|
bool action_check_prompt_result(pid_t pid, int exit_code);
|
||||||
|
|
||||||
void action_free(struct action *action);
|
void action_free(struct action *action);
|
||||||
void action_list_free(struct wl_list *action_list);
|
void action_list_free(struct wl_list *action_list);
|
||||||
|
|
||||||
|
|
|
||||||
135
src/action.c
135
src/action.c
|
|
@ -493,6 +493,11 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
break;
|
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'",
|
wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s'",
|
||||||
|
|
@ -775,16 +780,115 @@ view_for_action(struct view *activator, struct server *server,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static bool
|
||||||
match_queries(struct view *view, struct action *action)
|
match_queries(struct view *view, struct action *action)
|
||||||
{
|
{
|
||||||
|
assert(view);
|
||||||
|
|
||||||
struct wl_list *queries = action_get_querylist(action, "query");
|
struct wl_list *queries = action_get_querylist(action, "query");
|
||||||
if (!queries) {
|
if (!queries) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!view) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All queries are OR'ed */
|
/* All queries are OR'ed */
|
||||||
struct view_query *query;
|
struct view_query *query;
|
||||||
|
|
@ -1205,14 +1309,23 @@ run_action(struct view *view, struct server *server, struct action *action,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ACTION_TYPE_IF: {
|
case ACTION_TYPE_IF: {
|
||||||
struct wl_list *actions;
|
/* At least one of the queries was matched or there was no query */
|
||||||
if (match_queries(view, action)) {
|
if (action_get_str(action, "message.prompt", NULL)) {
|
||||||
actions = action_get_actionlist(action, "then");
|
/*
|
||||||
} else {
|
* We delay the selection and execution of the
|
||||||
actions = action_get_actionlist(action, "else");
|
* branch until we get a response from the user.
|
||||||
}
|
*/
|
||||||
if (actions) {
|
action_prompt_create(view, server, action);
|
||||||
actions_run(view, server, actions, ctx);
|
} 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
src/server.c
11
src/server.c
|
|
@ -46,6 +46,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "drm-lease-v1-protocol.h"
|
#include "drm-lease-v1-protocol.h"
|
||||||
|
#include "action.h"
|
||||||
#include "common/macros.h"
|
#include "common/macros.h"
|
||||||
#include "common/scaled-scene-buffer.h"
|
#include "common/scaled-scene-buffer.h"
|
||||||
#include "config/rcxml.h"
|
#include "config/rcxml.h"
|
||||||
|
|
@ -160,9 +161,11 @@ handle_sigchld(int signal, void *data)
|
||||||
const char *signame;
|
const char *signame;
|
||||||
switch (info.si_code) {
|
switch (info.si_code) {
|
||||||
case CLD_EXITED:
|
case CLD_EXITED:
|
||||||
wlr_log(info.si_status == 0 ? WLR_DEBUG : WLR_ERROR,
|
if (!action_check_prompt_result(info.si_pid, info.si_status)) {
|
||||||
"spawned child %ld exited with %d",
|
wlr_log(info.si_status == 0 ? WLR_DEBUG : WLR_ERROR,
|
||||||
(long)info.si_pid, info.si_status);
|
"spawned child %ld exited with %d",
|
||||||
|
(long)info.si_pid, info.si_status);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CLD_KILLED:
|
case CLD_KILLED:
|
||||||
case CLD_DUMPED:
|
case CLD_DUMPED:
|
||||||
|
|
@ -171,6 +174,8 @@ handle_sigchld(int signal, void *data)
|
||||||
"spawned child %ld terminated with signal %d (%s)",
|
"spawned child %ld terminated with signal %d (%s)",
|
||||||
(long)info.si_pid, info.si_status,
|
(long)info.si_pid, info.si_status,
|
||||||
signame ? signame : "unknown");
|
signame ? signame : "unknown");
|
||||||
|
/* Allow cleanup of killed prompt */
|
||||||
|
action_check_prompt_result(info.si_pid, -info.si_status);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wlr_log(WLR_ERROR,
|
wlr_log(WLR_ERROR,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue