Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package mako for openSUSE:Factory checked in 
at 2021-07-12 21:40:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mako (Old)
 and      /work/SRC/openSUSE:Factory/.mako.new.2625 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mako"

Mon Jul 12 21:40:20 2021 rev:6 rq:905773 version:1.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/mako/mako.changes        2021-05-04 
22:01:00.116597794 +0200
+++ /work/SRC/openSUSE:Factory/.mako.new.2625/mako.changes      2021-07-12 
21:40:49.715828912 +0200
@@ -1,0 +2,13 @@
+Mon Jul 12 07:10:54 UTC 2021 - Michael Vetter <[email protected]>
+
+- Update to 1.6:
+  * Modes allow to conditonally change options at runtime, and allow to
+    setup things like a "do not disturb" mode.
+  * Add support for synchronous hints, to easily replace an existing
+    notification from a script.
+  * Add an "exec" binding to execute a command
+  * Add "on-notify" bindings to trigger an action when a notification
+    is opened.
+  * Several small improvments and bugfixes:
+
+-------------------------------------------------------------------

Old:
----
  v1.5.tar.gz

New:
----
  v1.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mako.spec ++++++
--- /var/tmp/diff_new_pack.KAOAiG/_old  2021-07-12 21:40:50.179825255 +0200
+++ /var/tmp/diff_new_pack.KAOAiG/_new  2021-07-12 21:40:50.183825224 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           mako
-Version:        1.5
+Version:        1.6
 Release:        0
 Summary:        A Wayland notification daemon
 License:        MIT

++++++ v1.5.tar.gz -> v1.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/.builds/alpine.yml 
new/mako-1.6/.builds/alpine.yml
--- old/mako-1.5/.builds/alpine.yml     2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/.builds/alpine.yml     2021-07-11 10:52:44.000000000 +0200
@@ -1,4 +1,4 @@
-image: alpine/latest
+image: alpine/edge
 packages:
   - elogind-dev
   - meson
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/README.md new/mako-1.6/README.md
--- old/mako-1.5/README.md      2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/README.md      2021-07-11 10:52:44.000000000 +0200
@@ -6,9 +6,9 @@
   <img src="https://sr.ht/meoc.png"; alt="mako screenshot">
 </p>
 
-mako implements the [GNOME Desktop Notifications Specification][gnome-draft].
+mako implements the [FreeDesktop Notifications Specification][spec].
 
-Feel free to join the IRC channel: ##emersion on irc.freenode.net.
+Feel free to join the IRC channel: #emersion on irc.libera.chat.
 
 ## Running
 
@@ -67,5 +67,5 @@
 
 MIT
 
-[gnome-draft]: https://developer.gnome.org/notification-spec/
+[spec]: 
https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html
 [basu]: https://github.com/emersion/basu
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/config.c new/mako-1.6/config.c
--- old/mako-1.5/config.c       2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/config.c       2021-07-11 10:52:44.000000000 +0200
@@ -58,11 +58,6 @@
        config->max_history = 5;
        config->sort_criteria = MAKO_SORT_CRITERIA_TIME;
        config->sort_asc = 0;
-
-       config->button_bindings.left = MAKO_BINDING_INVOKE_DEFAULT_ACTION;
-       config->button_bindings.right = MAKO_BINDING_DISMISS;
-       config->button_bindings.middle = MAKO_BINDING_NONE;
-       config->touch = MAKO_BINDING_DISMISS;
 }
 
 void finish_config(struct mako_config *config) {
@@ -126,6 +121,11 @@
        style->anchor =
                ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | 
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
 
+       style->button_bindings.left.action = MAKO_BINDING_INVOKE_DEFAULT_ACTION;
+       style->button_bindings.right.action = MAKO_BINDING_DISMISS;
+       style->button_bindings.middle.action = MAKO_BINDING_NONE;
+       style->touch_binding.action = MAKO_BINDING_DISMISS;
+
        // Everything in the default config is explicitly specified.
        memset(&style->spec, true, sizeof(struct mako_style_spec));
 }
@@ -134,13 +134,32 @@
        memset(style, 0, sizeof(struct mako_style));
 }
 
+static void finish_binding(struct mako_binding *binding) {
+       free(binding->command);
+}
+
 void finish_style(struct mako_style *style) {
+       finish_binding(&style->button_bindings.left);
+       finish_binding(&style->button_bindings.middle);
+       finish_binding(&style->button_bindings.right);
+       finish_binding(&style->touch_binding);
+       finish_binding(&style->notify_binding);
        free(style->icon_path);
        free(style->font);
        free(style->format);
        free(style->output);
 }
 
+static void copy_binding(struct mako_binding *dst,
+               const struct mako_binding *src) {
+       finish_binding(dst);
+
+       *dst = *src;
+       if (src->command != NULL) {
+               dst->command = strdup(src->command);
+       }
+}
+
 // Update `target` with the values specified in `style`. If a failure occurs,
 // `target` will remain unchanged.
 bool apply_style(struct mako_style *target, const struct mako_style *style) {
@@ -335,6 +354,29 @@
                target->spec.max_visible = true;
        }
 
+       if (style->spec.button_bindings.left) {
+               copy_binding(&target->button_bindings.left, 
&style->button_bindings.left);
+               target->spec.button_bindings.left = true;
+       }
+       if (style->spec.button_bindings.middle) {
+               copy_binding(&target->button_bindings.middle, 
&style->button_bindings.middle);
+               target->spec.button_bindings.middle = true;
+       }
+       if (style->spec.button_bindings.right) {
+               copy_binding(&target->button_bindings.right, 
&style->button_bindings.right);
+               target->spec.button_bindings.right = true;
+       }
+
+       if (style->spec.touch_binding) {
+               copy_binding(&target->touch_binding, &style->touch_binding);
+               target->spec.touch_binding = true;
+       }
+
+       if (style->spec.notify_binding) {
+               copy_binding(&target->notify_binding, &style->notify_binding);
+               target->spec.notify_binding = true;
+       }
+
        return true;
 }
 
@@ -414,10 +456,10 @@
                                memcpy(&current_specifier, format_pos, 2);
                                if (!strstr(target->format, current_specifier)) 
{
                                        memcpy(target_format_pos, format_pos, 
2);
+                                       target_format_pos += 2; // This needs 
to go to the next slot.
                                }
 
                                ++format_pos; // Enough to move to the next 
match.
-                               target_format_pos += 2; // This needs to go to 
the next slot.
                        }
                }
        }
@@ -444,37 +486,6 @@
                        return false;
                }
                return true;
