[epiphany/pgriffis/web-extension/notifications: 3/3] WebExtensions: Implement notifications API




commit 8262cf9821443346901b02d6687242ef0418c53c
Author: Patrick Griffis <pgriffis igalia com>
Date:   Wed Jun 8 21:12:44 2022 -0500

    WebExtensions: Implement notifications API
    
    This implements as much of the API as we can backed by GNotification.
    
    There are options that aren't supported yet like icons that can be
    added later.
    
    Part-of: <https://gitlab.gnome.org/GNOME/epiphany/-/merge_requests/1141>

 .../resources/js/webextensions-common.js           |   4 +-
 .../resources/js/webextensions.js                  |   8 ++
 src/ephy-shell.c                                   |  12 ++-
 src/webextension/api/notifications.c               | 118 ++++++++++++++++++---
 src/webextension/ephy-web-extension-manager.c      |  37 +++++++
 src/webextension/ephy-web-extension-manager.h      |   3 +
 6 files changed, 165 insertions(+), 17 deletions(-)
---
diff --git a/embed/web-process-extension/resources/js/webextensions-common.js 
b/embed/web-process-extension/resources/js/webextensions-common.js
index fca23caed..86c8d8460 100644
--- a/embed/web-process-extension/resources/js/webextensions-common.js
+++ b/embed/web-process-extension/resources/js/webextensions-common.js
@@ -22,9 +22,9 @@ class EphyEventListener {
         return !!this._listeners.find(l => l.callback === cb);
     }
 
