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




commit 79994f978ea713e09480097fcfa5e4e2353d900f
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.

 .../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]