-       } else if (strncmp(name, "on-button-", 10) == 0
-                  || strcmp(name, "on-touch") == 0) {
-
-               enum mako_binding action;
-
-               if (strcmp(value, "none") == 0) {
-                       action = MAKO_BINDING_NONE;
-               } else if (strcmp(value, "dismiss") == 0) {
-                       action = MAKO_BINDING_DISMISS;
-               } else if (strcmp(value, "dismiss-all") == 0) {
-                       action = MAKO_BINDING_DISMISS_ALL;
-               } else if (strcmp(value, "dismiss-group") == 0) {
-                       action = MAKO_BINDING_DISMISS_GROUP;
-               } else if (strcmp(value, "invoke-default-action") == 0) {
-                       action = MAKO_BINDING_INVOKE_DEFAULT_ACTION;
-               } else {
-                       return false;
-               }
-
-               if (strcmp(name, "on-button-left") == 0) {
-                       config->button_bindings.left = action;
-               } else if (strcmp(name, "on-button-right") == 0) {
-                       config->button_bindings.right = action;
-               } else if (strcmp(name, "on-button-middle") == 0) {
-                       config->button_bindings.middle = action;
-               } else if (strcmp(name, "on-touch") == 0) {
-                       config->touch = action;
-               } else {
-                       return false;
-               }
-               return true;
        } else if (strcmp(name, "max-history") == 0) {
                return parse_int(value, &config->max_history);
        }
@@ -482,6 +493,10 @@
        return false;
 }
 
+static bool has_prefix(const char *str, const char *prefix) {
+       return strncmp(str, prefix, strlen(prefix)) == 0;
+}
+
 static bool apply_style_option(struct mako_style *style, const char *name,
                const char *value) {
        struct mako_style_spec *spec = &style->spec;
@@ -602,6 +617,45 @@
                return true;
        } else if (strcmp(name, "anchor") == 0) {
                return spec->anchor = parse_anchor(value, &style->anchor);
+       } else if (has_prefix(name, "on-")) {
+               struct mako_binding binding = {0};
+               if (strcmp(value, "none") == 0) {
+                       binding.action = MAKO_BINDING_NONE;
+               } else if (strcmp(value, "dismiss") == 0) {
+                       binding.action = MAKO_BINDING_DISMISS;
+               } else if (strcmp(value, "dismiss-all") == 0) {
+                       binding.action = MAKO_BINDING_DISMISS_ALL;
+               } else if (strcmp(value, "dismiss-group") == 0) {
+                       binding.action = MAKO_BINDING_DISMISS_GROUP;
+               } else if (strcmp(value, "invoke-default-action") == 0) {
+                       binding.action = MAKO_BINDING_INVOKE_DEFAULT_ACTION;
+               } else if (has_prefix(value, "exec ")) {
+                       binding.action = MAKO_BINDING_EXEC;
+                       binding.command = strdup(value + strlen("exec "));
+               } else {
+                       return false;
+               }
+
+               if (strcmp(name, "on-button-left") == 0) {
+                       copy_binding(&style->button_bindings.left, &binding);
+                       style->spec.button_bindings.left = true;
+               } else if (strcmp(name, "on-button-right") == 0) {
+                       copy_binding(&style->button_bindings.right, &binding);
+                       style->spec.button_bindings.right = true;
+               } else if (strcmp(name, "on-button-middle") == 0) {
+                       copy_binding(&style->button_bindings.middle, &binding);
+                       style->spec.button_bindings.middle = true;
+               } else if (strcmp(name, "on-touch") == 0) {
+                       copy_binding(&style->touch_binding, &binding);
+                       style->spec.touch_binding = true;
+               } else if (strcmp(name, "on-notify") == 0) {
+                       copy_binding(&style->notify_binding, &binding);
+                       style->spec.notify_binding = true;
+               } else {
+                       return false;
+               }
+
+               return true;
        }
 
        return false;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/contrib/completions/fish/mako.fish 
new/mako-1.6/contrib/completions/fish/mako.fish
--- old/mako-1.5/contrib/completions/fish/mako.fish     2021-05-03 
19:32:05.000000000 +0200
+++ new/mako-1.6/contrib/completions/fish/mako.fish     2021-07-11 
10:52:44.000000000 +0200
@@ -27,6 +27,8 @@
 complete -c mako -l format -d 'Format string' -x
 complete -c mako -l hidden-format -d 'Hidden format string' -x
 complete -c mako -l max-visible -d 'Max visible notifications' -x
+complete -c mako -l max-history -d 'Max size of history buffer' -x
+complete -c mako -l history -d 'Add expired notifications to history' -xa "1 0"
 complete -c mako -l sort -d 'Set notification sorting method' -x
 complete -c mako -l default-timeout -d 'Notification timeout in ms' -x
 complete -c mako -l ignore-timeout -d 'Enable notification timeout or not' -xa 
"1 0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/contrib/completions/fish/makoctl.fish 
new/mako-1.6/contrib/completions/fish/makoctl.fish
--- old/mako-1.5/contrib/completions/fish/makoctl.fish  1970-01-01 
01:00:00.000000000 +0100
+++ new/mako-1.6/contrib/completions/fish/makoctl.fish  2021-07-11 
10:52:44.000000000 +0200
@@ -0,0 +1,24 @@
+function __fish_makoctl_complete_no_subcommand
+       for i in (commandline -opc)
+               if contains -- $i dismiss restore invoke menu list reload help
+                       return 1
+               end
+       end
+       return 0
+end
+
+complete -c makoctl -n '__fish_makoctl_complete_no_subcommand' -a dismiss -d 
'Dismiss notification (the last one if none is given)' -x
+complete -c makoctl -n '__fish_makoctl_complete_no_subcommand' -a restore -d 
'Restore the most recently expired notification from the history buffer' -x
+complete -c makoctl -n '__fish_makoctl_complete_no_subcommand' -a invoke -d 
'Invoke an action on the notification (the last one if none is given)' -x
+complete -c makoctl -n '__fish_makoctl_complete_no_subcommand' -a menu -d 'Use 
a program to select one action to be invoked on the notification (the last one 
if none is given)' -x
+complete -c makoctl -n '__fish_makoctl_complete_no_subcommand' -a list -d 
'List notifications' -x
+complete -c makoctl -n '__fish_makoctl_complete_no_subcommand' -a reload -d 
'Reload the configuration file' -x
+complete -c makoctl -n '__fish_makoctl_complete_no_subcommand' -a help -d 
'Show help message and quit' -x
+
+complete -c makoctl -n '__fish_seen_subcommand_from dismiss' -s a -l all -d 
"Dismiss all notifications" -x
+complete -c makoctl -n '__fish_seen_subcommand_from dismiss' -s g -l group -d 
"Dismiss all the notifications in the last notification's group" -x
+complete -c makoctl -n '__fish_seen_subcommand_from dismiss' -s n -d "Dismiss 
the notification with the given id" -x
+complete -c makoctl -n '__fish_seen_subcommand_from invoke' -s n -d "Invoke an 
action on the notification with the given id" -x
+complete -c makoctl -n '__fish_seen_subcommand_from menu' -s n -d "Use a 
program to select one action on the notification with the given id" -x
+complete -c makoctl -n '__fish_seen_subcommand_from menu' -a 
"(__fish_complete_command)" -x
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/contrib/completions/meson.build 
new/mako-1.6/contrib/completions/meson.build
--- old/mako-1.5/contrib/completions/meson.build        2021-05-03 
19:32:05.000000000 +0200
+++ new/mako-1.6/contrib/completions/meson.build        2021-07-11 
10:52:44.000000000 +0200
@@ -10,7 +10,8 @@
 endif
 
 if get_option('fish-completions')
