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



commit 6feceab00f623d8baf0d332919bb892178366e6f
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.

 js/ui/notificationDaemon.js |   60 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 57 insertions(+), 3 deletions(-)
---
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index a899b13..38a227a 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -6,6 +6,7 @@ const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const Lang = imports.lang;
 const Shell = imports.gi.Shell;
+const Signals = imports.signals;
 const Mainloop = imports.mainloop;
 const St = imports.gi.St;
 
@@ -683,6 +684,7 @@ const GtkNotificationDaemonNotification = new Lang.Class({
     _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._serialized = GLib.Variant.new('a{sv}', notification);
 
         this._defaultAction = defaultAction ? defaultAction.unpack() : null;
 
@@ -708,6 +710,10 @@ const GtkNotificationDaemonNotification = new Lang.Class({
             this.source.open();
         this.parent();
     },
+
+    serialize: function() {
+        return this._serialized;
+    },
 });
 
 const FdoApplicationIface = <interface name="org.freedesktop.Application">
@@ -767,7 +773,7 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
         app.ActivateRemote(getPlatformData());
     },
 
-    addNotification: function(notificationId, notificationParams) {
+    addNotification: function(notificationId, notificationParams, showBanner) {
         if (this._notifications[notificationId])
             this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.EXPIRED);
 
@@ -777,14 +783,24 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
         }));
         this._notifications[notificationId] = notification;
 
-        this.notify(notification);
+        this.notify(notification, showBanner);
     },
 
     removeNotification: function(notificationId) {
         if (this._notifications[notificationId])
             
this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
     },
+
+    serialize: function() {
+        let notifications = [];
+        Object.keys(this._notifications).forEach(Lang.bind(this, function(notificationId) {
+            let notification = this._notifications[notificationId];
+            notifications.push([notificationId, notification.serialize()]);
+        }));
+        return [this._appId, notifications];
+    },
 });
+Signals.addSignalMethods(GtkNotificationDaemonAppSource.prototype);
 
 const GtkNotificationsIface = <interface name="org.gtk.Notifications">
 <method name="AddNotification">
@@ -804,6 +820,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');
 
@@ -816,17 +834,53 @@ 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-changed', 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(sv))', 'notifications');
+        if (value) {
+            let sources = value.deep_unpack();
+            sources.forEach(Lang.bind(this, function([appId, notifications]) {
+                if (notifications.length == 0)
+                    return;
+
+                let source = this._ensureAppSource(appId);
+                notifications.forEach(function([notificationId, notification]) {
+                    source.addNotification(notificationId, notification.deep_unpack(), false);
+                });
+            }));
+        }
+
+        this._isLoading = false;
+    },
+
+    _saveNotifications: function() {
+        if (this._isLoading)
+            return;
+
+        let sources = [];
+        Object.keys(this._sources).forEach(Lang.bind(this, function(appId) {
+            let source = this._sources[appId];
+            sources.push(source.serialize());
+        }));
+        global.set_persistent_state('notifications', GLib.Variant.new('a(sa(sv))', sources));
+    },
+
     AddNotificationAsync: function(params, invocation) {
         let [appId, notificationId, notification] = params;
         let source = this._ensureAppSource(appId);
-        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]