#ifndef __LABWC_ACTION_H
#define __LABWC_ACTION_H
-struct server;
struct view;
+struct server;
+struct wl_list;
struct action {
- uint32_t type;
- char *arg;
- struct wl_list link;
+ struct wl_list link; /* struct keybinding.actions,
+ * struct mousebinding.actions,
+ * struct menuitem.actions */
+
+ uint32_t type; /* enum action_type */
+ struct wl_list args; /* struct action_arg.link */
};
struct action *action_create(const char *action_name);
-void action_list_free(struct wl_list *action_list);
-
+void action_arg_add_str(struct action *action, char *key, const char *value);
void actions_run(struct view *activator, struct server *server,
struct wl_list *actions, uint32_t resize_edges);
+void action_list_free(struct wl_list *action_list);
-#endif
+#endif /* __LABWC_ACTION_H */
uint32_t modifiers;
xkb_keysym_t *keysyms;
size_t keysyms_len;
- struct wl_list actions;
- struct wl_list link;
+ struct wl_list actions; /* struct action.link */
+ struct wl_list link; /* struct rcxml.keybinds */
};
/**
/* ex: doubleclick, press, drag */
enum mouse_event mouse_event;
- struct wl_list actions;
+ struct wl_list actions; /* struct action.link */
- struct wl_list link; /* rcxml::mousebinds */
+ struct wl_list link; /* struct rcxml.mousebinds */
bool pressed_in_context; /* used in click events */
};
/* keyboard */
int repeat_rate;
int repeat_delay;
- struct wl_list keybinds;
+ struct wl_list keybinds; /* struct keybind.link */
/* mouse */
- long doubleclick_time; /* in ms */
- struct wl_list mousebinds;
+ long doubleclick_time; /* in ms */
+ struct wl_list mousebinds; /* struct mousebind.link */
/* libinput */
struct wl_list libinput_categories;
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __LABWC_PRIVATE_ACTION_H
+#define __LABWC_PRIVATE_ACTION_H
+
+/* Don't include ourself as search path starts at current directory */
+#include "../action.h"
+
+enum action_arg_type {
+ LAB_ACTION_ARG_STR = 0,
+};
+
+struct action_arg {
+ struct wl_list link; /* struct action.args */
+
+ const char *key; /* May be NULL if there is just one arg */
+ enum action_arg_type type;
+};
+
+struct action_arg_str {
+ struct action_arg base;
+ char *value;
+};
+
+#endif /* __LABWC_PRIVATE_ACTION_H */
// SPDX-License-Identifier: GPL-2.0-only
#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
#include <signal.h>
+#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <wlr/util/log.h>
#include "debug.h"
#include "labwc.h"
#include "menu/menu.h"
+#include "private/action.h"
#include "ssd.h"
-#include "action.h"
#include "workspaces.h"
enum action_type {
NULL
};
+static char *
+action_str_from_arg(struct action_arg *arg)
+{
+ assert(arg->type == LAB_ACTION_ARG_STR);
+ return ((struct action_arg_str *)arg)->value;
+}
+
+static struct action_arg *
+action_get_first_arg(struct action *action)
+{
+ struct action_arg *arg;
+ struct wl_list *item = action->args.next;
+ if (item == &action->args) {
+ return NULL;
+ }
+ return wl_container_of(item, arg, link);
+}
+
static enum action_type
action_type_from_str(const char *action_name)
{
}
struct action *action = calloc(1, sizeof(struct action));
action->type = action_type_from_str(action_name);
+ wl_list_init(&action->args);
return action;
}
void action_list_free(struct wl_list *action_list)
{
+ struct action_arg *arg, *arg_tmp;
struct action *action, *action_tmp;
+ /* Free actions */
wl_list_for_each_safe(action, action_tmp, action_list, link) {
wl_list_remove(&action->link);
- zfree(action->arg);
+ /* Free args */
+ wl_list_for_each_safe(arg, arg_tmp, &action->args, link) {
+ wl_list_remove(&arg->link);
+ zfree(arg->key);
+ if (arg->type == LAB_ACTION_ARG_STR) {
+ free(action_str_from_arg(arg));
+ }
+ zfree(arg);
+ }
zfree(action);
}
}
struct view *view;
struct action *action;
+ struct action_arg *arg;
wl_list_for_each(action, actions, link) {
- wlr_log(WLR_DEBUG, "Handling action %s (%u) with arg %s",
- action_names[action->type], action->type, action->arg);
+ wlr_log(WLR_DEBUG, "Handling action %s (%u)",
+ action_names[action->type], action->type);
+
+ /* Get arg now so we don't have to repeat every time we only need one */
+ arg = action_get_first_arg(action);
/*
* Refetch view because it may have been changed due to the
debug_dump_scene(server);
break;
case ACTION_TYPE_EXECUTE:
- {
- struct buf cmd;
- buf_init(&cmd);
- buf_add(&cmd, action->arg);
- buf_expand_shell_variables(&cmd);
- spawn_async_no_shell(cmd.buf);
- free(cmd.buf);
+ if (!arg) {
+ wlr_log(WLR_ERROR, "Missing argument for Execute");
+ break;
}
+ struct buf cmd;
+ buf_init(&cmd);
+ buf_add(&cmd, action_str_from_arg(arg));
+ buf_expand_shell_variables(&cmd);
+ spawn_async_no_shell(cmd.buf);
+ free(cmd.buf);
break;
case ACTION_TYPE_EXIT:
wl_display_terminate(server->wl_display);
break;
case ACTION_TYPE_MOVE_TO_EDGE:
- if (action->arg) {
- view_move_to_edge(view, action->arg);
+ if (arg) {
+ view_move_to_edge(view, action_str_from_arg(arg));
} else {
wlr_log(WLR_ERROR, "Missing argument for MoveToEdge");
}
break;
case ACTION_TYPE_SNAP_TO_EDGE:
- if (action->arg) {
- view_snap_to_edge(view, action->arg);
+ if (arg) {
+ view_snap_to_edge(view, action_str_from_arg(arg));
} else {
wlr_log(WLR_ERROR, "Missing argument for SnapToEdge");
}
kill(getpid(), SIGHUP);
break;
case ACTION_TYPE_SHOW_MENU:
- show_menu(server, view, action->arg);
+ if (arg) {
+ show_menu(server, view, action_str_from_arg(arg));
+ } else {
+ wlr_log(WLR_ERROR, "Missing argument for ShowMenu");
+ }
break;
case ACTION_TYPE_TOGGLE_MAXIMIZE:
if (view) {
}
break;
case ACTION_TYPE_GO_TO_DESKTOP:
- {
- struct workspace *target;
- target = workspaces_find(server->workspace_current, action->arg);
- if (target) {
- workspaces_switch_to(target);
- }
+ if (!arg) {
+ wlr_log(WLR_ERROR, "Missing argument for GoToDesktop");
+ break;
+ }
+ struct workspace *target;
+ char *target_name = action_str_from_arg(arg);
+ target = workspaces_find(server->workspace_current, target_name);
+ if (target) {
+ workspaces_switch_to(target);
}
break;
case ACTION_TYPE_SEND_TO_DESKTOP:
+ if (!arg) {
+ wlr_log(WLR_ERROR, "Missing argument for SendToDesktop");
+ break;
+ }
if (view) {
struct workspace *target;
- target = workspaces_find(view->workspace, action->arg);
+ char *target_name = action_str_from_arg(arg);
+ target = workspaces_find(view->workspace, target_name);
if (target) {
workspaces_send_to(view, target);
}
}
break;
case ACTION_TYPE_NONE:
- wlr_log(WLR_ERROR,
- "Not executing unknown action with arg %s",
- action->arg);
+ wlr_log(WLR_ERROR, "Not executing unknown action");
break;
default:
/*
* adding a new action without installing a handler here.
*/
wlr_log(WLR_ERROR,
- "Not executing invalid action (%u) with arg %s"
- " This is a BUG. Please report.",
- action->type, action->arg);
+ "Not executing invalid action (%u)"
+ " This is a BUG. Please report.", action->type);
}
}
}
+
+void
+action_arg_add_str(struct action *action, char *key, const char *value)
+{
+ assert(value && "Tried to add NULL action string argument");
+ struct action_arg_str *arg = calloc(1, sizeof(*arg));
+ arg->base.type = LAB_ACTION_ARG_STR;
+ if (key) {
+ arg->base.key = strdup(key);
+ }
+ arg->value = strdup(value);
+ wl_list_insert(action->args.prev, &arg->base.link);
+}
} else if (!current_keybind_action) {
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
"nodename: '%s' content: '%s'", nodename, content);
- } else if (current_keybind_action->arg) {
- wlr_log(WLR_ERROR, "Action argument already set: %s",
- current_keybind_action->arg);
} else if (!strcmp(nodename, "command.action")) {
/* Execute */
- current_keybind_action->arg = strdup(content);
+ action_arg_add_str(current_keybind_action, NULL, content);
} else if (!strcmp(nodename, "direction.action")) {
/* MoveToEdge, SnapToEdge */
- current_keybind_action->arg = strdup(content);
+ action_arg_add_str(current_keybind_action, NULL, content);
} else if (!strcmp(nodename, "menu.action")) {
/* ShowMenu */
- current_keybind_action->arg = strdup(content);
+ action_arg_add_str(current_keybind_action, NULL, content);
} else if (!strcmp(nodename, "to.action")) {
/* GoToDesktop, SendToDesktop */
- current_keybind_action->arg = strdup(content);
+ action_arg_add_str(current_keybind_action, NULL, content);
}
}
} else if (!current_mousebind_action) {
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
"nodename: '%s' content: '%s'", nodename, content);
- } else if (current_mousebind_action->arg) {
- wlr_log(WLR_ERROR, "Action argument already set: %s",
- current_mousebind_action->arg);
} else if (!strcmp(nodename, "command.action")) {
- current_mousebind_action->arg = strdup(content);
+ action_arg_add_str(current_mousebind_action, NULL, content);
} else if (!strcmp(nodename, "direction.action")) {
- current_mousebind_action->arg = strdup(content);
+ action_arg_add_str(current_mousebind_action, NULL, content);
} else if (!strcmp(nodename, "menu.action")) {
- current_mousebind_action->arg = strdup(content);
+ action_arg_add_str(current_mousebind_action, NULL, content);
}
}
wl_list_insert(k->actions.prev, &action->link);
if (key_combos[i].command) {
- action->arg = strdup(key_combos[i].command);
+ action_arg_add_str(action, NULL, key_combos[i].command);
}
}
}
wl_list_insert(m->actions.prev, &action->link);
if (mouse_combos[i].command) {
- action->arg = strdup(mouse_combos[i].command);
+ action_arg_add_str(action, NULL, mouse_combos[i].command);
}
}
}
wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
"nodename: '%s' content: '%s'", nodename, content);
} else if (!strcmp(nodename, "command.action")) {
- current_item_action->arg = strdup(content);
+ action_arg_add_str(current_item_action, NULL, content);
} else if (!strcmp(nodename, "execute.action")) {
/*
* <action name="Execute"><execute>foo</execute></action>
* is deprecated, but we support it anyway for backward
* compatibility with old openbox-menu generators
*/
- current_item_action->arg = strdup(content);
+ action_arg_add_str(current_item_action, NULL, content);
} else if (!strcmp(nodename, "to.action")) {
- current_item_action->arg = strdup(content);
+ action_arg_add_str(current_item_action, NULL, content);
}
}