Synchronize shell startup
The asynchronous nature of extension loading, session loading, and more, makes the code racy as to what is initialized first, and hard to debug. Additionally, since gjs is single-threaded, the only code we're running in a thread anyway is readdir, which is going to be I/O bound, so the code here is actually likely to be faster. Drop this in favor of some good old fashioned synchronous loading.
This commit is contained in:
parent
5f9e3edbe1
commit
da4238ec68
@ -206,11 +206,11 @@ const Application = new Lang.Class({
|
||||
_scanExtensions: function() {
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', Lang.bind(this, this._extensionFound));
|
||||
finder.connect('extensions-loaded', Lang.bind(this, this._extensionsLoaded));
|
||||
finder.scanExtensions();
|
||||
this._extensionsLoaded();
|
||||
},
|
||||
|
||||
_extensionFound: function(signals, extension) {
|
||||
_extensionFound: function(finder, extension) {
|
||||
let iter = this._model.append();
|
||||
this._model.set(iter, [0, 1], [extension.uuid, extension.metadata.name]);
|
||||
this._extensionIters[extension.uuid] = iter;
|
||||
|
@ -174,17 +174,9 @@ const ExtensionFinder = new Lang.Class({
|
||||
this.emit('extension-found', extension);
|
||||
},
|
||||
|
||||
_extensionsLoaded: function() {
|
||||
this.emit('extensions-loaded');
|
||||
},
|
||||
|
||||
scanExtensions: function() {
|
||||
let perUserDir = Gio.File.new_for_path(global.userdatadir);
|
||||
FileUtils.collectFromDatadirsAsync('extensions',
|
||||
{ processFile: Lang.bind(this, this._loadExtension),
|
||||
loadedCallback: Lang.bind(this, this._extensionsLoaded),
|
||||
includeUserDir: true,
|
||||
data: perUserDir });
|
||||
FileUtils.collectFromDatadirs('extensions', true, Lang.bind(this, this._loadExtension, perUserDir));
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ExtensionFinder.prototype);
|
||||
|
@ -25,60 +25,27 @@ function listDirAsync(file, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function _collectFromDirectoryAsync(dir, loadState) {
|
||||
function done() {
|
||||
loadState.numLoading--;
|
||||
if (loadState.loadedCallback &&
|
||||
loadState.numLoading == 0)
|
||||
loadState.loadedCallback(loadState.data);
|
||||
}
|
||||
|
||||
dir.query_info_async('standard::type', Gio.FileQueryInfoFlags.NONE,
|
||||
GLib.PRIORITY_DEFAULT, null, function(object, res) {
|
||||
try {
|
||||
object.query_info_finish(res);
|
||||
} catch (e) {
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
||||
log(e.message);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
listDirAsync(dir, Lang.bind(this, function(infos) {
|
||||
for (let i = 0; i < infos.length; i++)
|
||||
loadState.processFile(dir.get_child(infos[i].get_name()),
|
||||
infos[i], loadState.data);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function collectFromDatadirsAsync(subdir, params) {
|
||||
params = Params.parse(params, { includeUserDir: false,
|
||||
processFile: null,
|
||||
loadedCallback: null,
|
||||
data: null });
|
||||
let loadState = { data: params.data,
|
||||
numLoading: 0,
|
||||
loadedCallback: params.loadedCallback,
|
||||
processFile: params.processFile };
|
||||
|
||||
if (params.processFile == null) {
|
||||
if (params.loadedCallback)
|
||||
params.loadedCallback(params.data);
|
||||
return;
|
||||
}
|
||||
|
||||
function collectFromDatadirs(subdir, includeUserDir, processFile) {
|
||||
let dataDirs = GLib.get_system_data_dirs();
|
||||
if (params.includeUserDir)
|
||||
if (includeUserDir)
|
||||
dataDirs.unshift(GLib.get_user_data_dir());
|
||||
loadState.numLoading = dataDirs.length;
|
||||
|
||||
for (let i = 0; i < dataDirs.length; i++) {
|
||||
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', subdir]);
|
||||
let dir = Gio.File.new_for_path(path);
|
||||
|
||||
_collectFromDirectoryAsync(dir, loadState);
|
||||
let fileEnum;
|
||||
try {
|
||||
fileEnum = dir.enumerate_children('standard::name,standard::type',
|
||||
Gio.FileQueryInfoFlags.NONE, null);
|
||||
} catch (e) {
|
||||
fileEnum = null;
|
||||
}
|
||||
if (fileEnum != null) {
|
||||
let info;
|
||||
while ((info = fileEnum.next_file(null)))
|
||||
processFile(fileEnum.get_child(info), info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ function onEnabledExtensionsChanged() {
|
||||
newEnabledExtensions.filter(function(uuid) {
|
||||
return enabledExtensions.indexOf(uuid) == -1;
|
||||
}).forEach(function(uuid) {
|
||||
enableExtension(uuid);
|
||||
enableExtension(uuid);
|
||||
});
|
||||
|
||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||
@ -261,7 +261,7 @@ function onEnabledExtensionsChanged() {
|
||||
enabledExtensions.filter(function(item) {
|
||||
return newEnabledExtensions.indexOf(item) == -1;
|
||||
}).forEach(function(uuid) {
|
||||
disableExtension(uuid);
|
||||
disableExtension(uuid);
|
||||
});
|
||||
|
||||
enabledExtensions = newEnabledExtensions;
|
||||
@ -272,7 +272,7 @@ function _loadExtensions() {
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', function(signals, extension) {
|
||||
finder.connect('extension-found', function(finder, extension) {
|
||||
loadExtension(extension);
|
||||
});
|
||||
finder.scanExtensions();
|
||||
|
@ -112,11 +112,6 @@ function start() {
|
||||
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
||||
|
||||
sessionMode = new SessionMode.SessionMode();
|
||||
sessionMode.connect('sessions-loaded', _sessionsLoaded);
|
||||
sessionMode.init();
|
||||
}
|
||||
|
||||
function _sessionsLoaded() {
|
||||
sessionMode.connect('updated', _sessionUpdated);
|
||||
_initializePrefs();
|
||||
_initializeUI();
|
||||
|
@ -7,6 +7,7 @@ const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Search = imports.ui.search;
|
||||
|
||||
const KEY_FILE_GROUP = 'Shell Search Provider';
|
||||
@ -122,23 +123,7 @@ function loadRemoteSearchProviders(callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
let dataDirs = GLib.get_system_data_dirs();
|
||||
dataDirs.forEach(function(dataDir) {
|
||||
let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']);
|
||||
let dir = Gio.File.new_for_path(path);
|
||||
let fileEnum;
|
||||
try {
|
||||
fileEnum = dir.enumerate_children('standard::name,standard::type',
|
||||
Gio.FileQueryInfoFlags.NONE, null);
|
||||
} catch (e) {
|
||||
fileEnum = null;
|
||||
}
|
||||
if (fileEnum != null) {
|
||||
let info;
|
||||
while ((info = fileEnum.next_file(null)))
|
||||
loadRemoteSearchProvider(fileEnum.get_child(info));
|
||||
}
|
||||
});
|
||||
FileUtils.collectFromDatadirs('search-providers', false, loadRemoteSearchProvider);
|
||||
|
||||
let sortOrder = searchSettings.get_strv('sort-order');
|
||||
|
||||
|
@ -102,19 +102,12 @@ const _modes = {
|
||||
}
|
||||
};
|
||||
|
||||
function _getModes(modesLoadedCallback) {
|
||||
FileUtils.collectFromDatadirsAsync('modes',
|
||||
{ processFile: _loadMode,
|
||||
loadedCallback: modesLoadedCallback,
|
||||
data: _modes });
|
||||
}
|
||||
|
||||
function _loadMode(file, info, loadedData) {
|
||||
function _loadMode(file, info) {
|
||||
let name = info.get_name();
|
||||
let suffix = name.indexOf('.json');
|
||||
let modeName = suffix == -1 ? name : name.slice(name, suffix);
|
||||
|
||||
if (loadedData.hasOwnProperty(modeName))
|
||||
if (_modes.hasOwnProperty(modeName))
|
||||
return;
|
||||
|
||||
let fileContent, success, tag, newMode;
|
||||
@ -125,18 +118,23 @@ function _loadMode(file, info, loadedData) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadedData[modeName] = {};
|
||||
_modes[modeName] = {};
|
||||
let propBlacklist = ['unlockDialog'];
|
||||
for (let prop in loadedData[DEFAULT_MODE]) {
|
||||
if (newMode[prop] !== undefined &&
|
||||
propBlacklist.indexOf(prop) == -1)
|
||||
loadedData[modeName][prop]= newMode[prop];
|
||||
loadedData[modeName][prop] = newMode[prop];
|
||||
}
|
||||
loadedData[modeName]['isPrimary'] = true;
|
||||
_modes[modeName]['isPrimary'] = true;
|
||||
}
|
||||
|
||||
function _getModes() {
|
||||
FileUtils.collectFromDatadirs('modes', false, _loadMode);
|
||||
}
|
||||
|
||||
function listModes() {
|
||||
_getModes(function(modes) {
|
||||
let modes = _getModes();
|
||||
modes.forEach(function() {
|
||||
let names = Object.getOwnPropertyNames(modes);
|
||||
for (let i = 0; i < names.length; i++)
|
||||
if (_modes[names[i]].isPrimary)
|
||||
@ -149,17 +147,12 @@ function listModes() {
|
||||
const SessionMode = new Lang.Class({
|
||||
Name: 'SessionMode',
|
||||
|
||||
init: function() {
|
||||
_getModes(Lang.bind(this, function(modes) {
|
||||
this._modes = modes;
|
||||
let primary = modes[global.session_mode] &&
|
||||
modes[global.session_mode].isPrimary;
|
||||
let mode = primary ? global.session_mode : 'user';
|
||||
this._modeStack = [mode];
|
||||
this._sync();
|
||||
|
||||
this.emit('sessions-loaded');
|
||||
}));
|
||||
_init: function() {
|
||||
let isPrimary = (_modes[global.session_mode] &&
|
||||
_modes[global.session_mode].isPrimary);
|
||||
let mode = isPrimary ? global.session_mode : 'user';
|
||||
this._modeStack = [mode];
|
||||
this._sync();
|
||||
},
|
||||
|
||||
pushMode: function(mode) {
|
||||
@ -186,13 +179,13 @@ const SessionMode = new Lang.Class({
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let params = this._modes[this.currentMode];
|
||||
let params = _modes[this.currentMode];
|
||||
let defaults;
|
||||
if (params.parentMode)
|
||||
defaults = Params.parse(this._modes[params.parentMode],
|
||||
this._modes[DEFAULT_MODE]);
|
||||
defaults = Params.parse(_modes[params.parentMode],
|
||||
_modes[DEFAULT_MODE]);
|
||||
else
|
||||
defaults = this._modes[DEFAULT_MODE];
|
||||
defaults = _modes[DEFAULT_MODE];
|
||||
params = Params.parse(params, defaults);
|
||||
|
||||
// A simplified version of Lang.copyProperties, handles
|
||||
|
Loading…
Reference in New Issue
Block a user