mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	Rewrite action handling to allow multiple actions at once
This commit is contained in:
		
							parent
							
								
									a54ce40e1c
								
							
						
					
					
						commit
						0b45cce648
					
				
					 12 changed files with 276 additions and 140 deletions
				
			
		
							
								
								
									
										13
									
								
								include/action.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/action.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					/* 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
 | 
				
			||||||
| 
						 | 
					@ -11,8 +11,7 @@ struct keybind {
 | 
				
			||||||
	uint32_t modifiers;
 | 
						uint32_t modifiers;
 | 
				
			||||||
	xkb_keysym_t *keysyms;
 | 
						xkb_keysym_t *keysyms;
 | 
				
			||||||
	size_t keysyms_len;
 | 
						size_t keysyms_len;
 | 
				
			||||||
	char *action;
 | 
						struct wl_list actions;
 | 
				
			||||||
	char *command;
 | 
					 | 
				
			||||||
	struct wl_list link;
 | 
						struct wl_list link;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,8 +24,7 @@ struct mousebind {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* ex: doubleclick, press, drag */
 | 
						/* ex: doubleclick, press, drag */
 | 
				
			||||||
	enum mouse_event mouse_event;
 | 
						enum mouse_event mouse_event;
 | 
				
			||||||
	const char *action;
 | 
						struct wl_list actions;
 | 
				
			||||||
	const char *command;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_list link; /* rcxml::mousebinds */
 | 
						struct wl_list link; /* rcxml::mousebinds */
 | 
				
			||||||
	bool pressed_in_context; /* used in click events */
 | 
						bool pressed_in_context; /* used in click events */
 | 
				
			||||||
