[gnome-shell/wip/gdbus-2: 2/3] Try to do more async initialization
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/gdbus-2: 2/3] Try to do more async initialization
- Date: Fri, 2 Nov 2012 13:13:13 +0000 (UTC)
commit afcc1b7b5212d6f6309bcf76ade86c805ce3f112
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Fri Oct 26 19:19:03 2012 +0200
Try to do more async initialization
Synchronous calls in the main loop are a performance killer, especially
at login.
js/gdm/powerMenu.js | 26 ++++++-
js/gdm/realmd.js | 11 ++-
js/misc/loginManager.js | 158 +++++++++++++++++++++++++++++-----
js/ui/calendar.js | 26 ++----
js/ui/components/automountManager.js | 12 ++-
js/ui/components/autorunManager.js | 6 +-
js/ui/notificationDaemon.js | 6 +-
js/ui/remoteSearch.js | 46 +++++++++-
js/ui/screenShield.js | 10 ++-
js/ui/search.js | 3 +
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 a341619..552148f 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 4e93ce1..20a2305 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 7fca78d..67dd064 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 3da38f8..9afb306 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 9081e80..3d3d02b 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 fc55b0d..25d20e9 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 1a7a483..d23280a 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 5f45157..54fa1d6 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 52c7dcc..9843748 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 22f53d9..97acb5d 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 eecb75a..65d5339 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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]