[gnome-shell/wip/gtk-notification: 19/22] notificationDaemon: Implement the new GTK+ notifications API



commit a16815515f89b6d4cd010ea5a4c3d69e46938f0b
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.

 js/ui/notificationDaemon.js |  167 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 167 insertions(+), 0 deletions(-)
---
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index c267545..a899b13 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -675,10 +675,177 @@ const FdoNotificationDaemonSource = new Lang.Class({
     }
 });
 
+
+const GtkNotificationDaemonNotification = new Lang.Class({
+    Name: 'GtkNotificationDaemonNotification',
+    Extends: MessageTray.Notification,
+
+    _init: function(source, notification) {
+        let { title: title, body: body, gicon: gicon, actions: actions, defaultAction: defaultAction } = 
notification;
+        this.parent(source, title.unpack(), body.unpack(), { gicon: gicon });
+
+        this._defaultAction = defaultAction ? defaultAction.unpack() : null;
+
+        if (actions)
+            actions.deep_unpack().forEach(Lang.bind(this, function([title, actionId, target]) {
+                this.addButton(title, Lang.bind(this, function() {
+                    this._activateAction(actionId, target);
+                }));
+            }));
+    },
+
+    _activateAction: function(namespacedActionId, target) {
+        if (namespacedActionId.startsWith('app.')) {
+            let actionId = namespacedActionId.slice('app.'.length);
+            this.source.activateAction(actionId, target);
+        }
+    },
+
+    _onClicked: function() {
+        if (this._defaultAction)
+            this._activateAction(this._defaultAction);
+        else
+            this.source.open();
+        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 };
+}
+
+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');
+        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, getPlatformData());
+    },
+
+    open: function() {
+        let app = this._createApp();
+        app.ActivateRemote(getPlatformData());
+    },
+
+    addNotification: function(notificationId, notificationParams) {
+        if (this._notifications[notificationId])
+            this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.EXPIRED);
+
+        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 = this._ensureAppSource(appId);
+        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]