[polari/wip/fmuellner/flatpak-updates: 3/3] app: Offer restart on update



commit f095a72abb28a389d9fb2c1483c96960dd18f3a3
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu Nov 29 16:33:53 2018 +0100

    app: Offer restart on update
    
    Flatpak gives us a clearly defined way of detecting when the app has
    been updated, as well as a portal for spawning the latest version.
    Use that to offer a seamless restart whenever the app is updated.
    
    https://gitlab.gnome.org/GNOME/polari/merge_requests/80

 data/resources/main-window.ui | 27 ++++++++++++++++++++++++++
 src/application.js            | 45 +++++++++++++++++++++++++++++++++++++++++++
 src/mainWindow.js             | 14 +++++++++++++-
 3 files changed, 85 insertions(+), 1 deletion(-)
---
diff --git a/data/resources/main-window.ui b/data/resources/main-window.ui
index 9247e48..810cfc2 100644
--- a/data/resources/main-window.ui
+++ b/data/resources/main-window.ui
@@ -35,6 +35,33 @@
       <action-widget response="accept">backgroundButton</action-widget>
     </action-widgets>
   </object>
+  <object class="GtkMessageDialog" id="updateDialog">
+    <property name="text" translatable="yes">Polari has been updated</property>
+    <property name="secondary_text" translatable="yes">You can start using the new version immediately 
without interrupting existing connections, or keep using the current version until Polari is 
closed.</property>
+    <property name="destroy-with-parent">true</property>
+    <property name="modal">true</property>
+    <child type="action">
+      <object class="GtkButton" id="ignoreButton">
+        <property name="label" translatable="yes">Ignore</property>
+        <property name="visible">True</property>
+        <property name="can-default">True</property>
+      </object>
+    </child>
+    <child type="action">
+      <object class="GtkButton" id="restartButton">
+        <property name="label" translatable="yes">Restart Now</property>
+        <property name="visible">True</property>
+        <property name="can-default">True</property>
+        <style>
+          <class name="suggested-action"/>
+        </style>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="cancel">ignoreButton</action-widget>
+      <action-widget response="accept">restartButton</action-widget>
+    </action-widgets>
+  </object>
   <template class="Gjs_MainWindow">
     <property name="title" translatable="yes">Polari</property>
     <property name="icon-name">org.gnome.Polari</property>
diff --git a/src/application.js b/src/application.js
index 62f8f4a..c8e8b11 100644
--- a/src/application.js
+++ b/src/application.js
@@ -38,6 +38,7 @@ var Application = GObject.registerClass({
 
         this._windowRemovedId = 0;
         this._restarting = false;
+        this._updatePending = false;
 
         this.add_main_option('start-client', 0,
                              GLib.OptionFlags.NONE, GLib.OptionArg.NONE,
@@ -235,6 +236,9 @@ var Application = GObject.registerClass({
             accels: ['F1'] },
           { name: 'about',
             activate: this._onShowAbout.bind(this) },
+          { name: 'restart',
+            activate: this._onRestart.bind(this),
+            create_hook: a => { a.enabled = Utils.isFlatpakSandbox(); } },
           { name: 'quit',
             activate: this._onQuit.bind(this),
             accels: ['<Primary>q'] },
@@ -341,6 +345,18 @@ var Application = GObject.registerClass({
         Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
                                                  provider,
                                                  Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+        let file = Gio.File.new_for_path('/app/.updated');
+        this._updateMonitor = file.monitor_file(Gio.FileMonitorFlags.NONE, null);
+        this._updateMonitor.connect('changed', (mon, file, other, eventType) => {
+            if (eventType != Gio.FileMonitorEvent.CREATED)
+                return;
+
+            if (this.active_window)
+                this.active_window.showUpdateDialog();
+            else
+                this._updatePending = true;
+        });
     }
 
     vfunc_activate() {
@@ -371,6 +387,10 @@ var Application = GObject.registerClass({
         }
 
         this.active_window.present();
+
+        if (this._updatePending)
+            this.active_window.showUpdateDialog();
+        this._updatePending = false;
     }
 
     vfunc_window_added(window) {
@@ -861,6 +881,31 @@ var Application = GObject.registerClass({
         });
     }
 
+    _onRestart() {
+        let cwd = GLib.get_current_dir();
+        let argv = ['polari', '--gapplication-replace'];
+        let fds = [];
+        let envs = [];
+        let flags = 2; // respawn latest
+        let options = [];
+        this.get_dbus_connection().call(
+            'org.freedesktop.portal.Flatpak',
+            '/org/freedesktop/portal/Flatpak',
+            'org.freedesktop.portal.Flatpak',
+            'Spawn',
+            new GLib.Variant(
+                '(ayaaya{uh}a{ss}ua{sv})',
+                [cwd, argv, fds, envs, flags, options]),
+            null,
+            Gio.DBusCallFlags.NONE,
+            -1,
+            null,
+            (conn, res) => {
+                let [pid] = conn.call_finish(res).deep_unpack();
+                debug(`Restarted with PID ${pid}`);
+            });
+    }
+
     _onQuit() {
         if (this._windowRemovedId)
             this.disconnect(this._windowRemovedId);
diff --git a/src/mainWindow.js b/src/mainWindow.js
index dd65c51..e90c8a5 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -88,7 +88,8 @@ var MainWindow = GObject.registerClass({
                        'roomListRevealer',
                        'overlay',
                        'roomStack',
-                       'closeConfirmationDialog'],
+                       'closeConfirmationDialog',
+                       'updateDialog'],
     Properties: {
         subtitle: GObject.ParamSpec.string('subtitle',
                                            'subtitle',
@@ -193,6 +194,13 @@ var MainWindow = GObject.registerClass({
             this.destroy();
         });
 
+        this._updateDialog.transient_for = this;
+        this._updateDialog.connect('response', (dlg, response) => {
+            if (response == Gtk.ResponseType.ACCEPT)
+                this.application.activate_action('restart', null);
+            dlg.destroy();
+        });
+
         this.connect('window-state-event', this._onWindowStateEvent.bind(this));
         this.connect('size-allocate', this._onSizeAllocate.bind(this));
         this.connect('destroy', this._onDestroy.bind(this));
@@ -375,6 +383,10 @@ var MainWindow = GObject.registerClass({
             this._lastActiveRoom = null;
     }
 
+    showUpdateDialog() {
+        this._updateDialog.show();
+    }
+
     showJoinRoomDialog() {
         let dialog = new JoinDialog({ transient_for: this });
         dialog.show();


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