[gnome-shell] Rearchitect the Shell to have a components system



commit 2a800e4ce0912f098b4a469fc7a680ad094b3bfa
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Sun Sep 2 22:23:50 2012 -0300

    Rearchitect the Shell to have a components system
    
    Components are pieces of the shell code that can be added/removed
    at runtime, like extension, but are tied more directly to a session
    mode. The session polkit agent, the network agent, autorun/automount,
    are all components, keyring, recorder and telepathy client are all
    now copmonents.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=683156

 js/Makefile.am                                     |   20 +++--
 js/ui/components/__init__.js                       |   61 ++++++++++++++
 js/ui/{ => components}/automountManager.js         |   66 +++++----------
 js/ui/{ => components}/autorunManager.js           |   60 ++++++++------
 js/ui/{keyringPrompt.js => components/keyring.js}  |   40 ++++++---
 js/ui/{ => components}/networkAgent.js             |   30 ++-----
 .../polkitAgent.js}                                |   38 +++------
 js/ui/components/recorder.js                       |   58 +++++++++++++
 js/ui/{ => components}/telepathyClient.js          |   34 +++++---
 js/ui/main.js                                      |   74 +----------------
 js/ui/sessionMode.js                               |   15 +--
 src/shell-polkit-authentication-agent.c            |   87 ++++++++++----------
 src/shell-polkit-authentication-agent.h            |    3 +
 13 files changed, 314 insertions(+), 272 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index 3300981..351ced1 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -1,3 +1,4 @@
+NULL =
 
 EXTRA_DIST = misc/config.js.in
 CLEANFILES = misc/config.js
@@ -37,8 +38,6 @@ nobase_dist_js_DATA = 	\
 	ui/altTab.js		\
 	ui/appDisplay.js	\
 	ui/appFavorites.js	\
-	ui/automountManager.js  \
-	ui/autorunManager.js    \
 	ui/boxpointer.js	\
 	ui/calendar.js		\
 	ui/checkBox.js		\
@@ -47,15 +46,14 @@ nobase_dist_js_DATA = 	\
 	ui/dateMenu.js		\
 	ui/dnd.js		\
 	ui/endSessionDialog.js	\
-	ui/environment.js	\
 	ui/extensionSystem.js	\
 	ui/extensionDownloader.js \
+	ui/environment.js	\
 	ui/flashspot.js		\
 	ui/ibusCandidatePopup.js\
 	ui/grabHelper.js	\
 	ui/iconGrid.js		\
 	ui/keyboard.js		\
-	ui/keyringPrompt.js	\
 	ui/layout.js		\
 	ui/lightbox.js		\
 	ui/lookingGlass.js	\
@@ -64,7 +62,6 @@ nobase_dist_js_DATA = 	\
 	ui/main.js		\
 	ui/messageTray.js	\
 	ui/modalDialog.js	\
-	ui/networkAgent.js	\
 	ui/sessionMode.js	\
 	ui/shellEntry.js	\
 	ui/shellMountOperation.js \
@@ -74,7 +71,6 @@ nobase_dist_js_DATA = 	\
 	ui/panelMenu.js		\
 	ui/placeDisplay.js	\
 	ui/pointerWatcher.js    \
-	ui/polkitAuthenticationAgent.js \
 	ui/popupMenu.js		\
 	ui/remoteSearch.js	\
 	ui/runDialog.js		\
@@ -90,7 +86,6 @@ nobase_dist_js_DATA = 	\
 	ui/status/power.js	\
 	ui/status/volume.js	\
 	ui/status/bluetooth.js	\
-	ui/telepathyClient.js	\
 	ui/tweener.js		\
 	ui/unlockDialog.js	\
 	ui/userMenu.js		\
@@ -102,4 +97,13 @@ nobase_dist_js_DATA = 	\
 	ui/workspaceThumbnail.js	\
 	ui/workspacesView.js	\
 	ui/workspaceSwitcherPopup.js    \