-       fish_files = files('fish/mako.fish')
+       fish_files = files('fish/mako.fish', 'fish/makoctl.fish')
+       fish_comp = dependency('fish', required: false)
        if fish_comp.found()
                fish_install_dir = 
fish_comp.get_pkgconfig_variable('completionsdir')
        else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/contrib/completions/zsh/_mako 
new/mako-1.6/contrib/completions/zsh/_mako
--- old/mako-1.5/contrib/completions/zsh/_mako  2021-05-03 19:32:05.000000000 
+0200
+++ new/mako-1.6/contrib/completions/zsh/_mako  2021-07-11 10:52:44.000000000 
+0200
@@ -27,5 +27,5 @@
     '--ignore-timeout[If set, mako will ignore the expire timeout sent by 
notifications and use the one provided by default-timeout instead.]:Use default 
timeout:(0 1)' \
     '--output[Show notifications on this output.]:name:' \
     '--layer[Arrange notifications at this layer.]:layer:(background bottom 
top overlay)' \
-    '--anchor[Position on output to put notifications.]:position:(top-right 
bottom-right bottom-center bottom-left top-left top-center)' \
-    '--sort[Sorts incoming notifications by time and/or priority in 
ascending(+) or descending(-) order.]:sort pattern:'
+    '--anchor[Position on output to put notifications.]:position:(top-right 
bottom-right bottom-center bottom-left top-left top-center center-right 
center-left center)' \
+    '--sort[Sort incoming notifications by time and/or priority in 
ascending(+) or descending(-) order.]:sort pattern:'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/contrib/completions/zsh/_makoctl 
new/mako-1.6/contrib/completions/zsh/_makoctl
--- old/mako-1.5/contrib/completions/zsh/_makoctl       2021-05-03 
19:32:05.000000000 +0200
+++ new/mako-1.6/contrib/completions/zsh/_makoctl       2021-07-11 
10:52:44.000000000 +0200
@@ -3,11 +3,11 @@
 local -a makoctl_cmds
 
 makoctl_cmds=(
-       'dismiss:Dismisses notification (first by default)'
+       'dismiss:Dismiss notification (first by default)'
        'restore:Restore the most recently expired notification from the 
history buffer'
-       'invoke:Invokes an action on the first notification. If action is not 
specified, invokes the default action'
+       'invoke:Invoke an action on the first notification. If action is not 
specified, invoke the default action'
        'list:Retrieve a list of current notifications'
-       'reload:Reloads the configuration file'
+       'reload:Reload the configuration file'
        'help:Show help message and quit'
 )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/criteria.c new/mako-1.6/criteria.c
--- old/mako-1.5/criteria.c     2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/criteria.c     2021-07-11 10:52:44.000000000 +0200
@@ -40,6 +40,7 @@
        regfree(&criteria->body_pattern);
        free(criteria->raw_string);
        free(criteria->output);
+       free(criteria->mode);
        free(criteria);
 }
 
@@ -151,6 +152,10 @@
                return false;
        }
 
+       if (spec.mode && strcmp(criteria->mode, notif->state->current_mode) != 
0) {
+               return false;
+       }
+
        return true;
 }
 
@@ -351,6 +356,10 @@
                        criteria->output = strdup(value);
                        criteria->spec.output = true;
                        return true;
+               } else if (strcmp(key, "mode") == 0) {
+                       criteria->mode = strdup(value);
+                       criteria->spec.mode = true;
+                       return true;
                } else {
                        // Anything left must be one of the boolean fields, 
defined using
                        // standard syntax. Continue on.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/dbus/mako.c new/mako-1.6/dbus/mako.c
--- old/mako-1.5/dbus/mako.c    2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/dbus/mako.c    2021-07-11 10:52:44.000000000 +0200
@@ -109,7 +109,7 @@
                        struct mako_action *action;
                        wl_list_for_each(action, &notif->actions, link) {
                                if (strcmp(action->key, action_key) == 0) {
-                                       notify_action_invoked(action);
+                                       notify_action_invoked(action, NULL);
                                        break;
                                }
                        }
@@ -173,6 +173,12 @@
                        return ret;
                }
 
+               ret = sd_bus_message_append(reply, "{sv}", "category",
+                       "s", notif->category);
+               if (ret < 0) {
+                       return ret;
+               }
+
                ret = sd_bus_message_append(reply, "{sv}", "summary",
                        "s", notif->summary);
                if (ret < 0) {
@@ -296,6 +302,24 @@
        }
 }
 
+static int handle_set_mode(sd_bus_message *msg, void *data,
+               sd_bus_error *ret_error) {
+       struct mako_state *state = data;
+
+       const char *mode;
+       int ret = sd_bus_message_read(msg, "s", &mode);
+       if (ret < 0) {
+               return ret;
+       }
+
+       free(state->current_mode);
+       state->current_mode = strdup(mode);
+
+       reapply_config(state);
+
+       return sd_bus_reply_method_return(msg, "");
+}
+
 static int handle_reload(sd_bus_message *msg, void *data,
                sd_bus_error *ret_error) {
        struct mako_state *state = data;
@@ -322,6 +346,7 @@
        SD_BUS_METHOD("RestoreNotification", "", "", handle_restore_action, 
SD_BUS_VTABLE_UNPRIVILEGED),
        SD_BUS_METHOD("ListNotifications", "", "aa{sv}", 
handle_list_notifications, SD_BUS_VTABLE_UNPRIVILEGED),
        SD_BUS_METHOD("Reload", "", "", handle_reload, 
SD_BUS_VTABLE_UNPRIVILEGED),
+       SD_BUS_METHOD("SetMode", "s", "", handle_set_mode, 
SD_BUS_VTABLE_UNPRIVILEGED),
        SD_BUS_VTABLE_END
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/dbus/xdg.c new/mako-1.6/dbus/xdg.c
--- old/mako-1.5/dbus/xdg.c     2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/dbus/xdg.c     2021-07-11 10:52:44.000000000 +0200
@@ -59,6 +59,16 @@
                }
        }
 
