diff --git a/docs/dunst.pod b/docs/dunst.pod index c4d373e..9e864bd 100644 --- a/docs/dunst.pod +++ b/docs/dunst.pod @@ -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 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 Dunst can be paused by sending a notification with a summary of diff --git a/src/menu.c b/src/menu.c index 035d9e0..eec311c 100644 --- a/src/menu.c +++ b/src/menu.c @@ -94,11 +94,16 @@ char *extract_urls(const char *to_match) * 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(); if (browser_pid1) { + g_free(url); int status; waitpid(browser_pid1, &status, 0); } else { @@ -164,23 +169,10 @@ void dispatch_menu_result(const char *input) { char *in = g_strdup(input); g_strstrip(in); - switch (in[0]) { - case '#': + if (in[0] == '#') { invoke_action(in + 1); - break; - case '[': // named url. skip name and continue - 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; - } - } + } else { + open_browser(in); } g_free(in); } diff --git a/src/menu.h b/src/menu.h index 10fc045..298fd85 100644 --- a/src/menu.h +++ b/src/menu.h @@ -3,7 +3,7 @@ #define DUNST_MENU_H 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 regex_teardown(void); diff --git a/src/notification.c b/src/notification.c index 1ccb7c1..de711e2 100644 --- a/src/notification.c +++ b/src/notification.c @@ -588,4 +588,32 @@ int notification_get_ttl(notification *n) { int notification_get_age(notification *n) { 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: */ diff --git a/src/notification.h b/src/notification.h index 5d0fa5d..581f75f 100644 --- a/src/notification.h +++ b/src/notification.h @@ -73,6 +73,7 @@ char *notification_replace_format(const char *needle, const char *replacement, c void notification_update_text_to_render(notification *n); int notification_get_ttl(notification *n); int notification_get_age(notification *n); +void notification_do_action(notification *n); #endif /* vim: set tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/x11/x.c b/src/x11/x.c index 36ca5e5..9f7ac20 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -820,7 +820,7 @@ gboolean x_mainloop_fd_dispatch(GSource * source, GSourceFunc callback, case SelectionNotify: if (ev.xselection.property == xctx.utf8) break; - case ButtonPress: + case ButtonRelease: if (ev.xbutton.window == xctx.win) { x_handle_click(ev); } @@ -896,7 +896,7 @@ static void x_handle_click(XEvent ev) return; } - if (ev.xbutton.button == Button1) { + if (ev.xbutton.button == Button1 || ev.xbutton.button == Button2) { int y = settings.separator_height; notification *n = NULL; int first = true; @@ -910,8 +910,13 @@ static void x_handle_click(XEvent ev) if (first) 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.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | - ButtonPressMask | FocusChangeMask| StructureNotifyMask; + ButtonReleaseMask | FocusChangeMask| StructureNotifyMask; screen_info *scr = get_active_screen(); xctx.win =