-	ui/xdndHandler.js
+	ui/xdndHandler.js	\
+	ui/components/__init__.js		\
+	ui/components/autorunManager.js		\
+	ui/components/automountManager.js	\
+	ui/components/networkAgent.js		\
+	ui/components/polkitAgent.js		\
+	ui/components/recorder.js		\
+	ui/components/telepathyClient.js	\
+	ui/components/keyring.js		\
+	$(NULL)
diff --git a/js/ui/components/__init__.js b/js/ui/components/__init__.js
new file mode 100644
index 0000000..763c87d
--- /dev/null
+++ b/js/ui/components/__init__.js
@@ -0,0 +1,61 @@
+
+const Lang = imports.lang;
+const Main = imports.ui.main;
+
+const ComponentManager = new Lang.Class({
+    Name: 'ComponentManager',
+
+    _init: function() {
+        this._allComponents = {};
+        this._enabledComponents = [];
+
+        Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
+        this._sessionUpdated();
+    },
+
+    _sessionUpdated: function() {
+        let newEnabledComponents = Main.sessionMode.components;
+
+        newEnabledComponents.filter(Lang.bind(this, function(name) {
+            return this._enabledComponents.indexOf(name) == -1;
+        })).forEach(Lang.bind(this, function(name) {
+            this._enableComponent(name);
+        }));
+
+        this._enabledComponents.filter(Lang.bind(this, function(name) {
+            return newEnabledComponents.indexOf(name) == -1;
+        })).forEach(Lang.bind(this, function(name) {
+            this._disableComponent(name);
+        }));
+
+        this._enabledComponents = newEnabledComponents;
+    },
+
+    _importComponent: function(name) {
+        let module = imports.ui.components[name];
+        return module.Component;
+    },
+
+    _ensureComponent: function(name) {
+        let component = this._allComponents[name];
+        if (component)
+            return component;
+
+        let constructor = this._importComponent(name);
+        component = new constructor();
+        this._allComponents[name] = component;
+        return component;
+    },
+
+    _enableComponent: function(name) {
+        let component = this._ensureComponent(name);
+        component.enable();
+    },
+
+    _disableComponent: function(name) {
+        let component = this._allComponents[name];
+        if (component == null)
+            return;
+        component.disable();
+    }
+});
diff --git a/js/ui/automountManager.js b/js/ui/components/automountManager.js
similarity index 82%
rename from js/ui/automountManager.js
rename to js/ui/components/automountManager.js
index a49eb17..9081e80 100644
--- a/js/ui/automountManager.js
+++ b/js/ui/components/automountManager.js
@@ -34,28 +34,30 @@ const AutomountManager = new Lang.Class({
         this._inhibited = false;
 
         this._loginManager = LoginManager.getLoginManager();
+        this._volumeMonitor = Gio.VolumeMonitor.get();
+    },
 
-        Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._lockStatusChanged));
+    enable: function() {
+        this._volumeAddedId = this._volumeMonitor.connect('volume-added', Lang.bind(this, this._onVolumeAdded));
+        this._volumeRemovedId = this._volumeMonitor.connect('volume-removed', Lang.bind(this, this._onVolumeRemoved));
+        this._driveConnectedId = this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._onDriveConnected));
+        this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._onDriveDisconnected));
+        this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', Lang.bind(this, this._onDriveEjectButton));
 
-        this._volumeMonitor = Gio.VolumeMonitor.get();
+        this._mountAllId = Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
+    },
+
+    disable: function() {
+        this._volumeMonitor.disconnect(this._volumeAddedId);
+        this._volumeMonitor.disconnect(this._volumeRemovedId);
+        this._volumeMonitor.disconnect(this._driveConnectedId);
+        this._volumeMonitor.disconnect(this._driveDisconnectedId);
+        this._volumeMonitor.disconnect(this._driveEjectButtonId);
 
-        this._volumeMonitor.connect('volume-added',
-                                    Lang.bind(this,
-                                              this._onVolumeAdded));
-        this._volumeMonitor.connect('volume-removed',
-                                    Lang.bind(this,
-                                              this._onVolumeRemoved));
-        this._volumeMonitor.connect('drive-connected',
-                                    Lang.bind(this,
-                                              this._onDriveConnected));
-        this._volumeMonitor.connect('drive-disconnected',
-                                    Lang.bind(this,
-                                              this._onDriveDisconnected));
-        this._volumeMonitor.connect('drive-eject-button',
-                                    Lang.bind(this,
-                                              this._onDriveEjectButton));
-
-        Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
+        if (this._mountAllId > 0) {
+            Mainloop.source_remove(this._mountAllId);
+            this._mountAllId = 0;
+        }
     },
 
     _InhibitorsChanged: function(object, senderName, [inhibtor]) {
@@ -68,17 +70,6 @@ const AutomountManager = new Lang.Class({
                 }));
     },
 
-    _lockStatusChanged: function(shield, locked) {
-        if (!locked) {
-            this._volumeQueue.forEach(Lang.bind(this, function(volume) {
-                this._checkAndMountVolume(volume);
-            }));
-        }
-
-        // clear the queue anyway
-        this._volumeQueue = [];
-    },
-
     _startupMountAll: function() {
         let volumes = this._volumeMonitor.get_volumes();
         volumes.forEach(Lang.bind(this, function(volume) {
@@ -87,6 +78,7 @@ const AutomountManager = new Lang.Class({
                                                 allowAutorun: false });
         }));
 
+        this._mountAllId = 0;
         return false;
     },
 
@@ -96,9 +88,6 @@ const AutomountManager = new Lang.Class({
         if (!this._loginManager.sessionActive)
             return;
 
-        if (Main.screenShield.locked)
-            return;
-
         global.play_theme_sound(0, 'device-added-media');
     },
 
@@ -108,9 +97,6 @@ const AutomountManager = new Lang.Class({
         if (!this._loginManager.sessionActive)
             return;
 
-        if (Main.screenShield.locked)
-            return;
-
         global.play_theme_sound(0, 'device-removed-media');        
     },
 
@@ -159,13 +145,6 @@ const AutomountManager = new Lang.Class({
             // don't attempt automount
             if (!this._loginManager.sessionActive)
                 return;
-
-            if (Main.screenShield.locked) {
-                if (this._volumeQueue.indexOf(volume) == -1)
-                    this._volumeQueue.push(volume);
-
-                return;
-            }
         }
 
         if (this._inhibited)
@@ -259,3 +238,4 @@ const AutomountManager = new Lang.Class({
         });
     }
 });