+       ret = sd_bus_message_append(reply, "s", 
"x-canonical-private-synchronous");
+       if (ret < 0) {
+               return ret;
+       }
+
+       ret = sd_bus_message_append(reply, "s", "x-dunst-stack-tag");
+       if (ret < 0) {
+               return ret;
+       }
+
        ret = sd_bus_message_close_container(reply);
        if (ret < 0) {
                return ret;
@@ -239,6 +249,14 @@
                        // will win over app_icon if provided.
                        free(notif->app_icon);
                        notif->app_icon = strdup(image_path);
+               } else if (strcmp(hint, "x-canonical-private-synchronous") == 0 
||
+                               strcmp(hint, "x-dunst-stack-tag") == 0) {
+                       const char *tag = NULL;
+                       ret = sd_bus_message_read(msg, "v", "s", &tag);
+                       if (ret < 0) {
+                               return ret;
+                       }
+                       notif->tag = strdup(tag);
                } else if (strcmp(hint, "image-data") == 0 ||
                                strcmp(hint, "image_data") == 0 ||  // 
Deprecated.
                                strcmp(hint, "icon_data") == 0) {  // Even more 
deprecated.
@@ -343,6 +361,17 @@
        }
        notif->requested_timeout = requested_timeout;
 
+       if (notif->tag) {
+               // Find and replace the existing notfication with a matching tag
+               struct mako_notification *replace_notif = 
get_tagged_notification(state, notif->tag, app_name);
+               if (replace_notif) {
+                       notif->id = replace_notif->id;
+                       wl_list_insert(&replace_notif->link, &notif->link);
+                       destroy_notification(replace_notif);
+                       replaces_id = notif->id;
+               }
+       }
+
        // We can insert a notification prior to matching criteria, because 
sort is
        // global. We also know that inserting a notification into the global 
list
        // regardless of the configured sort criteria places it in the correct
@@ -400,6 +429,8 @@
        group_notifications(state, notif_criteria);
        destroy_criteria(notif_criteria);
 
+       notification_execute_binding(notif, &notif->style.notify_binding, NULL);
+
        set_dirty(notif->surface);
 
        return sd_bus_reply_method_return(msg, "u", notif->id);
@@ -460,7 +491,8 @@
                "NotificationClosed", "uu", notif->id, reason);
 }
 
-void notify_action_invoked(struct mako_action *action) {
+void notify_action_invoked(struct mako_action *action,
+               const char *activation_token) {
        if (!action->notification->style.actions) {
                // Actions are disabled for this notification, bail.
                return;
@@ -468,6 +500,11 @@
 
        struct mako_state *state = action->notification->state;
 
+       if (activation_token != NULL) {
+               sd_bus_emit_signal(state->bus, service_path, service_interface,
+                       "ActivationToken", "us", action->notification->id, 
activation_token);
+       }
+
        sd_bus_emit_signal(state->bus, service_path, service_interface,
                "ActionInvoked", "us", action->notification->id, action->key);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/icon.c new/mako-1.6/icon.c
--- old/mako-1.5/icon.c 2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/icon.c 2021-07-11 10:52:44.000000000 +0200
@@ -254,13 +254,12 @@
        icon->height = image_height * icon->scale;
 
        icon->image = create_cairo_surface_from_gdk_pixbuf(image);
+       g_object_unref(image);
        if (icon->image == NULL) {
                free(icon);
                return NULL;
        }
 
-       g_object_unref(image);
-
        return icon;
 }
 #else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/include/config.h 
new/mako-1.6/include/config.h
--- old/mako-1.5/include/config.h       2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/include/config.h       2021-07-11 10:52:44.000000000 +0200
@@ -7,12 +7,18 @@
 #include <pango/pango.h>
 #include "types.h"
 
-enum mako_binding {
+enum mako_binding_action {
        MAKO_BINDING_NONE,
        MAKO_BINDING_DISMISS,
        MAKO_BINDING_DISMISS_GROUP,
        MAKO_BINDING_DISMISS_ALL,
        MAKO_BINDING_INVOKE_DEFAULT_ACTION,
+       MAKO_BINDING_EXEC,
+};
+
+struct mako_binding {
+       enum mako_binding_action action;
+       char *command; // for MAKO_BINDING_EXEC
 };
 
 enum mako_sort_criteria {
@@ -38,6 +44,10 @@
        struct {
                bool background, text, border, progress;
        } colors;
+       struct {
+               bool left, right, middle;
+       } button_bindings;
+       bool touch_binding, notify_binding;
 };
 
 
@@ -81,6 +91,11 @@
        char *output;
        enum zwlr_layer_shell_v1_layer layer;
        uint32_t anchor;
+
+       struct {
+               struct mako_binding left, right, middle;
+       } button_bindings;
+       struct mako_binding touch_binding, notify_binding;
 };
 
 struct mako_config {
@@ -91,12 +106,6 @@
        int32_t max_history;
 
        struct mako_style superstyle;
-
-       struct {
-               enum mako_binding left, right, middle;
-       } button_bindings;
-
-       enum mako_binding touch;
 };
 
 void init_default_config(struct mako_config *config);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/include/criteria.h 
new/mako-1.6/include/criteria.h
--- old/mako-1.5/include/criteria.h     2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/include/criteria.h     2021-07-11 10:52:44.000000000 +0200
@@ -33,6 +33,8 @@
        char *body;
        regex_t body_pattern;
 
+       char *mode;
+
        // Second-pass matches:
        int group_index;
        bool grouped;  // Whether group_index is non-zero
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/include/dbus.h new/mako-1.6/include/dbus.h
--- old/mako-1.5/include/dbus.h 2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/include/dbus.h 2021-07-11 10:52:44.000000000 +0200
@@ -20,7 +20,8 @@
 void notify_notification_closed(struct mako_notification *notif,
        enum mako_notification_close_reason reason);
 
-void notify_action_invoked(struct mako_action *action);
+void notify_action_invoked(struct mako_action *action,
+       const char *activation_token);
 
 int init_dbus_xdg(struct mako_state *state);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/include/mako.h new/mako-1.6/include/mako.h
--- old/mako-1.5/include/mako.h 2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/include/mako.h 2021-07-11 10:52:44.000000000 +0200
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include <wayland-client.h>
+#include <wayland-cursor.h>
 #ifdef HAVE_LIBSYSTEMD
 #include <systemd/sd-bus.h>
 #elif HAVE_LIBELOGIND
@@ -16,6 +17,7 @@
 #include "pool-buffer.h"
 #include "wlr-layer-shell-unstable-v1-client-protocol.h"
 #include "xdg-output-unstable-v1-client-protocol.h"
+#include "xdg-activation-v1-client-protocol.h"
 
 struct mako_state;
 
@@ -55,14 +57,19 @@
        struct wl_shm *shm;
        struct zwlr_layer_shell_v1 *layer_shell;
        struct zxdg_output_manager_v1 *xdg_output_manager;
+       struct xdg_activation_v1 *xdg_activation;
        struct wl_list outputs; // mako_output::link
        struct wl_list seats; // mako_seat::link
+       struct wl_cursor_theme *cursor_theme;
+       const struct wl_cursor_image *cursor_image;
+       struct wl_surface *cursor_surface;
 
        struct wl_list surfaces; // mako_surface::link
 
        uint32_t last_id;
        struct wl_list notifications; // mako_notification::link
        struct wl_list history; // mako_notification::link
+       char *current_mode;
 
        int argc;
        char **argv;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/include/notification.h 
new/mako-1.6/include/notification.h
--- old/mako-1.5/include/notification.h 2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/include/notification.h 2021-07-11 10:52:44.000000000 +0200
@@ -42,6 +42,7 @@
        enum mako_notification_urgency urgency;
        char *category;
        char *desktop_entry;
+       char *tag;
        int32_t progress;
        struct mako_image_data *image_data;
 
@@ -69,6 +70,12 @@
        size_t count;
 };
 
+struct mako_binding_context {
+       struct mako_surface *surface;
+       struct mako_seat *seat;
+       uint32_t serial;
+};
+
 #define DEFAULT_ACTION_KEY "default"
 
 typedef char *(*mako_format_func_t)(char variable, bool *markup, void *data);
@@ -89,13 +96,15 @@
 char *format_notif_text(char variable, bool *markup, void *data);
 size_t format_text(const char *format, char *buf, mako_format_func_t func, 
void *data);
 struct mako_notification *get_notification(struct mako_state *state, uint32_t 
id);
+struct mako_notification *get_tagged_notification(struct mako_state *state, 
const char *tag, const char *app_name);
 size_t format_notification(struct mako_notification *notif, const char *format,
        char *buf);
 void notification_handle_button(struct mako_notification *notif, uint32_t 
button,
-       enum wl_pointer_button_state state);
-void notification_handle_touch(struct mako_notification *notif);
+       enum wl_pointer_button_state state, const struct mako_binding_context 
*ctx);
+void notification_handle_touch(struct mako_notification *notif,
+       const struct mako_binding_context *ctx);
 void notification_execute_binding(struct mako_notification *notif,
-       enum mako_binding binding);
+       const struct mako_binding *binding, const struct mako_binding_context 
*ctx);
 void insert_notification(struct mako_state *state, struct mako_notification 
*notif);
 int group_notifications(struct mako_state *state, struct mako_criteria 
*criteria);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/include/types.h new/mako-1.6/include/types.h
--- old/mako-1.5/include/types.h        2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/include/types.h        2021-07-11 10:52:44.000000000 +0200
@@ -55,6 +55,8 @@
        bool body;
        bool body_pattern;
 
