diff options
author | Giovanni Campagna <gcampagna@src.gnome.org> | 2012-10-26 19:19:03 +0200 |
---|---|---|
committer | Giovanni Campagna <gcampagna@src.gnome.org> | 2012-11-02 14:11:10 +0100 |
commit | afcc1b7b5212d6f6309bcf76ade86c805ce3f112 (patch) | |
tree | c0a32b8edc9480d751f85e11f96bb7f300c5b4a6 | |
parent | a6b4d68a1d2124c017d57a16bbbed4bb01a1e5a5 (diff) | |
download | gnome-shell-afcc1b7b5212d6f6309bcf76ade86c805ce3f112.tar.gz |
Try to do more async initialization
Synchronous calls in the main loop are a performance killer, especially
at login.
-rw-r--r-- | js/gdm/powerMenu.js | 26 | ||||
-rw-r--r-- | js/gdm/realmd.js | 11 | ||||
-rw-r--r-- | js/misc/loginManager.js | 158 | ||||
-rw-r--r-- | js/ui/calendar.js | 26 | ||||
-rw-r--r-- | js/ui/components/automountManager.js | 12 | ||||
-rw-r--r-- | js/ui/components/autorunManager.js | 6 | ||||
-rw-r--r-- | js/ui/notificationDaemon.js | 6 | ||||
-rw-r--r-- | js/ui/remoteSearch.js | 46 | ||||
-rw-r--r-- | js/ui/screenShield.js | 10 | ||||
-rw-r--r-- | js/ui/search.js | 3 | ||||
-rw-r--r-- | js/ui/userMenu.js | 33 |
11 files changed, 273 insertions, 64 deletions
diff --git a/js/gdm/powerMenu.js b/js/gdm/powerMenu.js index a341619fd..552148f40 100644 --- a/js/gdm/powerMenu.js +++ b/js/gdm/powerMenu.js @@ -35,7 +35,13 @@ const PowerMenuButton = new Lang.Class({ /* Translators: accessible name of the power menu in the login screen */ this.parent('system-shutdown-symbolic', _("Power")); - this._loginManager = LoginManager.getLoginManager(); + LoginManager.getLoginManager(Lang.bind(this, function(manager) { + this._loginManager = manager; + + this._updateHaveShutdown(); + this._updateHaveRestart(); + this._updateHaveSuspend(); + })); this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA }); this._settings.connect('changed::disable-restart-buttons', @@ -64,6 +70,12 @@ const PowerMenuButton = new Lang.Class({ }, _updateHaveShutdown: function() { + if (!this._loginManager) { + this._haveShutdown = false; + this._powerOffItem.actor.visible = false; + return; + } + this._loginManager.canPowerOff(Lang.bind(this, function(result) { this._haveShutdown = result; this._powerOffItem.actor.visible = this._haveShutdown; @@ -72,6 +84,12 @@ const PowerMenuButton = new Lang.Class({ }, _updateHaveRestart: function() { + if (!this._loginManager) { + this._haveRestart = false; + this._restartItem.actor.visible = false; + return; + } + this._loginManager.canReboot(Lang.bind(this, function(result) { this._haveRestart = result; this._restartItem.actor.visible = this._haveRestart; @@ -80,6 +98,12 @@ const PowerMenuButton = new Lang.Class({ }, _updateHaveSuspend: function() { + if (!this._loginManager) { + this._haveSuspend = false; + this._suspendItem.actor.visible = false; + return; + } + this._loginManager.canSuspend(Lang.bind(this, function(result) { this._haveSuspend = result; this._suspendItem.actor.visible = this._haveSuspend; diff --git a/js/gdm/realmd.js b/js/gdm/realmd.js index 4e93ce1ad..20a2305ba 100644 --- a/js/gdm/realmd.js +++ b/js/gdm/realmd.js @@ -86,7 +86,6 @@ const Manager = new Lang.Class({ _init: function(parentActor) { this._aggregateProvider = new Provider(); - this._aggregateProvider.init(null); this._realms = {}; this._aggregateProvider.connect('g-properties-changed', @@ -94,6 +93,16 @@ const Manager = new Lang.Class({ if ('Realms' in properties.deep_unpack()) this._reloadRealms(); })); + + this._aggregateProvider.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) { + try { + proxy.init_finish(result); + } catch(e) { + return; + } + + this._reloadRealms(); + })); }, _reloadRealms: function() { diff --git a/js/misc/loginManager.js b/js/misc/loginManager.js index 7fca78d40..67dd0642c 100644 --- a/js/misc/loginManager.js +++ b/js/misc/loginManager.js @@ -2,6 +2,7 @@ const GLib = imports.gi.GLib; const Gio = imports.gi.Gio; +const GObject = imports.gi.GObject; const Lang = imports.lang; const Mainloop = imports.mainloop; const Shell = imports.gi.Shell; @@ -105,41 +106,102 @@ function haveSystemd() { } let _loginManager = null; +let _pendingAsyncCallbacks = []; /** * LoginManager: * An abstraction over systemd/logind and ConsoleKit. * */ -function getLoginManager() { +function getLoginManager(asyncCallback) { if (_loginManager == null) { - if (haveSystemd()) - _loginManager = new LoginManagerSystemd(); - else - _loginManager = new LoginManagerConsoleKit(); - } + if (_pendingAsyncCallbacks.length == 0) { + let manager; + + if (haveSystemd()) + manager = new LoginManagerSystemd(); + else + manager = new LoginManagerConsoleKit(); + + manager.initAsync(null, function(obj, result) { + obj.initFinish(result); + + _loginManager = manager; - return _loginManager; + _pendingAsyncCallbacks.forEach(function (f) { f(obj) }); + _pendingAsyncCallbacks = []; + }); + + _pendingAsyncCallbacks = [asyncCallback]; + } else { + _pendingAsyncCallbacks.push(asyncCallback); + } + } else { + GLib.idle_add(GLib.PRIORITY_DEFAULT, function() { + asyncCallback(_loginManager); + }); + } } const LoginManagerSystemd = new Lang.Class({ Name: 'LoginManagerSystemd', + Extends: GObject.Object, _init: function() { + this.parent(); + this._proxy = new SystemdLoginManager(); - this._proxy.init(null); + }, + + initAsync: function(cancellable, asyncCallback) { + let simpleResult = Gio.SimpleAsyncResult.new(this, asyncCallback, null); + simpleResult.set_check_cancellable(cancellable); + + this._proxy.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) { + try { + proxy.init_finish(result); + + if (cancellable && cancellable.is_cancelled()) + return; + + this._fetchCurrentSession(cancellable, simpleResult); + } catch(e if e instanceof GLib.Error) { + simpleResult.set_from_error(e); + simpleResult.complete(); + } + })); + }, + + initFinish: function(simpleResult) { + if (!simpleResult.propagate_error()) + return simpleResult.get_op_res_gboolean(); + + return true; + }, + + _fetchCurrentSession: function(cancellable, simpleResult) { + this._currentSession = new SystemdLoginSession('/org/freedesktop/login1/session/' + + GLib.getenv('XDG_SESSION_ID')); + + this._currentSession.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) { + try { + proxy.init_finish(result); + + simpleResult.set_op_res_gboolean(true); + } catch(e if e instanceof GLib.Error) { + simpleResult.set_from_error(e); + } + + simpleResult.complete(); + })); }, // Having this function is a bit of a hack since the Systemd and ConsoleKit // session objects have different interfaces - but in both cases there are // Lock/Unlock signals, and that's all we count upon at the moment. + // + // This is only valid after async initialization getCurrentSessionProxy: function() { - if (!this._currentSession) { - this._currentSession = new SystemdLoginSession('/org/freedesktop/login1/session/' + - GLib.getenv('XDG_SESSION_ID')); - this._currentSession.init(null); - } - return this._currentSession; }, @@ -198,24 +260,76 @@ const LoginManagerSystemd = new Lang.Class({ const LoginManagerConsoleKit = new Lang.Class({ Name: 'LoginManagerConsoleKit', + Extends: GObject.Object, _init: function() { - this._proxy = new ConsoleKitManager(); - this._proxy.init(null); + this.parent(); + this._proxy = new ConsoleKitManager(); this._upClient = new UPowerGlib.Client(); }, + initAsync: function(cancellable, asyncCallback) { + let simpleResult = Gio.SimpleAsyncResult.new(this, asyncCallback, null); + simpleResult.set_check_cancellable(cancellable); + + this._proxy.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) { + try { + proxy.init_finish(result); + + if (cancellable && cancellable.is_cancelled()) + return; + + this._fetchCurrentSession(cancellable, simpleResult); + } catch(e if e instanceof GLib.Error) { + simpleResult.set_from_error(e); + simpleResult.complete(); + } + })); + }, + + initFinish: function(simpleResult) { + if (!simpleResult.propagate_error()) + return simpleResult.get_op_res_gboolean(); + + return true; + }, + + _fetchCurrentSession: function(cancellable, simpleResult) { + this._proxy.GetCurrentSessionRemote(cancellable, Lang.bind(this, function(proxy, result) { + try { + let [currentSessionId] = proxy.GetCurrentSessionFinish(result); + + if (cancellable && cancellable.is_cancelled()) + return; + + this._createSessionProxy(currentSessionId, cancellable, simpleResult); + } catch(e if e instanceof GLib.Error) { + simpleResult.set_from_error(e); + simpleResult.complete(); + } + })); + }, + + _createSessionProxy: function(currentSessionId, cancellable, simpleResult) { + this._currentSession = new ConsoleKitSession(currentSessionId); + this._currentSession.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) { + try { + proxy.init_finish(result); + + simpleResult.set_op_res_gboolean(true); + } catch(e if e instanceof GLib.Error) { + simpleResult.set_from_error(e); + } + + simpleResult.complete(); + })); + }, + // Having this function is a bit of a hack since the Systemd and ConsoleKit // session objects have different interfaces - but in both cases there are // Lock/Unlock signals, and that's all we count upon at the moment. getCurrentSessionProxy: function() { - if (!this._currentSession) { - let [currentSessionId] = this._proxy.GetCurrentSessionSync(null); - this._currentSession = new ConsoleKitSession(currentSessionId); - this._currentSession.init(null); - } - return this._currentSession; }, diff --git a/js/ui/calendar.js b/js/ui/calendar.js index 3da38f864..9afb306b4 100644 --- a/js/ui/calendar.js +++ b/js/ui/calendar.js @@ -239,14 +239,17 @@ const DBusEventSource = new Lang.Class({ this._resetCache(); this._dbusProxy = new CalendarServer(); - this._dbusProxy.init(null); this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged)); - this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() { - if (this._dbusProxy.g_name_owner) - this._onNameAppeared(); - else - this._onNameVanished(); + this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) { + try { + proxy.init_finish(result); + } catch(e) { + return; + } + + this._resetCache(); + this.emit('changed'); })); }, @@ -256,16 +259,6 @@ const DBusEventSource = new Lang.Class({ this._lastRequestEnd = null; }, - _onNameAppeared: function(owner) { - this._resetCache(); - this._loadEvents(true); - }, - - _onNameVanished: function(oldOwner) { - this._resetCache(); - this.emit('changed'); - }, - _onChanged: function() { this._loadEvents(false); }, @@ -404,7 +397,6 @@ const Calendar = new Lang.Class({ this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, function() { this._update(false); })); - this._update(true); } }, diff --git a/js/ui/components/automountManager.js b/js/ui/components/automountManager.js index 9081e80e6..3d3d02b42 100644 --- a/js/ui/components/automountManager.js +++ b/js/ui/components/automountManager.js @@ -33,7 +33,9 @@ const AutomountManager = new Lang.Class({ Lang.bind(this, this._InhibitorsChanged)); this._inhibited = false; - this._loginManager = LoginManager.getLoginManager(); + LoginManager.getLoginManager(Lang.bind(this, function(manager) { + this._loginManager = manager; + })); this._volumeMonitor = Gio.VolumeMonitor.get(); }, @@ -85,7 +87,7 @@ const AutomountManager = new Lang.Class({ _onDriveConnected: function() { // if we're not in the current ConsoleKit session, // or screensaver is active, don't play sounds - if (!this._loginManager.sessionActive) + if (!this._loginManager || !this._loginManager.sessionActive) return; global.play_theme_sound(0, 'device-added-media'); @@ -94,7 +96,7 @@ const AutomountManager = new Lang.Class({ _onDriveDisconnected: function() { // if we're not in the current ConsoleKit session, // or screensaver is active, don't play sounds - if (!this._loginManager.sessionActive) + if (!this._loginManager || !this._loginManager.sessionActive) return; global.play_theme_sound(0, 'device-removed-media'); @@ -103,7 +105,7 @@ const AutomountManager = new Lang.Class({ _onDriveEjectButton: function(monitor, drive) { // TODO: this code path is not tested, as the GVfs volume monitor // doesn't emit this signal just yet. - if (!this._loginManager.sessionActive) + if (!this._loginManager || !this._loginManager.sessionActive) return; // we force stop/eject in this case, so we don't have to pass a @@ -143,7 +145,7 @@ const AutomountManager = new Lang.Class({ if (params.checkSession) { // if we're not in the current ConsoleKit session, // don't attempt automount - if (!this._loginManager.sessionActive) + if (!this._loginManager || !this._loginManager.sessionActive) return; } diff --git a/js/ui/components/autorunManager.js b/js/ui/components/autorunManager.js index fc55b0d9d..25d20e9ec 100644 --- a/js/ui/components/autorunManager.js +++ b/js/ui/components/autorunManager.js @@ -171,7 +171,9 @@ const AutorunManager = new Lang.Class({ Name: 'AutorunManager', _init: function() { - this._loginManager = LoginManager.getLoginManager(); + LoginManager.getLoginManager(Lang.bind(this, function(manager) { + this._loginManager = manager; + })); this._volumeMonitor = Gio.VolumeMonitor.get(); @@ -224,7 +226,7 @@ const AutorunManager = new Lang.Class({ _onMountAdded: function(monitor, mount) { // don't do anything if our session is not the currently // active one - if (!this._loginManager.sessionActive) + if (!this._loginManager || !this._loginManager.sessionActive) return; this._processMount(mount, true); diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js index 1a7a48339..d23280a04 100644 --- a/js/ui/notificationDaemon.js +++ b/js/ui/notificationDaemon.js @@ -32,7 +32,10 @@ const Bus = new Gio.DBusProxyClass({ _init: function() { this.parent({ g_bus_type: Gio.BusType.SESSION, g_name: 'org.freedesktop.DBus', - g_object_path: '/org/freedesktop/DBus' }); + g_object_path: '/org/freedesktop/DBus', + g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES | + Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS | + Gio.DBusProxyFlags.DO_NOT_AUTO_START) }); } }); @@ -121,6 +124,7 @@ const NotificationDaemon = new Gio.DBusImplementerClass({ this._senderToPid = {}; this._notifications = {}; this._busProxy = new Bus(); + // This is synchronous but fast because of the flags we use. this._busProxy.init(null); this._trayManager = new Shell.TrayManager(); diff --git a/js/ui/remoteSearch.js b/js/ui/remoteSearch.js index 5f451572c..54fa1d60a 100644 --- a/js/ui/remoteSearch.js +++ b/js/ui/remoteSearch.js @@ -97,13 +97,22 @@ function loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallb icon, busName, objectPath); + remoteProvider.initAsync(null, function(obj, result) { + try { + remoteProvider.initFinish(result); + } catch(e) { + log('Failed to add search provider "%s": %s'.format(title, e.toString())); + return; + } + + addProviderCallback(remoteProvider); + }); + loadedProviders[objectPath] = remoteProvider; } catch(e) { log('Failed to add search provider "%s": %s'.format(title, e.toString())); continue; } - - addProviderCallback(remoteProvider); } })); @@ -114,14 +123,41 @@ const RemoteSearchProvider = new Lang.Class({ Extends: Search.SearchProvider, _init: function(title, icon, dbusName, dbusPath) { + this.parent(title.toUpperCase()); + this._proxy = new SearchProviderProxy({ g_name: dbusName, g_object_path: dbusPath }); - this._proxy.init(null); - - this.parent(title.toUpperCase()); this._cancellable = new Gio.Cancellable(); }, + initAsync: function(cancellable, asyncCallback) { + // Can't pass "this" as source object, because RemoteSearchProvider + // is not a GObject.Object (and in gjs you can't inherit from a JS + // type that in turn inherits from GObject) + + let simpleResult = Gio.SimpleAsyncResult.new(null, asyncCallback, null); + simpleResult.set_check_cancellable(cancellable); + + this._proxy.init_async(GLib.PRIORITY_DEFAULT, cancellable, Lang.bind(this, function(proxy, result) { + try { + proxy.init_finish(result); + + simpleResult.set_op_res_gboolean(true); + } catch(e if e instanceof GLib.Error) { + simpleResult.set_from_error(e); + } + + simpleResult.complete(); + })); + }, + + initFinish: function(simpleResult) { + if (!simpleResult.propagate_error()) + return simpleResult.get_op_res_gboolean(); + + return false; + }, + createIcon: function(size, meta) { if (meta['gicon']) { return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']), diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js index 52c7dcc75..984374880 100644 --- a/js/ui/screenShield.js +++ b/js/ui/screenShield.js @@ -418,10 +418,11 @@ const ScreenShield = new Lang.Class({ this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this); - this._loginManager = LoginManager.getLoginManager(); - this._loginSession = this._loginManager.getCurrentSessionProxy(); - this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); })); - this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.unlock(); })); + LoginManager.getLoginManager(Lang.bind(this, function(manager) { + this._loginSession = manager.getCurrentSessionProxy(); + this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); })); + this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.unlock(); })); + })); this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA }); @@ -875,6 +876,7 @@ const ScreenShieldFallback = new Lang.Class({ g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES), }); + // This is synchronous but it is the fallback case. this._proxy.init(null); this._proxy.connect('g-signal', Lang.bind(this, this._onSignal)); diff --git a/js/ui/search.js b/js/ui/search.js index 22f53d913..97acb5dcd 100644 --- a/js/ui/search.js +++ b/js/ui/search.js @@ -2,6 +2,7 @@ const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; const Lang = imports.lang; const Signals = imports.signals; const Shell = imports.gi.Shell; @@ -75,6 +76,8 @@ const SearchProvider = new Lang.Class({ Name: 'SearchProvider', _init: function(title) { + this.parent(); + this.title = title; this.searchSystem = null; }, diff --git a/js/ui/userMenu.js b/js/ui/userMenu.js index eecb75afb..65d5339ea 100644 --- a/js/ui/userMenu.js +++ b/js/ui/userMenu.js @@ -495,14 +495,22 @@ const UserMenuButton = new Lang.Class({ })); })); - this._session = new GnomeSession.SessionManager(); - this._session.init(null); + let session = new GnomeSession.SessionManager(); + session.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(proxy, result) { + // This should never fail. + proxy.init_finish(result); + + this._session = proxy; + this._updateHaveShutdown(); + })); this._haveShutdown = true; this._haveSuspend = true; this._accountMgr = Tp.AccountManager.dup(); - this._loginManager = LoginManager.getLoginManager(); + LoginManager.getLoginManager(Lang.bind(this, function(manager) { + this._loginManager = manager; + })); this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); this._iconBox = new St.Bin(); @@ -647,6 +655,11 @@ const UserMenuButton = new Lang.Class({ }, _updateHaveShutdown: function() { + if (!this._session) { + this._haveShutdown = false; + return; + } + this._session.CanShutdownRemote(null, Lang.bind(this, function(proxy, result) { try { [this._haveShutdown] = proxy.CanShutdownFinish(result); @@ -660,6 +673,11 @@ const UserMenuButton = new Lang.Class({ }, _updateHaveSuspend: function() { + if (!this._loginManager) { + this._haveSuspend = false; + return; + } + this._loginManager.canSuspend(Lang.bind(this, function(result) { this._haveSuspend = result; @@ -849,14 +867,17 @@ const UserMenuButton = new Lang.Class({ _onQuitSessionActivate: function() { Main.overview.hide(); - this._session.LogoutRemote(0, null, null); + + if (this._session) + this._session.LogoutRemote(0, null, null); }, _onInstallUpdatesActivate: function() { Main.overview.hide(); Util.spawn(['pkexec', '/usr/libexec/pk-trigger-offline-update']); - this._session.RebootRemote(); + if (this._haveShutdown) + this._session.RebootRemote(null, null); }, _onSuspendOrPowerOffActivate: function() { @@ -865,7 +886,7 @@ const UserMenuButton = new Lang.Class({ if (this._haveShutdown && this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) { this._session.ShutdownRemote(null, null); - } else { + } else if (this._haveSuspend) { if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY)) { let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() { Main.screenShield.disconnect(tmpId); |