[gnome-shell/wip/gtk-notification: 40/40] notificationDaemon: Write notifications out to disk



commit 74a9d9e73037c624c9c094de8ed16ad2d3a48e9a
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Sun Oct 13 18:52:37 2013 -0400

    notificationDaemon: Write notifications out to disk
    
    This allows notifications to persist even after reboots and
    gnome-shell restarts.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=710137

 js/ui/notificationDaemon.js |   70 +++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 67 insertions(+), 3 deletions(-)
---
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index 7027900..3ca2d52 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -692,6 +692,8 @@ const GtkNotificationDaemonNotification = new Lang.Class({
     Extends: MessageTray.Notification,
 
     setFrom: function(notification) {
+        this._serialized = GLib.Variant.new('a{sv}', notification);
+
         let { "title": title,
               "body": body,
               "icon": gicon,
@@ -733,6 +735,10 @@ const GtkNotificationDaemonNotification = new Lang.Class({
             this.source.open();
         this.parent();
     },
+
+    serialize: function() {
+        return this._serialized;
+    },
 });
 
 const FdoApplicationIface = <interface name="org.freedesktop.Application">
@@ -797,7 +803,7 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
         app.ActivateRemote(getPlatformData());
     },
 
-    addNotification: function(notificationId, notificationParams) {
+    addNotification: function(notificationId, notificationParams, showBanner) {
         let notification;
         if (this._notifications[notificationId]) {
             notification = this._notifications[notificationId];
@@ -810,13 +816,26 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
         }
 
         notification.setFrom(notificationParams);
-        this.notify(notification);
+
+        if (showBanner)
+            this.notify(notification);
+        else
+            this.pushNotification(notification);
     },
 
     removeNotification: function(notificationId) {
         if (this._notifications[notificationId])
             
this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
     },
+
+    serialize: function() {
+        let notifications = [];
+        for (let notificationId in this._notifications) {
+            let notification = this._notifications[notificationId];
+            notifications.push([notificationId, notification.serialize()]);
+        }
+        return GLib.Variant.new('(sa(sv))', this._appId, notifications);
+    },
 });
 
 const GtkNotificationsIface = <interface name="org.gtk.Notifications">
@@ -837,6 +856,8 @@ const GtkNotificationDaemon = new Lang.Class({
     _init: function() {
         this._sources = {};
 
+        this._loadNotifications();
+
         this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GtkNotificationsIface, this);
         this._dbusImpl.export(Gio.DBus.session, '/org/gtk/Notifications');
 
@@ -850,13 +871,56 @@ const GtkNotificationDaemon = new Lang.Class({
         let source = new GtkNotificationDaemonAppSource(appId);
 
         source.connect('destroy', Lang.bind(this, function() {
+            // When a source is destroyed, it should first
+            // destroy all of its notifications, so we should
+            // not need to call _saveNotifications here.
             delete this._sources[appId];
         }));
+        source.connect('count-updated', Lang.bind(this, this._saveNotifications));
         Main.messageTray.add(source);
         this._sources[appId] = source;
         return source;
     },
 
+    _loadNotifications: function() {
+        this._isLoading = true;
+
+        let value = global.get_persistent_state('a(sa(sa{sv}))', 'notifications');
+        if (value) {
+            let sources = value.deep_unpack();
+            sources.forEach(Lang.bind(this, function([appId, notifications]) {
+                if (notifications.length == 0)
+                    return;
+
+                let source;
+                try {
+                    source = this._ensureAppSource(appId);
+                } catch(e if e instanceof InvalidAppError) {
+                    return;
+                }
+
+                notifications.forEach(function([notificationId, notification]) {
+                    source.addNotification(notificationId, notification.deep_unpack(), false);
+                });
+            }));
+        }
+
+        this._isLoading = false;
+    },
+
+    _saveNotifications: function() {
+        if (this._isLoading)
+            return;
+
+        let sources = [];
+        for (let appId in this._sources) {
+            let source = this._sources[appId];
+            sources.push(source.serialize());
+        }
+
+        global.set_persistent_state('notifications', GLib.Variant.new_array('a@(sa{sa{sv}})', sources));
+    },
+
     AddNotificationAsync: function(params, invocation) {
         let [appId, notificationId, notification] = params;
 
@@ -868,7 +932,7 @@ const GtkNotificationDaemon = new Lang.Class({
             return;
         }
 
-        source.addNotification(notificationId, notification);
+        source.addNotification(notificationId, notification, true);
 
         invocation.return_value(null);
     },


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]