+       bool mode;
+
        bool none; // Special criteria that never matches, used for grouping
 
        // Fields that can only be matched after grouping, and thus can't be
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/include/wayland.h 
new/mako-1.6/include/wayland.h
--- old/mako-1.5/include/wayland.h      2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/include/wayland.h      2021-07-11 10:52:44.000000000 +0200
@@ -29,12 +29,14 @@
        struct {
                struct wl_pointer *wl_pointer;
                int32_t x, y;
+               struct mako_surface *surface;
        } pointer;
 
        struct {
                struct wl_touch *wl_touch;
                struct {
                        int32_t x, y;
+                       struct mako_surface *surface;
                } pts[MAX_TOUCHPOINTS];
        } touch;
 };
@@ -42,5 +44,7 @@
 bool init_wayland(struct mako_state *state);
 void finish_wayland(struct mako_state *state);
 void set_dirty(struct mako_surface *surface);
+char *create_xdg_activation_token(struct mako_surface *surface,
+       struct mako_seat *seat, uint32_t serial);
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/main.c new/mako-1.6/main.c
--- old/mako-1.5/main.c 2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/main.c 2021-07-11 10:52:44.000000000 +0200
@@ -42,7 +42,7 @@
        "      --hidden-format <format>        Format string.\n"
        "      --max-visible <n>               Max number of visible 
notifications.\n"
        "      --max-history <n>               Max size of history buffer.\n"
-       "      --history <0|1>                 Add expired notificatinos to 
history.\n"
+       "      --history <0|1>                 Add expired notifications to 
history.\n"
        "      --sort <sort_criteria>          Sorts incoming notifications by 
time\n"
        "                                      and/or priority in ascending(+) 
or\n"
        "                                      descending(-) order.\n"
@@ -69,10 +69,13 @@
        }
        wl_list_init(&state->notifications);
        wl_list_init(&state->history);
