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;
}
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) {
/* Get the 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 */
xmlAttr *keycomb = object->nodesetval->nodeTab[i]->properties;
while (strcmp((char *) keycomb->name, "key") != 0)
{
keycomb = keycomb->next;
}
char *sym;
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));
key_bind->sym = 0;
key_bind->modifiers = 0;
while ((s = strtok(sym, "-")) != NULL)
{
while ((s = strtok(sym, "-")) != NULL) {
if (strcmp(s, "A") == 0 || strcmp(s, "Alt") == 0)
modifiers |= WLR_MODIFIER_ALT;
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 */
xmlNode *cur_node;
xmlNode *new_node = object->nodesetval->nodeTab[i]->children;
xmlAttr *attr;
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;
}
}
get_action(new_node, key_bind);
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));
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.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);

View file

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

View file

@ -51,8 +51,7 @@ static bool handle_keybinding(struct wb_server *server, xkb_keysym_t sym, uint32
* client.
*/
if (!server->config)
{
if (!server->config) {
/* Some default key bindings, when the rc.xml file can't be
* parsed. */
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;
wl_list_for_each(key_binding, &server->config->key_bindings, link) {
if (sym == key_binding->sym && modifiers == key_binding->modifiers)
{
switch (key_binding->action)
{
case ACTION_NEXT_WINDOW:
cycle_views(server);
break;
case ACTION_PREVIOUS_WINDOW:
cycle_views_reverse(server);
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 (sym == key_binding->sym && modifiers == key_binding->modifiers) {
if (key_binding->action & ACTION_NEXT_WINDOW)
cycle_views(server);
if (key_binding->action & ACTION_PREVIOUS_WINDOW)
cycle_views_reverse(server);
if (key_binding->action & 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)
wlr_xdg_toplevel_send_close(current_view->xdg_toplevel);
wlr_xdg_toplevel_send_close(current_view->xdg_toplevel);
#else
wlr_xdg_toplevel_send_close(current_view->xdg_surface);
wlr_xdg_toplevel_send_close(current_view->xdg_surface);
#endif
break;
}
case ACTION_EXECUTE:
if (fork() == 0) {
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;
}
if (key_binding->action & ACTION_EXECUTE) {
if (fork() == 0) {
execl("/bin/sh", "/bin/sh", "-c", key_binding->cmd, (char *) NULL);
}
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;
}
}
@ -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. */
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)
rules->layout = server->config->keyboard_layout.layout;
if (server->config->keyboard_layout.model)