]> git.mdlowis.com Git - proto/labwc.git/commitdiff
src/action.c: Convert action->arg to a list of action_arg
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Fri, 10 Jun 2022 17:42:34 +0000 (19:42 +0200)
committerJohan Malm <johanmalm@users.noreply.github.com>
Mon, 4 Jul 2022 15:19:28 +0000 (16:19 +0100)
In preperation for Actions that require multiple arguments

include/action.h
include/config/keybind.h
include/config/mousebind.h
include/config/rcxml.h
include/private/action.h [new file with mode: 0644]
src/action.c
src/config/rcxml.c
src/menu/menu.c

index b23a0ec9ab85e5f2365e58045158323a62ce9539..e55060331aae28dde0b4d72dd5fa52658b46f2ed 100644 (file)
@@ -2,19 +2,23 @@
 #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 */
index 86eb4b52d05ae482534799040b7a49e7f8396e68..b11914eda60d8dc4e4bc79ed6406d16a9778c392 100644 (file)
@@ -11,8 +11,8 @@ struct keybind {
        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 */
 };
 
 /**
index ae66532adbf159812553a26f7fea3f1ef72db91a..af73dd4f928149ed843f9ef662d17c83d1571b3f 100644 (file)
@@ -26,9 +26,9 @@ struct mousebind {
 
        /* 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 */
 };
 
index 41382de2f346b6ee2f56d2edb31fbd9d5d3d5a62..5827f51a3ef8414fd8f000229eb26a416a4140dc 100644 (file)
@@ -37,11 +37,11 @@ struct rcxml {
        /* 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;
diff --git a/include/private/action.h b/include/private/action.h
new file mode 100644 (file)
index 0000000..0b8f60d
--- /dev/null
@@ -0,0 +1,24 @@
+/* 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 */
index d29048fbdae3ff958dbc9f4188f6dd86c5e86fe5..3b6dd4d405b636ef3fea10fcd70485738f45ecda 100644 (file)
@@ -1,6 +1,8 @@
 // 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>
@@ -9,8 +11,8 @@
 #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 {
@@ -64,6 +66,24 @@ const char *action_names[] = {
        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)
 {
@@ -85,15 +105,26 @@ action_create(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);
        }
 }
@@ -151,9 +182,13 @@ actions_run(struct view *activator, struct server *server,
 
        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
@@ -171,28 +206,30 @@ actions_run(struct view *activator, struct server *server,
                        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");
                        }
@@ -211,7 +248,11 @@ actions_run(struct view *activator, struct server *server,
                        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) {
@@ -263,27 +304,33 @@ actions_run(struct view *activator, struct server *server,
                        }
                        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:
                        /*
@@ -292,9 +339,21 @@ actions_run(struct view *activator, struct server *server,
                         * 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);
+}
index 19bd2133f16207883900bf07905a4fe0c07f7cc7..1d950f7abf0fb8264d3ae635154d91920ad0f2eb 100644 (file)
@@ -71,21 +71,18 @@ fill_keybind(char *nodename, char *content)
        } 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);
        }
 }
 
@@ -134,15 +131,12 @@ fill_mousebind(char *nodename, char *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);
        }
 }
 
@@ -544,7 +538,7 @@ load_default_key_bindings(void)
                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);
                }
        }
 }
@@ -604,7 +598,7 @@ load_default_mouse_bindings(void)
                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);
                }
        }
 }
index bb79295e33ae74c1ccd39a012069e4d24858091b..a2677c8b10918d140bdc8c2ece7318f72c387b4b 100644 (file)
@@ -238,16 +238,16 @@ fill_item(char *nodename, char *content)
                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);
        }
 }