+       state->current_mode = strdup("default");
        return true;
 }
 
 static void finish(struct mako_state *state) {
+       free(state->current_mode);
+
        struct mako_notification *notif, *tmp;
        wl_list_for_each_safe(notif, tmp, &state->notifications, link) {
                destroy_notification(notif);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/mako.5.scd new/mako-1.6/mako.5.scd
--- old/mako-1.5/mako.5.scd     2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/mako.5.scd     2021-07-11 10:52:44.000000000 +0200
@@ -29,11 +29,11 @@
 
        Default: -time
 
-# BUTTON AND TOUCH BINDINGS
-
-Specify the action to take per button or touch event. Supported values are
-_none_, _dismiss_, _dismiss-all_, _dismiss-group_, _invoke-default-action_,
+# BINDING OPTIONS
 
+Bindings allow to perform an action when an event is triggered. Supported
+values are _none_, _dismiss_, _dismiss-all_, _dismiss-group_,
+_invoke-default-action_ and _exec <command>_.
 
 *on-button-left*=_action_
        Default: invoke-default-action
@@ -47,6 +47,22 @@
 *on-touch*=_action_
        Default: dismiss
 
+*on-notify* = _action_
+       Default: none
+
+When _exec_ is used, the command will be executed in a POSIX shell. The
+shell variable _id_ will be set to the notification ID. For example, the
+following option will display an interactive action menu on middle click:
+
+```
+on-button-middle=exec makoctl menu -n "$id" dmenu -p 'Select action: '
+```
+
+The following option will play a sound when a new notification is opened:
+
+```
+on-notify=exec mpv /usr/share/sounds/freedesktop/stereo/message.oga
+```
 
 # STYLE OPTIONS
 
@@ -224,7 +240,7 @@
 *anchor*=_position_
        Show notifications at the specified position on the output. Supported 
values
        are _top-right_, _top-center_, _top-left_, _bottom-right_, 
_bottom-center_,
-       _bottom-left_, and _center_.
+       _bottom-left_, _center-right_, _center-left_ and _center_.
 
        Default: top-right
 
@@ -232,8 +248,9 @@
 
 In addition to the set of options at the top of the file, the config file may
 contain zero or more sections, each containing any combination of the
-*STYLE OPTIONS*. The sections, called criteria, are defined with an INI-like
-square bracket syntax. The brackets may contain any number of fields, like so:
+*BINDING OPTIONS* and *STYLE OPTIONS*. The sections, called criteria, are
+defined with an INI-like square bracket syntax. The brackets may contain any
+number of fields, like so:
 
        \[field=value field2=value2 ...\]
 
@@ -268,6 +285,10 @@
 - _desktop-entry_ (string)
 - _actionable_ (boolean)
 - _expiring_ (boolean)
+- _mode_ (string)
+       - Only apply style options in this section if the provided mode is
+         currently enabled. For more information about modes, see the _MODES_
+         section.
 
 The following fields are also available to match on a second pass based on
 where previous style options decided to place each notification:
@@ -388,6 +409,25 @@
 
 *%t*   Total number of notifications
 
+# MODES
+
+mako supports applying style options conditionally via modes. A configuration
+section with a _mode_ criteria will only be applied if the current mode
+matches. **makoctl**(1) can be used to change the current mode.
+
+The default mode is named "default".
+
+For example, to hide all notifications if the mode "do-not-disturb" is
+enabled:
+
+```
+[mode=do-not-disturb]
+invisible=1
+```
+
+_makoctl set-mode do-not-disturb_ will hide all notifications,
+_makoctl set-mode default_ will show them again.
+
 # AUTHORS
 
 Maintained by Simon Ser <[email protected]>, who is assisted by other
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/makoctl new/mako-1.6/makoctl
--- old/mako-1.5/makoctl        2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/makoctl        2021-07-11 10:52:44.000000000 +0200
@@ -15,12 +15,13 @@
        echo "  invoke [-n id] [action]        Invoke an action on the 
notification"
        echo "                                 with the given id, or the last"
        echo "                                 notification if none is given"
-       echo "  menu [-n id] [prog] [arg ...]  Use [prog] [args ...] to select 
one"
+       echo "  menu [-n id] <prog> [arg ...]  Use <prog> [args ...] to select 
one"
        echo "                                 action to be invoked on the 
notification"
        echo "                                 with the given id, or the last"
        echo "                                 notification if none is given"
        echo "  list                           List notifications"
        echo "  reload                         Reload the configuration file"
+       echo "  set-mode <name>                Switch the current mode"
        echo "  help                           Show this help"
 }
 
@@ -129,6 +130,9 @@
 "reload")
        call Reload
        ;;
+"set-mode")
+       call SetMode "s" "$2"
+       ;;
 "help"|"--help"|"-h")
        usage
        ;;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/makoctl.1.scd new/mako-1.6/makoctl.1.scd
--- old/mako-1.5/makoctl.1.scd  2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/makoctl.1.scd  2021-07-11 10:52:44.000000000 +0200
@@ -42,7 +42,7 @@
                Invoke the action on the notification with the given id. 
Defaults to
                the first notification.
 
-*menu* [-n <id>] [program] [argument...]
+*menu* [-n <id>] <program> [argument...]
        Use a program to select an action on a notification. The list of
        actions are joined on newlines and passed to _program_. The program 
should
        write the selected action to stdout. If an action is given, this action
@@ -70,6 +70,11 @@
 *reload*
        Reloads the configuration file.
 
+*set-mode* <name>
+       Switches the current mode to _name_. This replaces the previous mode.
+
+       See the _MODES_ section in **mako**(5) for more information about modes.
+
 *help, -h, --help*
        Show help message and quit.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/meson.build new/mako-1.6/meson.build
--- old/mako-1.5/meson.build    2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/meson.build    2021-07-11 10:52:44.000000000 +0200
@@ -1,7 +1,7 @@
 project(
        'mako',
        'c',
-       version: '1.4.1',
+       version: '1.6',
        license: 'MIT',
        meson_version: '>=0.50.0',
        default_options: [
@@ -11,8 +11,10 @@
        ],
 )
 
-add_project_arguments('-Wno-unused-parameter', language: 'c')
-add_project_arguments('-Wno-missing-braces', language: 'c')
+add_project_arguments([
+       '-Wno-unused-parameter',
+       '-Wno-missing-braces',
+], language: 'c')
 
 datadir = get_option('datadir')
 
@@ -27,7 +29,8 @@
 gobject = dependency('gobject-2.0')
 realtime = cc.find_library('rt')
 wayland_client = dependency('wayland-client')
-wayland_protos = dependency('wayland-protocols', version: '>=1.14')
+wayland_protos = dependency('wayland-protocols', version: '>=1.21')
+wayland_cursor = dependency('wayland-cursor')
 
 epoll = dependency('', required: false)
 if (not cc.has_function('timerfd_create', prefix: '#include <sys/timerfd.h>') 
or
@@ -105,6 +108,7 @@
                gobject,
                realtime,
                wayland_client,
+               wayland_cursor,
        ],
        include_directories: [mako_inc],
        install: true,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/notification.c new/mako-1.6/notification.c
--- old/mako-1.5/notification.c 2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/notification.c 2021-07-11 10:52:44.000000000 +0200
@@ -1,8 +1,12 @@
 #define _POSIX_C_SOURCE 200809L
+#include <assert.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
 #include <pango/pangocairo.h>
 #include <wayland-client.h>
 #include <linux/input-event-codes.h>
@@ -15,6 +19,7 @@
 #include "notification.h"
 #include "icon.h"
 #include "string-util.h"