+const Component = AutomountManager;
diff --git a/js/ui/autorunManager.js b/js/ui/components/autorunManager.js
similarity index 93%
rename from js/ui/autorunManager.js
rename to js/ui/components/autorunManager.js
index 2776fbb..3434e9b 100644
--- a/js/ui/autorunManager.js
+++ b/js/ui/components/autorunManager.js
@@ -147,18 +147,25 @@ const AutorunManager = new Lang.Class({
 
         this._volumeMonitor = Gio.VolumeMonitor.get();
 
-        this._volumeMonitor.connect('mount-added',
-                                    Lang.bind(this,
-                                              this._onMountAdded));
-        this._volumeMonitor.connect('mount-removed',
-                                    Lang.bind(this,
-                                              this._onMountRemoved));
+        this._transDispatcher = new AutorunTransientDispatcher(this);
+    },
 
-        this._transDispatcher = new AutorunTransientDispatcher();
-        this._createResidentSource();
+    enable: function() {
+        this._residentSource = new AutorunResidentSource(this);
+        this._scanMounts();
 
-        let mounts = this._volumeMonitor.get_mounts();
+        this._mountAddedId = this._volumeMonitor.connect('mount-added', Lang.bind(this, this._onMountAdded));
+        this._mountRemovedId = this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._onMountRemoved));
+    },
+
+    disable: function() {
+        this._residentSource.destroy();
+        this._volumeMonitor.disconnect(this._mountAddedId);
+        this._volumeMonitor.disconnect(this._mountRemovedId);
+    },
 
