mirror of
				https://github.com/labwc/labwc.git
				synced 2025-10-29 05:40:24 -04:00 
			
		
		
		
	First implemenation of <mouse> in rc.xml
Can successfully parse the following XML and and implement the action:
<mouse>
    <context name="TitleBar">
        <mousebind button="Left" action="DoubleClick">
            <action name="ToggleMaximize"/>
        </mousebind>
    </context>
</mouse>
The XML parsing code for this looks A LOT different than the already
existing XML parsing code. It may have to be reworked
			
			
This commit is contained in:
		
							parent
							
								
									75564d6b8d
								
							
						
					
					
						commit
						dfdb4e4b0e
					
				
					 6 changed files with 335 additions and 1 deletions
				
			
		
							
								
								
									
										41
									
								
								include/config/mousebind.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								include/config/mousebind.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| #ifndef __LABWC_MOUSEBIND_H | ||||
| #define __LABWC_MOUSEBIND_H | ||||
| 
 | ||||
| #include <wayland-util.h> | ||||
| 
 | ||||
| enum mouse_context { | ||||
| 	MOUSE_CONTEXT_TITLEBAR, | ||||
| 	MOUSE_CONTEXT_NONE | ||||
| }; | ||||
| 
 | ||||
| enum mouse_button { | ||||
| 	/*
 | ||||
| 	 * These values match the values returned by button event->button and were | ||||
| 	 * obtained experimentally | ||||
| 	 */ | ||||
| 	MOUSE_BUTTON_LEFT = 272, | ||||
| 	MOUSE_BUTTON_RIGHT = 273, | ||||
| 	MOUSE_BUTTON_MIDDLE = 274, | ||||
| 	MOUSE_BUTTON_NONE = -1 | ||||
| }; | ||||
| 
 | ||||
| enum action_mouse_did { | ||||
| 	MOUSE_ACTION_DOUBLECLICK, | ||||
| 	MOUSE_ACTION_NONE | ||||
| }; | ||||
| 
 | ||||
| struct mousebind { | ||||
| 	enum mouse_context context; /* ex: titlebar */ | ||||
| 	enum mouse_button button; /* ex: left, right, middle */ | ||||
| 	enum action_mouse_did mouse_action; /* ex: doubleclick, press, drag, etc */ | ||||
| 	const char* action; /* what to do because mouse did previous action */ | ||||
| 	const char* command; | ||||
| 	struct wl_list link; | ||||
| }; | ||||
| 
 | ||||
| struct mousebind* | ||||
| mousebind_create(const char* context_str, const char* mouse_button_str, | ||||
| 		const char* action_mouse_did_str, const char* action, | ||||
| 		const char* command); | ||||
| 
 | ||||
| #endif /* __LABWC_MOUSEBIND_H */ | ||||
|  | @ -19,6 +19,7 @@ struct rcxml { | |||
| 	int font_size_activewindow; | ||||
| 	int font_size_menuitem; | ||||
| 	struct wl_list keybinds; | ||||
| 	struct wl_list mousebinds; | ||||
| }; | ||||
| 
 | ||||
