Merge pull request #330 from miseran/click_action
Allow middle click on notification to invoke action
This commit is contained in:
commit
2927140d8b
@ -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
|
||||||
|
28
src/menu.c
28
src/menu.c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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: */
|
||||||
|
@ -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: */
|
||||||
|
13
src/x11/x.c
13
src/x11/x.c
@ -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)
|
|
||||||
|
if (n) {
|
||||||
|
if (ev.xbutton.button == Button1)
|
||||||
notification_close(n, 2);
|
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 =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user