Allow multiple actions per keybinding

This commit is contained in:
Keith Bowes 2022-02-25 18:29:20 -05:00
parent 8403f759c4
commit e9bf441ed0
3 changed files with 117 additions and 141 deletions

View file

@ -21,6 +21,48 @@ static char *parse_xpath_expr(char *expr, xmlXPathContextPtr ctxt) {
return (char *) ret; return (char *) ret;
} }
static void get_action(xmlNode *new_node, struct wb_key_binding *key_bind) {
xmlAttr *attr;
xmlNode *cur_node;
for (cur_node = new_node; cur_node; cur_node = cur_node->next) {
if (strcmp((char *) cur_node->name, "action") == 0) {
attr = cur_node->properties;
if (!attr) continue;
while (strcmp((char *) attr->name, "name") != 0) {
attr = attr->next;
}
char *action = (char *) attr->children->content;
if (strcmp(action, "Execute") == 0)
key_bind->action |= ACTION_EXECUTE;
else if (strcmp(action, "NextWindow") == 0)
key_bind->action |= ACTION_NEXT_WINDOW;
else if (strcmp(action, "PreviousWindow") == 0)
key_bind->action |= ACTION_PREVIOUS_WINDOW;
else if (strcmp(action, "Close") == 0)
key_bind->action |= ACTION_CLOSE;
else if (strcmp(action, "ToggleMaximize") == 0)
key_bind->action |= ACTION_TOGGLE_MAXIMIZE;
else if (strcmp(action, "Iconify") == 0)
key_bind->action |= ACTION_ICONIFY;
else if (strcmp(action, "Shade") == 0)
key_bind->action |= ACTION_SHADE;
else if (strcmp(action, "Unshade") == 0)
key_bind->action |= ACTION_UNSHADE;
else if (strcmp(action, "Exit") == 0)
key_bind->action |= ACTION_EXIT;
else if (strcmp(action, "Reconfigure") == 0)
key_bind->action |= ACTION_RECONFIGURE;
}
if (cur_node && cur_node->children)
get_action(cur_node->children, key_bind);
if (strcmp((char *) cur_node->name, "execute") == 0) {
key_bind->cmd = (char *) xmlStrdup(cur_node->children->content);
}
}
}
static bool parse_key_bindings(struct wb_config *config, xmlXPathContextPtr ctxt) { static bool parse_key_bindings(struct wb_config *config, xmlXPathContextPtr ctxt) {
/* Get the key bindings */ /* Get the key bindings */
wl_list_init(&config->key_bindings); wl_list_init(&config->key_bindings);
@ -42,9 +84,7 @@ static bool parse_key_bindings(struct wb_config *config, xmlXPathContextPtr ctxt
/* First get the key combinations */ /* First get the key combinations */
xmlAttr *keycomb = object->nodesetval->nodeTab[i]->properties; xmlAttr *keycomb = object->nodesetval->nodeTab[i]->properties;
while (strcmp((char *) keycomb->name, "key") != 0) while (strcmp((char *) keycomb->name, "key") != 0)
{
keycomb = keycomb->next; keycomb = keycomb->next;
}
char *sym; char *sym;
uint32_t modifiers = 0; uint32_t modifiers = 0;
@ -54,8 +94,7 @@ static bool parse_key_bindings(struct wb_config *config, xmlXPathContextPtr ctxt
struct wb_key_binding *key_bind = calloc(1, sizeof(struct wb_key_binding)); struct wb_key_binding *key_bind = calloc(1, sizeof(struct wb_key_binding));
key_bind->sym = 0; key_bind->sym = 0;
key_bind->modifiers = 0; key_bind->modifiers = 0;
while ((s = strtok(sym, "-")) != NULL) while ((s = strtok(sym, "-")) != NULL) {
{
if (strcmp(s, "A") == 0 || strcmp(s, "Alt") == 0) if (strcmp(s, "A") == 0 || strcmp(s, "Alt") == 0)
modifiers |= WLR_MODIFIER_ALT; modifiers |= WLR_MODIFIER_ALT;
else if (strcmp(s, "Caps") == 0) else if (strcmp(s, "Caps") == 0)
@ -78,50 +117,8 @@ static bool parse_key_bindings(struct wb_config *config, xmlXPathContextPtr ctxt
} }
/* Now get the actions */ /* Now get the actions */
xmlNode *cur_node;
xmlNode *new_node = object->nodesetval->nodeTab[i]->children; xmlNode *new_node = object->nodesetval->nodeTab[i]->children;
xmlAttr *attr; get_action(new_node, key_bind);
for (cur_node = new_node; cur_node; cur_node = cur_node->next)
{
if (strcmp((char *) cur_node->name, "action") == 0)
{
attr = cur_node->properties;
while (strcmp((char *) attr->name, "name") != 0)
{
attr = attr->next;
}
char *action = (char *) attr->children->content;
if (strcmp(action, "Execute") == 0)
key_bind->action = ACTION_EXECUTE;
else if (strcmp(action, "NextWindow") == 0)
key_bind->action = ACTION_NEXT_WINDOW;
else if (strcmp(action, "PreviousWindow") == 0)
key_bind->action = ACTION_PREVIOUS_WINDOW;
else if (strcmp(action, "Close") == 0)
key_bind->action = ACTION_CLOSE;
else if (strcmp(action, "ToggleMaximize") == 0)
key_bind->action = ACTION_TOGGLE_MAXIMIZE;
else if (strcmp(action, "Iconify") == 0)
key_bind->action = ACTION_ICONIFY;
else if (strcmp(action, "Shade") == 0)
key_bind->action = ACTION_SHADE;
else if (strcmp(action, "Unshade") == 0)
key_bind->action = ACTION_UNSHADE;
else if (strcmp(action, "Exit") == 0)
key_bind->action = ACTION_EXIT;
else if (strcmp(action, "Reconfigure") == 0)
key_bind->action = ACTION_RECONFIGURE;
if (key_bind->action != ACTION_EXECUTE)
break;
cur_node = cur_node->children;
}
if (strcmp((char *) cur_node->name, "execute") == 0)
{
key_bind->cmd = (char *) xmlStrdup(cur_node->children->content);
if (key_bind->action)
break;
}
}
wl_list_insert(&config->key_bindings, &key_bind->link); wl_list_insert(&config->key_bindings, &key_bind->link);
} }
@ -168,8 +165,7 @@ bool init_config(struct wb_server *server) {
struct wb_config *config = calloc(1, sizeof(struct wb_config)); struct wb_config *config = calloc(1, sizeof(struct wb_config));
config->keyboard_layout.use_config = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout", ctxt) != NULL; config->keyboard_layout.use_config = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout", ctxt) != NULL;
if (config->keyboard_layout.use_config) if (config->keyboard_layout.use_config) {
{
config->keyboard_layout.layout = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:layout", ctxt); config->keyboard_layout.layout = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:layout", ctxt);
config->keyboard_layout.model = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:model", ctxt); config->keyboard_layout.model = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:model", ctxt);
config->keyboard_layout.options = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:options", ctxt); config->keyboard_layout.options = parse_xpath_expr("//ob:keyboard//ob:keyboardLayout//ob:options", ctxt);

View file

@ -4,17 +4,16 @@
#include "waybox/server.h" #include "waybox/server.h"
enum action_type { enum action_type {
ACTION_FIRST, ACTION_CLOSE = 1,
ACTION_CLOSE, ACTION_EXECUTE = 2,
ACTION_EXECUTE, ACTION_EXIT = 4,
ACTION_EXIT, ACTION_ICONIFY = 8,
ACTION_ICONIFY, ACTION_NEXT_WINDOW = 16,
ACTION_NEXT_WINDOW, ACTION_PREVIOUS_WINDOW = 32,
ACTION_PREVIOUS_WINDOW, ACTION_RECONFIGURE = 64,
ACTION_RECONFIGURE, ACTION_SHADE = 128,
ACTION_SHADE, ACTION_TOGGLE_MAXIMIZE = 256,
ACTION_TOGGLE_MAXIMIZE, ACTION_UNSHADE = 512,
ACTION_UNSHADE,
}; };
struct wb_config { struct wb_config {

View file

@ -51,8 +51,7 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
* client. * client.
*/ */
if (!server->config) if (!server->config) {
{
/* Some default key bindings, when the rc.xml file can't be /* Some default key bindings, when the rc.xml file can't be
* parsed. */ * parsed. */
if (modifiers & WLR_MODIFIER_ALT && sym == XKB_KEY_Tab) if (modifiers & WLR_MODIFIER_ALT && sym == XKB_KEY_Tab)
@ -69,88 +68,71 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
struct wb_key_binding *key_binding; struct wb_key_binding *key_binding;
wl_list_for_each(key_binding, &server->config->key_bindings, link) { wl_list_for_each(key_binding, &server->config->key_bindings, link) {
if (sym == key_binding->sym && modifiers == key_binding->modifiers) if (sym == key_binding->sym && modifiers == key_binding->modifiers) {
{ if (key_binding->action & ACTION_NEXT_WINDOW)
switch (key_binding->action) cycle_views(server);
{ if (key_binding->action & ACTION_PREVIOUS_WINDOW)
case ACTION_NEXT_WINDOW: cycle_views_reverse(server);
cycle_views(server); if (key_binding->action & ACTION_CLOSE) {
break; struct wb_view *current_view = wl_container_of(
case ACTION_PREVIOUS_WINDOW: server->views.next, current_view, link);
cycle_views_reverse(server); if (wlr_surface_is_xdg_surface(current_view->xdg_toplevel->base->surface))
break;
case ACTION_CLOSE:
{
struct wb_view *current_view = wl_container_of(
server->views.next, current_view, link);
if (wlr_surface_is_xdg_surface(current_view->xdg_toplevel->base->surface))
#if WLR_CHECK_VERSION(0, 16, 0) #if WLR_CHECK_VERSION(0, 16, 0)
wlr_xdg_toplevel_send_close(current_view->xdg_toplevel); wlr_xdg_toplevel_send_close(current_view->xdg_toplevel);
#else #else
wlr_xdg_toplevel_send_close(current_view->xdg_surface); wlr_xdg_toplevel_send_close(current_view->xdg_surface);
#endif #endif
break; }
} if (key_binding->action & ACTION_EXECUTE) {
case ACTION_EXECUTE: if (fork() == 0) {
if (fork() == 0) { execl("/bin/sh", "/bin/sh", "-c", key_binding->cmd, (char *) NULL);
execl("/bin/sh", "/bin/sh", "-c", key_binding->cmd, (char *) NULL);
}
break;
case ACTION_TOGGLE_MAXIMIZE:
{
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface))
wl_signal_emit(&view->xdg_toplevel->events.request_maximize, view->xdg_toplevel->base);
break;
} }
case ACTION_ICONIFY:
{
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface))
{
view->xdg_toplevel->requested.minimized = true;
wl_signal_emit(&view->xdg_toplevel->events.request_minimize, view->xdg_toplevel->base);
struct wb_view *previous_view = wl_container_of(server->views.prev, previous_view, link);
focus_view(previous_view, previous_view->xdg_toplevel->base->surface);
}
break;
}
case ACTION_SHADE:
{
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface))
{
view->previous_position = view->current_position;
wlr_xdg_toplevel_set_size(view->xdg_toplevel->base,
view->current_position.width, view->decoration_height);
}
break;
}
case ACTION_UNSHADE:
{
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface))
{
#if WLR_CHECK_VERSION(0, 16, 0)
wlr_xdg_toplevel_set_size(view->xdg_toplevel,
view->previous_position.width, view->previous_position.height);
#else
wlr_xdg_toplevel_set_size(view->xdg_surface,
view->previous_position.width, view->previous_position.height);
#endif
}
break;
}
case ACTION_RECONFIGURE:
deinit_config(server->config);
init_config(server);
break;
case ACTION_EXIT:
wl_display_terminate(server->wl_display);
break;
default:
continue;
} }
if (key_binding->action & ACTION_TOGGLE_MAXIMIZE) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface))
wl_signal_emit(&view->xdg_toplevel->events.request_maximize, view->xdg_toplevel->base);
}
if (key_binding->action & ACTION_ICONIFY) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface)) {
view->xdg_toplevel->requested.minimized = true;
wl_signal_emit(&view->xdg_toplevel->events.request_minimize, view->xdg_toplevel->base);
struct wb_view *previous_view = wl_container_of(server->views.prev, previous_view, link);
focus_view(previous_view, previous_view->xdg_toplevel->base->surface);
}
}
if (key_binding->action & ACTION_SHADE) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface)) {
view->previous_position = view->current_position;
#if WLR_CHECK_VERSION(0, 16, 0)
wlr_xdg_toplevel_set_size(view->xdg_toplevel,
view->current_position.width, view->decoration_height);
#else
wlr_xdg_toplevel_set_size(view->xdg_surface,
view->current_position.width, view->decoration_height);
#endif
}
}
if (key_binding->action & ACTION_UNSHADE) {
struct wb_view *view = wl_container_of(server->views.next, view, link);
if (wlr_surface_is_xdg_surface(view->xdg_toplevel->base->surface)) {
#if WLR_CHECK_VERSION(0, 16, 0)
wlr_xdg_toplevel_set_size(view->xdg_toplevel,
view->previous_position.width, view->previous_position.height);
#else
wlr_xdg_toplevel_set_size(view->xdg_surface,
view->previous_position.width, view->previous_position.height);
#endif
}
}
if (key_binding->action & ACTION_RECONFIGURE) {
deinit_config(server->config);
init_config(server);
}
if (key_binding->action & ACTION_EXIT)
wl_display_terminate(server->wl_display);
return true; return true;
} }
} }
@ -216,8 +198,7 @@ static void handle_new_keyboard(struct wb_server *server,
/* We need to prepare an XKB keymap and assign it to the keyboard. */ /* We need to prepare an XKB keymap and assign it to the keyboard. */
struct xkb_rule_names *rules = malloc(sizeof(struct xkb_rule_names)); struct xkb_rule_names *rules = malloc(sizeof(struct xkb_rule_names));
if (server->config && server->config->keyboard_layout.use_config) if (server->config && server->config->keyboard_layout.use_config) {
{
if (server->config->keyboard_layout.layout) if (server->config->keyboard_layout.layout)
rules->layout = server->config->keyboard_layout.layout; rules->layout = server->config->keyboard_layout.layout;
if (server->config->keyboard_layout.model) if (server->config->keyboard_layout.model)