This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch master
in repository enlightenment.

View the commit online.

commit b23eedae98c180a8a2d7e4e33643d0dedb16c903
Author: Carsten Haitzler <ras...@rasterman.com>
AuthorDate: Sat Jun 18 00:44:17 2022 +0100

    notifications - extend to support actions, links and img tags
    
    we didn't support enough of noktifications to make everyone happy -
    this is why ffox, chrome etc. did their own notification windows and
    didn't use e's notifications. we now advertise doing everything. we
    say w edo sound though don't.... will add that later, but this now
    means we really do a lot more and thus pushes these other
    notifications into e's notifications so we're much better now and this
    annoyance i have noticed is now gone.
    
    @feat
---
 src/bin/e_notification.c               | 535 +++++++++++++++++++++++----------
 src/bin/e_notification.h               |  43 ++-
 src/modules/notification/e_mod_main.c  |  17 +-
 src/modules/notification/e_mod_main.h  |  51 ++--
 src/modules/notification/e_mod_popup.c | 175 ++++++++++-
 5 files changed, 621 insertions(+), 200 deletions(-)

diff --git a/src/bin/e_notification.c b/src/bin/e_notification.c
index b185f395b..8ddac7c0f 100644
--- a/src/bin/e_notification.c
+++ b/src/bin/e_notification.c
@@ -2,8 +2,8 @@
 
 typedef struct _Notification_Data
 {
-   Eldbus_Connection                 *conn;
-   Eldbus_Service_Interface          *iface;
+   Eldbus_Connection                *conn;
+   Eldbus_Service_Interface         *iface;
    E_Notification_Notify_Cb          notify_cb;
    E_Notification_Close_Cb           close_cb;
    void                             *data;
@@ -15,15 +15,28 @@ static Notification_Data *n_data = NULL;
 static void
 _notification_free(E_Notification_Notify *notify)
 {
+   int i;
+
    EINA_SAFETY_ON_NULL_RETURN(notify);
-   eina_stringshare_del(notify->app_name);
-   eina_stringshare_del(notify->body);
-   eina_stringshare_del(notify->icon.icon);
-   if (notify->icon.icon_path)
-     eina_stringshare_del(notify->icon.icon_path);
-   eina_stringshare_del(notify->summary);
-   if (notify->icon.raw.data)
-     free(notify->icon.raw.data);
+   if (notify->app_name) eina_stringshare_del(notify->app_name);
+   if (notify->body) eina_stringshare_del(notify->body);
+   if (notify->icon.icon) eina_stringshare_del(notify->icon.icon);
+   if (notify->icon.icon_path) eina_stringshare_del(notify->icon.icon_path);
+   if (notify->summary) eina_stringshare_del(notify->summary);
+   if (notify->icon.raw.data) free(notify->icon.raw.data);
+   if (notify->category) eina_stringshare_del(notify->category);
+   if (notify->desktop_entry) eina_stringshare_del(notify->desktop_entry);
+   if (notify->sound_file) eina_stringshare_del(notify->sound_file);
+   if (notify->sound_name) eina_stringshare_del(notify->sound_name);
+   if (notify->actions)
+     {
+        for (i = 0; notify->actions[i].action; i++)
+          {
+             eina_stringshare_del(notify->actions[i].action);
+             eina_stringshare_del(notify->actions[i].label);
+          }
+        free(notify->actions);
+     }
    free(notify);
 }
 
@@ -31,12 +44,15 @@ static void
 hints_dict_iter(void *data, const void *key, Eldbus_Message_Iter *var)
 {
    E_Notification_Notify *n = data;
-   if (!strcmp(key, "image-data") || !strcmp(key, "image_data"))
+
+   if ((!strcmp(key, "image-data")) || (!strcmp(key, "image_data")) ||
+       (!strcmp(key, "icon_data")))
      {
         Eldbus_Message_Iter *st, *data_iter;
         int w, h, r, bits, channels;
         Eina_Bool alpha;
         unsigned char *raw_data;
+
         if (!eldbus_message_iter_arguments_get(var, "(iiibiiay)", &st))
           return;
         if (!eldbus_message_iter_arguments_get(st, "iiibiiay", &w, &h, &r,
@@ -54,21 +70,135 @@ hints_dict_iter(void *data, const void *key, Eldbus_Message_Iter *var)
         n->icon.raw.data = "" * n->icon.raw.data_size);
         EINA_SAFETY_ON_NULL_RETURN(n->icon.raw.data);
         memcpy(n->icon.raw.data, raw_data, sizeof(char) * n->icon.raw.data_size);
+        printf("NOT: image-data="" w, h, alpha);
+     }
+   else if (!strcmp(key, "image-path") || !strcmp(key, "image_path"))
+     {
+        eldbus_message_iter_arguments_get(var, "s", &n->icon.icon_path);
+        n->icon.icon_path = eina_stringshare_add(n->icon.icon_path);
+        printf("NOT: image-path=[%s]\n", n->icon.icon_path);
+        // path to image file
      }
    else if (!strcmp(key, "urgency"))
      {
         unsigned char urgency;
+
         eldbus_message_iter_arguments_get(var, "y", &urgency);
-        if (urgency < 3)
-          n->urgency = urgency;
+        if (urgency < 3) n->urgency = urgency;
+        printf("NOT: urgency=%i\n", n->urgency);
+        // 0=low, 1=normal, 2=critical
      }
-   else if (!strcmp(key, "image-path") || !strcmp(key, "image_path"))
+   else if (!strcmp(key, "category"))
+     { // XXX: store category
+        const char *val = NULL;
+
+        eldbus_message_iter_arguments_get(var, "s", &val);
+        printf("NOT: category=[%s]\n", val);
+        // "device"               A generic device-related notification that doesn't fit into any other category.
+        // "device.added"         A device, such as a USB device, was added to the system.
+        // "device.error"         A device had some kind of error.
+        // "device.removed"       A device, such as a USB device, was removed from the system.
+        // "email"                A generic e-mail-related notification that doesn't fit into any other category.
+        // "email.arrived"        A new e-mail notification.
+        // "email.bounced"        A notification stating that an e-mail has bounced.
+        // "im"                   A generic instant message-related notification that doesn't fit into any other category.
+        // "im.error"             An instant message error notification.
+        // "im.received"          A received instant message notification.
+        // "network"              A generic network notification that doesn't fit into any other category.
+        // "network.connected"    A network connection notification, such as successful sign-on to a network service. This should not be confused with device.added for new network devices.
+        // "network.disconnected" A network disconnected notification. This should not be confused with device.removed for disconnected network devices.
+        // "network.error"        A network-related or connection-related error.
+        // "presence"             A generic presence change notification that doesn't fit into any other category, such as going away or idle.
+        // "presence.offline"     An offline presence change notification.
+        // "presence.online"      An online presence change notification.
+        // "transfer"             A generic file transfer or download notification that doesn't fit into any other category.
+        // "transfer.complete"    A file transfer or download complete notification.
+        // "transfer.error"       A file transfer or download error.
+        if (val) n->category = eina_stringshare_add(val);
+     }
+   else if (!strcmp(key, "desktop-entry"))
      {
-        eldbus_message_iter_arguments_get(var, "s", &n->icon.icon_path);
-        n->icon.icon_path = eina_stringshare_add(n->icon.icon_path);
+        const char *val = NULL;
+
+        eldbus_message_iter_arguments_get(var, "s", &val);
+        printf("NOT: desktop-entry=[%s]\n", val);
+        // if rage.desktop -> "rage"
+        // if terminology.desktop -> "terminology"
+        if (val) n->desktop_entry = eina_stringshare_add(val);
      }
-}
+   else if (!strcmp(key, "icon-actions"))
+     {
+        Eina_Bool val = 0;
+
+        eldbus_message_iter_arguments_get(var, "b", &val);
+        printf("NOT: icon-actions=%i\n", val);
+        // 1 == interpret action identifier == named icon in icon naming standards
+        n->icon_actions = val;
+     }
+   else if (!strcmp(key, "resident"))
+     {
+        Eina_Bool val = 0;
+
+        eldbus_message_iter_arguments_get(var, "b", &val);
+        printf("NOT: resident=%i\n", val);
+        // 1== remove  notification when action invoked - no timeout
+        n->resident = val;
+     }
+   else if (!strcmp(key, "supress-sound"))
+     {
+        Eina_Bool val = 0;
 
+        eldbus_message_iter_arguments_get(var, "b", &val);
+        printf("NOT: supress-sound=%i\n", val);
+        // 1== remove  notification when action invoked - no timeout
+        n->suppress_sound = val;
+     }
+   else if (!strcmp(key, "sound-file"))
+     {
+        const char *val = NULL;
+
+        eldbus_message_iter_arguments_get(var, "s", &val);
+        printf("NOT: sound-file=[%s]\n", val);
+        // path to sound file to play
+        if (val) n->sound_file = eina_stringshare_add(val);
+     }
+   else if (!strcmp(key, "sound-name"))
+     {
+        const char *val = NULL;
+
+        eldbus_message_iter_arguments_get(var, "s", &val);
+        printf("NOT: sound-file=[%s]\n", val);
+        // sound naming spec to play
+        // http://0pointer.de/public/sound-naming-spec.html
+        if (val) n->sound_name = eina_stringshare_add(val);
+     }
+   else if (!strcmp(key, "transient"))
+     {
+        Eina_Bool val = 0;
+
+        eldbus_message_iter_arguments_get(var, "b", &val);
+        printf("NOT: transient=%i\n", val);
+        n->transient = val;
+     }
+   else if (!strcmp(key, "x"))
+     {
+        int val = 0;
+
+        eldbus_message_iter_arguments_get(var, "i", &val);
+        printf("NOT: x=%i\n", val);
+        n->x = val;
+        n->have_xy = EINA_TRUE;
+     }
+   else if (!strcmp(key, "y"))
+     {
+        int val = 0;
+
+        eldbus_message_iter_arguments_get(var, "i", &val);
+        printf("NOT: y=%i\n", val);
+        n->y = val;
+        n->have_xy = EINA_TRUE;
+     }
+}
 
 /* this function should be external in edje for use in cases such as this module.
  *
@@ -93,134 +223,188 @@ _text_escape(Eina_Strbuf *txt, const char *text)
    return advance;
 }
 
-/* hardcoded list of allowed tags based on
- * https://people.gnome.org/~mccann/docs/notification-spec/notification-spec-latest.html#markup
- */
-static const char *tags[] =
+static int
+_tag_len(const char *txt)
 {
-   "<b",
-   "<i",
-   "<u",
-   //"<a", FIXME: we can't actually display these right now
-   //"<img",
-};
+   const char *s;
+   Eina_Bool backslash = EINA_FALSE;
+   Eina_Bool inquote = EINA_FALSE, indblquote = EINA_FALSE;
 
-static const char *
-_get_tag(const char *c)
+   if (txt[0] != '<') return 0;
+   for (s = txt; *s; s++)
+     {
+        if (!backslash)
+          {
+             if (*s == '\\') backslash = EINA_TRUE;
+             else
+               {
+                  if (inquote)
+                    {
+                       if (*s == '\'') inquote = EINA_FALSE;
+                    }
+                  else if (indblquote)
+                    {
+                       if (*s == '"') indblquote = EINA_FALSE;
+                    }
+                  else
+                    {
+                       if (*s == '>')
+                         {
+                            s++;
+                            break;
+                         }
+                       else if (*s == '\'') inquote = EINA_TRUE;
+                       else if (*s == '\"') indblquote = EINA_TRUE;
+                    }
+               }
+          }
+        else backslash = EINA_FALSE;
+     }
+   return s - txt;
+}
+
+static char *
+_path_get(const char *txt)
 {
-   unsigned int i;
+   Eina_Strbuf *buf;
+   char *ret;
+   const char *s;
+   Eina_Bool backslash = EINA_FALSE;
+   Eina_Bool inquote = EINA_FALSE, indblquote = EINA_FALSE;
 
-   if (c[1] != '>') return NULL;
-   for (i = 0; i < EINA_C_ARRAY_LENGTH(tags); i++)
-     if (tags[i][1] == c[0]) return tags[i];
-   return NULL;
+   if (txt[0] == '>') return NULL;
+
+   buf = eina_strbuf_new();
+   if (!buf) return NULL;
+
+   for (s = txt; *s; s++)
+     {
+        if (!backslash)
+          {
+             if (*s == '\\') backslash = EINA_TRUE;
+             else
+               {
+                  if (inquote)
+                    {
+                       if (*s == '\'') inquote = EINA_FALSE;
+                       else eina_strbuf_append_char(buf, *s);
+                    }
+                  else if (indblquote)
+                    {
+                       if (*s == '"') indblquote = EINA_FALSE;
+                       else eina_strbuf_append_char(buf, *s);
+                    }
+                  else
+                    {
+                       if      (*s == '>') break;
+                       else if (*s == ' ') break;
+                       else if (*s == '\'') inquote = EINA_TRUE;
+                       else if (*s == '\"') indblquote = EINA_TRUE;
+                       else eina_strbuf_append_char(buf, *s);
+                    }
+               }
+          }
+        else
+          {
+             eina_strbuf_append_char(buf, *s);
+             backslash = EINA_FALSE;
+          }
+     }
+   ret = eina_strbuf_string_steal(buf);
+   eina_strbuf_free(buf);
+   return ret;
 }
 
-char *
+static char *
 _nedje_text_escape(const char *text)
 {
    Eina_Strbuf *txt;
    char *ret;
    const char *text_end;
-   size_t text_len;
-   Eina_Array *arr;
-   const char *cur_tag = NULL;
+   int taglen;
 
    if (!text) return NULL;
 
    txt = eina_strbuf_new();
-   text_len = strlen(text);
-   arr = eina_array_new(3);
+   if (!txt) return NULL;
+
+   text_end = text + strlen(text);
 
-   text_end = text + text_len;
    while (text < text_end)
      {
-        int advance;
-
-        if ((text[0] == '<') && text[1])
+        taglen = _tag_len(text);
+        if (taglen == 0)
           {
-             const char *tag, *popped;
-             Eina_Bool closing = EINA_FALSE;
-
-             if (text[1] == '/') //closing tag
+             eina_strbuf_append_char(txt, text[0]);
+             text++;
+          }
+        else
+          {
+             if      (!strncmp(text, "<b>", 3))  eina_strbuf_append(txt, "<b>");
+             else if (!strncmp(text, "</b>", 4)) eina_strbuf_append(txt, "</b>");
+             else if (!strncmp(text, "<i>", 3))  eina_strbuf_append(txt, "<i>");
+             else if (!strncmp(text, "</i>", 4)) eina_strbuf_append(txt, "</i>");
+             else if (!strncmp(text, "<u>", 3))  eina_strbuf_append(txt, "<u>");
+             else if (!strncmp(text, "</u>", 4)) eina_strbuf_append(txt, "</u>");
+             else if (!strncmp(text, "<a ", 3))
                {
-                  closing = EINA_TRUE;
-                  tag = _get_tag(text + 2);
+                  eina_strbuf_append(txt, "<link>");
+                  eina_strbuf_append_n(txt, text, taglen);
                }
-             else
-               tag = _get_tag(text + 1);
-             if (closing)
+             else if (!strncmp(text, "</a>", 3))
                {
-                  if (cur_tag && (tag != cur_tag))
-                    {
-                       /* tag mismatch: autoclose all failure tags
-                        * not technically required by the spec,
-                        * but it makes me feel better about myself
-                        */
-                       do
-                         {
-                            popped = eina_array_pop(arr);
-                            if (eina_array_count(arr))
-                              cur_tag = eina_array_data_get(arr, eina_array_count(arr) - 1);
-                            else
-                              cur_tag = NULL;
-                            eina_strbuf_append_printf(txt, "</%c>", popped[1]);
-                         } while (cur_tag && (popped != tag));
-                       advance = 4;
-                    }
-                  else if (cur_tag)
-                    {
-                       /* tag match: just pop */
-                       popped = eina_array_pop(arr);
-                       if (eina_array_count(arr))
-                         cur_tag = eina_array_data_get(arr, eina_array_count(arr) - 1);
-                       else
-                         cur_tag = NULL;
-                       eina_strbuf_append_printf(txt, "</%c>", popped[1]);
-                       advance = 4;
-                    }
-                  else
-                    {
-                       /* no current tag: escape */
-                       advance = _text_escape(txt, text);
-                    }
+                  eina_strbuf_append(txt, "</a></link>");
                }
-             else
+             else if (!strncmp(text, "<img src="" 9))
                {
-                  if (tag)
+                  Evas_Object *o;
+                  int w = 0, h = 0;
+                  char *path;
+
+                  path = _path_get(text + 9);
+                  if ((path) && (strlen(path) > 0))
                     {
-                       cur_tag = tag;
-                       eina_array_push(arr, tag);
-                       eina_strbuf_append_printf(txt, "<%c>", tag[1]);
-                       advance = 3;
+                       o = evas_object_image_add(e_comp->evas);
+                       evas_object_image_file_set(o, path, NULL);
+                       evas_object_image_size_get(o, &w, &h);
+                       printf("NOT: imgpath=%s %ix%i\n", path, w, h);
+                       if ((w > 0) && (h > 0))
+                         {
+                            double neww = w, newh = h;
+
+                            if (neww > 200.0)
+                              {
+                                 double oldw = neww;
+
+                                 neww = 200.0;
+                                 newh = (newh * neww) / oldw;
+                              }
+                            if (newh > 100.0)
+                              {
+                                 double oldh = newh;
+
+                                 newh = 100.0;
+                                 neww = (neww * newh) / oldh;
+                              }
+                            neww *= e_scale;
+                            newh *= e_scale;
+                            w = neww + 0.5;
+                            h = newh + 0.5;
+                            eina_strbuf_append_printf
+                              (txt, "<item absize=%ix%i href="" w, h);
+                            eina_strbuf_append_n(txt, text + 9, taglen - 9);
+                            eina_strbuf_append(txt, "</item>");
+                         }
+                       evas_object_del(o);
                     }
-                  else
-                    advance = _text_escape(txt, text);
+                  free(path);
                }
+             text += taglen;
           }
-        else if (text[0] == '&')
-          {
-             const char *s;
-
-             s = strchr(text, ';');
-             if (s)
-               s = evas_textblock_escape_string_range_get(text, s + 1);
-             if (s)
-               {
-                  eina_strbuf_append_char(txt, text[0]);
-                  advance = 1;
-               }
-             else
-               advance = _text_escape(txt, text);
-          }
-        else
-          advance = _text_escape(txt, text);
-
-        text += advance;
      }
 
-   eina_array_free(arr);
    ret = eina_strbuf_string_steal(txt);
+   printf("NOT: body -> [%s]\n", ret);
    eina_strbuf_free(txt);
    return ret;
 }
@@ -231,28 +415,30 @@ notify_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Messag
    E_Notification_Notify *n;
    Eldbus_Message_Iter *actions_iter, *hints_iter;
    Eldbus_Message *reply;
-   char *txt;
+   char *txt, *txt2;
+   int num;
 
-   if (!n_data->notify_cb)
-     return NULL;
+   if (!n_data->notify_cb) return NULL;
 
    n = E_OBJECT_ALLOC(E_Notification_Notify, E_NOTIFICATION_TYPE, _notification_free);
    n->urgency = E_NOTIFICATION_NOTIFY_URGENCY_NORMAL;
-   if (!eldbus_message_arguments_get(msg, "susssasa{sv}i", &n->app_name,
-                                    &n->replaces_id, &n->icon.icon, &n->summary,
-                                    &n->body, &actions_iter, &hints_iter,
-                                    &n->timeout))
+   if (!eldbus_message_arguments_get(msg, "susssasa{sv}i",
+                                     &n->app_name, &n->replaces_id,
+                                     &n->icon.icon, &n->summary, &n->body,
+                                     &actions_iter, &hints_iter, &n->timeout))
      {
         ERR("Reading message.");
         e_object_del(E_OBJECT(n));
         return NULL;
      }
    if (e_screensaver_on_get() && e_config->screensaver_wake_on_notify)
-     {
+     { // XXX: this is an attempt to wake the screen? should be an option
         int x, y;
+
         ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
         ecore_evas_pointer_warp(e_comp->ee, x, y);
      }
+   // walk hints
    eldbus_message_iter_dict_iterate(hints_iter, "sv", hints_dict_iter, n);
    n->app_name = eina_stringshare_add(n->app_name);
    n->icon.icon = eina_stringshare_add(n->icon.icon);
@@ -261,22 +447,43 @@ notify_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Messag
    n->body = eina_stringshare_add(txt);
    free(txt);
 
+   num = 0;
+   while (eldbus_message_iter_get_and_next(actions_iter, 's', &txt))
+     {
+        if (eldbus_message_iter_get_and_next(actions_iter, 's', &txt2))
+          { // XXX: add actions to notification
+             E_Notification_Notify_Action *actions;
+
+             printf("NOT: act=[%s] [%s]\n", txt, txt2);
+             num++;
+             actions = realloc(n->actions, (num + 1) * sizeof(E_Notification_Notify));
+             if (actions)
+               {
+                  n->actions = actions;
+                  n->actions[num - 1].action = ""
+                  n->actions[num - 1].label = eina_stringshare_add(txt2);
+                  n->actions[num].action = ""
+                  n->actions[num].label = NULL;
+               }
+          }
+     }
+
    e_object_ref(E_OBJECT(n));
    n->id = n_data->notify_cb(n_data->data, n);
    reply = eldbus_message_method_return_new(msg);
    eldbus_message_arguments_append(reply, "u", n->id);
    e_object_unref(E_OBJECT(n));
+
    return reply;
 }
 
 static Eldbus_Message *
 close_notification_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
 {
-   unsigned id;
-   if (!eldbus_message_arguments_get(msg, "u", &id))
-     return NULL;
-   if (n_data->close_cb)
-     n_data->close_cb(n_data->data, id);
+   unsigned int id;
+
+   if (!eldbus_message_arguments_get(msg, "u", &id)) return NULL;
+   if (n_data->close_cb) n_data->close_cb(n_data->data, id);
    return eldbus_message_method_return_new(msg);
 }
 
@@ -291,8 +498,10 @@ capabilities_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_
    eldbus_message_iter_arguments_append(main_iter, "as", &array);
 
    for (i = 0; n_data->server_info->capabilities[i]; i++)
-     eldbus_message_iter_arguments_append(array, "s",
-                                         n_data->server_info->capabilities[i]);
+     {
+        eldbus_message_iter_arguments_append
+          (array, "s", n_data->server_info->capabilities[i]);
+     }
    eldbus_message_iter_container_close(main_iter, array);
    return reply;
 }
@@ -301,23 +510,32 @@ static Eldbus_Message *
 server_info_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
 {
    Eldbus_Message *reply = eldbus_message_method_return_new(msg);
-   eldbus_message_arguments_append(reply, "ssss", n_data->server_info->name,
-                                  n_data->server_info->vendor,
-                                  n_data->server_info->version,
-                                  n_data->server_info->spec_version);
+   eldbus_message_arguments_append(reply, "ssss",
+                                   n_data->server_info->name,
+                                   n_data->server_info->vendor,
+                                   n_data->server_info->version,
+                                   n_data->server_info->spec_version);
    return reply;
 }
 
 static const Eldbus_Method methods[] = {
    { "Notify",
-     ELDBUS_ARGS({"s", "app_name"}, {"u", "replaces_id"}, {"s", "app_icon"}, {"s", "summary"}, {"s", "body"}, {"as", "actions"}, {"a{sv}", "hints"}, {"i", "expire_timeout"}),
-     ELDBUS_ARGS({"u", "id"}), notify_cb, 0 },
-   { "CloseNotification", ELDBUS_ARGS({"u", "id"}), NULL, close_notification_cb, 0 },
-   { "GetCapabilities", NULL, ELDBUS_ARGS({"as", "capabilities"}),
-     capabilities_cb, 0 },
-   { "GetServerInformation", NULL,
-     ELDBUS_ARGS({"s", "name"}, {"s", "vendor"}, {"s", "version"}, {"s", "spec_version"}),
-     server_info_cb, 0 },
+      ELDBUS_ARGS({"s", "app_name"}, {"u", "replaces_id"}, {"s", "app_icon"}, {"s", "summary"}, {"s", "body"}, {"as", "actions"}, {"a{sv}", "hints"}, {"i", "expire_timeout"}),
+      ELDBUS_ARGS({"u", "id"}),
+      notify_cb, 0 },
+   { "CloseNotification",
+      ELDBUS_ARGS({"u", "id"}),
+      NULL,
+      close_notification_cb, 0 },
+   { "GetCapabilities",
+      NULL,
+      ELDBUS_ARGS({"as", "capabilities"}),
+      capabilities_cb, 0 },
+   { "GetServerInformation",
+      NULL,
+      ELDBUS_ARGS({"s", "name"}, {"s", "vendor"}, {"s", "version"}, {"s", "spec_version"}),
+      server_info_cb, 0 },
+
    { NULL, NULL, NULL, NULL, 0 }
 };
 
@@ -332,6 +550,7 @@ static const Eldbus_Signal signals[] = {
    { "NotificationClosed", ELDBUS_ARGS({"u", "id"}, {"u", "reason"}), 0 },
    [SIGNAL_ACTION_INVOKED] =
    { "ActionInvoked", ELDBUS_ARGS({"u", "id"}, {"s", "action_key"}), 0 },
+
    { NULL, NULL, 0}
 };
 
@@ -347,8 +566,8 @@ E_API Eina_Bool
 e_notification_server_register(const E_Notification_Server_Info *server_info, E_Notification_Notify_Cb n_cb, E_Notification_Close_Cb close_cb, const void *data)
 {
    EINA_SAFETY_ON_NULL_RETURN_VAL(server_info, EINA_FALSE);
-   if (n_data)
-     return EINA_FALSE;
+
+   if (n_data) return EINA_FALSE;
    n_data = calloc(1, sizeof(Notification_Data));
    EINA_SAFETY_ON_NULL_RETURN_VAL(n_data, EINA_FALSE);
 
@@ -359,8 +578,7 @@ e_notification_server_register(const E_Notification_Server_Info *server_info, E_
    n_data->data = "" *)data;
    n_data->server_info = server_info;
    eldbus_name_request(n_data->conn, BUS,
-                      ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING, NULL, NULL);
-
+                       ELDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING, NULL, NULL);
    return EINA_TRUE;
 }
 
@@ -381,7 +599,17 @@ e_notification_notify_close(E_Notification_Notify *notify, E_Notification_Notify
    EINA_SAFETY_ON_NULL_RETURN(notify);
    EINA_SAFETY_ON_FALSE_RETURN(reason <= E_NOTIFICATION_NOTIFY_CLOSED_REASON_UNDEFINED);
    eldbus_service_signal_emit(n_data->iface, SIGNAL_NOTIFICATION_CLOSED,
-                             notify->id, reason);
+                              notify->id, reason);
+}
+
+E_API void
+e_notification_notify_action(E_Notification_Notify *notify, const char *action)
+{
+   EINA_SAFETY_ON_NULL_RETURN(n_data);
+   EINA_SAFETY_ON_NULL_RETURN(notify);
+   if (!action) action = ""
+   eldbus_service_signal_emit(n_data->iface, SIGNAL_ACTION_INVOKED,
+                              notify->id, action);
 }
 
 E_API Evas_Object *
