--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __LABWC_ACTION_H
+#define __LABWC_ACTION_H
+
+struct action {
+ uint32_t type;
+ char *arg;
+ struct wl_list link;
+};
+
+struct action *action_create(const char *action_str);
+
+#endif
uint32_t modifiers;
xkb_keysym_t *keysyms;
size_t keysyms_len;
- char *action;
- char *command;
+ struct wl_list actions;
struct wl_list link;
};
/* ex: doubleclick, press, drag */
enum mouse_event mouse_event;
- const char *action;
- const char *command;
+ struct wl_list actions;
struct wl_list link; /* rcxml::mousebinds */
bool pressed_in_context; /* used in click events */
enum mouse_event mousebind_event_from_str(const char *str);
uint32_t mousebind_button_from_str(const char *str, uint32_t *modifiers);
struct mousebind *mousebind_create(const char *context);
-struct mousebind *mousebind_create_from(struct mousebind *from, const char *context);
#endif /* __LABWC_MOUSEBIND_H */
void server_start(struct server *server);
void server_finish(struct server *server);
-void action(struct view *activator, struct server *server, const char *action,
- const char *command, uint32_t resize_edges);
+void action(struct view *activator, struct server *server,
+ struct wl_list *actions, uint32_t resize_edges);
/* update onscreen display 'alt-tab' texture */
void osd_update(struct server *server);
#include <wlr/render/wlr_renderer.h>
struct menuitem {
- char *action;
- char *command;
+ struct wl_list actions;
struct menu *submenu;
struct wlr_box box;
struct {
#include "common/spawn.h"
#include "labwc.h"
#include "menu/menu.h"
+#include "action.h"
+
+enum action_type {
+ ACTION_TYPE_NONE = 0,
+ ACTION_TYPE_CLOSE,
+ ACTION_TYPE_DEBUG,
+ ACTION_TYPE_EXECUTE,
+ ACTION_TYPE_EXIT,
+ ACTION_TYPE_MOVE_TO_EDGE,
+ ACTION_TYPE_SNAP_TO_EDGE,
+ ACTION_TYPE_NEXT_WINDOW,
+ ACTION_TYPE_PREVIOUS_WINDOW,
+ ACTION_TYPE_RECONFIGURE,
+ ACTION_TYPE_SHOW_MENU,
+ ACTION_TYPE_TOGGLE_MAXIMIZE,
+ ACTION_TYPE_TOGGLE_FULLSCREEN,
+ ACTION_TYPE_TOGGLE_DECORATIONS,
+ ACTION_TYPE_FOCUS,
+ ACTION_TYPE_ICONIFY,
+ ACTION_TYPE_MOVE,
+ ACTION_TYPE_RAISE,
+ ACTION_TYPE_RESIZE,
+};
+
+const char *action_names[] = {
+ "NoOp",
+ "Close",
+ "Debug",
+ "Execute",
+ "Exit",
+ "MoveToEdge",
+ "SnapToEdge",
+ "NextWindow",
+ "PreviousWindow",
+ "Reconfigure",
+ "ShowMenu",
+ "ToggleMaximize",
+ "ToggleFullscreen",
+ "ToggleDecorations",
+ "Focus",
+ "Iconify",
+ "Move",
+ "Raise",
+ "Resize",
+ NULL
+};
+
+
+static enum action_type
+action_type_from_str(const char *action_name)
+{
+ for (size_t i=1; action_names[i] != NULL; i++) {
+ if (!strcasecmp(action_name, action_names[i])) {
+ return i;
+ }
+ }
+ wlr_log(WLR_ERROR, "Invalid action: %s", action_name);
+ return ACTION_TYPE_NONE;
+}
+
+struct action *
+action_create(const char *action_name)
+{
+ if (!action_name) {
+ wlr_log(WLR_ERROR, "action name not specified");
+ return NULL;
+ }
+ struct action *action = calloc(1, sizeof(struct action));
+ action->type = action_type_from_str(action_name);
+ return action;
+}
+
static void
show_menu(struct server *server, const char *menu)
}
void
-action(struct view *activator, struct server *server, const char *action, const char *command, uint32_t resize_edges)
+action(struct view *activator, struct server *server, struct wl_list *actions, uint32_t resize_edges)
{
- if (!action)
+ if (!actions) {
+ wlr_log(WLR_ERROR, "empty actions");
return;
- if (!strcasecmp(action, "Close")) {
- struct view *view = activator_or_focused_view(activator, server);
- if (view) {
- view_close(view);
- }
- } else if (!strcasecmp(action, "Debug")) {
- /* nothing */
- } else if (!strcasecmp(action, "Execute")) {
- struct buf cmd;
- buf_init(&cmd);
- buf_add(&cmd, command);
- buf_expand_shell_variables(&cmd);
- spawn_async_no_shell(cmd.buf);
- free(cmd.buf);
- } else if (!strcasecmp(action, "Exit")) {
- wl_display_terminate(server->wl_display);
- } else if (!strcasecmp(action, "MoveToEdge")) {
- view_move_to_edge(activator_or_focused_view(activator, server), command);
- } else if (!strcasecmp(action, "SnapToEdge")) {
- view_snap_to_edge(activator_or_focused_view(activator, server), command);
- } else if (!strcasecmp(action, "NextWindow")) {
- server->cycle_view =
- desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_FORWARD);
- osd_update(server);
- } else if (!strcasecmp(action, "PreviousWindow")) {
- server->cycle_view =
- desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_BACKWARD);
- osd_update(server);
- } else if (!strcasecmp(action, "Reconfigure")) {
- spawn_async_no_shell("killall -SIGHUP labwc");
- } else if (!strcasecmp(action, "ShowMenu")) {
- show_menu(server, command);
- } else if (!strcasecmp(action, "ToggleMaximize")) {
- struct view *view = activator_or_focused_view(activator, server);
- if (view) {
- view_toggle_maximize(view);
- }
- } else if (!strcasecmp(action, "ToggleFullscreen")) {
- struct view *view = activator_or_focused_view(activator, server);
- if (view) {
- view_toggle_fullscreen(view);
- }
- } else if (!strcasecmp(action, "ToggleDecorations")) {
- struct view *view = activator_or_focused_view(activator, server);
- if (view) {
- view_toggle_decorations(view);
- }
- } else if (!strcasecmp(action, "Focus")) {
- struct view *view = desktop_view_at_cursor(server);
- if (view) {
- desktop_focus_and_activate_view(&server->seat, view);
- damage_all_outputs(server);
- }
- } else if (!strcasecmp(action, "Iconify")) {
- struct view *view = activator_or_focused_view(activator, server);
- if (view) {
- view_minimize(view, true);
- }
- } else if (!strcasecmp(action, "Move")) {
- struct view *view = desktop_view_at_cursor(server);
- if (view) {
- interactive_begin(view, LAB_INPUT_STATE_MOVE, 0);
- }
- } else if (!strcasecmp(action, "Raise")) {
- struct view *view = activator_or_focused_view(activator, server);
- if (view) {
- desktop_move_to_front(view);
- damage_all_outputs(server);
- }
- } else if (!strcasecmp(action, "Resize")) {
- struct view *view = desktop_view_at_cursor(server);
- if (view) {
- interactive_begin(view, LAB_INPUT_STATE_RESIZE, resize_edges);
+ }
+
+ struct view *view;
+ struct action *action;
+ 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);
+
+ /* Refetch view because it may have been changed due to the previous action */
+ view = activator_or_focused_view(activator, server);
+
+ switch(action->type) {
+ case ACTION_TYPE_CLOSE:;
+ if (view) {
+ view_close(view);
+ }
+ break;
+ case ACTION_TYPE_DEBUG:;
+ /* nothing */
+ 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);
+ }
+ break;
+ case ACTION_TYPE_EXIT:;
+ wl_display_terminate(server->wl_display);
+ break;
+ case ACTION_TYPE_MOVE_TO_EDGE:;
+ view_move_to_edge(view, action->arg);
+ break;
+ case ACTION_TYPE_SNAP_TO_EDGE:;
+ view_snap_to_edge(view, action->arg);
+ break;
+ case ACTION_TYPE_NEXT_WINDOW:;
+ server->cycle_view =
+ desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_FORWARD);
+ osd_update(server);
+ break;
+ case ACTION_TYPE_PREVIOUS_WINDOW:;
+ server->cycle_view =
+ desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_BACKWARD);
+ osd_update(server);
+ break;
+ case ACTION_TYPE_RECONFIGURE:;
+ /* Should be changed to signal() */
+ spawn_async_no_shell("killall -SIGHUP labwc");
+ break;
+ case ACTION_TYPE_SHOW_MENU:;
+ show_menu(server, action->arg);
+ break;
+ case ACTION_TYPE_TOGGLE_MAXIMIZE:;
+ if (view) {
+ view_toggle_maximize(view);
+ }
+ break;
+ case ACTION_TYPE_TOGGLE_FULLSCREEN:;
+ if (view) {
+ view_toggle_fullscreen(view);
+ }
+ break;
+ case ACTION_TYPE_TOGGLE_DECORATIONS:;
+ if (view) {
+ view_toggle_decorations(view);
+ }
+ break;
+ case ACTION_TYPE_FOCUS:;
+ view = desktop_view_at_cursor(server);
+ if (view) {
+ desktop_focus_and_activate_view(&server->seat, view);
+ damage_all_outputs(server);
+ }
+ break;
+ case ACTION_TYPE_ICONIFY:;
+ if (view) {
+ view_minimize(view, true);
+ }
+ break;
+ case ACTION_TYPE_MOVE:;
+ view = desktop_view_at_cursor(server);
+ if (view) {
+ interactive_begin(view, LAB_INPUT_STATE_MOVE, 0);
+ }
+ break;
+ case ACTION_TYPE_RAISE:;
+ if (view) {
+ desktop_move_to_front(view);
+ damage_all_outputs(server);
+ }
+ break;
+ case ACTION_TYPE_RESIZE:;
+ view = desktop_view_at_cursor(server);
+ if (view) {
+ interactive_begin(view, LAB_INPUT_STATE_RESIZE, resize_edges);
+ }
+ break;
+ case ACTION_TYPE_NONE:;
+ wlr_log(WLR_ERROR, "Not executing unknown action with arg %s", action->arg);
+ break;
+ default:;
+ /*
+ * If we get here it must be a BUG caused most likely by
+ * action_names and action_type being out of sync or by
+ * 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);
}
- } else {
- wlr_log(WLR_ERROR, "(%s) not supported", action);
}
}
wl_list_insert(&rc.keybinds, &k->link);
k->keysyms = malloc(k->keysyms_len * sizeof(xkb_keysym_t));
memcpy(k->keysyms, keysyms, k->keysyms_len * sizeof(xkb_keysym_t));
+ wl_list_init(&k->actions);
return k;
}
if (m->context != LAB_SSD_NONE) {
wl_list_insert(&rc.mousebinds, &m->link);
}
- return m;
-}
-
-struct mousebind *
-mousebind_create_from(struct mousebind *from, const char *context)
-{
- if (!from) {
- wlr_log(WLR_ERROR, "invalid mousebind instance specified");
- return NULL;
- }
- struct mousebind *m = mousebind_create(context);
- m->button = from->button;
- m->modifiers = from->modifiers;
- m->mouse_event = from->mouse_event;
+ wl_list_init(&m->actions);
return m;
}
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/util/log.h>
+#include "action.h"
#include "common/dir.h"
#include "common/nodename.h"
#include "common/string-helpers.h"
static struct mousebind *current_mousebind;
static struct libinput_category *current_libinput_category;
static const char *current_mouse_context;
+static struct action *current_keybind_action;
+static struct action *current_mousebind_action;
enum font_place {
FONT_PLACE_UNKNOWN = 0,
return;
}
if (!strcmp(nodename, "name.action")) {
- current_keybind->action = strdup(content);
+ current_keybind_action = action_create(content);
+ wl_list_insert(current_keybind->actions.prev,
+ ¤t_keybind_action->link);
} else if (!strcmp(nodename, "command.action")) {
- current_keybind->command = strdup(content);
+ current_keybind_action->arg = strdup(content);
} else if (!strcmp(nodename, "direction.action")) {
- current_keybind->command = strdup(content);
+ current_keybind_action->arg = strdup(content);
} else if (!strcmp(nodename, "menu.action")) {
- current_keybind->command = strdup(content);
+ current_keybind_action->arg = strdup(content);
}
}
current_mousebind->mouse_event =
mousebind_event_from_str(content);
} else if (!strcmp(nodename, "name.action")) {
- if (current_mousebind->action) {
- current_mousebind = mousebind_create_from(current_mousebind,
- current_mouse_context);
- }
- current_mousebind->action = strdup(content);
+ current_mousebind_action = action_create(content);
+ wl_list_insert(current_mousebind->actions.prev,
+ ¤t_mousebind_action->link);
} else if (!strcmp(nodename, "command.action")) {
- current_mousebind->command = strdup(content);
+ current_mousebind_action->arg = strdup(content);
+ } else if (!strcmp(nodename, "direction.action")) {
+ current_mousebind_action->arg = strdup(content);
} else if (!strcmp(nodename, "menu.action")) {
- current_mousebind->command = strdup(content);
+ current_mousebind_action->arg = strdup(content);
}
}
static void
load_default_key_bindings(void)
{
+ struct keybind *k;
+ struct action *action;
for (int i = 0; key_combos[i].binding; i++) {
- struct keybind *k = keybind_create(key_combos[i].binding);
+ k = keybind_create(key_combos[i].binding);
if (!k) {
continue;
}
- k->action = strdup(key_combos[i].action);
+
+ action = action_create(key_combos[i].action);
+ wl_list_insert(k->actions.prev, &action->link);
+
if (key_combos[i].command) {
- k->command = strdup(key_combos[i].command);
+ action->arg = strdup(key_combos[i].command);
}
}
}
static void
load_default_mouse_bindings(void)
{
+ struct mousebind *m;
+ struct action *action;
for (int i = 0; mouse_combos[i].context; i++) {
- struct mousebind *m = mousebind_create(mouse_combos[i].context);
+ m = mousebind_create(mouse_combos[i].context);
m->button = mousebind_button_from_str(mouse_combos[i].button,
&m->modifiers);
m->mouse_event = mousebind_event_from_str(mouse_combos[i].event);
- m->action = strdup(mouse_combos[i].action);
+
+ action = action_create(mouse_combos[i].action);
+ wl_list_insert(m->actions.prev, &action->link);
+
if (mouse_combos[i].command) {
- m->command = strdup(mouse_combos[i].command);
+ action->arg = strdup(mouse_combos[i].command);
}
}
}
void
rcxml_finish(void)
{
+ struct action *action, *action_tmp;
+
zfree(rc.font_name_activewindow);
zfree(rc.font_name_menuitem);
zfree(rc.font_name_osd);
struct keybind *k, *k_tmp;
wl_list_for_each_safe(k, k_tmp, &rc.keybinds, link) {
wl_list_remove(&k->link);
- zfree(k->command);
- zfree(k->action);
+ wl_list_for_each_safe(action, action_tmp, &k->actions, link) {
+ wl_list_remove(&action->link);
+ zfree(action->arg);
+ zfree(action);
+ }
zfree(k->keysyms);
zfree(k);
}
struct mousebind *m, *m_tmp;
wl_list_for_each_safe(m, m_tmp, &rc.mousebinds, link) {
wl_list_remove(&m->link);
- zfree(m->command);
- zfree(m->action);
+ wl_list_for_each_safe(action, action_tmp, &m->actions, link) {
+ wl_list_remove(&action->link);
+ zfree(action->arg);
+ zfree(action);
+ }
zfree(m);
}
}
activated_any = true;
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
- action(view, server, mousebind->action,
- mousebind->command, resize_edges);
+ action(view, server, &mousebind->actions, resize_edges);
}
}
return activated_any && activated_any_frame;
}
activated_any = true;
activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
- action(view, server, mousebind->action,
- mousebind->command, resize_edges);
+ action(view, server, &mousebind->actions, resize_edges);
}
}
return activated_any && activated_any_frame;
for (size_t i = 0; i < keybind->keysyms_len; i++) {
if (xkb_keysym_to_lower(sym) == keybind->keysyms[i]) {
wlr_keyboard_set_repeat_info(kb, 0, 0);
- action(NULL, server, keybind->action,
- keybind->command, 0);
+ action(NULL, server, &keybind->actions, 0);
return true;
}
}
#include "labwc.h"
#include "menu/menu.h"
#include "theme.h"
+#include "action.h"
#define MENUWIDTH (110)
#define MENU_ITEM_PADDING_Y (4)
/* state-machine variables for processing <item></item> */
static bool in_item;
static struct menuitem *current_item;
+static struct action *current_item_action;
static int menu_level;
static struct menu *current_menu;
menuitem->texture.offset_x = MENU_ITEM_PADDING_X;
wl_list_insert(&menu->menuitems, &menuitem->link);
+ wl_list_init(&menuitem->actions);
return menuitem;
}
/* <item label=""> defines the start of a new item */
if (!strcmp(nodename, "label")) {
current_item = item_create(current_menu, content);
- }
- if (!current_item) {
- wlr_log(WLR_ERROR, "expect <item label=\"\"> element first");
- return;
- }
- if (!strcmp(nodename, "name.action")) {
- current_item->action = strdup(content);
+ } else if (!current_item) {
+ wlr_log(WLR_ERROR, "expect <item label=\"\"> element first. "
+ "nodename: '%s' content: '%s'", nodename, content);
+ } else if (!strcmp(nodename, "name.action")) {
+ current_item_action = action_create(content);
+ wl_list_insert(current_item->actions.prev, ¤t_item_action->link);
+ } else if (!current_item_action) {
+ wlr_log(WLR_ERROR, "expect <action name=\"\"> element first. "
+ "nodename: '%s' content: '%s'", nodename, content);
} else if (!strcmp(nodename, "command.action")) {
- current_item->command = strdup(content);
+ current_item_action->arg = strdup(content);
}
}
}
if (wl_list_empty(&server->rootmenu->menuitems)) {
current_item = item_create(server->rootmenu, "Reconfigure");
- current_item->action = strdup("Reconfigure");
+ fill_item("name.action", "Reconfigure");
current_item = item_create(server->rootmenu, "Exit");
- current_item->action = strdup("Exit");
+ fill_item("name.action", "Exit");
}
server->rootmenu->visible = true;
menu_finish(void)
{
struct menu *menu;
+ struct action *action, *action_tmp;
for (int i = 0; i < nr_menus; ++i) {
menu = menus + i;
struct menuitem *item, *next;
wl_list_for_each_safe(item, next, &menu->menuitems, link) {
- zfree(item->action);
- zfree(item->command);
wl_list_remove(&item->link);
+ wl_list_for_each_safe(action, action_tmp, &item->actions, link) {
+ wl_list_remove(&action->link);
+ zfree(action->arg);
+ zfree(action);
+ }
free(item);
}
}
struct menuitem *menuitem;
wl_list_for_each (menuitem, &menu->menuitems, link) {
if (menuitem->selected && !menuitem->submenu) {
- action(NULL, server, menuitem->action, menuitem->command, 0);
+ action(NULL, server, &menuitem->actions, 0);
break;
}
if (menuitem->submenu) {