| 
						 | 
					@ -34,6 +33,5 @@ struct mousebind {
 | 
				
			||||||
enum mouse_event mousebind_event_from_str(const char *str);
 | 
					enum mouse_event mousebind_event_from_str(const char *str);
 | 
				
			||||||
uint32_t mousebind_button_from_str(const char *str, uint32_t *modifiers);
 | 
					uint32_t mousebind_button_from_str(const char *str, uint32_t *modifiers);
 | 
				
			||||||
struct mousebind *mousebind_create(const char *context);
 | 
					struct mousebind *mousebind_create(const char *context);
 | 
				
			||||||
struct mousebind *mousebind_create_from(struct mousebind *from, const char *context);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __LABWC_MOUSEBIND_H */
 | 
					#endif /* __LABWC_MOUSEBIND_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -500,8 +500,8 @@ void server_init(struct server *server);
 | 
				
			||||||
void server_start(struct server *server);
 | 
					void server_start(struct server *server);
 | 
				
			||||||
void server_finish(struct server *server);
 | 
					void server_finish(struct server *server);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void action(struct view *activator, struct server *server, const char *action,
 | 
					void action(struct view *activator, struct server *server,
 | 
				
			||||||
	const char *command, uint32_t resize_edges);
 | 
						struct wl_list *actions, uint32_t resize_edges);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* update onscreen display 'alt-tab' texture */
 | 
					/* update onscreen display 'alt-tab' texture */
 | 
				
			||||||
void osd_update(struct server *server);
 | 
					void osd_update(struct server *server);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,8 +6,7 @@
 | 
				
			||||||
#include <wlr/render/wlr_renderer.h>
 | 
					#include <wlr/render/wlr_renderer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct menuitem {
 | 
					struct menuitem {
 | 
				
			||||||
	char *action;
 | 
						struct wl_list actions;
 | 
				
			||||||
	char *command;
 | 
					 | 
				
			||||||
	struct menu *submenu;
 | 
						struct menu *submenu;
 | 
				
			||||||
	struct wlr_box box;
 | 
						struct wlr_box box;
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										180
									
								
								src/action.c
									
										
									
									
									
								
							
							
						
						
									
										180
									
								
								src/action.c
									
										
									
									
									
								
							| 
						 | 
					@ -4,6 +4,78 @@
 | 
				
			||||||
#include "common/spawn.h"
 | 
					#include "common/spawn.h"
 | 
				
			||||||
#include "labwc.h"
 | 
					#include "labwc.h"
 | 
				
			||||||
#include "menu/menu.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
 | 
					static void
 | 
				
			||||||
show_menu(struct server *server, const char *menu)
 | 
					show_menu(struct server *server, const char *menu)
 | 
				
			||||||
| 
						 | 
					@ -26,85 +98,123 @@ activator_or_focused_view(struct view *activator, struct server *server)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					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;
 | 
							return;
 | 
				
			||||||
	if (!strcasecmp(action, "Close")) {
 | 
						}
 | 
				
			||||||
		struct view *view = activator_or_focused_view(activator, server);
 | 
					
 | 
				
			||||||
 | 
						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) {
 | 
								if (view) {
 | 
				
			||||||
				view_close(view);
 | 
									view_close(view);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "Debug")) {
 | 
								break;
 | 
				
			||||||
 | 
							case ACTION_TYPE_DEBUG:;
 | 
				
			||||||
			/* nothing */
 | 
								/* nothing */
 | 
				
			||||||
	} else if (!strcasecmp(action, "Execute")) {
 | 
								break;
 | 
				
			||||||
 | 
							case ACTION_TYPE_EXECUTE:;
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
				struct buf cmd;
 | 
									struct buf cmd;
 | 
				
			||||||
				buf_init(&cmd);
 | 
									buf_init(&cmd);
 | 
				
			||||||
		buf_add(&cmd, command);
 | 
									buf_add(&cmd, action->arg);
 | 
				
			||||||
				buf_expand_shell_variables(&cmd);
 | 
									buf_expand_shell_variables(&cmd);
 | 
				
			||||||
				spawn_async_no_shell(cmd.buf);
 | 
									spawn_async_no_shell(cmd.buf);
 | 
				
			||||||
				free(cmd.buf);
 | 
									free(cmd.buf);
 | 
				
			||||||
	} else if (!strcasecmp(action, "Exit")) {
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case ACTION_TYPE_EXIT:;
 | 
				
			||||||
			wl_display_terminate(server->wl_display);
 | 
								wl_display_terminate(server->wl_display);
 | 
				
			||||||
	} else if (!strcasecmp(action, "MoveToEdge")) {
 | 
								break;
 | 
				
			||||||
		view_move_to_edge(activator_or_focused_view(activator, server), command);
 | 
							case ACTION_TYPE_MOVE_TO_EDGE:;
 | 
				
			||||||
	} else if (!strcasecmp(action, "SnapToEdge")) {
 | 
								view_move_to_edge(view, action->arg);
 | 
				
			||||||
		view_snap_to_edge(activator_or_focused_view(activator, server), command);
 | 
								break;
 | 
				
			||||||
	} else if (!strcasecmp(action, "NextWindow")) {
 | 
							case ACTION_TYPE_SNAP_TO_EDGE:;
 | 
				
			||||||
 | 
								view_snap_to_edge(view, action->arg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case ACTION_TYPE_NEXT_WINDOW:;
 | 
				
			||||||
			server->cycle_view =
 | 
								server->cycle_view =
 | 
				
			||||||
				desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_FORWARD);
 | 
									desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_FORWARD);
 | 
				
			||||||
			osd_update(server);
 | 
								osd_update(server);
 | 
				
			||||||
	} else if (!strcasecmp(action, "PreviousWindow")) {
 | 
								break;
 | 
				
			||||||
 | 
							case ACTION_TYPE_PREVIOUS_WINDOW:;
 | 
				
			||||||
			server->cycle_view =
 | 
								server->cycle_view =
 | 
				
			||||||
				desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_BACKWARD);
 | 
									desktop_cycle_view(server, server->cycle_view, LAB_CYCLE_DIR_BACKWARD);
 | 
				
			||||||
			osd_update(server);
 | 
								osd_update(server);
 | 
				
			||||||
	} else if (!strcasecmp(action, "Reconfigure")) {
 | 
								break;
 | 
				
			||||||
 | 
							case ACTION_TYPE_RECONFIGURE:;
 | 
				
			||||||
 | 
								/* Should be changed to signal() */
 | 
				
			||||||
			spawn_async_no_shell("killall -SIGHUP labwc");
 | 
								spawn_async_no_shell("killall -SIGHUP labwc");
 | 
				
			||||||
	} else if (!strcasecmp(action, "ShowMenu")) {
 | 
								break;
 | 
				
			||||||
		show_menu(server, command);
 | 
							case ACTION_TYPE_SHOW_MENU:;
 | 
				
			||||||
	} else if (!strcasecmp(action, "ToggleMaximize")) {
 | 
								show_menu(server, action->arg);
 | 
				
			||||||
		struct view *view = activator_or_focused_view(activator, server);
 | 
								break;
 | 
				
			||||||
 | 
							case ACTION_TYPE_TOGGLE_MAXIMIZE:;
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				view_toggle_maximize(view);
 | 
									view_toggle_maximize(view);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "ToggleFullscreen")) {
 | 
								break;
 | 
				
			||||||
		struct view *view = activator_or_focused_view(activator, server);
 | 
							case ACTION_TYPE_TOGGLE_FULLSCREEN:;
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				view_toggle_fullscreen(view);
 | 
									view_toggle_fullscreen(view);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "ToggleDecorations")) {
 | 
								break;
 | 
				
			||||||
		struct view *view = activator_or_focused_view(activator, server);
 | 
							case ACTION_TYPE_TOGGLE_DECORATIONS:;
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				view_toggle_decorations(view);
 | 
									view_toggle_decorations(view);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "Focus")) {
 | 
								break;
 | 
				
			||||||
		struct view *view = desktop_view_at_cursor(server);
 | 
							case ACTION_TYPE_FOCUS:;
 | 
				
			||||||
 | 
								view = desktop_view_at_cursor(server);
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				desktop_focus_and_activate_view(&server->seat, view);
 | 
									desktop_focus_and_activate_view(&server->seat, view);
 | 
				
			||||||
				damage_all_outputs(server);
 | 
									damage_all_outputs(server);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "Iconify")) {
 | 
								break;
 | 
				
			||||||
		struct view *view = activator_or_focused_view(activator, server);
 | 
							case ACTION_TYPE_ICONIFY:;
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				view_minimize(view, true);
 | 
									view_minimize(view, true);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "Move")) {
 | 
								break;
 | 
				
			||||||
		struct view *view = desktop_view_at_cursor(server);
 | 
							case ACTION_TYPE_MOVE:;
 | 
				
			||||||
 | 
								view = desktop_view_at_cursor(server);
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				interactive_begin(view, LAB_INPUT_STATE_MOVE, 0);
 | 
									interactive_begin(view, LAB_INPUT_STATE_MOVE, 0);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "Raise")) {
 | 
								break;
 | 
				
			||||||
		struct view *view = activator_or_focused_view(activator, server);
 | 
							case ACTION_TYPE_RAISE:;
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				desktop_move_to_front(view);
 | 
									desktop_move_to_front(view);
 | 
				
			||||||
				damage_all_outputs(server);
 | 
									damage_all_outputs(server);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else if (!strcasecmp(action, "Resize")) {
 | 
								break;
 | 
				
			||||||
		struct view *view = desktop_view_at_cursor(server);
 | 
							case ACTION_TYPE_RESIZE:;
 | 
				
			||||||
 | 
								view = desktop_view_at_cursor(server);
 | 
				
			||||||
			if (view) {
 | 
								if (view) {
 | 
				
			||||||
				interactive_begin(view, LAB_INPUT_STATE_RESIZE, resize_edges);
 | 
									interactive_begin(view, LAB_INPUT_STATE_RESIZE, resize_edges);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	} else {
 | 
								break;
 | 
				
			||||||
		wlr_log(WLR_ERROR, "(%s) not supported", action);
 | 
							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);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,5 +61,6 @@ keybind_create(const char *keybind)
 | 
				
			||||||
	wl_list_insert(&rc.keybinds, &k->link);
 | 
						wl_list_insert(&rc.keybinds, &k->link);
 | 
				
			||||||
	k->keysyms = malloc(k->keysyms_len * sizeof(xkb_keysym_t));
 | 
						k->keysyms = malloc(k->keysyms_len * sizeof(xkb_keysym_t));
 | 
				
			||||||
	memcpy(k->keysyms, keysyms, 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;
 | 
						return k;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,19 +108,6 @@ mousebind_create(const char *context)
 | 
				
			||||||
	if (m->context != LAB_SSD_NONE) {
 | 
						if (m->context != LAB_SSD_NONE) {
 | 
				
			||||||
		wl_list_insert(&rc.mousebinds, &m->link);
 | 
							wl_list_insert(&rc.mousebinds, &m->link);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return m;
 | 
						wl_list_init(&m->actions);
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
	return m;
 | 
						return m;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
 | 
					#include "action.h"
 | 
				
			||||||
#include "common/dir.h"
 | 
					#include "common/dir.h"
 | 
				
			||||||
#include "common/nodename.h"
 | 
					#include "common/nodename.h"
 | 
				
			||||||
#include "common/string-helpers.h"
 | 
					#include "common/string-helpers.h"
 | 
				
			||||||
| 
						 | 
					@ -29,6 +30,8 @@ static struct keybind *current_keybind;
 | 
				
			||||||
static struct mousebind *current_mousebind;
 | 
					static struct mousebind *current_mousebind;
 | 
				
			||||||
static struct libinput_category *current_libinput_category;
 | 
					static struct libinput_category *current_libinput_category;
 | 
				
			||||||
static const char *current_mouse_context;
 | 
					static const char *current_mouse_context;
 | 
				
			||||||
 | 
					static struct action *current_keybind_action;
 | 
				
			||||||
 | 
					static struct action *current_mousebind_action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum font_place {
 | 
					enum font_place {
 | 
				
			||||||
	FONT_PLACE_UNKNOWN = 0,
 | 
						FONT_PLACE_UNKNOWN = 0,
 | 
				
			||||||
| 
						 | 
					@ -59,13 +62,15 @@ fill_keybind(char *nodename, char *content)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!strcmp(nodename, "name.action")) {
 | 
						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")) {
 | 
						} else if (!strcmp(nodename, "command.action")) {
 | 
				
			||||||
		current_keybind->command = strdup(content);
 | 
							current_keybind_action->arg = strdup(content);
 | 
				
			||||||
	} else if (!strcmp(nodename, "direction.action")) {
 | 
						} else if (!strcmp(nodename, "direction.action")) {
 | 
				
			||||||
		current_keybind->command = strdup(content);
 | 
							current_keybind_action->arg = strdup(content);
 | 
				
			||||||
	} else if (!strcmp(nodename, "menu.action")) {
 | 
						} else if (!strcmp(nodename, "menu.action")) {
 | 
				
			||||||
		current_keybind->command = strdup(content);
 | 
							current_keybind_action->arg = strdup(content);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,15 +104,15 @@ fill_mousebind(char *nodename, char *content)
 | 
				
			||||||
		current_mousebind->mouse_event =
 | 
							current_mousebind->mouse_event =
 | 
				
			||||||
			mousebind_event_from_str(content);
 | 
								mousebind_event_from_str(content);
 | 
				
			||||||
	} else if (!strcmp(nodename, "name.action")) {
 | 
						} else if (!strcmp(nodename, "name.action")) {
 | 
				
			||||||
		if (current_mousebind->action) {
 | 
							current_mousebind_action = action_create(content);
 | 
				
			||||||
			current_mousebind = mousebind_create_from(current_mousebind,
 | 
							wl_list_insert(current_mousebind->actions.prev,
 | 
				
			||||||
				current_mouse_context);
 | 
								¤t_mousebind_action->link);
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		current_mousebind->action = strdup(content);
 | 
					 | 
				
			||||||
	} else if (!strcmp(nodename, "command.action")) {
 | 
						} 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")) {
 | 
						} else if (!strcmp(nodename, "menu.action")) {
 | 
				
			||||||
		current_mousebind->command = strdup(content);
 | 
							current_mousebind_action->arg = strdup(content);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -476,14 +481,19 @@ static struct {
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
load_default_key_bindings(void)
 | 
					load_default_key_bindings(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct keybind *k;
 | 
				
			||||||
 | 
						struct action *action;
 | 
				
			||||||
	for (int i = 0; key_combos[i].binding; i++) {
 | 
						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) {
 | 
							if (!k) {
 | 
				
			||||||
			continue;
 | 
								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) {
 | 
							if (key_combos[i].command) {
 | 
				
			||||||
			k->command = strdup(key_combos[i].command);
 | 
								action->arg = strdup(key_combos[i].command);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -527,14 +537,19 @@ static struct {
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
load_default_mouse_bindings(void)
 | 
					load_default_mouse_bindings(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mousebind *m;
 | 
				
			||||||
 | 
						struct action *action;
 | 
				
			||||||
	for (int i = 0; mouse_combos[i].context; i++) {
 | 
						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->button = mousebind_button_from_str(mouse_combos[i].button,
 | 
				
			||||||
			&m->modifiers);
 | 
								&m->modifiers);
 | 
				
			||||||
		m->mouse_event = mousebind_event_from_str(mouse_combos[i].event);
 | 
							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) {
 | 
							if (mouse_combos[i].command) {
 | 
				
			||||||
			m->command = strdup(mouse_combos[i].command);
 | 
								action->arg = strdup(mouse_combos[i].command);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -635,6 +650,8 @@ no_config:
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
rcxml_finish(void)
 | 
					rcxml_finish(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct action *action, *action_tmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	zfree(rc.font_name_activewindow);
 | 
						zfree(rc.font_name_activewindow);
 | 
				
			||||||
	zfree(rc.font_name_menuitem);
 | 
						zfree(rc.font_name_menuitem);
 | 
				
			||||||
	zfree(rc.font_name_osd);
 | 
						zfree(rc.font_name_osd);
 | 
				
			||||||
| 
						 | 
					@ -643,8 +660,11 @@ rcxml_finish(void)
 | 
				
			||||||
	struct keybind *k, *k_tmp;
 | 
						struct keybind *k, *k_tmp;
 | 
				
			||||||
	wl_list_for_each_safe(k, k_tmp, &rc.keybinds, link) {
 | 
						wl_list_for_each_safe(k, k_tmp, &rc.keybinds, link) {
 | 
				
			||||||
		wl_list_remove(&k->link);
 | 
							wl_list_remove(&k->link);
 | 
				
			||||||
		zfree(k->command);
 | 
							wl_list_for_each_safe(action, action_tmp, &k->actions, link) {
 | 
				
			||||||
		zfree(k->action);
 | 
								wl_list_remove(&action->link);
 | 
				
			||||||
 | 
								zfree(action->arg);
 | 
				
			||||||
 | 
								zfree(action);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		zfree(k->keysyms);
 | 
							zfree(k->keysyms);
 | 
				
			||||||
		zfree(k);
 | 
							zfree(k);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -652,8 +672,11 @@ rcxml_finish(void)
 | 
				
			||||||
	struct mousebind *m, *m_tmp;
 | 
						struct mousebind *m, *m_tmp;
 | 
				
			||||||
	wl_list_for_each_safe(m, m_tmp, &rc.mousebinds, link) {
 | 
						wl_list_for_each_safe(m, m_tmp, &rc.mousebinds, link) {
 | 
				
			||||||
		wl_list_remove(&m->link);
 | 
							wl_list_remove(&m->link);
 | 
				
			||||||
		zfree(m->command);
 | 
							wl_list_for_each_safe(action, action_tmp, &m->actions, link) {
 | 
				
			||||||
		zfree(m->action);
 | 
								wl_list_remove(&action->link);
 | 
				
			||||||
 | 
								zfree(action->arg);
 | 
				
			||||||
 | 
								zfree(action);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		zfree(m);
 | 
							zfree(m);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -470,8 +470,7 @@ handle_release_mousebinding(struct view *view, struct server *server,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			activated_any = true;
 | 
								activated_any = true;
 | 
				
			||||||
			activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
 | 
								activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
 | 
				
			||||||
			action(view, server, mousebind->action,
 | 
								action(view, server, &mousebind->actions, resize_edges);
 | 
				
			||||||
				mousebind->command, resize_edges);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return activated_any && activated_any_frame;
 | 
						return activated_any && activated_any_frame;
 | 
				
			||||||
| 
						 | 
					@ -532,8 +531,7 @@ handle_press_mousebinding(struct view *view, struct server *server,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			activated_any = true;
 | 
								activated_any = true;
 | 
				
			||||||
			activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
 | 
								activated_any_frame |= mousebind->context == LAB_SSD_FRAME;
 | 
				
			||||||
			action(view, server, mousebind->action,
 | 
								action(view, server, &mousebind->actions, resize_edges);
 | 
				
			||||||
				mousebind->command, resize_edges);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return activated_any && activated_any_frame;
 | 
						return activated_any && activated_any_frame;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,8 +67,7 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym)
 | 
				
			||||||
		for (size_t i = 0; i < keybind->keysyms_len; i++) {
 | 
							for (size_t i = 0; i < keybind->keysyms_len; i++) {
 | 
				
			||||||
			if (xkb_keysym_to_lower(sym) == keybind->keysyms[i]) {
 | 
								if (xkb_keysym_to_lower(sym) == keybind->keysyms[i]) {
 | 
				
			||||||
				wlr_keyboard_set_repeat_info(kb, 0, 0);
 | 
									wlr_keyboard_set_repeat_info(kb, 0, 0);
 | 
				
			||||||
				action(NULL, server, keybind->action,
 | 
									action(NULL, server, &keybind->actions, 0);
 | 
				
			||||||
				       keybind->command, 0);
 | 
					 | 
				
			||||||
				return true;
 | 
									return true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@
 | 
				
			||||||
#include "labwc.h"
 | 
					#include "labwc.h"
 | 
				
			||||||
#include "menu/menu.h"
 | 
					#include "menu/menu.h"
 | 
				
			||||||
#include "theme.h"
 | 
					#include "theme.h"
 | 
				
			||||||
 | 
					#include "action.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MENUWIDTH (110)
 | 
					#define MENUWIDTH (110)
 | 
				
			||||||
#define MENU_ITEM_PADDING_Y (4)
 | 
					#define MENU_ITEM_PADDING_Y (4)
 | 
				
			||||||
| 
						 | 
					@ -26,6 +27,7 @@
 | 
				
			||||||
/* state-machine variables for processing <item></item> */
 | 
					/* state-machine variables for processing <item></item> */
 | 
				
			||||||
static bool in_item;
 | 
					static bool in_item;
 | 
				
			||||||
static struct menuitem *current_item;
 | 
					static struct menuitem *current_item;
 | 
				
			||||||
 | 
					static struct action *current_item_action;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int menu_level;
 | 
					static int menu_level;
 | 
				
			||||||
static struct menu *current_menu;
 | 
					static struct menu *current_menu;
 | 
				
			||||||
| 
						 | 
					@ -94,6 +96,7 @@ item_create(struct menu *menu, const char *text)
 | 
				
			||||||
	menuitem->texture.offset_x = MENU_ITEM_PADDING_X;
 | 
						menuitem->texture.offset_x = MENU_ITEM_PADDING_X;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_insert(&menu->menuitems, &menuitem->link);
 | 
						wl_list_insert(&menu->menuitems, &menuitem->link);
 | 
				
			||||||
 | 
						wl_list_init(&menuitem->actions);
 | 
				
			||||||
	return menuitem;
 | 
						return menuitem;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,15 +116,17 @@ fill_item(char *nodename, char *content)
 | 
				
			||||||
	/* <item label=""> defines the start of a new item */
 | 
						/* <item label=""> defines the start of a new item */
 | 
				
			||||||
	if (!strcmp(nodename, "label")) {
 | 
						if (!strcmp(nodename, "label")) {
 | 
				
			||||||
		current_item = item_create(current_menu, content);
 | 
							current_item = item_create(current_menu, content);
 | 
				
			||||||
	}
 | 
						} else if (!current_item) {
 | 
				
			||||||
	if (!current_item) {
 | 
							wlr_log(WLR_ERROR, "expect <item label=\"\"> element first. "
 | 
				
			||||||
		wlr_log(WLR_ERROR, "expect <item label=\"\"> element first");
 | 
								"nodename: '%s' content: '%s'", nodename, content);
 | 
				
			||||||
		return;
 | 
						} else if (!strcmp(nodename, "name.action")) {
 | 
				
			||||||
	}
 | 
							current_item_action = action_create(content);
 | 
				
			||||||
	if (!strcmp(nodename, "name.action")) {
 | 
							wl_list_insert(current_item->actions.prev, ¤t_item_action->link);
 | 
				
			||||||
		current_item->action = strdup(content);
 | 
						} 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")) {
 | 
						} else if (!strcmp(nodename, "command.action")) {
 | 
				
			||||||
		current_item->command = strdup(content);
 | 
							current_item_action->arg = strdup(content);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -310,9 +315,9 @@ menu_init_rootmenu(struct server *server)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (wl_list_empty(&server->rootmenu->menuitems)) {
 | 
						if (wl_list_empty(&server->rootmenu->menuitems)) {
 | 
				
			||||||
		current_item = item_create(server->rootmenu, "Reconfigure");
 | 
							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 = item_create(server->rootmenu, "Exit");
 | 
				
			||||||
		current_item->action = strdup("Exit");
 | 
							fill_item("name.action", "Exit");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	server->rootmenu->visible = true;
 | 
						server->rootmenu->visible = true;
 | 
				
			||||||
| 
						 | 
					@ -323,13 +328,17 @@ void
 | 
				
			||||||
menu_finish(void)
 | 
					menu_finish(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct menu *menu;
 | 
						struct menu *menu;
 | 
				
			||||||
 | 
						struct action *action, *action_tmp;
 | 
				
			||||||
	for (int i = 0; i < nr_menus; ++i) {
 | 
						for (int i = 0; i < nr_menus; ++i) {
 | 
				
			||||||
		menu = menus + i;
 | 
							menu = menus + i;
 | 
				
			||||||
		struct menuitem *item, *next;
 | 
							struct menuitem *item, *next;
 | 
				
			||||||
		wl_list_for_each_safe(item, next, &menu->menuitems, link) {
 | 
							wl_list_for_each_safe(item, next, &menu->menuitems, link) {
 | 
				
			||||||
			zfree(item->action);
 | 
					 | 
				
			||||||
			zfree(item->command);
 | 
					 | 
				
			||||||
			wl_list_remove(&item->link);
 | 
								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);
 | 
								free(item);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -416,7 +425,7 @@ menu_action_selected(struct server *server, struct menu *menu)
 | 
				
			||||||
	struct menuitem *menuitem;
 | 
						struct menuitem *menuitem;
 | 
				
			||||||
	wl_list_for_each (menuitem, &menu->menuitems, link) {
 | 
						wl_list_for_each (menuitem, &menu->menuitems, link) {
 | 
				
			||||||
		if (menuitem->selected && !menuitem->submenu) {
 | 
							if (menuitem->selected && !menuitem->submenu) {
 | 
				
			||||||
			action(NULL, server, menuitem->action, menuitem->command, 0);
 | 
								action(NULL, server, &menuitem->actions, 0);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (menuitem->submenu) {
 | 
							if (menuitem->submenu) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue