extensionUtils: Create and allow access to a new "extension" object
The "extension" object is what I previously called the "helper" object. It contains the extension importer object as well as the metadata object. Things that were previously added on to the metadata (state, path, dir, etc.) are now part of this new "extension" object. With the new importer changes brought on by the extension prefs tool, extensions are left without a way to import submodules at the global scope, which would make them rely on techniques like: var MySubModule; function init(meta) { MySubModule = meta.importer.mySubModule; } That is, there's now a lot more meaningless boilerplate that nobody wants to write and nobody wants to reivew. Let's solve this with a few clever hacks. Allow extensions to get their current extension object with: let extension = imports.misc.extensionUtils.getCurrentExtension(); As such, extensions can now get their own extension object before the 'init' method is called, so they can import submodules or do other things at the module scope: const MySubModule = extension.imports.mySubModule; const dataPath = GLib.build_filenamev([extension.path, 'awesome-data.json']); https://bugzilla.gnome.org/show_bug.cgi?id=668429
This commit is contained in:
parent
831099cca5
commit
a622aba7eb
@ -43,7 +43,6 @@ const Application = new Lang.Class({
|
||||
this.application.connect('command-line', Lang.bind(this, this._onCommandLine));
|
||||
this.application.connect('startup', Lang.bind(this, this._onStartup));
|
||||
|
||||
this._extensionMetas = {};
|
||||
this._extensionPrefsModules = {};
|
||||
|
||||
this._extensionIters = {};
|
||||
@ -55,15 +54,15 @@ const Application = new Lang.Class({
|
||||
},
|
||||
|
||||
_extensionAvailable: function(uuid) {
|
||||
let meta = this._extensionMetas[uuid];
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
|
||||
if (!meta)
|
||||
if (!extension)
|
||||
return false;
|
||||
|
||||
if (ExtensionUtils.isOutOfDate(meta))
|
||||
if (ExtensionUtils.isOutOfDate(extension))
|
||||
return false;
|
||||
|
||||
if (!meta.dir.get_child('prefs.js').query_exists(null))
|
||||
if (!extension.dir.get_child('prefs.js').query_exists(null))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -75,16 +74,18 @@ const Application = new Lang.Class({
|
||||
cell.set_sensitive(false);
|
||||
},
|
||||
|
||||
_getExtensionPrefsModule: function(meta) {
|
||||
if (this._extensionPrefsModules.hasOwnProperty(meta.uuid))
|
||||
return this._extensionPrefsModules[meta.uuid];
|
||||
_getExtensionPrefsModule: function(extension) {
|
||||
let uuid = extension.metadata.uuid;
|
||||
|
||||
ExtensionUtils.installImporter(meta);
|
||||
if (this._extensionPrefsModules.hasOwnProperty(uuid))
|
||||
return this._extensionPrefsModules[uuid];
|
||||
|
||||
let prefsModule = meta.importer.prefs;
|
||||
prefsModule.init(meta);
|
||||
ExtensionUtils.installImporter(extension);
|
||||
|
||||
this._extensionPrefsModules[meta.uuid] = prefsModule;
|
||||
let prefsModule = extension.imports.prefs;
|
||||
prefsModule.init(extension.metadata);
|
||||
|
||||
this._extensionPrefsModules[uuid] = prefsModule;
|
||||
return prefsModule;
|
||||
},
|
||||
|
||||
@ -92,14 +93,14 @@ const Application = new Lang.Class({
|
||||
if (!this._extensionAvailable(uuid))
|
||||
return;
|
||||
|
||||
let meta = this._extensionMetas[uuid];
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
let widget;
|
||||
|
||||
try {
|
||||
let prefsModule = this._getExtensionPrefsModule(meta);
|
||||
widget = prefsModule.buildPrefsWidget(meta);
|
||||
let prefsModule = this._getExtensionPrefsModule(extension);
|
||||
widget = prefsModule.buildPrefsWidget();
|
||||
} catch (e) {
|
||||
widget = this._buildErrorUI(meta, e);
|
||||
widget = this._buildErrorUI(extension, e);
|
||||
}
|
||||
|
||||
// Destroy the current prefs widget, if it exists
|
||||
@ -119,10 +120,10 @@ const Application = new Lang.Class({
|
||||
this._selectExtension(uuid);
|
||||
},
|
||||
|
||||
_buildErrorUI: function(meta, exc) {
|
||||
_buildErrorUI: function(extension, exc) {
|
||||
let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
||||
let label = new Gtk.Label({
|
||||
label: _("There was an error loading the preferences dialog for %s:").format(meta.name)
|
||||
label: _("There was an error loading the preferences dialog for %s:").format(extension.metadata.name)
|
||||
});
|
||||
box.add(label);
|
||||
|
||||
@ -194,7 +195,7 @@ const Application = new Lang.Class({
|
||||
|
||||
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
|
||||
this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
|
||||
if (!this._extensionMetas.hasOwnProperty(uuid))
|
||||
if (ExtensionUtils.extensions[uuid] !== undefined)
|
||||
this._scanExtensions();
|
||||
}));
|
||||
|
||||
@ -203,21 +204,19 @@ const Application = new Lang.Class({
|
||||
|
||||
_scanExtensions: function() {
|
||||
ExtensionUtils.scanExtensions(Lang.bind(this, function(uuid, dir, type) {
|
||||
if (this._extensionMetas.hasOwnProperty(uuid))
|
||||
if (ExtensionUtils.extensions[uuid] !== undefined)
|
||||
return;
|
||||
|
||||
let meta;
|
||||
let extension;
|
||||
try {
|
||||
meta = ExtensionUtils.loadMetadata(uuid, dir, type);
|
||||
extension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||
} catch(e) {
|
||||
global.logError('' + e);
|
||||
return;
|
||||
}
|
||||
|
||||
this._extensionMetas[uuid] = meta;
|
||||
|
||||
let iter = this._model.append();
|
||||
this._model.set(iter, [0, 1], [uuid, meta.name]);
|
||||
this._model.set(iter, [0, 1], [uuid, extension.metadata.name]);
|
||||
this._extensionIters[uuid] = iter;
|
||||
}));
|
||||
},
|
||||
|
@ -17,6 +17,38 @@ const ExtensionType = {
|
||||
// GFile for user extensions
|
||||
var userExtensionsDir = null;
|
||||
|
||||
// Maps uuid -> metadata object
|
||||
const extensions = {};
|
||||
|
||||
function getCurrentExtension() {
|
||||
let stack = (new Error()).stack;
|
||||
|
||||
// Assuming we're importing this directly from an extension (and we shouldn't
|
||||
// ever not be), its UUID should be directly in the path here.
|
||||
let extensionStackLine = stack.split('\n')[1];
|
||||
if (!extensionStackLine)
|
||||
throw new Error('Could not find current extension');
|
||||
|
||||
// The stack line is like:
|
||||
// init([object Object])@/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
||||
//
|
||||
// In the case that we're importing from
|
||||
// module scope, the first field is blank:
|
||||
// @/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
||||
let match = new RegExp('@(.+):\\d+').exec(extensionStackLine);
|
||||
if (!match)
|
||||
throw new Error('Could not find current extension');
|
||||
|
||||
let path = match[1];
|
||||
let uuid = GLib.path_get_basename(GLib.path_get_dirname(path));
|
||||
|
||||
let extension = extensions[uuid];
|
||||
if (extension === undefined)
|
||||
throw new Error('Could not find current extension');
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* versionCheck:
|
||||
* @required: an array of versions we're compatible with
|
||||
@ -47,17 +79,17 @@ function versionCheck(required, current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isOutOfDate(meta) {
|
||||
if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION))
|
||||
function isOutOfDate(extension) {
|
||||
if (!versionCheck(extension.metadata['shell-version'], Config.PACKAGE_VERSION))
|
||||
return true;
|
||||
|
||||
if (meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))
|
||||
if (extension.metadata['js-version'] && !versionCheck(extension.metadata['js-version'], Config.GJS_VERSION))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function loadMetadata(uuid, dir, type) {
|
||||
function createExtensionObject(uuid, dir, type) {
|
||||
let info;
|
||||
|
||||
let metadataFile = dir.get_child('metadata.json');
|
||||
@ -95,21 +127,27 @@ function loadMetadata(uuid, dir, type) {
|
||||
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
||||
}
|
||||
|
||||
meta.type = type;
|
||||
meta.dir = dir;
|
||||
meta.path = dir.get_path();
|
||||
meta.error = '';
|
||||
meta.hasPrefs = dir.get_child('prefs.js').query_exists(null);
|
||||
let extension = {};
|
||||
|
||||
return meta;
|
||||
extension.metadata = meta;
|
||||
extension.uuid = meta.uuid;
|
||||
extension.type = type;
|
||||
extension.dir = dir;
|
||||
extension.path = dir.get_path();
|
||||
extension.error = '';
|
||||
extension.hasPrefs = dir.get_child('prefs.js').query_exists(null);
|
||||
|
||||
extensions[uuid] = extension;
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
var _meta = null;
|
||||
var _extension = null;
|
||||
|
||||
function installImporter(meta) {
|
||||
_meta = meta;
|
||||
ShellJS.add_extension_importer('imports.misc.extensionUtils._meta', 'importer', meta.path);
|
||||
_meta = null;
|
||||
function installImporter(extension) {
|
||||
_extension = extension;
|
||||
ShellJS.add_extension_importer('imports.misc.extensionUtils._extension', 'imports', extension.path);
|
||||
_extension = null;
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
@ -53,15 +53,10 @@ function _getCertFile() {
|
||||
|
||||
_httpSession.ssl_ca_file = _getCertFile();
|
||||
|
||||
// Maps uuid -> metadata object
|
||||
const extensionMeta = {};
|
||||
// Maps uuid -> extension state object (returned from init())
|
||||
const extensionStateObjs = {};
|
||||
// Contains the order that extensions were enabled in.
|
||||
const extensionOrder = [];
|
||||
|
||||
// Arrays of uuids
|
||||
var enabledExtensions;
|
||||
// Contains the order that extensions were enabled in.
|
||||
const extensionOrder = [];
|
||||
|
||||
// We don't really have a class to add signals on. So, create
|
||||
// a simple dummy object, add the signal methods, and export those
|
||||
@ -72,9 +67,6 @@ Signals.addSignalMethods(_signals);
|
||||
const connect = Lang.bind(_signals, _signals.connect);
|
||||
const disconnect = Lang.bind(_signals, _signals.disconnect);
|
||||
|
||||
// UUID => Array of error messages
|
||||
var errors = {};
|
||||
|
||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||
|
||||
function installExtensionFromUUID(uuid, version_tag) {
|
||||
@ -94,8 +86,8 @@ function installExtensionFromUUID(uuid, version_tag) {
|
||||
}
|
||||
|
||||
function uninstallExtensionFromUUID(uuid) {
|
||||
let meta = extensionMeta[uuid];
|
||||
if (!meta)
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return false;
|
||||
|
||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||
@ -104,17 +96,17 @@ function uninstallExtensionFromUUID(uuid) {
|
||||
disableExtension(uuid);
|
||||
|
||||
// Don't try to uninstall system extensions
|
||||
if (meta.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||
return false;
|
||||
|
||||
meta.state = ExtensionState.UNINSTALLED;
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
extension.state = ExtensionState.UNINSTALLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
|
||||
delete extensionMeta[uuid];
|
||||
delete ExtensionUtils.extensions[uuid];
|
||||
delete extensionStateObjs[uuid];
|
||||
delete errors[uuid];
|
||||
|
||||
FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(meta.path));
|
||||
FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(extension.path));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -164,11 +156,11 @@ function gotExtensionZipFile(session, message, uuid) {
|
||||
}
|
||||
|
||||
function disableExtension(uuid) {
|
||||
let meta = extensionMeta[uuid];
|
||||
if (!meta)
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
if (meta.state != ExtensionState.ENABLED)
|
||||
if (extension.state != ExtensionState.ENABLED)
|
||||
return;
|
||||
|
||||
let extensionState = extensionStateObjs[uuid];
|
||||
@ -212,41 +204,45 @@ function disableExtension(uuid) {
|
||||
|
||||
extensionOrder.splice(orderIdx, 1);
|
||||
|
||||
meta.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
function enableExtension(uuid) {
|
||||
let meta = extensionMeta[uuid];
|
||||
if (!meta)
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
if (meta.state == ExtensionState.INITIALIZED) {
|
||||
loadExtension(meta.dir, meta.type, true);
|
||||
if (extension.state == ExtensionState.INITIALIZED) {
|
||||
loadExtension(extension.dir, extension.type, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (meta.state != ExtensionState.DISABLED)
|
||||
if (extension.state != ExtensionState.DISABLED)
|
||||
return;
|
||||
|
||||
let extensionState = extensionStateObjs[uuid];
|
||||
|
||||
extensionOrder.push(uuid);
|
||||
|
||||
try {
|
||||
extensionState.enable();
|
||||
extension.stateObj.enable();
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
meta.state = ExtensionState.ENABLED;
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
extension.state = ExtensionState.ENABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
function logExtensionError(uuid, message, state) {
|
||||
if (!errors[uuid]) errors[uuid] = [];
|
||||
errors[uuid].push(message);
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
if (!extension.errors)
|
||||
extension.errors = [];
|
||||
|
||||
extension.errors.push(message);
|
||||
global.logError('Extension "%s" had error: %s'.format(uuid, message));
|
||||
state = state || ExtensionState.ERROR;
|
||||
_signals.emit('extension-state-changed', { uuid: uuid,
|
||||
@ -256,32 +252,30 @@ function logExtensionError(uuid, message, state) {
|
||||
|
||||
function loadExtension(dir, type, enabled) {
|
||||
let uuid = dir.get_basename();
|
||||
let meta;
|
||||
let extension;
|
||||
|
||||
if (extensionMeta[uuid] != undefined) {
|
||||
if (ExtensionUtils.extensions[uuid] != undefined) {
|
||||
throw new Error('extension already loaded');
|
||||
}
|
||||
|
||||
try {
|
||||
meta = ExtensionUtils.loadMetadata(uuid, dir, type);
|
||||
extension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
extensionMeta[uuid] = meta;
|
||||
|
||||
// Default to error, we set success as the last step
|
||||
meta.state = ExtensionState.ERROR;
|
||||
extension.state = ExtensionState.ERROR;
|
||||
|
||||
if (ExtensionUtils.isOutOfDate(meta)) {
|
||||
if (ExtensionUtils.isOutOfDate(extension)) {
|
||||
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
|
||||
meta.state = ExtensionState.OUT_OF_DATE;
|
||||
extension.state = ExtensionState.OUT_OF_DATE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
meta.state = ExtensionState.INITIALIZED;
|
||||
extension.state = ExtensionState.INITIALIZED;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -306,8 +300,8 @@ function loadExtension(dir, type, enabled) {
|
||||
let extensionModule;
|
||||
let extensionState = null;
|
||||
try {
|
||||
ExtensionUtils.installImporter(meta);
|
||||
extensionModule = meta.importer.extension;
|
||||
ExtensionUtils.installImporter(extension);
|
||||
extensionModule = extension.imports.extension;
|
||||
} catch (e) {
|
||||
if (stylesheetPath != null)
|
||||
theme.unload_stylesheet(stylesheetPath);
|
||||
@ -321,7 +315,7 @@ function loadExtension(dir, type, enabled) {
|
||||
}
|
||||
|
||||
try {
|
||||
extensionState = extensionModule.init(meta);
|
||||
extensionState = extensionModule.init(extension);
|
||||
} catch (e) {
|
||||
if (stylesheetPath != null)
|
||||
theme.unload_stylesheet(stylesheetPath);
|
||||
@ -331,7 +325,7 @@ function loadExtension(dir, type, enabled) {
|
||||
|
||||
if (!extensionState)
|
||||
extensionState = extensionModule;
|
||||
extensionStateObjs[uuid] = extensionState;
|
||||
extension.stateObj = extensionState;
|
||||
|
||||
if (!extensionState.enable) {
|
||||
logExtensionError(uuid, 'missing \'enable\' function');
|
||||
@ -342,13 +336,13 @@ function loadExtension(dir, type, enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
meta.state = ExtensionState.DISABLED;
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
|
||||
enableExtension(uuid);
|
||||
|
||||
_signals.emit('extension-loaded', meta.uuid);
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
global.log('Loaded extension ' + meta.uuid);
|
||||
_signals.emit('extension-loaded', uuid);
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
global.log('Loaded extension ' + uuid);
|
||||
}
|
||||
|
||||
function onEnabledExtensionsChanged() {
|
||||
@ -430,13 +424,13 @@ const InstallExtensionDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_onInstallButtonPressed: function(button, event) {
|
||||
let meta = { uuid: this._uuid,
|
||||
let extension = { uuid: this._uuid,
|
||||
state: ExtensionState.DOWNLOADING,
|
||||
error: '' };
|
||||
|
||||
extensionMeta[this._uuid] = meta;
|
||||
ExtensionUtils.extensions[this._uuid] = extension;
|
||||
|
||||
_signals.emit('extension-state-changed', meta);
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
|
||||
let params = { version_tag: this._version_tag,
|
||||
shell_version: Config.PACKAGE_VERSION,
|
||||
|
@ -15,6 +15,7 @@ const Mainloop = imports.mainloop;
|
||||
|
||||
const History = imports.misc.history;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Link = imports.ui.link;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
@ -728,7 +729,7 @@ const Extensions = new Lang.Class({
|
||||
this._extensionsList.add(this._noExtensions);
|
||||
this.actor.add(this._extensionsList);
|
||||
|
||||
for (let uuid in ExtensionSystem.extensionMeta)
|
||||
for (let uuid in ExtensionUtils.extensions)
|
||||
this._loadExtension(null, uuid);
|
||||
|
||||
ExtensionSystem.connect('extension-loaded',
|
||||
@ -736,10 +737,10 @@ const Extensions = new Lang.Class({
|
||||
},
|
||||
|
||||
_loadExtension: function(o, uuid) {
|
||||
let extension = ExtensionSystem.extensionMeta[uuid];
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
// There can be cases where we create dummy extension metadata
|
||||
// that's not really a proper extension. Don't bother with these.
|
||||
if (!extension.name)
|
||||
if (!extension.metadata.name)
|
||||
return;
|
||||
|
||||
let extensionDisplay = this._createExtensionDisplay(extension);
|
||||
@ -751,25 +752,24 @@ const Extensions = new Lang.Class({
|
||||
},
|
||||
|
||||
_onViewSource: function (actor) {
|
||||
let meta = actor._extensionMeta;
|
||||
let file = Gio.file_new_for_path(meta.path);
|
||||
let uri = file.get_uri();
|
||||
let extension = actor._extension;
|
||||
let uri = extension.dir.get_uri();
|
||||
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context());
|
||||
Main.lookingGlass.close();
|
||||
},
|
||||
|
||||
_onWebPage: function (actor) {
|
||||
let meta = actor._extensionMeta;
|
||||
Gio.app_info_launch_default_for_uri(meta.url, global.create_app_launch_context());
|
||||
let extension = actor._extension;
|
||||
Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context());
|
||||
Main.lookingGlass.close();
|
||||
},
|
||||
|
||||
_onViewErrors: function (actor) {
|
||||
let meta = actor._extensionMeta;
|
||||
let extension = actor._extension;
|
||||
let shouldShow = !actor._isShowing;
|
||||
|
||||
if (shouldShow) {
|
||||
let errors = ExtensionSystem.errors[meta.uuid];
|
||||
let errors = extension.errors;
|
||||
let errorDisplay = new St.BoxLayout({ vertical: true });
|
||||
if (errors && errors.length) {
|
||||
for (let i = 0; i < errors.length; i ++)
|
||||
@ -809,36 +809,36 @@ const Extensions = new Lang.Class({
|
||||
return 'Unknown'; // Not translated, shouldn't appear
|
||||
},
|
||||
|
||||
_createExtensionDisplay: function(meta) {
|
||||
_createExtensionDisplay: function(extension) {
|
||||
let box = new St.BoxLayout({ style_class: 'lg-extension', vertical: true });
|
||||
let name = new St.Label({ style_class: 'lg-extension-name',
|
||||
text: meta.name });
|
||||
text: extension.metadata.name });
|
||||
box.add(name, { expand: true });
|
||||
let description = new St.Label({ style_class: 'lg-extension-description',
|
||||
text: meta.description || 'No description' });
|
||||
text: extension.metadata.description || 'No description' });
|
||||
box.add(description, { expand: true });
|
||||
|
||||
let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
|
||||
box.add(metaBox);
|
||||
let stateString = this._stateToString(meta.state);
|
||||
let stateString = this._stateToString(extension.state);
|
||||
let state = new St.Label({ style_class: 'lg-extension-state',
|
||||
text: this._stateToString(meta.state) });
|
||||
text: this._stateToString(extension.state) });
|
||||
metaBox.add(state);
|
||||
|
||||
let viewsource = new Link.Link({ label: _("View Source") });
|
||||
viewsource.actor._extensionMeta = meta;
|
||||
viewsource.actor._extension = extension;
|
||||
viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource));
|
||||
metaBox.add(viewsource.actor);
|
||||
|
||||
if (meta.url) {
|
||||
if (extension.metadata.url) {
|
||||
let webpage = new Link.Link({ label: _("Web Page") });
|
||||
webpage.actor._extensionMeta = meta;
|
||||
webpage.actor._extension = extension;
|
||||
webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage));
|
||||
metaBox.add(webpage.actor);
|
||||
}
|
||||
|
||||
let viewerrors = new Link.Link({ label: _("Show Errors") });
|
||||
viewerrors.actor._extensionMeta = meta;
|
||||
viewerrors.actor._extension = extension;
|
||||
viewerrors.actor._parentBox = box;
|
||||
viewerrors.actor._isShowing = false;
|
||||
viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
|
||||
|
@ -7,6 +7,7 @@ const Shell = imports.gi.Shell;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Flashspot = imports.ui.flashspot;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
@ -182,7 +183,7 @@ const GnomeShell = new Lang.Class({
|
||||
|
||||
ListExtensions: function() {
|
||||
let out = {};
|
||||
for (let uuid in ExtensionSystem.extensionMeta) {
|
||||
for (let uuid in ExtensionUtils.extensions) {
|
||||
let dbusObj = this.GetExtensionInfo(uuid);
|
||||
out[uuid] = dbusObj;
|
||||
}
|
||||
@ -190,10 +191,23 @@ const GnomeShell = new Lang.Class({
|
||||
},
|
||||
|
||||
GetExtensionInfo: function(uuid) {
|
||||
let meta = ExtensionSystem.extensionMeta[uuid] || {};
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return {};
|
||||
|
||||
let obj = {};
|
||||
Lang.copyProperties(extension.metadata, obj);
|
||||
|
||||
// Only serialize the properties that we actually need.
|
||||
const serializedProperties = ["type", "state", "path", "error", "hasPrefs"];
|
||||
|
||||
serializedProperties.forEach(function(prop) {
|
||||
obj[prop] = extension[prop];
|
||||
});
|
||||
|
||||
let out = {};
|
||||
for (let key in meta) {
|
||||
let val = meta[key];
|
||||
for (let key in obj) {
|
||||
let val = obj[key];
|
||||
let type;
|
||||
switch (typeof val) {
|
||||
case 'string':
|
||||
@ -210,11 +224,19 @@ const GnomeShell = new Lang.Class({
|
||||
}
|
||||
out[key] = GLib.Variant.new(type, val);
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
GetExtensionErrors: function(uuid) {
|
||||
return ExtensionSystem.errors[uuid] || [];
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return [];
|
||||
|
||||
if (!extension.errors)
|
||||
return [];
|
||||
|
||||
return extension.errors;
|
||||
},
|
||||
|
||||
EnableExtension: function(uuid) {
|
||||
|
Loading…
Reference in New Issue
Block a user