-    _emit (data) {
+    _emit (...data) {
         for (const listener of this._listeners)
-            listener.callback (data);
+            listener.callback (...data);
     }
 
     _emit_with_reply (message, sender, message_guid) {
diff --git a/embed/web-process-extension/resources/js/webextensions.js 
b/embed/web-process-extension/resources/js/webextensions.js
index db4d9d08c..6c9f40c63 100644
--- a/embed/web-process-extension/resources/js/webextensions.js
+++ b/embed/web-process-extension/resources/js/webextensions.js
@@ -43,7 +43,15 @@ window.browser.tabs = {
 };
 
 window.browser.notifications = {
+    clear: function (...args) { return ephy_message ('notifications.clear', args); },
     create: function (...args) { return ephy_message ('notifications.create', args); },
+    update: function (...args) { return ephy_message ('notifications.update', args); },
+    onClicked: new EphyEventListener (),
+    onButtonClicked: new EphyEventListener (),
+    // The remaining APIs here are stubs as long as we use GNotification since we don't have this 
information.
+    getAll: function (...args) { return ephy_message ('notifications.getAll', args); },
+    onClosed: new EphyEventListener (),
+    onShown: new EphyEventListener (),
 };
 
 // browser.extension is defined in ephy-webextension-common.c
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index f319e49b5..3c8c4464c 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -352,6 +352,15 @@ notification_clicked (GSimpleAction *action,
     webkit_notification_clicked (notification);
 }
 
+static void
+webextension_action (GSimpleAction *action,
+                     GVariant      *parameter,
+                     gpointer       user_data)
+{
+  EphyWebExtensionManager *manager = ephy_web_extension_manager_get_default ();
+  ephy_web_extension_manager_handle_notifications_action (manager, parameter);
+}
+
 static GActionEntry app_entries[] = {
   { "new-window", new_window, NULL, NULL, NULL },
   { "new-incognito", new_incognito_window, NULL, NULL, NULL },
@@ -367,7 +376,8 @@ static GActionEntry app_entries[] = {
   { "quit", quit_application, NULL, NULL, NULL },
   { "show-downloads", show_downloads, NULL, NULL, NULL },
   { "launch-app", launch_app, "s", NULL, NULL },
-  { "notification-clicked", notification_clicked, "t", NULL, NULL},
+  { "notification-clicked", notification_clicked, "t", NULL, NULL },
+  { "webextension-notification", webextension_action, "(ssi)", NULL, NULL },
 };
 
 static GActionEntry non_incognito_extra_app_entries[] = {
diff --git a/src/webextension/api/notifications.c b/src/webextension/api/notifications.c
index fcf8c841d..c0ee0bff1 100644
--- a/src/webextension/api/notifications.c
+++ b/src/webextension/api/notifications.c
@@ -20,11 +20,29 @@
 
 #include "config.h"
 
-#include "ephy-notification.h"
+#include "ephy-shell.h"
 #include "ephy-web-extension.h"
 
 #include "notifications.h"
 
+static char *
+get_string_property (JSCValue   *obj,
+                     const char *name)
+{
+  g_autoptr (JSCValue) value = jsc_value_object_get_property (obj, name);
+  if (!jsc_value_is_string (value))
+    return NULL;
+  return jsc_value_to_string (value);
+}
+
+static char *
+create_extension_notification_id (EphyWebExtension *web_extension,
+                                  const char       *id)
+{
+  /* We need to namespace notification ids. */
+  return g_strconcat (ephy_web_extension_get_guid (web_extension), ".", id, NULL);
+}
+
 static char *
 notifications_handler_create (EphyWebExtension  *self,
                               char              *name,
@@ -33,31 +51,103 @@ notifications_handler_create (EphyWebExtension  *self,
                               GError           **error)
 {
   g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
-  g_autofree char *title_str = NULL;
-  g_autofree char *message_str = NULL;
-  g_autoptr (JSCValue) title = NULL;
-  g_autoptr (JSCValue) message = NULL;
-  EphyNotification *notify;
+  g_autoptr (JSCValue) button_array = NULL;
+  g_autofree char *id = NULL;
+  g_autofree char *namespaced_id = NULL;
+  g_autofree char *title = NULL;
+  g_autofree char *message = NULL;
+  g_autoptr (GNotification) notification = NULL;
+  const char *extension_guid = ephy_web_extension_get_guid (self);
+
+  /* We share the same "create" and "update" function here because our
+   * implementation would be the same. The only difference is we require
+   * an id if its for an update. */
+  if (jsc_value_is_string (value)) {
+    id = jsc_value_to_string (value);
+    g_object_unref (value);
+    value = jsc_value_object_get_property_at_index (args, 1);
+  } else {
+    if (strcmp (name, "update") == 0) {
+      g_set_error_literal (error, WEB_EXTENSION_ERROR, WEB_EXTENSION_ERROR_INVALID_ARGUMENT, 
"notifications.update(): id not given");
+      return NULL;
+    }
+    id = g_dbus_generate_guid ();
+  }
 
   if (!jsc_value_is_object (value)) {
-    g_set_error_literal (error, WEB_EXTENSION_ERROR, WEB_EXTENSION_ERROR_INVALID_ARGUMENT, "Invalid 
Arguments");
+    g_set_error (error, WEB_EXTENSION_ERROR, WEB_EXTENSION_ERROR_INVALID_ARGUMENT, "notifications.%s(): 
notificationOptions not given", name);
     return NULL;
   }
 
-  title = jsc_value_object_get_property (value, "title");
-  title_str = jsc_value_to_string (title);
+  title = get_string_property (value, "title");
+  message = get_string_property (value, "message");
+
+  if (!title || !message) {
+    g_set_error (error, WEB_EXTENSION_ERROR, WEB_EXTENSION_ERROR_INVALID_ARGUMENT, "notifications.%s(): 
title and message are required", name);
+    return NULL;
+  }
 
-  message = jsc_value_object_get_property (value, "message");
-  message_str = jsc_value_to_string (message);
+  notification = g_notification_new (title);
+  g_notification_set_body (notification, message);
+  g_notification_set_default_action_and_target (notification, "app.webextension-notification", "(ssi)", 
extension_guid, id, -1);
+
+  button_array = jsc_value_object_get_property (value, "buttons");
+  if (jsc_value_is_array (button_array)) {
+    for (guint i = 0; i < 2; i++) {
+      g_autoptr (JSCValue) button = jsc_value_object_get_property_at_index (button_array, i);
+      g_autofree char *button_title = get_string_property (button, "title");
+      if (button_title)
+        g_notification_add_button_with_target (notification, button_title, "app.webextension-notification", 
"(ssi)", extension_guid, id, i);
+    }
+  }
 
-  notify = ephy_notification_new (g_strdup (title_str), g_strdup (message_str));
-  ephy_notification_show (notify);
+  namespaced_id = create_extension_notification_id (self, id);
+  g_application_send_notification (G_APPLICATION (ephy_shell_get_default ()), namespaced_id, notification);
 
-  return NULL;
+  return g_strdup_printf ("\"%s\"", id);
+}
+
+static char *
+notifications_handler_clear (EphyWebExtension  *self,
+                             char              *name,
+                             JSCValue          *args,
+                             WebKitWebView     *web_view,
+                             GError           **error)
+{
+  g_autoptr (JSCValue) value = jsc_value_object_get_property_at_index (args, 0);
+  g_autofree char *id = NULL;
+  g_autofree char *namespaced_id = NULL;
+
+  if (!jsc_value_is_string (value)) {
+    g_set_error_literal (error, WEB_EXTENSION_ERROR, WEB_EXTENSION_ERROR_INVALID_ARGUMENT, 
"notifications.clear(): id not given");
+    return NULL;
+  }
+
+  id = jsc_value_to_string (value);
+  namespaced_id = create_extension_notification_id (self, id);
+
+  g_application_withdraw_notification (G_APPLICATION (ephy_shell_get_default ()), namespaced_id);
+
+  /* We don't actually know if a notification was withdrawn but lets assume it was. */
+  return g_strdup ("true");
+}
+
+static char *
+notifications_handler_get_all (EphyWebExtension  *self,
+                               char              *name,
+                               JSCValue          *args,
+                               WebKitWebView     *web_view,
+                               GError           **error)
+{
+  /* GNotification does not provide information on the state of notifications. */
+  return g_strdup ("[]");
 }
 
 static EphyWebExtensionSyncApiHandler notifications_handlers[] = {
   {"create", notifications_handler_create},
+  {"clear", notifications_handler_clear},
+  {"getAll", notifications_handler_get_all},
+  {"update", notifications_handler_create},
 };
 
 void
diff --git a/src/webextension/ephy-web-extension-manager.c b/src/webextension/ephy-web-extension-manager.c
index 9d1046ded..0b4269b23 100644
--- a/src/webextension/ephy-web-extension-manager.c
+++ b/src/webextension/ephy-web-extension-manager.c
@@ -1323,6 +1323,43 @@ ephy_web_extension_manager_get_page_action (EphyWebExtensionManager *self,
   return ret;
 }
 
+static EphyWebExtension *
+ephy_web_extension_manager_get_extension_by_guid (EphyWebExtensionManager *self,
+                                                  const char              *guid)
+{
+  for (GList *l = self->web_extensions; l; l = g_list_next (l)) {
+    EphyWebExtension *web_extension = l->data;
+    if (strcmp (guid, ephy_web_extension_get_guid (web_extension)) == 0)
+      return web_extension;
+  }
+
+  return NULL;
+}
+
+void
+ephy_web_extension_manager_handle_notifications_action (EphyWebExtensionManager *self,
+                                                        GVariant                *params)
+{
+  EphyWebExtension *web_extension;
+  g_autofree char *json = NULL;
+  const char *extension_guid;
+  const char *notification_id;
+  int index;
+
+  g_variant_get (params, "(&s&si)", &extension_guid, &notification_id, &index);
+  web_extension = ephy_web_extension_manager_get_extension_by_guid (self, extension_guid);
+  if (!web_extension)
+    return;
+
+  if (index == -1) {
+    json = g_strdup_printf ("\"%s\"", notification_id);
+    ephy_web_extension_manager_emit_in_extension_views (self, web_extension, "notifications.onClicked", 
json);
+  } else {
+    json = g_strdup_printf ("\"%s\", %d", notification_id, index);
+    ephy_web_extension_manager_emit_in_extension_views (self, web_extension, 
"notifications.onButtonClicked", json);
+  }
+}
+
 static void
 handle_message_reply (EphyWebExtension *web_extension,
                       JSCValue         *args)
diff --git a/src/webextension/ephy-web-extension-manager.h b/src/webextension/ephy-web-extension-manager.h
index e9fd62412..decb1016c 100644
--- a/src/webextension/ephy-web-extension-manager.h
+++ b/src/webextension/ephy-web-extension-manager.h
@@ -69,6 +69,9 @@ GtkWidget               *ephy_web_extension_manager_get_page_action
 WebKitWebView           *ephy_web_extension_manager_get_background_web_view         (EphyWebExtensionManager 
*self,
                                                                                      EphyWebExtension        
*web_extension);
 
+void                     ephy_web_extension_manager_handle_notifications_action     (EphyWebExtensionManager 
*self,
+                                                                                     GVariant                
*params);
+
 void                     ephy_web_extension_manager_emit_in_extension_views         (EphyWebExtensionManager 
*self,
                                                                                      EphyWebExtension        
*web_extension,
                                                                                      const char              
*name,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]