| extern struct rcxml rc; | ||||
|  |  | |||
|  | @ -2,4 +2,5 @@ labwc_sources += files( | |||
|   'rcxml.c', | ||||
|   'keybind.c', | ||||
|   'session.c', | ||||
|   'mousebind.c', | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										90
									
								
								src/config/mousebind.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/config/mousebind.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| #define _POSIX_C_SOURCE 200809L | ||||
| #include "config/mousebind.h" | ||||
| #include "config/rcxml.h" | ||||
| #include <wlr/util/log.h> | ||||
| #include <strings.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| static enum mouse_context | ||||
| context_from_str(const char* str) | ||||
| { | ||||
| 	if(str == NULL) { | ||||
| 		return MOUSE_CONTEXT_NONE; | ||||
| 	} | ||||
| 	else if(strcasecmp(str, "Titlebar") == 0) { | ||||
| 		return MOUSE_CONTEXT_TITLEBAR; | ||||
| 	} else { | ||||
| 		return MOUSE_CONTEXT_NONE; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static enum mouse_button | ||||
| mouse_button_from_str(const char* str) | ||||
| { | ||||
| 	if(str == NULL) { | ||||
| 		return MOUSE_BUTTON_NONE; | ||||
| 	} | ||||
| 	else if(strcasecmp(str, "Left") == 0) { | ||||
| 		return MOUSE_BUTTON_LEFT; | ||||
| 	} else if(strcasecmp(str, "Right") == 0) { | ||||
| 		return MOUSE_BUTTON_RIGHT; | ||||
| 	} else if(strcasecmp(str, "Middle") == 0) { | ||||
| 		return MOUSE_BUTTON_MIDDLE; | ||||
| 	} else { | ||||
| 		return MOUSE_BUTTON_NONE; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static enum action_mouse_did | ||||
| action_mouse_did_from_str(const char* str) | ||||
| { | ||||
| 	if(str == NULL) { | ||||
| 		return MOUSE_ACTION_NONE; | ||||
| 	} | ||||
| 	else if(strcasecmp(str, "doubleclick") == 0) { | ||||
| 		return MOUSE_ACTION_DOUBLECLICK; | ||||
| 	} else { | ||||
| 		return MOUSE_ACTION_NONE; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct mousebind* | ||||
| mousebind_create(const char* context_str, const char* mouse_button_str, | ||||
| 		const char* action_mouse_did_str, const char* action, | ||||
| 		const char* command) | ||||
| { | ||||
| 	struct mousebind* m = calloc(1, sizeof(struct mousebind)); | ||||
| 
 | ||||
| 	enum mouse_context context = context_from_str(context_str); | ||||
| 	enum mouse_button button = mouse_button_from_str(mouse_button_str); | ||||
| 	enum action_mouse_did action_mouse_did = action_mouse_did_from_str(action_mouse_did_str); | ||||
| 
 | ||||
| 	if(context == MOUSE_CONTEXT_NONE) { | ||||
| 		wlr_log(WLR_ERROR, "unknown mouse context (%s)", context_str); | ||||
| 		goto CREATE_ERROR; | ||||
| 	} | ||||
| 	if(button == MOUSE_BUTTON_NONE) { | ||||
| 		wlr_log(WLR_ERROR, "unknown button (%s)", mouse_button_str); | ||||
| 		goto CREATE_ERROR; | ||||
| 	} | ||||
| 	if(action_mouse_did == MOUSE_ACTION_NONE) { | ||||
| 		wlr_log(WLR_ERROR, "unknown mouse action (%s)", action_mouse_did_str); | ||||
| 		goto CREATE_ERROR; | ||||
| 	} | ||||
| 	if(action == NULL) { | ||||
| 		wlr_log(WLR_ERROR, "action is NULL\n"); | ||||
| 		goto CREATE_ERROR; | ||||
| 	} | ||||
| 
 | ||||
| 	m->context = context; | ||||
| 	m->button = button; | ||||
| 	m->mouse_action = action_mouse_did; | ||||
| 	m->action = strdup(action); /* TODO: replace with strndup? */ | ||||
| 	m->command = strdup(command); | ||||
| 
 | ||||
| 	return m; | ||||
| 
 | ||||
| CREATE_ERROR: | ||||
| 	free(m); | ||||
| 	return NULL; | ||||
| } | ||||
|  | @ -16,11 +16,13 @@ | |||
| #include "common/string-helpers.h" | ||||
| #include "common/zfree.h" | ||||
| #include "config/keybind.h" | ||||
| #include "config/mousebind.h" | ||||
| #include "config/rcxml.h" | ||||
| 
 | ||||
| static bool in_keybind = false; | ||||
| static bool is_attribute = false; | ||||
| static struct keybind *current_keybind; | ||||
| static const char* current_mouse_context = ""; | ||||
| 
 | ||||
| enum font_place { | ||||
| 	FONT_PLACE_UNKNOWN = 0, | ||||
|  | @ -223,6 +225,184 @@ traverse(xmlNode *n) | |||
| 	xml_tree_walk(n->children); | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| is_ignorable_node(const xmlNode* n) | ||||
| { | ||||
| 	if(n->type == XML_COMMENT_NODE) { | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if(n->type == XML_TEXT_NODE) { | ||||
| 		for(const char* s = (const char*)n->content; s && (*s != '\0'); s++) { | ||||
| 			if(!isspace(*s)) { | ||||
| 				return false; | ||||
| 			}  | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| traverse_mousebind_action(xmlNode* node, const char* button_str, const char* mouse_action) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * Right now, all we have implemented is: | ||||
| 	 * | ||||
| 	 * <action name="ToggleMaximize"/>             ] -- only supported attribute is "name" | ||||
| 	 * | ||||
| 	 * <action name="Execute>                     | ||||
| 	 *      <command>command text here</command>   ] -- if name is execute, we support a child node of name command | ||||
| 	 * </action>                                 | ||||
| 	 */ | ||||
| 	const char* action_to_do = ""; | ||||
| 	const char* command = ""; | ||||
| 	for(xmlAttr* attr = node->properties; attr; attr = attr->next) { | ||||
| 		if(strcasecmp((const char*)attr->name, "name") == 0) { | ||||
| 			action_to_do = (const char*)attr->children->content; | ||||
| 		} else { | ||||
| 			wlr_log(WLR_ERROR, "hit unexpected attr (%s) in mousebind action\n", (const char*) attr->name); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(strcasecmp((const char*)action_to_do, "Execute") == 0) { | ||||
| 		for(xmlNode* n = node->children; n && n->name; n = n->next) { | ||||
| 			if(strcasecmp((const char*)n->name, "command") == 0) { | ||||
| 				for(xmlNode* t = n->children; t; t = t->next) { | ||||
| 					if( (t->type == XML_TEXT_NODE) ) { | ||||
| 						command = (const char*)t->content; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	struct mousebind* mousebind = mousebind_create(current_mouse_context, | ||||
| 			button_str, | ||||
| 			mouse_action, | ||||
| 			action_to_do, | ||||
| 			command); | ||||
| 	if(mousebind != NULL) { | ||||
| 		wl_list_insert(&rc.mousebinds, &mousebind->link); | ||||
| 	} else { | ||||
| 		wlr_log(WLR_ERROR, "failed to create mousebind:\n" | ||||
| 						   "    context: (%s)\n" | ||||
| 						   "    button:  (%s)\n" | ||||
| 						   "    mouse action: (%s)\n" | ||||
| 						   "    action: (%s)\n" | ||||
| 						   "    command: (%s)\n", | ||||
| 						   current_mouse_context, | ||||
| 						   button_str, | ||||
| 						   mouse_action, | ||||
| 						   action_to_do, | ||||
| 						   command); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| traverse_mousebind(xmlNode* node) | ||||
| { | ||||
|     /*
 | ||||
|      * Right now, all we have implemented is: | ||||
|      * | ||||
|      *  this node | ||||
|      *     |          this node's only supported attributes are "button" and "action" | ||||
|      *     |              |            | | ||||
|      *     v              v            v | ||||
|      * <mousebind button="Left" action="DoubleClick>                  | ||||
|      *     <action name="ToggleMaximize"/>           -|  | ||||
|      *     <action name="Execute>                     | -- This node's only supported children are actions | ||||
|      *          <command>command text here</command>  |    | ||||
|      *     </action>                                 -|        | ||||
|      * </context>                | ||||
|      */ | ||||
| 	const char* button_str = ""; | ||||
| 	const char* action_mouse_did_str = ""; | ||||
| 	for(xmlAttr* attr = node->properties; attr; attr = attr->next) { | ||||
| 		if(strcasecmp((const char*)attr->name, "button") == 0) { | ||||
| 			button_str = (const char*)attr->children->content; | ||||
| 		} else if(strcasecmp((const char*)attr->name, "action") == 0) { | ||||
| 			action_mouse_did_str = (const char*)attr->children->content; | ||||
| 		} else { | ||||
| 			wlr_log(WLR_ERROR, "hit unexpected attr (%s) in mousebind\n", (const char*)attr->name); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for(xmlNode* n = node->children; n && n->name; n = n->next) { | ||||
| 		if(strcasecmp((const char*)n->name, "action") == 0) { | ||||
| 			traverse_mousebind_action(n, button_str, action_mouse_did_str); | ||||
| 		} else if(is_ignorable_node(n)) { | ||||
| 			continue; | ||||
| 		} else { | ||||
| 			wlr_log(WLR_ERROR, "hit unexpected node (%s) in mousebind\n", (const char*) n->name); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| traverse_context(xmlNode* node) | ||||
| { | ||||
|     /*
 | ||||
|      * Right now, all we have implemented is: | ||||
|      * | ||||
|      *  this node | ||||
|      *     |          this node's only supported attribute is "name" | ||||
|      *     |              | | ||||
|      *     v              v | ||||
|      * <context name="TitleBar"> | ||||
|      * 	  <mousebind....>     -| | ||||
|      *          ...            | -- This node's only supported child is mousebind | ||||
|      * 	  </mousebind>        -| | ||||
|      * </context> | ||||
|      */ | ||||
| 	for(xmlAttr* attr = node->properties; attr; attr = attr->next) { | ||||
| 		if(strcasecmp((const char*)attr->name, "name") == 0) { | ||||
| 			current_mouse_context = (const char*)attr->children->content; | ||||
| 		} else { | ||||
| 			wlr_log(WLR_ERROR, "hit unexpected attr (%s) in context\n", (const char*)attr->name); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for(xmlNode* n = node->children; n && n->name; n = n->next) { | ||||
| 		if(strcasecmp((const char*)n->name, "mousebind") == 0) { | ||||
| 			traverse_mousebind(n); | ||||
| 		} else if(is_ignorable_node(n)) { | ||||
| 			continue; | ||||
| 		} else { | ||||
| 			wlr_log(WLR_ERROR, "hit unexpected node (%s) in context\n", (const char*)n->name); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| traverse_mouse(xmlNode* node) | ||||
| { | ||||
|     /*
 | ||||
|      * Right now, all we have implemented is: | ||||
|      * | ||||
|      *  this node | ||||
|      *    | | ||||
|      *    | | ||||
|      *    v | ||||
|      * <mouse> | ||||
|      *     <context name="TitleBar"> -| | ||||
|      *     	<mousebind....>           | | ||||
|      *           ...                  | -- This node's only supported child is context | ||||
|      *     	</mousebind>              | | ||||
|      *     </context>                -| | ||||
|      * </mouse> | ||||
|      */ | ||||
| 	for(xmlNode* n = node->children; n && n->name; n = n->next) { | ||||
| 		if(strcasecmp((const char*)n->name, "context") == 0) { | ||||
| 			traverse_context(n); | ||||
| 		} else if(is_ignorable_node(n)) { | ||||
| 			continue; | ||||
| 		} else { | ||||
| 			wlr_log(WLR_ERROR, "hit unexpected node (%s) in mouse\n", (const char*)n->name); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| xml_tree_walk(xmlNode *node) | ||||
| { | ||||
|  | @ -235,6 +415,10 @@ xml_tree_walk(xmlNode *node) | |||
| 			traverse(n); | ||||
| 			in_keybind = false; | ||||
| 			continue; | ||||
| 		}  | ||||
| 		if(!strcasecmp((char *)n->name, "mouse")) { | ||||
| 			traverse_mouse(n); | ||||
| 			continue; | ||||
| 		} | ||||
| 		traverse(n); | ||||
| 	} | ||||
|  | @ -265,6 +449,7 @@ rcxml_init() | |||
| 	has_run = true; | ||||
| 	LIBXML_TEST_VERSION | ||||
| 	wl_list_init(&rc.keybinds); | ||||
| 	wl_list_init(&rc.mousebinds); | ||||
| 	rc.xdg_shell_server_side_deco = true; | ||||
| 	rc.corner_radius = 8; | ||||
| 	rc.font_size_activewindow = 10; | ||||
|  | @ -400,4 +585,12 @@ rcxml_finish(void) | |||
| 		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); | ||||
| 		zfree(m); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
							
								
								
									
										10
									
								
								src/cursor.c
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/cursor.c
									
										
									
									
									
								
							|  | @ -5,6 +5,7 @@ | |||
| #include "labwc.h" | ||||
| #include "menu/menu.h" | ||||
| #include "ssd.h" | ||||
| #include "config/mousebind.h" | ||||
| #include <wlr/types/wlr_primary_selection.h> | ||||
| 
 | ||||
| static void | ||||
|  | @ -343,7 +344,14 @@ cursor_button(struct wl_listener *listener, void *data) | |||
| 	damage_all_outputs(server); | ||||
| 
 | ||||
| 	if (is_double_click(500) && view_area == LAB_SSD_PART_TITLEBAR) { | ||||
| 		view_toggle_maximize(view); | ||||
| 		struct mousebind* mousebind; | ||||
| 		wl_list_for_each_reverse(mousebind, &rc.mousebinds, link) { | ||||
| 			if( (mousebind->context == MOUSE_CONTEXT_TITLEBAR) && | ||||
| 				(mousebind->mouse_action == MOUSE_ACTION_DOUBLECLICK) && | ||||
| 				(mousebind->button == (enum mouse_button)event->button) ) { | ||||
| 				action(server, mousebind->action, mousebind->command); | ||||
| 			} | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 alex
						alex