Merge pull request #330 from miseran/click_action

Allow middle click on notification to invoke action
This commit is contained in:
Nikos Tsipinakis 2017-06-30 08:00:41 +03:00 committed by GitHub
commit 2927140d8b
6 changed files with 55 additions and 24 deletions

View File

@ -614,6 +614,11 @@ The "context" keybinding is used to interact with these actions, by showing a
menu of possible actions. This feature requires "dmenu" or a dmenu drop-in menu of possible actions. This feature requires "dmenu" or a dmenu drop-in
replacement present. replacement present.
Alternatively, you can invoke an action with a middle click on the notification.
If there is exactly one associated action, or one is marked as default, that one
is invoked. If there are multiple, the context menu is shown. The same applies
to URLs when there are no actions.
=head1 MISCELLANEOUS =head1 MISCELLANEOUS
Dunst can be paused by sending a notification with a summary of Dunst can be paused by sending a notification with a summary of

View File

@ -94,11 +94,16 @@ char *extract_urls(const char *to_match)
* Open url in browser. * Open url in browser.
* *
*/ */
void open_browser(const char *url) void open_browser(const char *in) {
{ // remove prefix and test url
char *url = extract_urls(in);
if (!url)
return;
int browser_pid1 = fork(); int browser_pid1 = fork();
if (browser_pid1) { if (browser_pid1) {
g_free(url);
int status; int status;
waitpid(browser_pid1, &status, 0); waitpid(browser_pid1, &status, 0);
} else { } else {
@ -164,23 +169,10 @@ void dispatch_menu_result(const char *input)
{ {
char *in = g_strdup(input); char *in = g_strdup(input);
g_strstrip(in); g_strstrip(in);
switch (in[0]) { if (in[0] == '#') {
case '#':
invoke_action(in + 1); invoke_action(in + 1);
break; } else {
case '[': // named url. skip name and continue open_browser(in);
in = strchr(in, ']');
if (in == NULL)
break;
default:
{ // test and open url
char *maybe_url = extract_urls(in);
if (maybe_url) {
open_browser(maybe_url);
g_free(maybe_url);
break;
}
}
} }
g_free(in); g_free(in);
} }

View File

@ -3,7 +3,7 @@
#define DUNST_MENU_H #define DUNST_MENU_H
char *extract_urls(const char *to_match); char *extract_urls(const char *to_match);
void open_browser(const char *url); void open_browser(const char *in);
void invoke_action(const char *action); void invoke_action(const char *action);
void regex_teardown(void); void regex_teardown(void);

View File

@ -588,4 +588,32 @@ int notification_get_ttl(notification *n) {
int notification_get_age(notification *n) { int notification_get_age(notification *n) {
return time(NULL) - n->timestamp; return time(NULL) - n->timestamp;
} }
/*
* 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.
*/
void notification_do_action(notification *n) {
if (n->actions) {
if (n->actions->count == 2) {
action_invoked(n, n->actions->actions[0]);
return;
}
for (int i = 0; i < n->actions->count; i += 2) {
if (strcmp(n->actions->actions[i], "default") == 0) {
action_invoked(n, n->actions->actions[i]);
return;
}
}
context_menu();
} else if (n->urls) {
if (strstr(n->urls, "\n") == NULL)
open_browser(n->urls);
else
context_menu();
}
}
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -73,6 +73,7 @@ char *notification_replace_format(const char *needle, const char *replacement, c
void notification_update_text_to_render(notification *n); void notification_update_text_to_render(notification *n);
int notification_get_ttl(notification *n); int notification_get_ttl(notification *n);
int notification_get_age(notification *n); int notification_get_age(notification *n);
void notification_do_action(notification *n);
#endif #endif
/* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -820,7 +820,7 @@ gboolean x_mainloop_fd_dispatch(GSource * source, GSourceFunc callback,
case SelectionNotify: case SelectionNotify:
if (ev.xselection.property == xctx.utf8) if (ev.xselection.property == xctx.utf8)
break; break;
case ButtonPress: case ButtonRelease:
if (ev.xbutton.window == xctx.win) { if (ev.xbutton.window == xctx.win) {
x_handle_click(ev); x_handle_click(ev);
} }
@ -896,7 +896,7 @@ static void x_handle_click(XEvent ev)
return; return;
} }
if (ev.xbutton.button == Button1) { if (ev.xbutton.button == Button1 || ev.xbutton.button == Button2) {
int y = settings.separator_height; int y = settings.separator_height;
notification *n = NULL; notification *n = NULL;
int first = true; int first = true;
@ -910,8 +910,13 @@ static void x_handle_click(XEvent ev)
if (first) if (first)
y += settings.frame_width; y += settings.frame_width;
} }
if (n)
notification_close(n, 2); if (n) {
if (ev.xbutton.button == Button1)
notification_close(n, 2);
else
notification_do_action(n);
}
} }
} }
@ -1055,7 +1060,7 @@ static void x_win_setup(void)
wa.background_pixmap = ParentRelative; wa.background_pixmap = ParentRelative;
wa.event_mask = wa.event_mask =
ExposureMask | KeyPressMask | VisibilityChangeMask | ExposureMask | KeyPressMask | VisibilityChangeMask |
ButtonPressMask | FocusChangeMask| StructureNotifyMask; ButtonReleaseMask | FocusChangeMask| StructureNotifyMask;
screen_info *scr = get_active_screen(); screen_info *scr = get_active_screen();
xctx.win = xctx.win =