+    _scanMounts: function() {
+        let mounts = this._volumeMonitor.get_mounts();
         mounts.forEach(Lang.bind(this, function (mount) {
             let discoverer = new ContentTypeDiscoverer(Lang.bind (this, 
                 function (mount, apps) {
@@ -169,13 +176,6 @@ const AutorunManager = new Lang.Class({
         }));
     },
 
-    _createResidentSource: function() {
-        this._residentSource = new AutorunResidentSource();
-        this._residentSource.connect('destroy',
-                                     Lang.bind(this,
-                                               this._createResidentSource));
-    },
-
     _onMountAdded: function(monitor, mount) {
         // don't do anything if our session is not the currently
         // active one
@@ -260,13 +260,14 @@ const AutorunResidentSource = new Lang.Class({
     Name: 'AutorunResidentSource',
     Extends: MessageTray.Source,
 
-    _init: function() {
+    _init: function(manager) {
         this.parent(_("Removable Devices"), 'media-removable');
         this.showInLockScreen = false;
 
         this._mounts = [];
 
-        this._notification = new AutorunResidentNotification(this);
+        this._notification = new AutorunResidentNotification(this._manager, this);
+        this._manager = manager;
     },
 
     addMount: function(mount, apps) {
@@ -316,7 +317,7 @@ const AutorunResidentNotification = new Lang.Class({
     Name: 'AutorunResidentNotification',
     Extends: MessageTray.Notification,
 
-    _init: function(source) {
+    _init: function(manager, source) {
         this.parent(source, source.title, null, { customContent: true });
 
         // set the notification as resident
@@ -324,6 +325,7 @@ const AutorunResidentNotification = new Lang.Class({
 
         this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
                                            vertical: true });
+        this._manager = manager;
 
         this.addActor(this._layout,
                       { x_expand: true,
@@ -382,11 +384,11 @@ const AutorunResidentNotification = new Lang.Class({
 
         // now connect signals
         mountButton.connect('clicked', Lang.bind(this, function(actor, event) {
-            startAppForMount(apps[0], mount);
+            this._manager.startAppForMount(apps[0], mount);
         }));
 
         ejectButton.connect('clicked', Lang.bind(this, function() {
-            Main.autorunManager.ejectMount(mount);
+            this._manager.ejectMount(mount);
         }));
 
         return item;
@@ -396,7 +398,8 @@ const AutorunResidentNotification = new Lang.Class({
 const AutorunTransientDispatcher = new Lang.Class({
     Name: 'AutorunTransientDispatcher',
 
-    _init: function() {
+    _init: function(manager) {
+        this._manager = manager;
         this._sources = [];
         this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
     },
@@ -439,7 +442,7 @@ const AutorunTransientDispatcher = new Lang.Class({
             return;
      
         // add a new source
-        this._sources.push(new AutorunTransientSource(mount, apps));
+        this._sources.push(new AutorunTransientSource(this._manager, mount, apps));
     },
 
     addMount: function(mount, apps, contentTypes) {
@@ -492,13 +495,14 @@ const AutorunTransientSource = new Lang.Class({
     Name: 'AutorunTransientSource',
     Extends: MessageTray.Source,
 
-    _init: function(mount, apps) {
+    _init: function(manager, mount, apps) {
+        this._manager = manager;
         this.mount = mount;
         this.apps = apps;
 
         this.parent(mount.get_name());
 
-        this._notification = new AutorunTransientNotification(this);
+        this._notification = new AutorunTransientNotification(this._manager, this);
 
         // add ourselves as a source, and popup the notification
         Main.messageTray.add(this);
@@ -515,9 +519,10 @@ const AutorunTransientNotification = new Lang.Class({
     Name: 'AutorunTransientNotification',
     Extends: MessageTray.Notification,
 
-    _init: function(source) {
+    _init: function(manager, source) {
         this.parent(source, source.title, null, { customContent: true });
 
+        this._manager = manager;
         this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
                                        vertical: true });
         this.addActor(this._box);
@@ -586,10 +591,11 @@ const AutorunTransientNotification = new Lang.Class({
                                      style_class: 'hotplug-notification-item' });
 
         button.connect('clicked', Lang.bind(this, function() {
-            Main.autorunManager.ejectMount(this._mount);
+            this._manager.ejectMount(this._mount);
         }));
 
         return button;
     }
 });
 
+const Component = AutorunManager;
diff --git a/js/ui/keyringPrompt.js b/js/ui/components/keyring.js
similarity index 91%
rename from js/ui/keyringPrompt.js
rename to js/ui/components/keyring.js
index 814c946..dfa7cc0 100644
--- a/js/ui/keyringPrompt.js
+++ b/js/ui/components/keyring.js
@@ -192,23 +192,35 @@ const KeyringDialog = new Lang.Class({
     },
 
     _onContinueButton: function() {
-        this.prompt.complete()
+        this.prompt.complete();
     },
 
     _onCancelButton: function() {
-        this.prompt.cancel()
+        this.prompt.cancel();
     },
 });
 
-function init() {
-    prompter = new Gcr.SystemPrompter();
-    prompter.connect('new-prompt', function(prompter) {
-        let dialog = new KeyringDialog();
-        return dialog.prompt;
-    });
-
-    let connection = Gio.DBus.session;
-    prompter.register(connection);
-    Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
-                                    Gio.BusNameOwnerFlags.REPLACE, null, null);
-}
+const KeyringPrompter = new Lang.Class({
+    Name: 'KeyringPrompter',
+
+    _init: function() {
+        this._prompter = new Gcr.SystemPrompter();
+        this._prompter.connect('new-prompt', function(prompter) {
+            let dialog = new KeyringDialog();
+            return dialog.prompt;
+        });
+        this._dbusId = null;
+    },
+
+    enable: function() {
+        this._prompter.register(Gio.DBus.session);
+        this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
+                                                 Gio.BusNameOwnerFlags.REPLACE, null, null);
+    },
+
+    disable: function() {
+        Gio.DBus.session.unown_name(this._dbusId);
+    }
+});
+
+const Component = KeyringPrompter;
diff --git a/js/ui/networkAgent.js b/js/ui/components/networkAgent.js
similarity index 97%
rename from js/ui/networkAgent.js
rename to js/ui/components/networkAgent.js
index dbfb758..2eaca0c 100644
--- a/js/ui/networkAgent.js
+++ b/js/ui/components/networkAgent.js
@@ -1,23 +1,4 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/*
- * Copyright 2011 Giovanni Campagna <scampa giovanni gmail com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- */
 
 const Clutter = imports.gi.Clutter;
 const Gio = imports.gi.Gio;
@@ -603,7 +584,7 @@ const NetworkAgent = new Lang.Class({
     Name: 'NetworkAgent',
 
     _init: function() {
-        this._native = new Shell.NetworkAgent({ auto_register: true,
+        this._native = new Shell.NetworkAgent({ auto_register: false,
                                                 identifier: 'org.gnome.Shell.NetworkAgent' });
 
         this._dialogs = { };
@@ -613,6 +594,14 @@ const NetworkAgent = new Lang.Class({
         this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
     },
 
+    enable: function() {
+        this._native.register();
+    },
+
+    disable: function() {
+        this._native.unregister();
+    },
+
     _newRequest:  function(agent, requestId, connection, settingName, hints, flags) {
         if (settingName == 'vpn') {
             this._vpnRequest(requestId, connection, hints, flags);
@@ -702,3 +691,4 @@ const NetworkAgent = new Lang.Class({
         }
     }
 });
+const Component = NetworkAgent;
diff --git a/js/ui/polkitAuthenticationAgent.js b/js/ui/components/polkitAgent.js
similarity index 94%
rename from js/ui/polkitAuthenticationAgent.js
rename to js/ui/components/polkitAgent.js
index 92e4c6a..0fa9ba4 100644
--- a/js/ui/polkitAuthenticationAgent.js
+++ b/js/ui/components/polkitAgent.js
@@ -1,24 +1,4 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/*
- * Copyright 2010 Red Hat, Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
-*
- * Author: David Zeuthen <davidz redhat com>
- */
 
 const Lang = imports.lang;
 const Signals = imports.signals;
@@ -33,6 +13,7 @@ const Mainloop = imports.mainloop;
 const Polkit = imports.gi.Polkit;
 const PolkitAgent = imports.gi.PolkitAgent;
 
+const Components = imports.ui.components;
 const ModalDialog = imports.ui.modalDialog;
 const ShellEntry = imports.ui.shellEntry;
 const UserMenu = imports.ui.userMenu;
@@ -336,11 +317,20 @@ const AuthenticationAgent = new Lang.Class({
     Name: 'AuthenticationAgent',
 
     _init: function() {
+        this._currentDialog = null;
+        this._isCompleting = false;
+        this._handle = null;
         this._native = new Shell.PolkitAuthenticationAgent();
         this._native.connect('initiate', Lang.bind(this, this._onInitiate));
         this._native.connect('cancel', Lang.bind(this, this._onCancel));
-        this._currentDialog = null;
-        this._isCompleting = false;
+    },
+
+    enable: function() {
+        this._native.register();
+    },
+
+    disable: function() {
+        this._native.unregister();
     },
 
     _onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
@@ -398,6 +388,4 @@ const AuthenticationAgent = new Lang.Class({
     }
 });
 
-function init() {
-    let agent = new AuthenticationAgent();
-}
+const Component = AuthenticationAgent;
diff --git a/js/ui/components/recorder.js b/js/ui/components/recorder.js
new file mode 100644
index 0000000..94c49ce
--- /dev/null
+++ b/js/ui/components/recorder.js
@@ -0,0 +1,58 @@
+
+const Lang = imports.lang;
+
+const Gio = imports.gi.Gio;
+const Meta = imports.gi.Meta;
+const Shell = imports.gi.Shell;
+
+const Recorder = new Lang.Class({
+    Name: 'Recorder',
+
+    _init: function() {
+        this._recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
+        this._desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
+        this._bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
+        this._recorder = null;
+    },
+
+    enable: function() {
+        global.display.add_keybinding('toggle-recording',
+                                      this._bindingSettings,
+                                      Meta.KeyBindingFlags.NONE, Lang.bind(this, this._toggleRecorder));
+    },
+
+    disable: function() {
+        global.display.remove_keybinding('toggle-recording');
+    },
+
+    _ensureRecorder: function() {
+        if (this._recorder == null)
+            this._recorder = new Shell.Recorder({ stage: global.stage });
+        return this._recorder;
+    },
+
+    _toggleRecorder: function() {
+        let recorder = this._ensureRecorder();
+        if (recorder.is_recording()) {
+            recorder.close();
+            Meta.enable_unredirect_for_screen(global.screen);
+        } else if (!desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
+            // read the parameters from GSettings always in case they have changed
+            recorder.set_framerate(recorderSettings.get_int('framerate'));
+            /* Translators: this is a filename used for screencast recording */
+            // xgettext:no-c-format
+            recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
+            let pipeline = recorderSettings.get_string('pipeline');
+
+            if (!pipeline.match(/^\s*$/))
+                recorder.set_pipeline(pipeline);
+            else
+                recorder.set_pipeline(null);
+
+            Meta.disable_unredirect_for_screen(global.screen);
+            recorder.record();
+        }
+    }
+});
+
+const Component = Recorder;
diff --git a/js/ui/telepathyClient.js b/js/ui/components/telepathyClient.js
similarity index 98%
rename from js/ui/telepathyClient.js
rename to js/ui/components/telepathyClient.js
index 08218d7..a6abeb1 100644
--- a/js/ui/telepathyClient.js
+++ b/js/ui/components/telepathyClient.js
@@ -63,10 +63,10 @@ function makeMessageFromTplEvent(event) {
     };
 }
 
-const Client = new Lang.Class({
-    Name: 'Client',
+const TelepathyClient = new Lang.Class({
+    Name: 'TelepathyClient',
 
-    _init : function() {
+    _init: function() {
         // channel path -> ChatSource
         this._chatSources = {};
         this._chatState = Tp.ChannelChatState.ACTIVE;
@@ -89,9 +89,9 @@ const Client = new Lang.Class({
         // channel matching its filters is detected.
         // The second argument, recover, means _observeChannels will be run
         // for any existing channel as well.
-        this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
-                                              'name': 'GnomeShell',
-                                              'uniquify-name': true })
+        this._tpClient = new Shell.TpClient({ name: 'GnomeShell',
+                                              account_manager: this._accountManager,
+                                              uniquify_name: true });
         this._tpClient.set_observe_channels_func(
             Lang.bind(this, this._observeChannels));
         this._tpClient.set_approve_channels_func(
@@ -99,6 +99,10 @@ const Client = new Lang.Class({
         this._tpClient.set_handle_channels_func(
             Lang.bind(this, this._handleChannels));
 
+        // Watch subscription requests and connection errors
+        this._subscriptionSource = null;
+        this._accountSource = null;
+
         // Workaround for gjs not supporting GPtrArray in signals.
         // See BGO bug #653941 for context.
         this._tpClient.set_contact_list_changed_func(
@@ -108,21 +112,26 @@ const Client = new Lang.Class({
         // needed
         this._tpClient.set_delegated_channels_callback(
             Lang.bind(this, this._delegatedChannelsCb));
+    },
 
+    enable: function() {
         try {
             this._tpClient.register();
         } catch (e) {
             throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
         }
 
-        // Watch subscription requests and connection errors
-        this._subscriptionSource = null;
-        this._accountSource = null;
+        this._accountManagerValidityChangedId = this._accountManager.connect('account-validity-changed',
+                                                                             Lang.bind(this, this._accountValidityChanged));
 
-        this._accountManager.connect('account-validity-changed',
-            Lang.bind(this, this._accountValidityChanged));
+        if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
+            this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
+    },
 
-        this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
+    disable: function() {
+        this._tpClient.unregister();
+        this._accountManager.disconnect(this._accountManagerValidityChangedId);
+        this._accountManagerValidityChangedId = 0;
     },
 
     _observeChannels: function(observer, account, conn, channels,
@@ -1399,3 +1408,4 @@ const AccountNotification = new Lang.Class({
         this.parent();
     }
 });
+const Component = TelepathyClient;
diff --git a/js/ui/main.js b/js/ui/main.js
index 1d8ad4c..9410c23 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -10,12 +10,9 @@ const Meta = imports.gi.Meta;
 const Shell = imports.gi.Shell;
 const St = imports.gi.St;
 
-const AutomountManager = imports.ui.automountManager;
-const AutorunManager = imports.ui.autorunManager;
+const Components = imports.ui.components;
 const CtrlAltTab = imports.ui.ctrlAltTab;
 const EndSessionDialog = imports.ui.endSessionDialog;
-const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
-const KeyringPrompt = imports.ui.keyringPrompt;
 const Environment = imports.ui.environment;
 const ExtensionSystem = imports.ui.extensionSystem;
 const ExtensionDownloader = imports.ui.extensionDownloader;
@@ -27,7 +24,6 @@ const PlaceDisplay = imports.ui.placeDisplay;
 const RunDialog = imports.ui.runDialog;
 const Layout = imports.ui.layout;
 const LookingGlass = imports.ui.lookingGlass;
-const NetworkAgent = imports.ui.networkAgent;
 const NotificationDaemon = imports.ui.notificationDaemon;
 const WindowAttentionHandler = imports.ui.windowAttentionHandler;
 const ScreenShield = imports.ui.screenShield;
@@ -35,7 +31,6 @@ const Scripting = imports.ui.scripting;
 const SessionMode = imports.ui.sessionMode;
 const ShellDBus = imports.ui.shellDBus;
 const ShellMountOperation = imports.ui.shellMountOperation;
-const TelepathyClient = imports.ui.telepathyClient;
 const UnlockDialog = imports.ui.unlockDialog;
 const WindowManager = imports.ui.windowManager;
 const Magnifier = imports.ui.magnifier;
@@ -45,8 +40,7 @@ const Util = imports.misc.util;
 const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
 const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2266bbff);
 
-let automountManager = null;
-let autorunManager = null;
+let componentManager = null;
 let panel = null;
 let overview = null;
 let runDialog = null;
@@ -56,9 +50,7 @@ let messageTray = null;
 let screenShield = null;
 let notificationDaemon = null;
 let windowAttentionHandler = null;
-let telepathyClient = null;
 let ctrlAltTabManager = null;
-let recorder = null;
 let sessionMode = null;
 let shellDBusService = null;
 let shellMountOpDBusService = null;
@@ -70,7 +62,6 @@ let magnifier = null;
 let xdndHandler = null;
 let keyboard = null;
 let layoutManager = null;
-let networkAgent = null;
 let _startDate;
 let _defaultCssStylesheet = null;
 let _cssStylesheet = null;
@@ -78,19 +69,6 @@ let _overridesSettings = null;
 
 let background = null;
 
-function createUserSession() {
-    telepathyClient = new TelepathyClient.Client();
-    automountManager = new AutomountManager.AutomountManager();
-    autorunManager = new AutorunManager.AutorunManager();
-    networkAgent = new NetworkAgent.NetworkAgent();
-
-    _initRecorder();
-}
-
-function createGDMSession() {
-    screenShield.showDialog();
-}
-
 function createGDMLoginDialog(parentActor) {
     // We do this this here instead of at the top to prevent GDM
     // related code from getting loaded in normal user sessions
@@ -105,47 +83,8 @@ function createSessionUnlockDialog(parentActor) {
     return [dialog, false];
 }
 
-function createInitialSetupSession() {
-    networkAgent = new NetworkAgent.NetworkAgent();
-}
-
-function _initRecorder() {
-    let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
-    let desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
-    let bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
-
-    global.display.add_keybinding('toggle-recording',
-                                  bindingSettings,
-                                  Meta.KeyBindingFlags.NONE, function() {
-        if (recorder == null) {
-            recorder = new Shell.Recorder({ stage: global.stage });
-        }
-
-        if (recorder.is_recording()) {
-            recorder.close();
-            Meta.enable_unredirect_for_screen(global.screen);
-        } else if (!desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
-            // read the parameters from GSettings always in case they have changed
-            recorder.set_framerate(recorderSettings.get_int('framerate'));
-            /* Translators: this is a filename used for screencast recording */
-            // xgettext:no-c-format
-            recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
-            let pipeline = recorderSettings.get_string('pipeline');
-
-            if (!pipeline.match(/^\s*$/))
-                recorder.set_pipeline(pipeline);
-            else
-                recorder.set_pipeline(null);
-
-            Meta.disable_unredirect_for_screen(global.screen);
-            recorder.record();
-        }
-    });
-}
-
 function _sessionUpdated() {
     Meta.keybindings_set_custom_handler('panel-run-dialog', sessionMode.hasRunDialog ? openRunDialog : null);
-    loadTheme();
 }
 
 function start() {
@@ -219,8 +158,7 @@ function start() {
     keyboard = new Keyboard.Keyboard();
     notificationDaemon = new NotificationDaemon.NotificationDaemon();
     windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
-
-    sessionMode.createSession();
+    componentManager = new Components.ComponentManager();
 
     layoutManager.init();
     keyboard.init();
@@ -238,12 +176,6 @@ function start() {
     // initiate logouts.
     EndSessionDialog.init();
 
-    // Attempt to become a PolicyKit authentication agent
-    PolkitAuthenticationAgent.init()
-
-    // Become a prompter for gnome keyring
-    KeyringPrompt.init();
-
     _startDate = new Date();
 
     global.stage.connect('captured-event', _globalKeyPressHandler);
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
index 09c0560..5728643 100644
--- a/js/ui/sessionMode.js
+++ b/js/ui/sessionMode.js
@@ -17,8 +17,8 @@ const _modes = {
              hasRunDialog: false,
              hasWorkspaces: false,
              hasWindows: false,
-             createSession: Main.createGDMSession,
              createUnlockDialog: Main.createGDMLoginDialog,
+             components: [],
              panel: {
                  left: [],
                  center: ['dateMenu'],
@@ -36,6 +36,7 @@ const _modes = {
         hasRunDialog: false,
         hasWorkspaces: false,
         hasWindows: false,
+        components: ['networkAgent', 'polkitAgent', 'telepathyClient'],
         panel: {
             left: ['userMenu'],
             center: [],
@@ -50,7 +51,7 @@ const _modes = {
                        allowKeybindingsWhenModal: false,
                        hasRunDialog: false,
                        hasWorkspaces: false,
-                       createSession: Main.createInitialSetupSession,
+                       components: ['keyring'],
                        panel: {
                            left: [],
                            center: ['dateMenu'],
@@ -66,8 +67,9 @@ const _modes = {
               hasRunDialog: true,
               hasWorkspaces: true,
               hasWindows: true,
-              createSession: Main.createUserSession,
               createUnlockDialog: Main.createSessionUnlockDialog,
+              components: ['networkAgent', 'polkitAgent', 'telepathyClient',
+                           'keyring', 'recorder', 'autorunManager', 'automountManager'],
               panel: {
                   left: ['activities', 'appMenu'],
                   center: ['dateMenu'],
@@ -112,8 +114,6 @@ const SessionMode = new Lang.Class({
         let params = _modes[this.currentMode];
         params = Params.parse(params, _modes[DEFAULT_MODE]);
 
-        this._createSession = params.createSession;
-        delete params.createSession;
         this._createUnlockDialog = params.createUnlockDialog;
         delete params.createUnlockDialog;
 
@@ -121,11 +121,6 @@ const SessionMode = new Lang.Class({
         this.emit('updated');
     },
 
-    createSession: function() {
-        if (this._createSession)
-            this._createSession();
-    },
-
     createUnlockDialog: function() {
         if (this._createUnlockDialog)
             return this._createUnlockDialog.apply(this, arguments);
diff --git a/src/shell-polkit-authentication-agent.c b/src/shell-polkit-authentication-agent.c
index e85354a..f1e8bf6 100644
--- a/src/shell-polkit-authentication-agent.c
+++ b/src/shell-polkit-authentication-agent.c
@@ -62,8 +62,9 @@ struct _ShellPolkitAuthenticationAgent {
   PolkitAgentListener parent_instance;
 
   GList *scheduled_requests;
-
   AuthRequest *current_request;
+
+  gpointer handle;
 };
 
 /* Signals */
@@ -93,55 +94,40 @@ static gboolean initiate_authentication_finish (PolkitAgentListener  *listener,
                                                 GAsyncResult         *res,
                                                 GError              **error);
 
-static void
+void
 shell_polkit_authentication_agent_init (ShellPolkitAuthenticationAgent *agent)
 {
-  gpointer handle;
-  PolkitSubject *subject;
-  GError *error;
+}
 
-  subject = NULL;
+void
+shell_polkit_authentication_agent_register (ShellPolkitAuthenticationAgent *agent,
+                                            GError                        **error_out)
+{
+  GError *error = NULL;
+  PolkitSubject *subject;
 
-  error = NULL;
   subject = polkit_unix_session_new_for_process_sync (getpid (),
                                                       NULL, /* GCancellable* */
                                                       &error);
   if (subject == NULL)
     {
-      if (error) /* polkit version 104 and older don't properly set error on failure */
-        {
-          g_warning ("Error getting session for the process we are in: %s (%s %d)",
-                     error->message,
-                     g_quark_to_string (error->domain),
-                     error->code);
-          g_error_free (error);
-        }
-      else
-        {
-          g_warning ("Error getting session for the process we are in");
-        }
+      if (error == NULL) /* polkit version 104 and older don't properly set error on failure */
+        error = g_error_new (POLKIT_ERROR, POLKIT_ERROR_FAILED,
+                             "PolKit failed to properly get our session");
       goto out;
     }
 
-  handle = polkit_agent_listener_register (POLKIT_AGENT_LISTENER (agent),
-                                           POLKIT_AGENT_REGISTER_FLAGS_NONE,
-                                           subject,
-                                           NULL, /* use default object path */
-                                           NULL, /* GCancellable */
-                                           &error);
-  if (handle == NULL)
-    {
-      g_warning ("Error registering polkit authentication agent: %s (%s %d)",
-                 error->message,
-                 g_quark_to_string (error->domain),
-                 error->code);
-      g_error_free (error);
-      goto out;
-    }
-
-  /* We don't need to register so skip saving handle */
+  agent->handle = polkit_agent_listener_register (POLKIT_AGENT_LISTENER (agent),
+                                                  POLKIT_AGENT_REGISTER_FLAGS_NONE,
+                                                  subject,
+                                                  NULL, /* use default object path */
+                                                  NULL, /* GCancellable */
+                                                  &error);
 
  out:
+  if (error != NULL)
+    g_propagate_error (error_out, error);
+
   if (subject != NULL)
     g_object_unref (subject);
 }
@@ -149,12 +135,8 @@ shell_polkit_authentication_agent_init (ShellPolkitAuthenticationAgent *agent)
 static void
 shell_polkit_authentication_agent_finalize (GObject *object)
 {
-  /* ShellPolkitAuthenticationAgent *agent = SHELL_POLKIT_AUTHENTICATION_AGENT (object); */
-
-  /* Specifically left empty since the object stays alive forever - if code
-   *  is reused it would need to free outstanding requests etc.
-   */
-
+  ShellPolkitAuthenticationAgent *agent = SHELL_POLKIT_AUTHENTICATION_AGENT (object);
+  shell_polkit_authentication_agent_unregister (agent);
   G_OBJECT_CLASS (shell_polkit_authentication_agent_parent_class)->finalize (object);
 }
 
@@ -325,6 +307,27 @@ on_request_cancelled (GCancellable *cancellable,
   g_idle_add (handle_cancelled_in_idle, request);
 }
 
+static void
+auth_request_dismiss (AuthRequest *request)
+{
+  auth_request_complete (request, TRUE);
+}
+
+void
+shell_polkit_authentication_agent_unregister (ShellPolkitAuthenticationAgent *agent)
+{
+  if (agent->scheduled_requests != NULL)
+    {
+      g_list_foreach (agent->scheduled_requests, (GFunc)auth_request_dismiss, NULL);
+      agent->scheduled_requests = NULL;
+    }
+  if (agent->current_request != NULL)
+    auth_request_dismiss (agent->current_request);
+
+  polkit_agent_listener_unregister (agent->handle);
+  agent->handle = NULL;
+}
+
 static void maybe_process_next_request (ShellPolkitAuthenticationAgent *agent);
 
 static void
diff --git a/src/shell-polkit-authentication-agent.h b/src/shell-polkit-authentication-agent.h
index a8758ae..745f0c9 100644
--- a/src/shell-polkit-authentication-agent.h
+++ b/src/shell-polkit-authentication-agent.h
@@ -27,6 +27,9 @@ GType                           shell_polkit_authentication_agent_get_type (void
 ShellPolkitAuthenticationAgent *shell_polkit_authentication_agent_new      (void);
 void                            shell_polkit_authentication_agent_complete (ShellPolkitAuthenticationAgent *agent,
                                                                             gboolean                        dismissed);
+void                            shell_polkit_authentication_agent_register (ShellPolkitAuthenticationAgent *agent,
+                                                                            GError                        **error_out);
+void                            shell_polkit_authentication_agent_unregister (ShellPolkitAuthenticationAgent *agent);
 
 G_END_DECLS
 



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