+#include "wayland.h"
 
 bool hotspot_at(struct mako_hotspot *hotspot, int32_t x, int32_t y) {
        return x >= hotspot->x &&
@@ -44,6 +49,7 @@
        free(notif->body);
        free(notif->category);
        free(notif->desktop_entry);
+       free(notif->tag);
        if (notif->image_data != NULL) {
                free(notif->image_data->data);
                free(notif->image_data);
@@ -55,6 +61,7 @@
        notif->body = strdup("");
        notif->category = strdup("");
        notif->desktop_entry = strdup("");
+       notif->tag = strdup("");
 
        notif->image_data = NULL;
 
@@ -133,6 +140,19 @@
        return NULL;
 }
 
+struct mako_notification *get_tagged_notification(struct mako_state *state,
+               const char *tag, const char *app_name) {
+       struct mako_notification *notif;
+       wl_list_for_each(notif, &state->notifications, link) {
+               if (notif->tag && strlen(notif->tag) != 0 &&
+                       strcmp(notif->tag, tag) == 0 &&
+                       strcmp(notif->app_name, app_name) == 0) {
+                       return notif;
+               }
+       }
+       return NULL;
+}
+
 void close_group_notifications(struct mako_notification *top_notif,
               enum mako_notification_close_reason reason) {
        struct mako_state *state = top_notif->state;
@@ -305,22 +325,23 @@
        return len;
 }
 
-static enum mako_binding get_binding(struct mako_config *config,
+static const struct mako_binding *get_button_binding(struct mako_style *style,
                uint32_t button) {
        switch (button) {
        case BTN_LEFT:
-               return config->button_bindings.left;
+               return &style->button_bindings.left;
        case BTN_RIGHT:
-               return config->button_bindings.right;
+               return &style->button_bindings.right;
        case BTN_MIDDLE:
-               return config->button_bindings.middle;
+               return &style->button_bindings.middle;
        }
-       return MAKO_BINDING_NONE;
+       return NULL;
 }
 
 void notification_execute_binding(struct mako_notification *notif,
-               enum mako_binding binding) {
-       switch (binding) {
+               const struct mako_binding *binding,
+               const struct mako_binding_context *ctx) {
+       switch (binding->action) {
        case MAKO_BINDING_NONE:
                break;
        case MAKO_BINDING_DISMISS:
@@ -336,28 +357,74 @@
                struct mako_action *action;
                wl_list_for_each(action, &notif->actions, link) {
                        if (strcmp(action->key, DEFAULT_ACTION_KEY) == 0) {
-                               notify_action_invoked(action);
+                               char *activation_token = NULL;
+                               if (ctx != NULL) {
+                                       activation_token = 
create_xdg_activation_token(ctx->surface,
+                                               ctx->seat, ctx->serial);
+                               }
+                               notify_action_invoked(action, activation_token);
+                               free(activation_token);
                                break;
                        }
                }
                close_notification(notif, MAKO_NOTIFICATION_CLOSE_DISMISSED);
                break;
+       case MAKO_BINDING_EXEC:
+               assert(binding->command != NULL);
+               pid_t pid = fork();
+               if (pid < 0) {
+                       perror("fork failed");
+                       break;
+               } else if (pid == 0) {
+                       // Double-fork to avoid SIGCHLD issues
+                       pid = fork();
+                       if (pid < 0) {
+                               perror("fork failed");
+                               _exit(1);
+                       } else if (pid == 0) {
+                               // We pass variables using additional sh 
arguments. To convert
+                               // back the arguments to variables, insert a 
short script
+                               // preamble before the user's command.
+                               const char setup_vars[] = "id=\"$1\"\n";
+
+                               size_t cmd_size = strlen(setup_vars) + 
strlen(binding->command) + 1;
+                               char *cmd = malloc(cmd_size);
+                               snprintf(cmd, cmd_size, "%s%s", setup_vars, 
binding->command);
+
+                               char id_str[32];
+                               snprintf(id_str, sizeof(id_str), "%" PRIu32, 
notif->id);
+
+                               char *const argv[] = { "sh", "-c", cmd, "sh", 
id_str, NULL };
+                               execvp("sh", argv);
+                               perror("exec failed");
+                               _exit(1);
+                       }
+                       _exit(0);
+               }
+               if (waitpid(pid, NULL, 0) < 0) {
+                       perror("waitpid failed");
+               }
+               break;
        }
 }
 
 void notification_handle_button(struct mako_notification *notif, uint32_t 
button,
-               enum wl_pointer_button_state state) {
+               enum wl_pointer_button_state state,
+               const struct mako_binding_context *ctx) {
        if (state != WL_POINTER_BUTTON_STATE_PRESSED) {
                return;
        }
 
-       notification_execute_binding(notif,
-               get_binding(&notif->state->config, button));
+       const struct mako_binding *binding =
+               get_button_binding(&notif->style, button);
+       if (binding != NULL) {
+               notification_execute_binding(notif, binding, ctx);
+       }
 }
 
-void notification_handle_touch(struct mako_notification *notif) {
-       notification_execute_binding(notif,
-               notif->state->config.touch);
+void notification_handle_touch(struct mako_notification *notif,
+               const struct mako_binding_context *ctx) {
+       notification_execute_binding(notif, &notif->style.touch_binding, ctx);
 }
 
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/protocol/meson.build 
new/mako-1.6/protocol/meson.build
--- old/mako-1.5/protocol/meson.build   2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/protocol/meson.build   2021-07-11 10:52:44.000000000 +0200
@@ -23,6 +23,7 @@
 
 client_protocols = [
        [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
+       [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
        [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
        ['wlr-layer-shell-unstable-v1.xml'],
 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/types.c new/mako-1.6/types.c
--- old/mako-1.5/types.c        2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/types.c        2021-07-11 10:52:44.000000000 +0200
@@ -348,6 +348,10 @@
        } else if (strcmp(string, "bottom-left") == 0) {
                *out = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
                        ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
+       } else if (strcmp(string, "center-right") == 0) {
+               *out = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+       } else if (strcmp(string, "center-left") == 0) {
+               *out = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
        } else if (strcmp(string, "center") == 0) {
                *out = 0;
        } else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mako-1.5/wayland.c new/mako-1.6/wayland.c
--- old/mako-1.5/wayland.c      2021-05-03 19:32:05.000000000 +0200
+++ new/mako-1.6/wayland.c      2021-07-11 10:52:44.000000000 +0200
@@ -100,6 +100,17 @@
        free(output);
 }
 
+static struct mako_surface *get_surface(struct mako_state *state,
+               struct wl_surface *wl_surface) {
+       struct mako_surface *surface;
+       wl_list_for_each(surface, &state->surfaces, link) {
+               if (surface->surface == wl_surface) {
+                       return surface;
+               }
+       }
+       return NULL;
+}
+
 static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
                uint32_t time, int32_t id,
                wl_fixed_t surface_x, wl_fixed_t surface_y) {
@@ -112,14 +123,15 @@
 }
 
 static void touch_handle_down(void *data, struct wl_touch *wl_touch,
-               uint32_t serial, uint32_t time, struct wl_surface *sfc, int32_t 
id,
-               wl_fixed_t surface_x, wl_fixed_t surface_y) {
+               uint32_t serial, uint32_t time, struct wl_surface *wl_surface,
+               int32_t id, wl_fixed_t surface_x, wl_fixed_t surface_y) {
        struct mako_seat *seat = data;
        if (id >= MAX_TOUCHPOINTS) {
                return;
        }
        seat->touch.pts[id].x = wl_fixed_to_int(surface_x);
        seat->touch.pts[id].y = wl_fixed_to_int(surface_y);
+       seat->touch.pts[id].surface = get_surface(seat->state, wl_surface);
 }
 
 static void touch_handle_up(void *data, struct wl_touch *wl_touch,
@@ -127,19 +139,50 @@
        struct mako_seat *seat = data;
        struct mako_state *state = seat->state;
 
-       struct mako_notification *notif;
        if (id >= MAX_TOUCHPOINTS) {
                return;
        }
+
+       const struct mako_binding_context ctx = {
+               .surface = seat->touch.pts[id].surface,
+               .seat = seat,
+               .serial = serial,
+       };
+
+       struct mako_notification *notif;
        wl_list_for_each(notif, &state->notifications, link) {
                if (hotspot_at(&notif->hotspot, seat->touch.pts[id].x, 
seat->touch.pts[id].y)) {
                        struct mako_surface *surface = notif->surface;
-                       notification_handle_touch(notif);
+                       notification_handle_touch(notif, &ctx);
                        set_dirty(surface);
                        break;
                }
        }
 
+       seat->touch.pts[id].surface = NULL;
+}
+
+static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
+               uint32_t serial, struct wl_surface *wl_surface,
+               wl_fixed_t surface_x, wl_fixed_t surface_y) {
+       struct mako_seat *seat = data;
+       struct mako_state *state = seat->state;
+
+       seat->pointer.x = wl_fixed_to_int(surface_x);
+       seat->pointer.y = wl_fixed_to_int(surface_y);
+       seat->pointer.surface = get_surface(state, wl_surface);
+
+       // Change the mouse cursor to "left_ptr"
+       if (state->cursor_theme != NULL) {
+               wl_pointer_set_cursor(wl_pointer, serial, state->cursor_surface,
+                       state->cursor_image->hotspot_x, 
state->cursor_image->hotspot_y);
+       }
+}
+
+static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
+               uint32_t serial, struct wl_surface *wl_surface) {
+       struct mako_seat *seat = data;
+       seat->pointer.surface = NULL;
 }
 
 static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
@@ -155,21 +198,26 @@
        struct mako_seat *seat = data;
        struct mako_state *state = seat->state;
 
+       const struct mako_binding_context ctx = {
+               .surface = seat->pointer.surface,
+               .seat = seat,
+               .serial = serial,
+       };
+
        struct mako_notification *notif;
        wl_list_for_each(notif, &state->notifications, link) {
                if (hotspot_at(&notif->hotspot, seat->pointer.x, 
seat->pointer.y)) {
                        struct mako_surface *surface = notif->surface;
-                       notification_handle_button(notif, button, button_state);
+                       notification_handle_button(notif, button, button_state, 
&ctx);
                        set_dirty(surface);
                        break;
                }
        }
-
 }
 
 static const struct wl_pointer_listener pointer_listener = {
-       .enter = noop,
-       .leave = noop,
+       .enter = pointer_handle_enter,
+       .leave = pointer_handle_leave,
        .motion = pointer_handle_motion,
        .button = pointer_handle_button,
        .axis = noop,
@@ -331,6 +379,9 @@
                state->xdg_output_manager = wl_registry_bind(registry, name,
                        &zxdg_output_manager_v1_interface,
                        ZXDG_OUTPUT_V1_NAME_SINCE_VERSION);
+       } else if (strcmp(interface, xdg_activation_v1_interface.name) == 0) {
+               state->xdg_activation = wl_registry_bind(registry, name,
+                       &xdg_activation_v1_interface, 1);
        }
 }
 
@@ -400,6 +451,39 @@
                }
        }
 
