[epiphany/pgriffis/web-extension/notifications: 2/2] WebExtensions: Implement notifications API
- From: Patrick Griffis <pgriffis src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/pgriffis/web-extension/notifications: 2/2] WebExtensions: Implement notifications API
- Date: Thu, 9 Jun 2022 02:13:14 +0000 (UTC)
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, ¬ification_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]