[epiphany/pgriffis/web-extension/notifications: 3/3] WebExtensions: Implement notifications API
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/pgriffis/web-extension/notifications: 3/3] WebExtensions: Implement notifications API
- Date: Thu, 9 Jun 2022 13:25:56 +0000 (UTC)
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, ¬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]