+       // Set up the cursor. It needs a wl_surface with the cursor loaded into 
it.
+       // If one of these fail, mako will work fine without the cursor being 
able to change.
+       const char *cursor_size_env = getenv("XCURSOR_SIZE");
+       int cursor_size = 24;
+       if (cursor_size_env != NULL) {
+               errno = 0;
+               char *end;
+               int temp_size = (int)strtol(cursor_size_env, &end, 10);
+               if (errno == 0 && cursor_size_env[0] != 0 && end[0] == 0 && 
temp_size > 0) {
+                       cursor_size = temp_size;
+               } else {
+                       fprintf(stderr, "Error: XCURSOR_SIZE is invalid\n");
+               }
+       }
+       state->cursor_theme = wl_cursor_theme_load(NULL, cursor_size, 
state->shm);
+       if (state->cursor_theme == NULL) {
+               fprintf(stderr, "couldn't find a cursor theme\n");
+               return true;
+       }
+       struct wl_cursor *cursor = 
wl_cursor_theme_get_cursor(state->cursor_theme, "left_ptr");
+       if (cursor == NULL) {
+               fprintf(stderr, "couldn't find cursor icon \"left_ptr\"\n");
+               wl_cursor_theme_destroy(state->cursor_theme);
+               // Set to NULL so it doesn't get free'd again
+               state->cursor_theme = NULL;
+               return true;
+       }
+       state->cursor_image = cursor->images[0];
+       struct wl_buffer *cursor_buffer = 
wl_cursor_image_get_buffer(cursor->images[0]);
+       state->cursor_surface = wl_compositor_create_surface(state->compositor);
+       wl_surface_attach(state->cursor_surface, cursor_buffer, 0, 0);
+       wl_surface_commit(state->cursor_surface);
+
        return true;
 }
 
@@ -419,9 +503,18 @@
                destroy_seat(seat);
        }
 
+       if (state->xdg_activation != NULL) {
+               xdg_activation_v1_destroy(state->xdg_activation);
+       }
        if (state->xdg_output_manager != NULL) {
                zxdg_output_manager_v1_destroy(state->xdg_output_manager);
        }
+
+       if (state->cursor_theme != NULL) {
+               wl_cursor_theme_destroy(state->cursor_theme);
+               wl_surface_destroy(state->cursor_surface);
+       }
+
        zwlr_layer_shell_v1_destroy(state->layer_shell);
        wl_compositor_destroy(state->compositor);
        wl_shm_destroy(state->shm);
@@ -622,3 +715,38 @@
        surface->dirty = true;
        schedule_frame_and_commit(surface);
 }
+
+static void activation_token_handle_done(void *data,
+               struct xdg_activation_token_v1 *token, const char *token_str) {
+       char **out = data;
+       *out = strdup(token_str);
+}
+
+static const struct xdg_activation_token_v1_listener activation_token_listener 
= {
+       .done = activation_token_handle_done,
+};
+
+char *create_xdg_activation_token(struct mako_surface *surface,
+               struct mako_seat *seat, uint32_t serial) {
+       struct mako_state *state = seat->state;
+       if (state->xdg_activation == NULL) {
+               return NULL;
+       }
+
+       char *token_str = NULL;
+       struct xdg_activation_token_v1 *token =
+               xdg_activation_v1_get_activation_token(state->xdg_activation);
+       xdg_activation_token_v1_add_listener(token, &activation_token_listener,
+               &token_str);
+       xdg_activation_token_v1_set_serial(token, serial, seat->wl_seat);
+       xdg_activation_token_v1_set_surface(token, surface->surface);
+       xdg_activation_token_v1_commit(token);
+
+       while (wl_display_dispatch(state->display) >= 0 && token_str == NULL) {
+               // This space is intentionally left blank
+       }
+
+       xdg_activation_token_v1_destroy(token);
+
+       return token_str;
+}

Reply via email to