Merge pull request #848 from lukasrad02/feature-mouse-action-context
Add mouse action to show context menu
This commit is contained in:
		
						commit
						652cb7efb4
					
				| @ -511,7 +511,7 @@ single notification. | ||||
| To avoid the corners clipping the icon or text the corner radius will be | ||||
| automatically lowered to half of the notification height if it exceeds it. | ||||
| 
 | ||||
| =item B<mouse_left/middle/right_click> (values: [none/do_action/close_current/close_all]) | ||||
| =item B<mouse_left/middle/right_click> (values: [none/do_action/close_current/close_all/context/context_all]) | ||||
| 
 | ||||
| Defines action of mouse click. A touch input in Wayland acts as a mouse left | ||||
| click. | ||||
| @ -524,7 +524,13 @@ Don't do anything. | ||||
| 
 | ||||
| =item B<do_action> (default for mouse_middle_click) | ||||
| 
 | ||||
| If the notification has exactly one action, or one is marked as default, invoke it. If there are multiple and no default, open the context menu. | ||||
| Invoke the action determined by the action_name rule. If there is no such | ||||
| action, open the context menu. | ||||
| 
 | ||||
| =item B<open_url> | ||||
| 
 | ||||
| If the notification has exactly one url, open it. If there are multiple | ||||
| ones, open the context menu. | ||||
| 
 | ||||
| =item B<close_current> (default for mouse_left_click) | ||||
| 
 | ||||
| @ -534,6 +540,14 @@ Close current notification. | ||||
| 
 | ||||
| Close all notifications. | ||||
| 
 | ||||
| =item B<context> | ||||
| 
 | ||||
| Open context menu for the notification. | ||||
| 
 | ||||
| =item B<context_all> | ||||
| 
 | ||||
| Open context menu for all notifications. | ||||
| 
 | ||||
| =back | ||||
| 
 | ||||
| 
 | ||||
| @ -860,6 +874,13 @@ later. Use C<msg_urgency> to match it. | ||||
| Setting this to true will prevent the notification from being displayed | ||||
| initially but will be saved in history for later viewing. | ||||
| 
 | ||||
| =item C<action_name> | ||||
| 
 | ||||
| Sets the name of the action to be invoked on do_action. If not specified, the | ||||
| action set as default action or the only available action will be invoked. | ||||
| 
 | ||||
| Default: "default" | ||||
| 
 | ||||
| =back | ||||
| 
 | ||||
| As with the filtering attributes, each one corresponds to | ||||
|  | ||||
							
								
								
									
										9
									
								
								dunstrc
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								dunstrc
									
									
									
									
									
								
							| @ -277,10 +277,14 @@ | ||||
|     # Defines list of actions for each mouse event | ||||
|     # Possible values are: | ||||
|     # * none: Don't do anything. | ||||
|     # * do_action: If the notification has exactly one action, or one is marked as default, | ||||
|     #              invoke it. If there are multiple and no default, open the context menu. | ||||
|     # * do_action: Invoke the action determined by the action_name rule. If there is no | ||||
|     #              such action, open the context menu. | ||||
|     # * open_url: If the notification has exactly one url, open it. If there are multiple | ||||
|     #             ones, open the context menu. | ||||
|     # * close_current: Close current notification. | ||||
|     # * close_all: Close all notifications. | ||||
|     # * context: Open context menu for the notification. | ||||
|     # * context_all: Open context menu for all notifications. | ||||
|     # These values can be strung together for each mouse event, and | ||||
|     # will be executed in sequence. | ||||
|     mouse_left_click = close_current | ||||
| @ -373,6 +377,7 @@ | ||||
| #    set_transient | ||||
| #    timeout | ||||
| #    urgency | ||||
| #    action_name | ||||
| # | ||||
| # Shell-like globbing will get expanded. | ||||
| # | ||||
|  | ||||
							
								
								
									
										14
									
								
								src/input.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/input.c
									
									
									
									
									
								
							| @ -1,5 +1,6 @@ | ||||
| #include "input.h" | ||||
| #include "log.h" | ||||
| #include "menu.h" | ||||
| #include "settings.h" | ||||
| #include "queues.h" | ||||
| #include <stddef.h> | ||||
| @ -41,7 +42,12 @@ void input_handle_click(unsigned int button, bool button_down, int mouse_x, int | ||||
|                         return; | ||||
|                 } | ||||
| 
 | ||||
