[gnome-shell: 8/11] notificationDaemon: Implement the new GTK+ notifications API
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell: 8/11] notificationDaemon: Implement the new GTK+ notifications API
- Date: Mon, 21 Oct 2013 19:19:59 +0000 (UTC)
commit e0b87f1e143447b375e321212a86b05bdb5375ea
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Sun Oct 13 13:04:02 2013 -0400
notificationDaemon: Implement the new GTK+ notifications API
The new API is designed to support features like persistence and uses
the new org.freedesktop.Application specification for activating
actions on notifications. While we won't add support for persistence
yet, implement the new notification spec with parity of the old one.
https://bugzilla.gnome.org/show_bug.cgi?id=710137
js/ui/notificationDaemon.js | 198 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 198 insertions(+), 0 deletions(-)
---
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index ac5b543..6a55509 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -710,10 +710,208 @@ const FdoNotificationDaemonSource = new Lang.Class({
}
});
+
+const GtkNotificationDaemonNotification = new Lang.Class({
+ Name: 'GtkNotificationDaemonNotification',
+ Extends: MessageTray.Notification,
+
+ _init: function(source, notification) {
+ this.parent(source);
+
+ let { "title": title,
+ "body": body,
+ "icon": gicon,
+ "urgent": urgent,
+ "buttons": buttons,
+ "default-action": defaultAction,
+ "default-action-target": defaultActionTarget } = notification;
+
+ this.setUrgency(urgent ? MessageTray.Urgency.CRITICAL : MessageTray.Urgency.NORMAL);
+
+ if (buttons) {
+ buttons.deep_unpack().forEach(Lang.bind(this, function(button) {
+ this.addAction(button.label, Lang.bind(this, this._onButtonClicked, button));
+ }));
+ }
+
+ this._defaultAction = defaultAction ? defaultAction.unpack() : null;
+ this._defaultActionTarget = defaultActionTarget ? defaultActionTarget.unpack() : null;
+
+ this.update(title.unpack(), body ? body.unpack() : null, { gicon: gicon });
+ },
+
+ _activateAction: function(namespacedActionId, target) {
+ if (namespacedActionId) {
+ if (namespacedActionId.startsWith('app.')) {
+ let actionId = namespacedActionId.slice('app.'.length);
+ this.source.activateAction(actionId, target);
+ }
+ } else {
+ this.source.open();
+ }
+ },
+
+ _onButtonClicked: function(button) {
+ let { "action": action, "action-target": actionTarget } = button;
+ this._activateAction(action, actionTarget);
+ },
+
+ _onClicked: function() {
+ this._activateAction(this._defaultAction, this._defaultActionTarget);
+ this.parent();
+ },
+});
+
+const FdoApplicationIface = <interface name="org.freedesktop.Application">
+<method name="ActivateAction">
+ <arg type="s" direction="in" />
+ <arg type="av" direction="in" />
+ <arg type="a{sv}" direction="in" />
+</method>
+<method name="Activate">
+ <arg type="a{sv}" direction="in" />
+</method>
+</interface>;
+const FdoApplicationProxy = Gio.DBusProxy.makeProxyWrapper(FdoApplicationIface);
+
+function objectPathFromAppId(appId) {
+ return '/' + appId.replace(/\./g, '/');
+}
+
+function getPlatformData() {
+ let startupId = GLib.Variant.new('s', '_TIME' + global.get_current_time());
+ return { "desktop-startup-id": startupId };
+}
+
+function InvalidAppError() {}
+
+const GtkNotificationDaemonAppSource = new Lang.Class({
+ Name: 'GtkNotificationDaemonAppSource',
+ Extends: MessageTray.Source,
+
+ _init: function(appId) {
+ this._appId = appId;
+ this._objectPath = objectPathFromAppId(appId);
+
+ this._app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
+ if (!this._app)
+ throw new InvalidAppError();
+
+ this._notifications = {};
+
+ this.parent(this._app.get_name());
+ },
+
+ createIcon: function(size) {
+ return this._app.create_icon_texture(size);
+ },
+
+ _createPolicy: function() {
+ return new MessageTray.NotificationApplicationPolicy(this._appId);
+ },
+
+ _createApp: function() {
+ return new FdoApplicationProxy(Gio.DBus.session, this._appId, this._objectPath);
+ },
+
+ activateAction: function(actionId, target) {
+ let app = this._createApp();
+ app.ActivateActionRemote(actionId, target ? [target] : [], getPlatformData());
+ },
+
+ open: function() {
+ let app = this._createApp();
+ app.ActivateRemote(getPlatformData());
+ },
+
+ addNotification: function(notificationId, notificationParams) {
+ if (this._notifications[notificationId])
+ this._notifications[notificationId].destroy();
+
+ let notification = new GtkNotificationDaemonNotification(this, notificationParams);
+ notification.connect('destroy', Lang.bind(this, function() {
+ delete this._notifications[notificationId];
+ }));
+ this._notifications[notificationId] = notification;
+
+ this.notify(notification);
+ },
+
+ removeNotification: function(notificationId) {
+ if (this._notifications[notificationId])
+
this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
+ },
+});
+
+const GtkNotificationsIface = <interface name="org.gtk.Notifications">
+<method name="AddNotification">
+ <arg type="s" direction="in" />
+ <arg type="s" direction="in" />
+ <arg type="a{sv}" direction="in" />
+</method>
+<method name="RemoveNotification">
+ <arg type="s" direction="in" />
+ <arg type="s" direction="in" />
+</method>
+</interface>;
+
+const GtkNotificationDaemon = new Lang.Class({
+ Name: 'GtkNotificationDaemon',
+
+ _init: function() {
+ this._sources = {};
+
+ this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GtkNotificationsIface, this);
+ this._dbusImpl.export(Gio.DBus.session, '/org/gtk/Notifications');
+
+ Gio.DBus.session.own_name('org.gtk.Notifications', Gio.BusNameOwnerFlags.REPLACE, null, null);
+ },
+
+ _ensureAppSource: function(appId) {
+ if (this._sources[appId])
+ return this._sources[appId];
+
+ let source = new GtkNotificationDaemonAppSource(appId);
+
+ source.connect('destroy', Lang.bind(this, function() {
+ delete this._sources[appId];
+ }));
+ Main.messageTray.add(source);
+ this._sources[appId] = source;
+ return source;
+ },
+
+ AddNotificationAsync: function(params, invocation) {
+ let [appId, notificationId, notification] = params;
+
+ let source;
+ try {
+ source = this._ensureAppSource(appId);
+ } catch(e if e instanceof InvalidAppError) {
+ invocation.return_dbus_error('org.gtk.Notifications.InvalidApp', 'The app by ID "%s" could not
be found'.format(appId));
+ return;
+ }
+
+ source.addNotification(notificationId, notification);
+
+ invocation.return_value(null);
+ },
+
+ RemoveNotificationAsync: function(params, invocation) {
+ let [appId, notificationId] = params;
+ let source = this._sources[appId];
+ if (source)
+ source.removeNotification(notificationId);
+
+ invocation.return_value(null);
+ },
+});
+
const NotificationDaemon = new Lang.Class({
Name: 'NotificationDaemon',
_init: function() {
this._fdoNotificationDaemon = new FdoNotificationDaemon();
+ this._gtkNotificationDaemon = new GtkNotificationDaemon();
},
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]