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
|
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.
|
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
|
Defines action of mouse click. A touch input in Wayland acts as a mouse left
|
||||||
click.
|
click.
|
||||||
@ -524,7 +524,13 @@ Don't do anything.
|
|||||||
|
|
||||||
=item B<do_action> (default for mouse_middle_click)
|
=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)
|
=item B<close_current> (default for mouse_left_click)
|
||||||
|
|
||||||
@ -534,6 +540,14 @@ Close current notification.
|
|||||||
|
|
||||||
Close all notifications.
|
Close all notifications.
|
||||||
|
|
||||||
|
=item B<context>
|
||||||
|
|
||||||
|
Open context menu for the notification.
|
||||||
|
|
||||||
|
=item B<context_all>
|
||||||
|
|
||||||
|
Open context menu for all notifications.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
||||||
@ -860,6 +874,13 @@ later. Use C<msg_urgency> to match it.
|
|||||||
Setting this to true will prevent the notification from being displayed
|
Setting this to true will prevent the notification from being displayed
|
||||||
initially but will be saved in history for later viewing.
|
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
|
=back
|
||||||
|
|
||||||
As with the filtering attributes, each one corresponds to
|
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
|
# Defines list of actions for each mouse event
|
||||||
# Possible values are:
|
# Possible values are:
|
||||||
# * none: Don't do anything.
|
# * none: Don't do anything.
|
||||||
# * do_action: If the notification has exactly one action, or one is marked as default,
|
# * do_action: Invoke the action determined by the action_name rule. If there is no
|
||||||
# invoke it. If there are multiple and no default, open the context menu.
|
# 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_current: Close current notification.
|
||||||
# * close_all: Close all notifications.
|
# * 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
|
# These values can be strung together for each mouse event, and
|
||||||
# will be executed in sequence.
|
# will be executed in sequence.
|
||||||
mouse_left_click = close_current
|
mouse_left_click = close_current
|
||||||
@ -373,6 +377,7 @@
|
|||||||
# set_transient
|
# set_transient
|
||||||
# timeout
|
# timeout
|
||||||
# urgency
|
# urgency
|
||||||
|
# action_name
|
||||||
#
|
#
|
||||||
# Shell-like globbing will get expanded.
|
# Shell-like globbing will get expanded.
|
||||||
#
|
#
|
||||||
|
14
src/input.c
14
src/input.c
@ -1,5 +1,6 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "menu.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "queues.h"
|
#include "queues.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@ -41,7 +42,12 @@ void input_handle_click(unsigned int button, bool button_down, int mouse_x, int
|
|||||||
return;
|
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;
|
int y = settings.separator_height;
|
||||||
struct notification *n = NULL;
|
struct notification *n = NULL;
|
||||||
int first = true;
|
int first = true;
|
||||||
@ -59,8 +65,12 @@ void input_handle_click(unsigned int button, bool button_down, int mouse_x, int
|
|||||||
if (n) {
|
if (n) {
|
||||||
if (act == MOUSE_CLOSE_CURRENT) {
|
if (act == MOUSE_CLOSE_CURRENT) {
|
||||||
n->marked_for_closure = REASON_USER;
|
n->marked_for_closure = REASON_USER;
|
||||||
} else {
|
} else if (act == MOUSE_DO_ACTION) {
|
||||||
notification_do_action(n);
|
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 */
|
/* see menu.h */
|
||||||
void context_menu(void)
|
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) {
|
if (menu_ctx.locked_notifications) {
|
||||||
LOG_W("Context menu already running, refusing to rerun");
|
LOG_W("Context menu already running, refusing to rerun");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GList *notifications = get_actionable_notifications();
|
|
||||||
menu_ctx.locked_notifications = notifications;
|
menu_ctx.locked_notifications = notifications;
|
||||||
|
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
|
10
src/menu.h
10
src/menu.h
@ -2,6 +2,8 @@
|
|||||||
#ifndef DUNST_MENU_H
|
#ifndef DUNST_MENU_H
|
||||||
#define DUNST_MENU_H
|
#define DUNST_MENU_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract all urls from the given string.
|
* Extract all urls from the given string.
|
||||||
*
|
*
|
||||||
@ -16,9 +18,15 @@ void invoke_action(const char *action);
|
|||||||
void regex_teardown(void);
|
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);
|
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
|
#endif
|
||||||
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
|
/* 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_free(n->desktop_entry);
|
||||||
|
|
||||||
g_hash_table_unref(n->actions);
|
g_hash_table_unref(n->actions);
|
||||||
|
g_free(n->default_action_name);
|
||||||
|
|
||||||
if (n->icon)
|
if (n->icon)
|
||||||
g_object_unref(n->icon);
|
g_object_unref(n->icon);
|
||||||
@ -386,6 +387,7 @@ struct notification *notification_create(void)
|
|||||||
n->fullscreen = FS_SHOW;
|
n->fullscreen = FS_SHOW;
|
||||||
|
|
||||||
n->actions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
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;
|
n->script_count = 0;
|
||||||
return n;
|
return n;
|
||||||
@ -647,27 +649,43 @@ void notification_update_text_to_render(struct notification *n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* see notification.h */
|
/* 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_size(n->actions)) {
|
||||||
if (g_hash_table_contains(n->actions, "default")) {
|
if (g_hash_table_contains(n->actions, n->default_action_name)) {
|
||||||
signal_action_invoked(n, "default");
|
signal_action_invoked(n, n->default_action_name);
|
||||||
return;
|
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);
|
GList *keys = g_hash_table_get_keys(n->actions);
|
||||||
signal_action_invoked(n, keys->data);
|
signal_action_invoked(n, keys->data);
|
||||||
g_list_free(keys);
|
g_list_free(keys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context_menu();
|
notification_open_context_menu(n);
|
||||||
|
|
||||||
} else if (n->urls) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see notification.h */
|
||||||
|
void notification_open_url(struct notification *n)
|
||||||
|
{
|
||||||
if (strstr(n->urls, "\n"))
|
if (strstr(n->urls, "\n"))
|
||||||
context_menu();
|
notification_open_context_menu(n);
|
||||||
else
|
else
|
||||||
open_browser(n->urls);
|
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) {
|
void notification_invalidate_actions(struct notification *n) {
|
||||||
|
@ -61,6 +61,7 @@ struct notification {
|
|||||||
int locked; /**< If non-zero the notification is locked **/
|
int locked; /**< If non-zero the notification is locked **/
|
||||||
|
|
||||||
GHashTable *actions;
|
GHashTable *actions;
|
||||||
|
char *default_action_name; /**< The name of the action to be invoked on do_action */
|
||||||
|
|
||||||
enum markup_mode markup;
|
enum markup_mode markup;
|
||||||
const char *format;
|
const char *format;
|
||||||
@ -195,11 +196,24 @@ void notification_replace_single_field(char **haystack,
|
|||||||
void notification_update_text_to_render(struct notification *n);
|
void notification_update_text_to_render(struct notification *n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the notification has exactly one action, or one is marked as default,
|
* If the notification has an action named n->default_action_name or there is only one
|
||||||
* invoke it. If there are multiple and no default, open the context menu. If
|
* action and n->default_action_name is set to "default", invoke it. If there is no
|
||||||
* there are no actions, proceed similarly with urls.
|
* 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.
|
* 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("do_action", MOUSE_DO_ACTION);
|
||||||
STRING_PARSE_RET("close_current", MOUSE_CLOSE_CURRENT);
|
STRING_PARSE_RET("close_current", MOUSE_CLOSE_CURRENT);
|
||||||
STRING_PARSE_RET("close_all", MOUSE_CLOSE_ALL);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ void rule_apply(struct rule *r, struct notification *n)
|
|||||||
n->transient = r->set_transient;
|
n->transient = r->set_transient;
|
||||||
if (r->skip_display != -1)
|
if (r->skip_display != -1)
|
||||||
n->skip_display = r->skip_display;
|
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)
|
if (r->markup != MARKUP_NULL)
|
||||||
n->markup = r->markup;
|
n->markup = r->markup;
|
||||||
if (r->new_icon)
|
if (r->new_icon)
|
||||||
|
@ -23,6 +23,7 @@ struct rule {
|
|||||||
/* actions */
|
/* actions */
|
||||||
gint64 timeout;
|
gint64 timeout;
|
||||||
enum urgency urgency;
|
enum urgency urgency;
|
||||||
|
char *action_name;
|
||||||
enum markup_mode markup;
|
enum markup_mode markup;
|
||||||
int history_ignore;
|
int history_ignore;
|
||||||
int match_transient;
|
int match_transient;
|
||||||
|
@ -862,6 +862,7 @@ void load_settings(char *cmdline_config_path)
|
|||||||
g_free(c);
|
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->urgency = ini_get_urgency(cur_section, "urgency", r->urgency);
|
||||||
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency);
|
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency);
|
||||||
r->fg = ini_get_string(cur_section, "foreground", r->fg);
|
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 vertical_alignment { VERTICAL_TOP, VERTICAL_CENTER, VERTICAL_BOTTOM };
|
||||||
enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM };
|
enum separator_color { SEP_FOREGROUND, SEP_AUTO, SEP_FRAME, SEP_CUSTOM };
|
||||||
enum follow_mode { FOLLOW_NONE, FOLLOW_MOUSE, FOLLOW_KEYBOARD };
|
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
|
#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
|
||||||
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
|
#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
|
||||||
// Needed for compiling without wayland dependency
|
// Needed for compiling without wayland dependency
|
||||||
|
Loading…
x
Reference in New Issue
Block a user