|                 if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT) { | ||||
|                 if (act == MOUSE_CONTEXT_ALL) { | ||||
|                         context_menu(); | ||||
|                         continue; | ||||
|                 } | ||||
| 
 | ||||
|                 if (act == MOUSE_DO_ACTION || act == MOUSE_CLOSE_CURRENT || act == MOUSE_CONTEXT || act == MOUSE_OPEN_URL) { | ||||
|                         int y = settings.separator_height; | ||||
|                         struct notification *n = NULL; | ||||
|                         int first = true; | ||||
| @ -59,8 +65,12 @@ void input_handle_click(unsigned int button, bool button_down, int mouse_x, int | ||||
|                         if (n) { | ||||
|                                 if (act == MOUSE_CLOSE_CURRENT) { | ||||
|                                         n->marked_for_closure = REASON_USER; | ||||
|                                 } else { | ||||
|                                 } else if (act == MOUSE_DO_ACTION) { | ||||
|                                         notification_do_action(n); | ||||
|                                 } else if (act == MOUSE_OPEN_URL) { | ||||
|                                         notification_open_url(n); | ||||
|                                 } else { | ||||
|                                         notification_open_context_menu(n); | ||||
|                                 } | ||||
|                         } | ||||
|                 } | ||||
|  | ||||
| @ -312,13 +312,19 @@ static GList *get_actionable_notifications(void) | ||||
| 
 | ||||
| /* see menu.h */ | ||||
| void context_menu(void) | ||||
| { | ||||
|         GList *notifications = get_actionable_notifications(); | ||||
|         context_menu_for(notifications); | ||||
| } | ||||
| 
 | ||||
| /* see menu.h */ | ||||
| void context_menu_for(GList *notifications) | ||||
| { | ||||
|         if (menu_ctx.locked_notifications) { | ||||
|                 LOG_W("Context menu already running, refusing to rerun"); | ||||
|                 return; | ||||
|         } | ||||
| 
 | ||||
|         GList *notifications = get_actionable_notifications(); | ||||
|         menu_ctx.locked_notifications = notifications; | ||||
| 
 | ||||
|         GError *err = NULL; | ||||
|  | ||||
							
								
								
									
										10
									
								
								src/menu.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/menu.h
									
									
									
									
									
								
							| @ -2,6 +2,8 @@ | ||||
| #ifndef DUNST_MENU_H | ||||
| #define DUNST_MENU_H | ||||
| 
 | ||||
| #include <glib.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * Extract all urls from the given string. | ||||
|  * | ||||
| @ -16,9 +18,15 @@ void invoke_action(const char *action); | ||||
| void regex_teardown(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * Open the context menu that lets the user select urls/actions/etc. | ||||
|  * Open the context menu that lets the user select urls/actions/etc for all displayed notifications. | ||||
|  */ | ||||
| void context_menu(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * Open the context menu that lets the user select urls/actions/etc for the specified notifications. | ||||
|  * @param notifications (nullable) List of notifications for which the context menu should be opened | ||||
|  */ | ||||
| void context_menu_for(GList *notifications); | ||||
| 
 | ||||
| #endif | ||||
| /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ | ||||
|  | ||||
| @ -288,6 +288,7 @@ void notification_unref(struct notification *n) | ||||
|         g_free(n->desktop_entry); | ||||
| 
 | ||||
|         g_hash_table_unref(n->actions); | ||||
|         g_free(n->default_action_name); | ||||
| 
 | ||||
|         if (n->icon) | ||||
|                 g_object_unref(n->icon); | ||||
| @ -386,6 +387,7 @@ struct notification *notification_create(void) | ||||
|         n->fullscreen = FS_SHOW; | ||||
| 
 | ||||
|         n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | ||||
|         n->default_action_name = g_strdup("default"); | ||||
| 
 | ||||
|         n->script_count = 0; | ||||
|         return n; | ||||
| @ -647,29 +649,45 @@ void notification_update_text_to_render(struct notification *n) | ||||
| } | ||||
| 
 | ||||
| /* see notification.h */ | ||||
| void notification_do_action(const struct notification *n) | ||||
| void notification_do_action(struct notification *n) | ||||
| { | ||||
|         assert(n->default_action_name); | ||||
|          | ||||
|         if (g_hash_table_size(n->actions)) { | ||||
|                 if (g_hash_table_contains(n->actions, "default")) { | ||||
|                         signal_action_invoked(n, "default"); | ||||
|                 if (g_hash_table_contains(n->actions, n->default_action_name)) { | ||||
|                         signal_action_invoked(n, n->default_action_name); | ||||
|                         return; | ||||
|                 } | ||||
|                 if (g_hash_table_size(n->actions) == 1) { | ||||
|                 if (strcmp(n->default_action_name, "default") == 0 && g_hash_table_size(n->actions) == 1) { | ||||
|                         GList *keys = g_hash_table_get_keys(n->actions); | ||||
|                         signal_action_invoked(n, keys->data); | ||||
|                         g_list_free(keys); | ||||
|                         return; | ||||
|                 } | ||||
|                 context_menu(); | ||||
|                 notification_open_context_menu(n); | ||||
| 
 | ||||
|         } else if (n->urls) { | ||||
|                 if (strstr(n->urls, "\n")) | ||||
|                         context_menu(); | ||||
|                 else | ||||
|                         open_browser(n->urls); | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| /* see notification.h */ | ||||
| void notification_open_url(struct notification *n) | ||||
| { | ||||
|         if (strstr(n->urls, "\n")) | ||||
|                 notification_open_context_menu(n); | ||||
|         else | ||||
|                 open_browser(n->urls); | ||||
| } | ||||
| 
 | ||||
| /* see notification.h */ | ||||
| void notification_open_context_menu(struct notification *n) | ||||
| { | ||||
|         GList *notifications = NULL; | ||||
|         notifications = g_list_append(notifications, n); | ||||
|         notification_lock(n); | ||||
| 
 | ||||
|         context_menu_for(notifications); | ||||
| } | ||||
| 
 | ||||
| void notification_invalidate_actions(struct notification *n) { | ||||
|         g_hash_table_remove_all(n->actions); | ||||
| } | ||||
|  | ||||
| @ -61,6 +61,7 @@ struct notification { | ||||
|         int locked;     /**< If non-zero the notification is locked **/ | ||||
| 
 | ||||
|         GHashTable *actions; | ||||
|         char *default_action_name; /**< The name of the action to be invoked on do_action */ | ||||
| 
 | ||||
|         enum markup_mode markup; | ||||
|         const char *format; | ||||
| @ -195,11 +196,24 @@ void notification_replace_single_field(char **haystack, | ||||
| void notification_update_text_to_render(struct notification *n); | ||||
| 
 | ||||
| /**
 | ||||
|  * If the notification has exactly one action, or one is marked as default, | ||||
|  * invoke it. If there are multiple and no default, open the context menu. If | ||||
|  * there are no actions, proceed similarly with urls. | ||||
|  * If the notification has an action named n->default_action_name or there is only one | ||||
|  * action and n->default_action_name is set to "default", invoke it. If there is no | ||||
|  * such action, open the context menu if threre are other actions. Otherwise, do nothing. | ||||
|  */ | ||||
| void notification_do_action(const struct notification *n); | ||||
| void notification_do_action(struct notification *n); | ||||
| 
 | ||||
| /**
 | ||||
|  * If the notification has exactly one url, invoke it. If there are multiple, | ||||
|  * open the context menu. If there are no urls, do nothing. | ||||
|  */ | ||||
| void notification_open_url(struct notification *n); | ||||
| 
 | ||||
| /**
 | ||||
|  * Open the context menu for the notification. | ||||
|  *  | ||||
|  * Convenience function that creates the GList and passes it to context_menu_for(). | ||||
|  */ | ||||
| void notification_open_context_menu(struct notification *n); | ||||
| 
 | ||||
| /**
 | ||||
|  * Remove all client action data from the notification. | ||||
|  | ||||
| @ -137,6 +137,9 @@ bool string_parse_mouse_action(const char *s, enum mouse_action *ret) | ||||
|         STRING_PARSE_RET("do_action",      MOUSE_DO_ACTION); | ||||
|         STRING_PARSE_RET("close_current",  MOUSE_CLOSE_CURRENT); | ||||
|         STRING_PARSE_RET("close_all",      MOUSE_CLOSE_ALL); | ||||
|         STRING_PARSE_RET("context",        MOUSE_CONTEXT); | ||||
|         STRING_PARSE_RET("context_all",    MOUSE_CONTEXT_ALL); | ||||
|         STRING_PARSE_RET("open_url",       MOUSE_OPEN_URL); | ||||
| 
 | ||||
|         return false; | ||||
| } | ||||
|  | ||||
| @ -26,6 +26,10 @@ void rule_apply(struct rule *r, struct notification *n) | ||||
|                 n->transient = r->set_transient; | ||||
|         if (r->skip_display != -1) | ||||
|                 n->skip_display = r->skip_display; | ||||
|         if (r->action_name) { | ||||
|                 g_free(n->default_action_name); | ||||
|                 n->default_action_name = g_strdup(r->action_name); | ||||
|         } | ||||
|         if (r->markup != MARKUP_NULL) | ||||
|                 n->markup = r->markup; | ||||
|         if (r->new_icon) | ||||
|  | ||||
| @ -23,6 +23,7 @@ struct rule { | ||||
|         /* actions */ | ||||
|         gint64 timeout; | ||||
|         enum urgency urgency; | ||||
|         char *action_name; | ||||
|         enum markup_mode markup; | ||||
|         int history_ignore; | ||||
|         int match_transient; | ||||
|  | ||||
| @ -862,6 +862,7 @@ void load_settings(char *cmdline_config_path) | ||||
|                         g_free(c); | ||||
|                 } | ||||
| 
 | ||||
|                 r->action_name = ini_get_string(cur_section, "action_name", NULL); | ||||
|                 r->urgency = ini_get_urgency(cur_section, "urgency", r->urgency); | ||||
|                 r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency); | ||||
|                 r->fg = ini_get_string(cur_section, "foreground", r->fg); | ||||
|  | ||||
| @ -18,7 +18,7 @@ enum icon_position { ICON_LEFT, ICON_RIGHT, ICON_OFF }; | ||||
| enum vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM }; | ||||
| enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM }; | ||||
| enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD }; | ||||
| enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL }; | ||||
| enum mouse_action { MOUSE_NONE, MOUSE_DO_ACTION, MOUSE_CLOSE_CURRENT, MOUSE_CLOSE_ALL, MOUSE_CONTEXT, MOUSE_CONTEXT_ALL, MOUSE_OPEN_URL }; | ||||
| #ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM | ||||
| #define ZWLR_LAYER_SHELL_V1_LAYER_ENUM | ||||
| // Needed for compiling without wayland dependency
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikos Tsipinakis
						Nikos Tsipinakis