%PDF- %PDF-
| Direktori : /usr/share/gnome-shell/ |
| Current File : //usr/share/gnome-shell/org.gnome.Extensions.src.gresource |
GVariant p (
N
| p v � 7 �H�. 7 v @ ?% ��Q� ?% v P% -4 ��0* -4 v @4 ?d VCb� ?d L Dd Ld Oq�e Ld v `d �l KP� �l L �l �l �s� �l L �l �l Ե �����l L �l �l ��$0 �l L m m � �� m v m Jm �0I Jm L Pm dm extensionsWindow.js � import Adw from 'gi://Adw?version=1';
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import Shew from 'gi://Shew';
const Package = imports.package;
import * as Gettext from 'gettext';
import * as Config from './misc/config.js';
import {ExtensionRow} from './extensionRow.js';
Gio._promisify(Adw.AlertDialog.prototype, 'choose');
Gio._promisify(Gio.DBusConnection.prototype, 'call');
Gio._promisify(Shew.WindowExporter.prototype, 'export');
export const ExtensionsWindow = GObject.registerClass({
GTypeName: 'ExtensionsWindow',
Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui',
InternalChildren: [
'sortModel',
'searchFilter',
'userListModel',
'systemListModel',
'searchListModel',
'userGroup',
'userList',
'systemGroup',
'systemList',
'searchList',
'mainStack',
'searchBar',
'searchEntry',
'updatesBanner',
],
}, class ExtensionsWindow extends Adw.ApplicationWindow {
_init(params) {
super._init(params);
if (Config.PROFILE === 'development')
this.add_css_class('devel');
this._exporter = new Shew.WindowExporter({window: this});
this._exportedHandle = '';
this.add_action_entries(
[{
name: 'show-about',
activate: () => this._showAbout(),
}, {
name: 'logout',
activate: () => this._logout(),
}, {
name: 'user-extensions-enabled',
state: 'false',
change_state: (a, state) => {
const {extensionManager} = this.application;
extensionManager.userExtensionsEnabled = state.get_boolean();
},
}]);
const settings = new Gio.Settings({
schema_id: 'org.gnome.Extensions',
});
settings.bind('window-width',
this, 'default-width',
Gio.SettingsBindFlags.DEFAULT);
settings.bind('window-height',
this, 'default-height',
Gio.SettingsBindFlags.DEFAULT);
settings.bind('window-maximized',
this, 'maximized',
Gio.SettingsBindFlags.DEFAULT);
this._searchEntry.connect('search-changed',
() => (this._searchFilter.search = this._searchEntry.text));
this._searchBar.connect('notify::search-mode-enabled',
() => this._syncVisiblePage());
this._searchListModel.connect('notify::n-items',
() => this._syncVisiblePage());
this._userList.connect('row-activated', (_list, row) => row.activate());
this._userGroup.connect('notify::visible', () => this._syncVisiblePage());
this._systemList.connect('row-activated', (_list, row) => row.activate());
this._systemGroup.connect('notify::visible', () => this._syncVisiblePage());
const {extensionManager} = this.application;
extensionManager.connect('notify::failed',
() => this._syncVisiblePage());
extensionManager.connect('notify::n-updates',
() => this._checkUpdates());
extensionManager.connect('notify::user-extensions-enabled',
this._onUserExtensionsEnabledChanged.bind(this));
this._onUserExtensionsEnabledChanged();
this._sortModel.model = extensionManager.extensions;
this._userList.bind_model(this._userListModel,
extension => new ExtensionRow(extension));
this._systemList.bind_model(this._systemListModel,
extension => new ExtensionRow(extension));
this._searchList.bind_model(this._searchListModel,
extension => new ExtensionRow(extension));
extensionManager.connect('extensions-loaded',
() => this._extensionsLoaded());
}
async uninstall(extension) {
const dialog = new Adw.AlertDialog({
heading: _('Remove “%s”?').format(extension.name),
body: _('If you remove the extension, you need to return to download it if you want to enable it again'),
});
dialog.add_response('cancel', _('_Cancel'));
dialog.add_response('remove', _('_Remove'));
dialog.set_response_appearance('remove',
Adw.ResponseAppearance.DESTRUCTIVE);
const {extensionManager} = this.application;
const response = await dialog.choose(this, null);
if (response === 'remove')
extensionManager.uninstallExtension(extension.uuid);
}
async openPrefs(extension) {
if (!this._exportedHandle) {
try {
this._exportedHandle = await this._exporter.export();
} catch (e) {
console.warn(`Failed to export window: ${e.message}`);
}
}
const {extensionManager} = this.application;
extensionManager.openExtensionPrefs(extension.uuid, this._exportedHandle);
}
_showAbout() {
const [version] = Package.version.split(' ');
const aboutDialog = Adw.AboutDialog.new_from_appdata(
'/org/gnome/Extensions/metainfo.xml', version);
aboutDialog.set({
developers: [
'Florian Müllner <fmuellner@gnome.org>',
'Jasper St. Pierre <jstpierre@mecheye.net>',
'Didier Roche <didrocks@ubuntu.com>',
'Romain Vigier <contact@romainvigier.fr>',
],
designers: [
'Allan Day <allanpday@gmail.com>',
'Tobias Bernard <tbernard@gnome.org>',
],
translator_credits: _('translator-credits'),
version: Package.version,
});
aboutDialog.present(this);
}
_logout() {
this.application.get_dbus_connection().call(
'org.gnome.SessionManager',
'/org/gnome/SessionManager',
'org.gnome.SessionManager',
'Logout',
new GLib.Variant('(u)', [0]),
null,
Gio.DBusCallFlags.NONE,
-1,
null);
}
_onUserExtensionsEnabledChanged() {
const {userExtensionsEnabled} = this.application.extensionManager;
const action = this.lookup_action('user-extensions-enabled');
action.set_state(new GLib.Variant('b', userExtensionsEnabled));
}
_syncVisiblePage() {
const {extensionManager} = this.application;
const {searchModeEnabled} = this._searchBar;
if (extensionManager.failed)
this._mainStack.visible_child_name = 'noshell';
else if (searchModeEnabled && this._searchListModel.get_n_items() > 0)
this._mainStack.visible_child_name = 'search';
else if (searchModeEnabled)
this._mainStack.visible_child_name = 'noresults';
else if (this._userGroup.visible || this._systemGroup.visible)
this._mainStack.visible_child_name = 'main';
else
this._mainStack.visible_child_name = 'placeholder';
}
_checkUpdates() {
const {nUpdates} = this.application.extensionManager;
this._updatesBanner.title = Gettext.ngettext(
'%d extension will be updated on next login.',
'%d extensions will be updated on next login.',
nUpdates).format(nUpdates);
this._updatesBanner.revealed = nUpdates > 0;
}
_extensionsLoaded() {
this._syncVisiblePage();
this._checkUpdates();
}
});
(uuay)main.js � import Adw from 'gi://Adw?version=1';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import {setConsoleLogDomain} from 'console';
const Package = imports.package;
Package.initFormat();
import {ExtensionManager} from './extensionManager.js';
import {ExtensionsWindow} from './extensionsWindow.js';
var Application = GObject.registerClass(
class Application extends Adw.Application {
_init() {
GLib.set_prgname('gnome-extensions-app');
super._init({
application_id: Package.name,
version: Package.version,
});
this.connect('window-removed', (a, window) => window.run_dispose());
}
get extensionManager() {
return this._extensionManager;
}
vfunc_activate() {
this._extensionManager.checkForUpdates();
this._window.present();
}
vfunc_startup() {
super.vfunc_startup();
this.add_action_entries(
[{
name: 'quit',
activate: () => this._window.close(),
}]);
this.set_accels_for_action('app.quit', ['<Primary>q']);
this._extensionManager = new ExtensionManager();
this._window = new ExtensionsWindow({application: this});
}
});
/**
* Main entrypoint for the app
*
* @param {string[]} argv - command line arguments
* @returns {void}
*/
export async function main(argv) {
Package.initGettext();
setConsoleLogDomain('Extensions');
await new Application().runAsync(argv);
}
(uuay)extensionRow.js � import Adw from 'gi://Adw?version=1';
import Gio from 'gi://Gio';
import GObject from 'gi://GObject';
import {ExtensionState} from './misc/extensionUtils.js';
import {Extension} from './extensionManager.js';
export const ExtensionRow = GObject.registerClass({
GTypeName: 'ExtensionRow',
Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
Properties: {
'extension': GObject.ParamSpec.object(
'extension', null, null,
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
Extension),
},
InternalChildren: [
'detailsPopover',
'versionLabel',
'switch',
'actionsBox',
],
}, class ExtensionRow extends Adw.ActionRow {
constructor(extension) {
super({extension});
this._app = Gio.Application.get_default();
this._actionGroup = new Gio.SimpleActionGroup();
this.insert_action_group('row', this._actionGroup);
const actionEntries = [
{
name: 'show-prefs',
activate: () => {
this._detailsPopover.popdown();
this.get_root().openPrefs(extension);
},
enabledProp: 'has-prefs',
}, {
name: 'show-url',
activate: () => {
this._detailsPopover.popdown();
Gio.AppInfo.launch_default_for_uri(
extension.url, this.get_display().get_app_launch_context());
},
enabledProp: 'url',
enabledTransform: s => s !== '',
}, {
name: 'uninstall',
activate: () => {
this._detailsPopover.popdown();
this.get_root().uninstall(extension).catch(logError);
},
enabledProp: 'is-user',
},
];
this._actionGroup.add_action_entries(actionEntries);
this._bindActionEnabled(actionEntries);
this._switch.connect('state-set', (sw, state) => {
const {uuid, enabled} = this._extension;
if (enabled === state)
return true;
if (state)
this._app.extensionManager.enableExtension(uuid);
else
this._app.extensionManager.disableExtension(uuid);
return true;
});
this._extension.bind_property_full('state',
this._switch, 'state',
GObject.BindingFlags.SYNC_CREATE,
(bind, source) => [true, source === ExtensionState.ACTIVE],
null);
this._extension.bind_property_full('version',
this._versionLabel, 'label',
GObject.BindingFlags.SYNC_CREATE,
(bind, source) => [true, _('Version %s').format(source)],
null);
}
get extension() {
return this._extension ?? null;
}
set extension(ext) {
this._extension = ext;
}
_bindActionEnabled(entries) {
for (const entry of entries) {
const {name, enabledProp, enabledTransform} = entry;
if (!enabledProp)
continue;
const action = this._actionGroup.lookup_action(name);
if (enabledTransform) {
this._extension.bind_property_full(enabledProp,
action, 'enabled',
GObject.BindingFlags.SYNC_CREATE,
(bind, source) => [true, enabledTransform(source)],
null);
} else {
this._extension.bind_property(enabledProp,
action, 'enabled',
GObject.BindingFlags.SYNC_CREATE);
}
}
}
});
(uuay)extensionManager.js�/ import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import {
ExtensionState, ExtensionType, deserializeExtension
} from './misc/extensionUtils.js';
const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
let shellVersion;
function loadInterfaceXML(iface) {
const uri = `resource:///org/gnome/Extensions/dbus-interfaces/${iface}.xml`;
const f = Gio.File.new_for_uri(uri);
try {
let [ok_, bytes] = f.load_contents(null);
return new TextDecoder().decode(bytes);
} catch (e) {
console.error(`Failed to load D-Bus interface ${iface}`);
}
return null;
}
const Extension = GObject.registerClass({
GTypeName: 'Extension',
Properties: {
'uuid': GObject.ParamSpec.string(
'uuid', null, null,
GObject.ParamFlags.READABLE,
''),
'name': GObject.ParamSpec.string(
'name', null, null,
GObject.ParamFlags.READABLE,
''),
'description': GObject.ParamSpec.string(
'description', null, null,
GObject.ParamFlags.READABLE,
''),
'state': GObject.ParamSpec.int(
'state', null, null,
GObject.ParamFlags.READABLE,
1, 99, ExtensionState.INITIALIZED),
'enabled': GObject.ParamSpec.boolean(
'enabled', null, null,
GObject.ParamFlags.READABLE,
false),
'creator': GObject.ParamSpec.string(
'creator', null, null,
GObject.ParamFlags.READABLE,
''),
'url': GObject.ParamSpec.string(
'url', null, null,
GObject.ParamFlags.READABLE,
''),
'version': GObject.ParamSpec.string(
'version', null, null,
GObject.ParamFlags.READABLE,
''),
'error': GObject.ParamSpec.string(
'error', null, null,
GObject.ParamFlags.READABLE,
''),
'has-error': GObject.ParamSpec.boolean(
'has-error', null, null,
GObject.ParamFlags.READABLE,
false),
'has-prefs': GObject.ParamSpec.boolean(
'has-prefs', null, null,
GObject.ParamFlags.READABLE,
false),
'has-update': GObject.ParamSpec.boolean(
'has-update', null, null,
GObject.ParamFlags.READABLE,
false),
'has-version': GObject.ParamSpec.boolean(
'has-version', null, null,
GObject.ParamFlags.READABLE,
false),
'can-change': GObject.ParamSpec.boolean(
'can-change', null, null,
GObject.ParamFlags.READABLE,
false),
'is-user': GObject.ParamSpec.boolean(
'is-user', null, null,
GObject.ParamFlags.READABLE,
false),
},
}, class Extension extends GObject.Object {
constructor(variant) {
super();
this.update(variant);
}
update(variant) {
const deserialized = deserializeExtension(variant);
const {
uuid, type, state, enabled, error, hasPrefs, hasUpdate, canChange, metadata,
} = deserialized;
if (!this._uuid)
this._uuid = uuid;
if (this._uuid !== uuid)
throw new Error(`Invalid update of extension ${this._uuid} with data from ${uuid}`);
this.freeze_notify();
const {name} = metadata;
if (this._name !== name) {
this._name = name;
this.notify('name');
}
const [desc] = metadata.description.split('\n');
if (this._description !== desc) {
this._description = desc;
this.notify('description');
}
if (this._type !== type) {
this._type = type;
this.notify('is-user');
}
if (this._errorDetail !== error) {
this._errorDetail = error;
this.notify('error');
}
if (this._enabled !== enabled) {
this._enabled = enabled;
this.notify('enabled');
}
if (this._state !== state) {
const hadError = this.hasError;
this._state = state;
this.notify('state');
// Compat with older shell versions
if (this._enabled === undefined)
this.notify('enabled');
if (this.hasError !== hadError) {
this.notify('has-error');
this.notify('error');
}
}
const creator = metadata.creator ?? '';
if (this._creator !== creator) {
this._creator = creator;
this.notify('creator');
}
const url = metadata.url ?? '';
if (this._url !== url) {
this._url = url;
this.notify('url');
}
const version = String(
metadata['version-name'] || metadata['version'] || '');
if (this._version !== version) {
this._version = version;
this.notify('version');
this.notify('has-version');
}
if (this._hasPrefs !== hasPrefs) {
this._hasPrefs = hasPrefs;
this.notify('has-prefs');
}
if (this._hasUpdate !== hasUpdate) {
this._hasUpdate = hasUpdate;
this.notify('has-update');
}
if (this._canChange !== canChange) {
this._canChange = canChange;
this.notify('can-change');
}
this.thaw_notify();
}
get uuid() {
return this._uuid;
}
get name() {
return this._name;
}
get description() {
return this._description;
}
get state() {
return this._state;
}
get enabled() {
// Compat with older shell versions
if (this._enabled === undefined) {
return this.state === ExtensionState.ACTIVE ||
this.state === ExtensionState.ACTIVATING;
}
return this._enabled;
}
get creator() {
return this._creator;
}
get url() {
return this._url;
}
get version() {
return this._version;
}
get error() {
if (!this.hasError)
return '';
if (this.state === ExtensionState.OUT_OF_DATE) {
return this.version !== ''
? _('The installed version of this extension (%s) is incompatible with the current version of GNOME (%s). The extension has been disabled.').format(this.version, shellVersion)
: _('The installed version of this extension is incompatible with the current version of GNOME (%s). The extension has been disabled.').format(shellVersion);
}
const message = [
_('An error has occurred in this extension. This could cause issues elsewhere in the system. It is recommended to turn the extension off until the error is resolved.'),
];
if (this._errorDetail) {
message.push(
// translators: Details for an extension error
_('Error details:'), this._errorDetail);
}
return message.join('\n\n');
}
get hasError() {
return this.state === ExtensionState.OUT_OF_DATE ||
this.state === ExtensionState.ERROR;
}
get hasPrefs() {
return this._hasPrefs;
}
get hasUpdate() {
return this._hasUpdate;
}
get hasVersion() {
return this._version !== '';
}
get canChange() {
return this._canChange;
}
get isUser() {
return this._type === ExtensionType.PER_USER;
}
});
const {$gtype: TYPE_EXTENSION} = Extension;
export {TYPE_EXTENSION as Extension};
export const ExtensionManager = GObject.registerClass({
Properties: {
'user-extensions-enabled': GObject.ParamSpec.boolean(
'user-extensions-enabled', null, null,
GObject.ParamFlags.READWRITE,
true),
'extensions': GObject.ParamSpec.object(
'extensions', null, null,
GObject.ParamFlags.READABLE,
Gio.ListModel),
'n-updates': GObject.ParamSpec.int(
'n-updates', null, null,
GObject.ParamFlags.READABLE,
0, 999, 0),
'failed': GObject.ParamSpec.boolean(
'failed', null, null,
GObject.ParamFlags.READABLE,
false),
},
Signals: {
'extensions-loaded': {},
},
}, class ExtensionManager extends GObject.Object {
constructor() {
super();
this._extensions = new Gio.ListStore({itemType: Extension});
this._proxyReady = false;
this._shellProxy = new GnomeShellProxy(Gio.DBus.session,
'org.gnome.Shell.Extensions', '/org/gnome/Shell/Extensions',
() => {
this._proxyReady = true;
shellVersion = this._shellProxy.ShellVersion;
this._shellProxy.connect('notify::g-name-owner',
() => this.notify('failed'));
this.notify('failed');
});
this._shellProxy.connect('g-properties-changed', (proxy, properties) => {
const enabledChanged = !!properties.lookup_value('UserExtensionsEnabled', null);
if (enabledChanged)
this.notify('user-extensions-enabled');
});
this._shellProxy.connectSignal(
'ExtensionStateChanged', this._onExtensionStateChanged.bind(this));
this._loadExtensions().catch(console.error);
}
get extensions() {
return this._extensions;
}
get userExtensionsEnabled() {
return this._shellProxy.UserExtensionsEnabled ?? false;
}
set userExtensionsEnabled(enabled) {
this._shellProxy.UserExtensionsEnabled = enabled;
}
get nUpdates() {
let nUpdates = 0;
for (const ext of this._extensions) {
if (ext.isUser && ext.hasUpdate)
nUpdates++;
}
return nUpdates;
}
get failed() {
return this._proxyReady && this._shellProxy.gNameOwner === null;
}
enableExtension(uuid) {
this._shellProxy.EnableExtensionAsync(uuid).catch(console.error);
}
disableExtension(uuid) {
this._shellProxy.DisableExtensionAsync(uuid).catch(console.error);
}
uninstallExtension(uuid) {
this._shellProxy.UninstallExtensionAsync(uuid).catch(console.error);
}
openExtensionPrefs(uuid, parentHandle) {
this._shellProxy.OpenExtensionPrefsAsync(uuid,
parentHandle,
{modal: new GLib.Variant('b', true)}).catch(console.error);
}
checkForUpdates() {
this._shellProxy.CheckForUpdatesAsync().catch(console.error);
}
async _loadExtensions() {
const [extensionsMap] = await this._shellProxy.ListExtensionsAsync();
for (let uuid in extensionsMap) {
const extension = new Extension(extensionsMap[uuid]);
this._extensions.append(extension);
}
this.emit('extensions-loaded');
}
_findExtension(uuid) {
const len = this._extensions.get_n_items();
for (let pos = 0; pos < len; pos++) {
const extension = this._extensions.get_item(pos);
if (extension.uuid === uuid)
return [extension, pos];
}
return [null, -1];
}
_onExtensionStateChanged(p, sender, [uuid, newState]) {
const [extension, pos] = this._findExtension(uuid);
if (extension)
extension.update(newState);
if (!extension)
this._extensions.append(new Extension(newState));
else if (extension.state === ExtensionState.UNINSTALLED)
this._extensions.remove(pos);
if (this._updatesCheckId)
return;
this._updatesCheckId = GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT, 1, () => {
this.notify('n-updates');
delete this._updatesCheckId;
return GLib.SOURCE_REMOVE;
});
}
});
(uuay)misc/
extensionUtils.js k // Common utils for the extension system, the extensions D-Bus service
// and the Extensions app
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
export const ExtensionType = {
SYSTEM: 1,
PER_USER: 2,
};
/**
* @enum {number}
*/
export const ExtensionState = {
ACTIVE: 1,
INACTIVE: 2,
ERROR: 3,
OUT_OF_DATE: 4,
DOWNLOADING: 5,
INITIALIZED: 6,
DEACTIVATING: 7,
ACTIVATING: 8,
// Used as an error state for operations on unknown extensions,
// should never be in a real extensionMeta object.
UNINSTALLED: 99,
};
const SERIALIZED_PROPERTIES = [
'type',
'state',
'enabled',
'path',
'error',
'hasPrefs',
'hasUpdate',
'canChange',
];
/**
* Serialize extension into an object that can be used
* in a vardict {GLib.Variant}
*
* @param {object} extension - an extension object
* @returns {object}
*/
export function serializeExtension(extension) {
let obj = {...extension.metadata};
SERIALIZED_PROPERTIES.forEach(prop => {
obj[prop] = extension[prop];
});
let res = {};
for (let key in obj) {
let val = obj[key];
let type;
switch (typeof val) {
case 'string':
type = 's';
break;
case 'number':
type = 'd';
break;
case 'boolean':
type = 'b';
break;
default:
continue;
}
res[key] = GLib.Variant.new(type, val);
}
return res;
}
/**
* Deserialize an unpacked variant into an extension object
*
* @param {object} variant - an unpacked {GLib.Variant}
* @returns {object}
*/
export function deserializeExtension(variant) {
let res = {metadata: {}};
for (let prop in variant) {
let val = variant[prop].unpack();
if (SERIALIZED_PROPERTIES.includes(prop))
res[prop] = val;
else
res.metadata[prop] = val;
}
// add the 2 additional properties to create a valid extension object, as createExtensionObject()
res.uuid = res.metadata.uuid;
res.dir = Gio.File.new_for_path(res.path);
return res;
}
(uuay)org/ Extensions/ / gnome/ config.js "