@@ -491,6 +719,7 @@ notification_client_dbus_send(E_Notification_Notify *notify, E_Notification_Clie
      {
         Eldbus_Message_Iter *st, *data_iter;
         int i;
+
         eldbus_message_iter_arguments_append(hints, "{sv}", &entry);
         eldbus_message_iter_arguments_append(entry, "s", "image-data");
         var = eldbus_message_iter_container_new(entry, 'v', "(iiibiiay)");
@@ -533,8 +762,7 @@ notification_client_dbus_send(E_Notification_Notify *notify, E_Notification_Clie
 
    p = eldbus_connection_send(conn, msg, client_notify_cb, data, 5000);
    EINA_SAFETY_ON_NULL_GOTO(p, error);
-   if (cb)
-     eldbus_pending_data_set(p, "cb", cb);
+   if (cb) eldbus_pending_data_set(p, "cb", cb);
    eldbus_pending_data_set(p, "conn", conn);
 
    return EINA_TRUE;
@@ -547,8 +775,7 @@ error:
 static void
 normalize_notify(E_Notification_Notify *notify)
 {
-   if (!notify->timeout)
-     notify->timeout = -1;
+   if (!notify->timeout) notify->timeout = -1;
 }
 
 E_API Eina_Bool
@@ -562,11 +789,12 @@ e_notification_client_send(E_Notification_Notify *notify, E_Notification_Client_
 
    if (!n_data)
      {
-        fprintf(stderr, "UNHANDLED NOTIFICATION:\nSummary: %s\nBody: %s\n", notify->summary, notify->body);
+        fprintf(stderr, "UNHANDLED NOTIFICATION:\nSummary: %s\nBody: %s\n",
+                notify->summary, notify->body);
         return notification_client_dbus_send(notify, cb, data);
      }
 
-   //local
+   // local
    copy = malloc(sizeof(E_Notification_Notify));
    EINA_SAFETY_ON_NULL_RETURN_VAL(copy, EINA_FALSE);
    memcpy(copy, notify, sizeof(E_Notification_Notify));
@@ -579,8 +807,7 @@ e_notification_client_send(E_Notification_Notify *notify, E_Notification_Client_
      copy->icon.icon_path = eina_stringshare_add(notify->icon.icon_path);
 
    id = n_data->notify_cb(n_data->data, copy);
-   if (cb)
-     cb((void *)data, id);
+   if (cb) cb((void *)data, id);
    return EINA_TRUE;
 }
 
diff --git a/src/bin/e_notification.h b/src/bin/e_notification.h
index 46228982d..c93d553f4 100644
--- a/src/bin/e_notification.h
+++ b/src/bin/e_notification.h
@@ -7,35 +7,39 @@
 
 typedef enum _E_Notification_Notify_Urgency
 {
-  E_NOTIFICATION_NOTIFY_URGENCY_LOW,
-  E_NOTIFICATION_NOTIFY_URGENCY_NORMAL,
-  E_NOTIFICATION_NOTIFY_URGENCY_CRITICAL
+  E_NOTIFICATION_NOTIFY_URGENCY_LOW = 0,
+  E_NOTIFICATION_NOTIFY_URGENCY_NORMAL = 1,
+  E_NOTIFICATION_NOTIFY_URGENCY_CRITICAL = 2
 } E_Notification_Notify_Urgency;
 
 typedef enum _E_Notification_Notify_Closed_Reason
 {
-  E_NOTIFICATION_NOTIFY_CLOSED_REASON_EXPIRED, /** The notification expired. */
-  E_NOTIFICATION_NOTIFY_CLOSED_REASON_DISMISSED, /** The notification was dismissed by the user. */
-  E_NOTIFICATION_NOTIFY_CLOSED_REASON_REQUESTED, /** The notification was closed by a call to CloseNotification method. */
-  E_NOTIFICATION_NOTIFY_CLOSED_REASON_UNDEFINED /** Undefined/reserved reasons. */
+  E_NOTIFICATION_NOTIFY_CLOSED_REASON_EXPIRED   = 1,
+  E_NOTIFICATION_NOTIFY_CLOSED_REASON_DISMISSED = 2,
+  E_NOTIFICATION_NOTIFY_CLOSED_REASON_REQUESTED = 3,
+  E_NOTIFICATION_NOTIFY_CLOSED_REASON_UNDEFINED = 4
 } E_Notification_Notify_Closed_Reason;
 
+typedef struct _E_Notification_Notify_Action
+{
+   const char *action;
+   const char *label;
+} E_Notification_Notify_Action;
+
 typedef struct _E_Notification_Notify
 {
    E_Object e_obj_inherit;
    unsigned int id;
    const char *app_name;
-   unsigned replaces_id;
+   unsigned int replaces_id;
    const char *summary;
    const char *body;
-   int timeout;
+   int timeout; // time in ms
    E_Notification_Notify_Urgency urgency;
-   struct
-   {
+   struct {
       const char *icon;
       const char *icon_path;
-      struct
-      {
+      struct {
          int width;
          int height;
          int rowstride;
@@ -46,6 +50,17 @@ typedef struct _E_Notification_Notify
          int data_size;
       } raw;
    } icon;
+   const char *category;
+   const char *desktop_entry;
+   const char *sound_file;
+   const char *sound_name;
+   int x, y;
+   Eina_Bool have_xy;
+   Eina_Bool icon_actions;
+   Eina_Bool resident;
+   Eina_Bool suppress_sound;
+   Eina_Bool transient;
+   E_Notification_Notify_Action *actions;
 } E_Notification_Notify;
 
 typedef unsigned int (*E_Notification_Notify_Cb)(void *data, E_Notification_Notify *n);
@@ -80,7 +95,9 @@ E_API Evas_Object *e_notification_notify_raw_image_get(E_Notification_Notify *no
 
 //client
 typedef void (*E_Notification_Client_Send_Cb)(void *data, unsigned int id);
+
 E_API Eina_Bool e_notification_client_send(E_Notification_Notify *notify, E_Notification_Client_Send_Cb cb, const void *data);
+E_API void e_notification_notify_action(E_Notification_Notify *notify, const char *action);
 E_API Eina_Bool e_notification_util_send(const char *summary, const char *body);
 #endif
 
diff --git a/src/modules/notification/e_mod_main.c b/src/modules/notification/e_mod_main.c
index e8afe13b4..ec3c9eb8c 100644
--- a/src/modules/notification/e_mod_main.c
+++ b/src/modules/notification/e_mod_main.c
@@ -28,11 +28,20 @@ _notification_notify(E_Notification_Notify *n)
 E_API E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Notification"};
 
 static const E_Notification_Server_Info server_info = {
-   .name = "e17",
-   .vendor = "enlightenment.org",
-   .version = "0.17",
+   .name = "Notification Service",
+   .vendor = "Enlightenment",
+   .version = PACKAGE_VERSION,
    .spec_version = "1.2",
-   .capabilities = { "body", "body-markup", NULL }
+   .capabilities = {
+      "body", "body-markup",
+      "body-hyperlinks", "body-images",
+      "actions", "action-icons",
+//      "icon-multi",
+// or
+//      "icon-static",
+      "persistence",
+//      "sound",
+      NULL }
 };
 
 /* Callbacks */
diff --git a/src/modules/notification/e_mod_main.h b/src/modules/notification/e_mod_main.h
index 714448166..094e23847 100644
--- a/src/modules/notification/e_mod_main.h
+++ b/src/modules/notification/e_mod_main.h
@@ -31,34 +31,37 @@ typedef enum
 
 struct _Config
 {
-  E_Config_Dialog *cfd;
-
-  int version;
-  int show_low;
-  int show_normal;
-  int show_critical;
-  int force_timeout;
-  int ignore_replacement;
-  Popup_Display_Policy dual_screen;
-  float timeout;
-  Popup_Corner corner;
-
-  Eina_List  *popups;
-  unsigned int         next_id;
+   E_Config_Dialog *cfd;
+
+   int version;
+   int show_low;
+   int show_normal;
+   int show_critical;
+   int force_timeout;
+   int ignore_replacement;
+   Popup_Display_Policy dual_screen;
+   float timeout;
+   Popup_Corner corner;
+
+   Eina_List  *popups;
+   unsigned int         next_id;
 };
 
 struct _Popup_Data
 {
-  unsigned id;
-  E_Notification_Notify *notif;
-  Evas_Object *win;
-  Eina_List *mirrors;
-  Evas *e;
-  Evas_Object *theme;
-  const char  *app_name;
-  Evas_Object *app_icon;
-  Ecore_Timer *timer;
-  Eina_Bool pending E_BITFIELD;
+   unsigned id;
+   E_Notification_Notify *notif;
+   Evas_Object *win;
+   Eina_List *mirrors;
+   Evas *e;
+   Evas_Object *theme;
+   const char  *app_name;
+   Evas_Object *app_icon;
+   Evas_Object *desktop_icon;
+   Evas_Object *action_box;
+   Eina_List *actions;
+   Ecore_Timer *timer;
+   Eina_Bool pending E_BITFIELD;
 };
 
 
diff --git a/src/modules/notification/e_mod_popup.c b/src/modules/notification/e_mod_popup.c
index 444bc551f..6cf2ccc54 100644
--- a/src/modules/notification/e_mod_popup.c
+++ b/src/modules/notification/e_mod_popup.c
@@ -239,6 +239,61 @@ _notification_theme_cb_find(Popup_Data *popup,
      }
 }
 
+static void
+_notification_theme_cb_anchor(Popup_Data *popup EINA_UNUSED,
+                              Evas_Object *obj EINA_UNUSED,
+                              const char  *emission,
+                              const char  *source EINA_UNUSED)
+{
+   if (!strncmp(emission, "anchor,mouse,clicked,1,",
+                strlen("anchor,mouse,clicked,1,")))
+     {
+        const char *href = "" + strlen("anchor,mouse,clicked,1,");
+        Eina_Strbuf *buf = eina_strbuf_new();
+
+        if (buf)
+          {
+             const char *s;
+
+             eina_strbuf_append(buf, href);
+             s = eina_strbuf_string_get(buf);
+             if ((s) && (*s == '"'))
+               {
+                  eina_strbuf_remove(buf, 0, 1);
+                  s = eina_strbuf_string_get(buf);
+                  if ((s) && (strlen(s) > 0) && (s[strlen(s) - 1] == '"'))
+                    eina_strbuf_replace_last(buf, "\"", "");
+               }
+             if ((s) && (*s == '\''))
+               {
+                  eina_strbuf_remove(buf, 0, 1);
+                  s = eina_strbuf_string_get(buf);
+                  if ((s) && (strlen(s) > 0) && (s[strlen(s) - 1] == '\''))
+                    eina_strbuf_replace_last(buf, "'", "");
+               }
+             printf("NOT: clicked=[%s]\n", eina_strbuf_string_get(buf));
+             e_util_open(eina_strbuf_string_get(buf), NULL);
+             eina_strbuf_free(buf);
+          }
+     }
+}
+
+static void
+_notification_theme_cb_action(Popup_Data *popup,
+                              Evas_Object *obj,
+                              const char  *emission EINA_UNUSED,
+                              const char  *source EINA_UNUSED)
+{
+   const char *action = "" "action");
+
+   if (action)
+     {
+        printf("NOT: action="" action);
+        e_notification_notify_action(popup->notif, action);
+     }
+}
+
+
 static void
 _notification_popup_place_coords_get(int zw, int zh, int ow, int oh, int pos, int *x, int *y)
 {
@@ -269,6 +324,22 @@ _notification_popup_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EIN
    popup->win = NULL;
 }
 
+static Evas_Object *
+_cb_item_provider(void *data, Evas_Object *obj EINA_UNUSED, const char *part, const char *item)
+{
+   Popup_Data *popup = data;
+
+   printf("NOT: PROVIDER.... [%s] item: [%s]\n", part, item);
+//   if (!strcmp(part, "notification.textblock.message"))
+     {
+        Evas_Object *o = e_icon_add(popup->e);
+
+        e_icon_file_set(o, item);
+        return o;
+     }
+   return NULL;
+}
+
 static Popup_Data *
 _notification_popup_new(E_Notification_Notify *n, unsigned id)
 {
@@ -307,6 +378,7 @@ _notification_popup_new(E_Notification_Notify *n, unsigned id)
 
    /* Setup the theme */
    popup->theme = edje_object_add(popup->e);
+   edje_object_item_provider_set(popup->theme, _cb_item_provider, popup);
    e_theme_edje_object_set(popup->theme,
                            "base/theme/modules/notification",
                            "e/modules/notification/main");
@@ -318,14 +390,17 @@ _notification_popup_new(E_Notification_Notify *n, unsigned id)
    evas_object_event_callback_add(popup->win, EVAS_CALLBACK_DEL, _notification_popup_del_cb, popup);
 
    edje_object_signal_callback_add
-     (popup->theme, "notification,deleted", "theme",
+     (popup->theme, "notification,deleted", "*",
      (Edje_Signal_Cb)_notification_theme_cb_deleted, popup);
    edje_object_signal_callback_add
-     (popup->theme, "notification,close", "theme",
+     (popup->theme, "notification,close", "*",
      (Edje_Signal_Cb)_notification_theme_cb_close, popup);
    edje_object_signal_callback_add
-     (popup->theme, "notification,find", "theme",
+     (popup->theme, "notification,find", "*",
      (Edje_Signal_Cb)_notification_theme_cb_find, popup);
+   edje_object_signal_callback_add
+     (popup->theme, "anchor,mouse,clicked,1,*", "notification.textblock.message",
+     (Edje_Signal_Cb)_notification_theme_cb_anchor, popup);
 
    _notification_popup_refresh(popup);
    next_pos = _notification_popup_place(popup, next_pos);
@@ -386,17 +461,35 @@ _notification_popup_refresh(Popup_Data *popup)
    const char *app_icon_max;
    int w, h, width = 80, height = 80;
    E_Zone *zone;
+   Evas_Object *o;
 
    if (!popup) return;
 
    popup->app_name = popup->notif->app_name;
 
+   EINA_LIST_FREE(popup->actions, o)
+     {
+        evas_object_del(o);
+     }
+   if (popup->action_box)
+     {
+        e_comp_object_util_del_list_remove(popup->win, popup->action_box);
+        E_FREE_FUNC(popup->action_box, evas_object_del);
+        edje_object_signal_emit(popup->theme, "e,state,actions,hide", "e");
+     }
+
    if (popup->app_icon)
      {
         e_comp_object_util_del_list_remove(popup->win, popup->app_icon);
         E_FREE_FUNC(popup->app_icon, evas_object_del);
      }
 
+   if (popup->desktop_icon)
+     {
+        e_comp_object_util_del_list_remove(popup->win, popup->desktop_icon);
+        E_FREE_FUNC(popup->desktop_icon, evas_object_del);
+     }
+
    app_icon_max = edje_object_data_get(popup->theme, "app_icon_max");
    if (app_icon_max)
      {
@@ -452,7 +545,7 @@ _notification_popup_refresh(Popup_Data *popup)
                     icon_path = new_path;
                   else
                     {
-                       Evas_Object *o = e_icon_add(popup->e);
+                       o = e_icon_add(popup->e);
                        if (!e_util_icon_theme_set(o, icon_path))
                          evas_object_del(o);
                        else
@@ -510,12 +603,79 @@ _notification_popup_refresh(Popup_Data *popup)
                             popup->app_icon);
    edje_object_signal_emit(popup->theme, "notification,icon", "notification");
 
+   if ((popup->notif->desktop_entry) &&
+       (edje_object_part_exists(popup->theme, "notification.swallow.desktop_icon")))
+     {
+        Efreet_Desktop *desktop;
+        unsigned int size;
+        const char *icon_path;
+        char buf[1024];
+
+        snprintf(buf, sizeof(buf), "%s.desktop", popup->notif->desktop_entry);
+        desktop = efreet_util_desktop_file_id_find(buf);
+        if ((desktop) && (desktop->icon))
+          {
+             size = e_util_icon_size_normalize(width * e_scale);
+             icon_path = efreet_icon_path_find(e_config->icon_theme,
+                                               desktop->icon, size);
+             efreet_desktop_free(desktop);
+
+             o = e_icon_add(popup->e);
+             if (!e_util_icon_theme_set(o, icon_path))
+               evas_object_del(o);
+             else
+               {
+                  popup->desktop_icon = o;
+                  edje_object_part_swallow(popup->theme,
+                                           "notification.swallow.desktop_icon",
+                                           popup->desktop_icon);
+                  evas_object_show(o);
+                  e_comp_object_util_del_list_append(popup->win, o);
+               }
+          }
+     }
    /* Fill up the event message */
    _notification_format_message(popup);
 
+   if (popup->notif->actions)
+     {
+        int i;
+
+        o = popup->action_box = elm_box_add(e_comp->elm);
+        elm_box_homogeneous_set(o, EINA_TRUE);
+        elm_box_horizontal_set(o, EINA_TRUE);
+        e_comp_object_util_del_list_append(popup->win, o);
+        for (i = 0; popup->notif->actions[i].action; i++)
+          {
+             o = edje_object_add(popup->e);
+             e_theme_edje_object_set(o,
+                                     "base/theme/modules/notification",
+                                     "e/modules/notification/action");
+             evas_object_data_set(o, "action", popup->notif->actions[i].action);
+             edje_object_part_text_unescaped_set(o, "e.text.label",
+                                                 popup->notif->actions[i].label);
+             edje_object_signal_callback_add
+               (o, "e,action,clicked", "e",
+                (Edje_Signal_Cb)_notification_theme_cb_action, popup);
+             edje_object_size_min_calc(o, &w, &h);
+             evas_object_size_hint_min_set(o, w, h);
+             printf("NOT: act %ix%i\n", w, h);
+             elm_box_pack_end(popup->action_box, o);
+             evas_object_show(o);
+          }
+//        evas_smart_objects_calculate(popup->e);
+//        edje_message_signal_process();
+        evas_smart_objects_calculate(popup->e);
+        evas_object_size_hint_min_get(popup->action_box, &w, &h);
+        printf("NOT: actbox %ix%i\n", w, h);
+        edje_object_part_swallow(popup->theme, "notification.swallow.actions", popup->action_box);
+        edje_object_signal_emit(popup->theme, "e,state,actions,show", "e");
+     }
+
    /* Compute the new size of the popup */
    edje_object_calc_force(popup->theme);
    edje_object_size_min_calc(popup->theme, &w, &h);
+   printf("NOT: min %ix%i\n", w, h);
    if ((zone = e_comp_object_util_zone_get(popup->win)))
      {
         w = MIN(w, zone->w / 2);
@@ -585,13 +745,18 @@ _notification_format_message(Popup_Data *popup)
 {
    Evas_Object *o = popup->theme;
    Eina_Strbuf *buf = eina_strbuf_new();
+
+   printf("NOT: set message... [%s]\n", popup->notif->body);
    edje_object_part_text_unescaped_set(o, "notification.text.title",
-                             popup->notif->summary);
+                                       popup->notif->summary);
    /* FIXME: Filter to only include allowed markup? */
    /* We need to replace \n with <ps/>. FIXME: We need to handle all the
    * newline kinds, and paragraph separator. ATM this will suffice. */
    eina_strbuf_append(buf, popup->notif->body);
    eina_strbuf_replace_all(buf, "\n", "<br/>");
+   // message is thge shadow sizer part
+   edje_object_part_text_set(o, "message",
+                             eina_strbuf_string_get(buf));
    edje_object_part_text_set(o, "notification.textblock.message",
                              eina_strbuf_string_get(buf));
    eina_strbuf_free(buf);

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to