2019-01-31 14:07:06 +00:00
|
|
|
/* exported main */
|
2019-08-21 17:36:42 +00:00
|
|
|
imports.gi.versions.Gdk = '3.0';
|
|
|
|
imports.gi.versions.Gtk = '3.0';
|
|
|
|
|
2012-01-19 02:21:56 +00:00
|
|
|
const Gettext = imports.gettext;
|
2020-03-19 19:38:16 +00:00
|
|
|
const Package = imports.package;
|
2019-11-30 03:12:54 +00:00
|
|
|
const { Gdk, GLib, Gio, GObject, Gtk } = imports.gi;
|
2012-01-19 02:21:56 +00:00
|
|
|
|
2020-03-19 19:38:16 +00:00
|
|
|
Package.initFormat();
|
2012-01-19 02:21:56 +00:00
|
|
|
|
|
|
|
const ExtensionUtils = imports.misc.extensionUtils;
|
|
|
|
|
2019-11-30 05:06:08 +00:00
|
|
|
const { ExtensionState, ExtensionType } = ExtensionUtils;
|
2018-11-01 12:55:17 +00:00
|
|
|
|
2018-09-06 00:55:20 +00:00
|
|
|
const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
|
2012-01-19 02:21:56 +00:00
|
|
|
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
|
|
|
|
|
2020-03-07 18:26:06 +00:00
|
|
|
function loadInterfaceXML(iface) {
|
|
|
|
const uri = 'resource:///org/gnome/Extensions/dbus-interfaces/%s.xml'.format(iface);
|
|
|
|
const f = Gio.File.new_for_uri(uri);
|
|
|
|
|
|
|
|
try {
|
|
|
|
let [ok_, bytes] = f.load_contents(null);
|
|
|
|
return imports.byteArray.toString(bytes);
|
|
|
|
} catch (e) {
|
|
|
|
log('Failed to load D-Bus interface %s'.format(iface));
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-03-05 17:46:18 +00:00
|
|
|
function toggleState(action) {
|
|
|
|
let state = action.get_state();
|
|
|
|
action.change_state(new GLib.Variant('b', !state.get_boolean()));
|
|
|
|
}
|
|
|
|
|
2019-10-28 18:35:33 +00:00
|
|
|
var Application = GObject.registerClass(
|
|
|
|
class Application extends Gtk.Application {
|
2019-05-28 21:22:37 +00:00
|
|
|
_init() {
|
2012-01-19 02:21:56 +00:00
|
|
|
GLib.set_prgname('gnome-shell-extension-prefs');
|
2020-03-05 18:44:28 +00:00
|
|
|
super._init({ application_id: 'org.gnome.Extensions' });
|
2019-11-30 01:48:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get shellProxy() {
|
|
|
|
return this._shellProxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
vfunc_activate() {
|
2020-01-26 23:47:18 +00:00
|
|
|
this._shellProxy.CheckForUpdatesRemote();
|
2019-11-30 01:48:18 +00:00
|
|
|
this._window.present();
|
|
|
|
}
|
|
|
|
|
|
|
|
vfunc_startup() {
|
|
|
|
super.vfunc_startup();
|
|
|
|
|
2020-01-24 01:02:10 +00:00
|
|
|
let provider = new Gtk.CssProvider();
|
2020-03-05 16:44:27 +00:00
|
|
|
let uri = 'resource:///org/gnome/Extensions/css/application.css';
|
2020-01-24 01:02:10 +00:00
|
|
|
try {
|
|
|
|
provider.load_from_file(Gio.File.new_for_uri(uri));
|
|
|
|
} catch (e) {
|
|
|
|
logError(e, 'Failed to add application style');
|
|
|
|
}
|
|
|
|
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
|
|
|
|
provider,
|
|
|
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
|
|
|
|
|
2019-11-30 01:48:18 +00:00
|
|
|
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
|
|
|
|
this._window = new ExtensionsWindow({ application: this });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-11-30 01:48:18 +00:00
|
|
|
var ExtensionsWindow = GObject.registerClass({
|
|
|
|
GTypeName: 'ExtensionsWindow',
|
2020-03-05 16:44:27 +00:00
|
|
|
Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui',
|
2019-11-30 01:48:18 +00:00
|
|
|
InternalChildren: [
|
2019-11-30 07:08:05 +00:00
|
|
|
'userList',
|
|
|
|
'systemList',
|
2020-01-30 00:28:02 +00:00
|
|
|
'mainBox',
|
2019-11-30 01:48:18 +00:00
|
|
|
'mainStack',
|
2020-01-30 00:28:02 +00:00
|
|
|
'scrolledWindow',
|
2019-11-30 14:20:04 +00:00
|
|
|
'updatesBar',
|
|
|
|
'updatesLabel',
|
2019-11-30 01:48:18 +00:00
|
|
|
],
|
|
|
|
}, class ExtensionsWindow extends Gtk.ApplicationWindow {
|
2019-11-30 01:48:18 +00:00
|
|
|
_init(params) {
|
|
|
|
super._init(params);
|
2012-01-19 02:21:56 +00:00
|
|
|
|
2019-11-30 01:48:18 +00:00
|
|
|
this._prefsDialog = null;
|
2019-11-30 14:20:04 +00:00
|
|
|
this._updatesCheckId = 0;
|
2019-11-30 01:48:18 +00:00
|
|
|
|
2020-01-30 00:28:02 +00:00
|
|
|
this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
|
|
|
|
|
2019-11-30 05:51:35 +00:00
|
|
|
let action;
|
|
|
|
action = new Gio.SimpleAction({ name: 'show-about' });
|
|
|
|
action.connect('activate', this._showAbout.bind(this));
|
|
|
|
this.add_action(action);
|
|
|
|
|
2019-11-30 14:20:04 +00:00
|
|
|
action = new Gio.SimpleAction({ name: 'logout' });
|
|
|
|
action.connect('activate', this._logout.bind(this));
|
|
|
|
this.add_action(action);
|
|
|
|
|
2020-03-05 17:46:18 +00:00
|
|
|
action = new Gio.SimpleAction({
|
|
|
|
name: 'user-extensions-enabled',
|
|
|
|
state: new GLib.Variant('b', false),
|
|
|
|
});
|
|
|
|
action.connect('activate', toggleState);
|
|
|
|
action.connect('change-state', (a, state) => {
|
|
|
|
this._shellProxy.UserExtensionsEnabled = state.get_boolean();
|
|
|
|
});
|
|
|
|
this.add_action(action);
|
2019-11-30 01:48:18 +00:00
|
|
|
|
2019-11-30 07:08:05 +00:00
|
|
|
this._userList.set_sort_func(this._sortList.bind(this));
|
|
|
|
this._userList.set_header_func(this._updateHeader.bind(this));
|
|
|
|
|
|
|
|
this._systemList.set_sort_func(this._sortList.bind(this));
|
|
|
|
this._systemList.set_header_func(this._updateHeader.bind(this));
|
2019-11-30 01:48:18 +00:00
|
|
|
|
|
|
|
this._shellProxy.connectSignal('ExtensionStateChanged',
|
|
|
|
this._onExtensionStateChanged.bind(this));
|
|
|
|
|
2020-03-05 17:46:18 +00:00
|
|
|
this._shellProxy.connect('g-properties-changed',
|
|
|
|
this._onUserExtensionsEnabledChanged.bind(this));
|
|
|
|
this._onUserExtensionsEnabledChanged();
|
|
|
|
|
2019-11-30 01:48:18 +00:00
|
|
|
this._scanExtensions();
|
2018-11-01 12:55:17 +00:00
|
|
|
}
|
|
|
|
|
2019-11-30 01:48:18 +00:00
|
|
|
get _shellProxy() {
|
|
|
|
return this.application.shellProxy;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:06:08 +00:00
|
|
|
uninstall(uuid) {
|
|
|
|
let row = this._findExtensionRow(uuid);
|
|
|
|
|
|
|
|
let dialog = new Gtk.MessageDialog({
|
|
|
|
transient_for: this,
|
|
|
|
modal: true,
|
|
|
|
text: _('Remove “%s”?').format(row.name),
|
|
|
|
secondary_text: _('If you remove the extension, you need to return to download it if you want to enable it again'),
|
|
|
|
});
|
|
|
|
|
|
|
|
dialog.add_button(_('Cancel'), Gtk.ResponseType.CANCEL);
|
|
|
|
dialog.add_button(_('Remove'), Gtk.ResponseType.ACCEPT)
|
|
|
|
.get_style_context().add_class('destructive-action');
|
|
|
|
|
|
|
|
dialog.connect('response', (dlg, response) => {
|
|
|
|
if (response === Gtk.ResponseType.ACCEPT)
|
|
|
|
this._shellProxy.UninstallExtensionRemote(uuid);
|
|
|
|
dialog.destroy();
|
|
|
|
});
|
|
|
|
dialog.present();
|
|
|
|
}
|
|
|
|
|
2019-11-30 01:48:18 +00:00
|
|
|
openPrefs(uuid) {
|
|
|
|
if (this._prefsDialog)
|
2020-03-05 18:44:28 +00:00
|
|
|
return;
|
2019-11-30 01:48:18 +00:00
|
|
|
|
2019-11-30 07:08:05 +00:00
|
|
|
let row = this._findExtensionRow(uuid);
|
2020-03-06 00:03:45 +00:00
|
|
|
this._prefsDialog = new ExtensionPrefsDialog(row);
|
2020-03-05 18:44:28 +00:00
|
|
|
this._prefsDialog.set({ transient_for: this, modal: true });
|
2014-05-26 23:36:41 +00:00
|
|
|
|
2020-03-05 18:44:28 +00:00
|
|
|
this._prefsDialog.connect('destroy', () => (this._prefsDialog = null));
|
2014-05-26 23:36:41 +00:00
|
|
|
|
2019-11-30 01:48:18 +00:00
|
|
|
this._prefsDialog.show();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-19 02:21:56 +00:00
|
|
|
|
2019-11-30 05:51:35 +00:00
|
|
|
_showAbout() {
|
|
|
|
let aboutDialog = new Gtk.AboutDialog({
|
|
|
|
authors: [
|
|
|
|
'Florian Müllner <fmuellner@gnome.org>',
|
|
|
|
'Jasper St. Pierre <jstpierre@mecheye.net>',
|
|
|
|
'Didier Roche <didrocks@ubuntu.com>',
|
|
|
|
],
|
|
|
|
translator_credits: _('translator-credits'),
|
2020-01-24 16:00:24 +00:00
|
|
|
program_name: _('Extensions'),
|
2019-11-30 05:51:35 +00:00
|
|
|
comments: _('Manage your GNOME Extensions'),
|
|
|
|
license_type: Gtk.License.GPL_2_0,
|
|
|
|
logo_icon_name: 'org.gnome.Extensions',
|
2020-03-05 16:44:27 +00:00
|
|
|
version: imports.package.version,
|
2019-11-30 05:51:35 +00:00
|
|
|
|
|
|
|
transient_for: this,
|
|
|
|
modal: true,
|
|
|
|
});
|
|
|
|
aboutDialog.present();
|
|
|
|
}
|
|
|
|
|
2019-11-30 14:20:04 +00:00
|
|
|
_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,
|
|
|
|
(o, res) => {
|
|
|
|
o.call_finish(res);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_sortList(row1, row2) {
|
2018-11-01 12:50:30 +00:00
|
|
|
return row1.name.localeCompare(row2.name);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-05-23 02:49:37 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_updateHeader(row, before) {
|
2014-05-23 02:49:37 +00:00
|
|
|
if (!before || row.get_header())
|
|
|
|
return;
|
|
|
|
|
|
|
|
let sep = new Gtk.Separator({ orientation: Gtk.Orientation.HORIZONTAL });
|
|
|
|
row.set_header(sep);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-05-23 02:49:37 +00:00
|
|
|
|
2018-11-01 12:55:17 +00:00
|
|
|
_findExtensionRow(uuid) {
|
2019-11-30 07:08:05 +00:00
|
|
|
return [
|
|
|
|
...this._userList.get_children(),
|
|
|
|
...this._systemList.get_children(),
|
|
|
|
].find(c => c.uuid === uuid);
|
2018-11-01 12:55:17 +00:00
|
|
|
}
|
|
|
|
|
2020-03-05 17:46:18 +00:00
|
|
|
_onUserExtensionsEnabledChanged() {
|
|
|
|
let action = this.lookup_action('user-extensions-enabled');
|
|
|
|
action.set_state(
|
|
|
|
new GLib.Variant('b', this._shellProxy.UserExtensionsEnabled));
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:55:17 +00:00
|
|
|
_onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
|
2019-11-30 05:01:44 +00:00
|
|
|
let extension = ExtensionUtils.deserializeExtension(newState);
|
2018-11-01 12:55:17 +00:00
|
|
|
let row = this._findExtensionRow(uuid);
|
2019-11-30 05:01:44 +00:00
|
|
|
|
2019-11-30 14:20:04 +00:00
|
|
|
this._queueUpdatesCheck();
|
|
|
|
|
2019-11-30 07:08:05 +00:00
|
|
|
// the extension's type changed; remove the corresponding row
|
|
|
|
// and reset the variable to null so that we create a new row
|
|
|
|
// below and add it to the appropriate list
|
|
|
|
if (row && row.type !== extension.type) {
|
|
|
|
row.destroy();
|
|
|
|
row = null;
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:55:17 +00:00
|
|
|
if (row) {
|
2019-11-30 05:01:44 +00:00
|
|
|
if (extension.state === ExtensionState.UNINSTALLED)
|
2018-11-01 12:55:17 +00:00
|
|
|
row.destroy();
|
2020-03-12 21:55:43 +00:00
|
|
|
} else {
|
|
|
|
this._addExtensionRow(extension);
|
2018-11-01 12:55:17 +00:00
|
|
|
}
|
2020-03-12 21:55:43 +00:00
|
|
|
|
|
|
|
this._syncListVisibility();
|
2018-11-01 12:55:17 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_scanExtensions() {
|
2018-11-01 12:55:17 +00:00
|
|
|
this._shellProxy.ListExtensionsRemote(([extensionsMap], e) => {
|
|
|
|
if (e) {
|
|
|
|
if (e instanceof Gio.DBusError) {
|
2020-02-14 15:10:34 +00:00
|
|
|
log('Failed to connect to shell proxy: %s'.format(e.toString()));
|
2018-11-01 12:55:17 +00:00
|
|
|
this._mainStack.visible_child_name = 'noshell';
|
2019-08-20 00:51:42 +00:00
|
|
|
} else {
|
2018-11-01 12:55:17 +00:00
|
|
|
throw e;
|
2019-08-20 00:51:42 +00:00
|
|
|
}
|
2018-11-01 12:55:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let uuid in extensionsMap) {
|
|
|
|
let extension = ExtensionUtils.deserializeExtension(extensionsMap[uuid]);
|
|
|
|
this._addExtensionRow(extension);
|
|
|
|
}
|
|
|
|
this._extensionsLoaded();
|
|
|
|
});
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-01-19 02:21:56 +00:00
|
|
|
|
2018-11-01 12:55:17 +00:00
|
|
|
_addExtensionRow(extension) {
|
2018-11-01 12:50:30 +00:00
|
|
|
let row = new ExtensionRow(extension);
|
2014-05-23 02:49:37 +00:00
|
|
|
row.show_all();
|
2019-11-30 07:08:05 +00:00
|
|
|
|
|
|
|
if (row.type === ExtensionType.PER_USER)
|
|
|
|
this._userList.add(row);
|
|
|
|
else
|
|
|
|
this._systemList.add(row);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-06-04 21:14:18 +00:00
|
|
|
|
2019-11-30 14:20:04 +00:00
|
|
|
_queueUpdatesCheck() {
|
|
|
|
if (this._updatesCheckId)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._updatesCheckId = GLib.timeout_add_seconds(
|
|
|
|
GLib.PRIORITY_DEFAULT, 1, () => {
|
|
|
|
this._checkUpdates();
|
|
|
|
|
|
|
|
this._updatesCheckId = 0;
|
|
|
|
return GLib.SOURCE_REMOVE;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-03-12 21:55:43 +00:00
|
|
|
_syncListVisibility() {
|
|
|
|
this._userList.visible = this._userList.get_children().length > 0;
|
|
|
|
this._systemList.visible = this._systemList.get_children().length > 0;
|
|
|
|
|
|
|
|
if (this._userList.visible || this._systemList.visible)
|
|
|
|
this._mainStack.visible_child_name = 'main';
|
|
|
|
else
|
|
|
|
this._mainStack.visible_child_name = 'placeholder';
|
|
|
|
}
|
|
|
|
|
2019-11-30 14:20:04 +00:00
|
|
|
_checkUpdates() {
|
|
|
|
let nUpdates = this._userList.get_children().filter(c => c.hasUpdate).length;
|
|
|
|
|
|
|
|
this._updatesLabel.label = Gettext.ngettext(
|
|
|
|
'%d extension will be updated on next login.',
|
2020-02-04 17:51:57 +00:00
|
|
|
'%d extensions will be updated on next login.',
|
2019-11-30 14:20:04 +00:00
|
|
|
nUpdates).format(nUpdates);
|
|
|
|
this._updatesBar.visible = nUpdates > 0;
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_extensionsLoaded() {
|
2020-03-12 21:55:43 +00:00
|
|
|
this._syncListVisibility();
|
2019-11-30 14:20:04 +00:00
|
|
|
this._checkUpdates();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2019-05-28 21:22:37 +00:00
|
|
|
});
|
2012-01-19 02:21:56 +00:00
|
|
|
|
2019-11-30 03:12:54 +00:00
|
|
|
var ExtensionRow = GObject.registerClass({
|
|
|
|
GTypeName: 'ExtensionRow',
|
2020-03-05 16:44:27 +00:00
|
|
|
Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
|
2019-11-30 03:12:54 +00:00
|
|
|
InternalChildren: [
|
|
|
|
'nameLabel',
|
|
|
|
'descriptionLabel',
|
2019-11-30 17:11:03 +00:00
|
|
|
'versionLabel',
|
|
|
|
'authorLabel',
|
2019-11-30 14:20:04 +00:00
|
|
|
'updatesIcon',
|
2020-01-24 01:02:10 +00:00
|
|
|
'revealButton',
|
|
|
|
'revealer',
|
2019-11-30 03:12:54 +00:00
|
|
|
],
|
|
|
|
}, class ExtensionRow extends Gtk.ListBoxRow {
|
2018-11-01 12:50:30 +00:00
|
|
|
_init(extension) {
|
2017-10-31 01:23:39 +00:00
|
|
|
super._init();
|
2014-05-23 02:49:37 +00:00
|
|
|
|
2018-11-01 12:55:17 +00:00
|
|
|
this._app = Gio.Application.get_default();
|
2018-11-01 12:50:30 +00:00
|
|
|
this._extension = extension;
|
|
|
|
this._prefsModule = null;
|
2014-05-23 02:49:37 +00:00
|
|
|
|
2019-11-30 03:24:39 +00:00
|
|
|
this._actionGroup = new Gio.SimpleActionGroup();
|
|
|
|
this.insert_action_group('row', this._actionGroup);
|
2019-11-30 03:12:54 +00:00
|
|
|
|
2019-11-30 03:24:39 +00:00
|
|
|
let action;
|
|
|
|
action = new Gio.SimpleAction({
|
|
|
|
name: 'show-prefs',
|
|
|
|
enabled: this.hasPrefs,
|
|
|
|
});
|
|
|
|
action.connect('activate', () => this.get_toplevel().openPrefs(this.uuid));
|
|
|
|
this._actionGroup.add_action(action);
|
2019-11-30 03:12:54 +00:00
|
|
|
|
2019-11-30 17:11:03 +00:00
|
|
|
action = new Gio.SimpleAction({
|
|
|
|
name: 'show-url',
|
|
|
|
enabled: this.url !== '',
|
|
|
|
});
|
|
|
|
action.connect('activate', () => {
|
|
|
|
Gio.AppInfo.launch_default_for_uri(
|
|
|
|
this.url, this.get_display().get_app_launch_context());
|
|
|
|
});
|
|
|
|
this._actionGroup.add_action(action);
|
|
|
|
|
2019-11-30 05:06:08 +00:00
|
|
|
action = new Gio.SimpleAction({
|
|
|
|
name: 'uninstall',
|
|
|
|
enabled: this.type === ExtensionType.PER_USER,
|
|
|
|
});
|
|
|
|
action.connect('activate', () => this.get_toplevel().uninstall(this.uuid));
|
|
|
|
this._actionGroup.add_action(action);
|
|
|
|
|
2019-11-30 03:24:39 +00:00
|
|
|
action = new Gio.SimpleAction({
|
|
|
|
name: 'enabled',
|
|
|
|
state: new GLib.Variant('b', false),
|
|
|
|
});
|
2020-03-05 17:46:18 +00:00
|
|
|
action.connect('activate', toggleState);
|
2019-11-30 03:24:39 +00:00
|
|
|
action.connect('change-state', (a, state) => {
|
|
|
|
if (state.get_boolean())
|
2019-11-30 03:12:54 +00:00
|
|
|
this._app.shellProxy.EnableExtensionRemote(this.uuid);
|
|
|
|
else
|
|
|
|
this._app.shellProxy.DisableExtensionRemote(this.uuid);
|
|
|
|
});
|
2019-11-30 03:24:39 +00:00
|
|
|
this._actionGroup.add_action(action);
|
|
|
|
|
2020-03-03 23:26:04 +00:00
|
|
|
this._nameLabel.label = this.name;
|
2019-11-30 03:24:39 +00:00
|
|
|
|
|
|
|
let desc = this._extension.metadata.description.split('\n')[0];
|
|
|
|
this._descriptionLabel.label = desc;
|
2019-09-09 15:06:55 +00:00
|
|
|
|
2020-01-24 01:02:10 +00:00
|
|
|
this._revealButton.connect('clicked', () => {
|
|
|
|
this._revealer.reveal_child = !this._revealer.reveal_child;
|
|
|
|
});
|
|
|
|
this._revealer.connect('notify::reveal-child', () => {
|
|
|
|
if (this._revealer.reveal_child)
|
|
|
|
this._revealButton.get_style_context().add_class('expanded');
|
|
|
|
else
|
|
|
|
this._revealButton.get_style_context().remove_class('expanded');
|
|
|
|
});
|
|
|
|
|
2019-11-30 03:12:54 +00:00
|
|
|
this.connect('destroy', this._onDestroy.bind(this));
|
2019-09-09 15:06:55 +00:00
|
|
|
|
2018-11-01 12:55:17 +00:00
|
|
|
this._extensionStateChangedId = this._app.shellProxy.connectSignal(
|
|
|
|
'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
|
|
|
|
if (this.uuid !== uuid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._extension = ExtensionUtils.deserializeExtension(newState);
|
2019-11-30 03:12:54 +00:00
|
|
|
this._updateState();
|
2017-10-31 00:38:18 +00:00
|
|
|
});
|
2019-11-30 03:12:54 +00:00
|
|
|
this._updateState();
|
2017-10-31 01:23:39 +00:00
|
|
|
}
|
2014-05-23 02:49:37 +00:00
|
|
|
|
2018-11-01 12:50:30 +00:00
|
|
|
get uuid() {
|
|
|
|
return this._extension.uuid;
|
|
|
|
}
|
|
|
|
|
|
|
|
get name() {
|
|
|
|
return this._extension.metadata.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
get hasPrefs() {
|
|
|
|
return this._extension.hasPrefs;
|
|
|
|
}
|
2014-05-23 02:49:37 +00:00
|
|
|
|
2019-11-30 14:20:04 +00:00
|
|
|
get hasUpdate() {
|
|
|
|
return this._extension.hasUpdate || false;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:06:08 +00:00
|
|
|
get type() {
|
|
|
|
return this._extension.type;
|
|
|
|
}
|
|
|
|
|
2019-11-30 17:11:03 +00:00
|
|
|
get creator() {
|
|
|
|
return this._extension.metadata.creator || '';
|
|
|
|
}
|
|
|
|
|
2018-11-01 12:50:30 +00:00
|
|
|
get url() {
|
2019-11-30 17:11:03 +00:00
|
|
|
return this._extension.metadata.url || '';
|
|
|
|
}
|
|
|
|
|
|
|
|
get version() {
|
|
|
|
return this._extension.metadata.version || '';
|
2018-11-01 12:50:30 +00:00
|
|
|
}
|
|
|
|
|
2019-11-30 03:12:54 +00:00
|
|
|
_updateState() {
|
|
|
|
let state = this._extension.state === ExtensionState.ENABLED;
|
|
|
|
|
2019-11-30 03:24:39 +00:00
|
|
|
let action = this._actionGroup.lookup('enabled');
|
|
|
|
action.set_state(new GLib.Variant('b', state));
|
|
|
|
action.enabled = this._canToggle();
|
2019-11-30 17:11:03 +00:00
|
|
|
|
2019-11-30 14:20:04 +00:00
|
|
|
this._updatesIcon.visible = this.hasUpdate;
|
|
|
|
|
2020-02-19 18:25:35 +00:00
|
|
|
this._versionLabel.label = this.version.toString();
|
2019-11-30 17:11:03 +00:00
|
|
|
this._versionLabel.visible = this.version !== '';
|
|
|
|
|
2020-02-19 18:25:35 +00:00
|
|
|
this._authorLabel.label = this.creator.toString();
|
2019-11-30 17:11:03 +00:00
|
|
|
this._authorLabel.visible = this.creator !== '';
|
2019-11-30 03:12:54 +00:00
|
|
|
}
|
|
|
|
|
2018-11-01 12:55:17 +00:00
|
|
|
_onDestroy() {
|
|
|
|
if (!this._app.shellProxy)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (this._extensionStateChangedId)
|
|
|
|
this._app.shellProxy.disconnectSignal(this._extensionStateChangedId);
|
|
|
|
this._extensionStateChangedId = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_canToggle() {
|
|
|
|
return this._extension.canChange;
|
2014-05-23 02:49:37 +00:00
|
|
|
}
|
2018-11-01 12:50:30 +00:00
|
|
|
|
|
|
|
get prefsModule() {
|
2019-11-30 18:15:14 +00:00
|
|
|
// give extension prefs access to their own extension object
|
|
|
|
ExtensionUtils.getCurrentExtension = () => this._extension;
|
|
|
|
|
2018-11-01 12:50:30 +00:00
|
|
|
if (!this._prefsModule) {
|
|
|
|
ExtensionUtils.installImporter(this._extension);
|
|
|
|
|
|
|
|
this._prefsModule = this._extension.imports.prefs;
|
|
|
|
this._prefsModule.init(this._extension.metadata);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this._prefsModule;
|
|
|
|
}
|
2014-05-23 02:49:37 +00:00
|
|
|
});
|
|
|
|
|
2020-03-06 00:03:45 +00:00
|
|
|
var ExtensionPrefsDialog = GObject.registerClass({
|
|
|
|
GTypeName: 'ExtensionPrefsDialog',
|
|
|
|
Template: 'resource:///org/gnome/Extensions/ui/extension-prefs-dialog.ui',
|
|
|
|
InternalChildren: [
|
|
|
|
'headerBar',
|
|
|
|
'stack',
|
|
|
|
'expander',
|
|
|
|
'expanderArrow',
|
|
|
|
'revealer',
|
|
|
|
'errorView',
|
|
|
|
],
|
|
|
|
}, class ExtensionPrefsDialog extends Gtk.Window {
|
|
|
|
_init(extension) {
|
|
|
|
super._init();
|
|
|
|
|
|
|
|
this._uuid = extension.uuid;
|
|
|
|
this._url = extension.url;
|
|
|
|
|
|
|
|
this._headerBar.title = extension.name;
|
|
|
|
|
|
|
|
this._actionGroup = new Gio.SimpleActionGroup();
|
|
|
|
this.insert_action_group('win', this._actionGroup);
|
|
|
|
|
|
|
|
this._initActions();
|
|
|
|
|
|
|
|
this._gesture = new Gtk.GestureMultiPress({
|
|
|
|
widget: this._expander,
|
|
|
|
button: 0,
|
|
|
|
exclusive: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
this._gesture.connect('released', (gesture, nPress) => {
|
|
|
|
if (nPress === 1)
|
|
|
|
this._revealer.reveal_child = !this._revealer.reveal_child;
|
|
|
|
});
|
|
|
|
|
|
|
|
this._revealer.connect('notify::reveal-child', () => {
|
|
|
|
this._expanderArrow.icon_name = this._revealer.reveal_child
|
|
|
|
? 'pan-down-symbolic'
|
|
|
|
: 'pan-end-symbolic';
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
const widget = extension.prefsModule.buildPrefsWidget();
|
|
|
|
this._stack.add(widget);
|
|
|
|
this._stack.visible_child = widget;
|
|
|
|
} catch (e) {
|
|
|
|
this._setError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_setError(exc) {
|
|
|
|
this._errorView.buffer.text = '%s\n\nStack trace:\n'.format(exc);
|
|
|
|
// Indent stack trace.
|
|
|
|
this._errorView.buffer.text +=
|
|
|
|
exc.stack.split('\n').map(line => ' %s'.format(line)).join('\n');
|
|
|
|
|
|
|
|
// markdown for pasting in gitlab issues
|
|
|
|
let lines = [
|
|
|
|
'The settings of extension %s had an error:'.format(this._uuid),
|
|
|
|
'```', // '`' (xgettext throws up on odd number of backticks)
|
|
|
|
exc.toString(),
|
|
|
|
'```', // '`'
|
|
|
|
'',
|
|
|
|
'Stack trace:',
|
|
|
|
'```', // '`'
|
|
|
|
exc.stack.replace(/\n$/, ''), // stack without trailing newline
|
|
|
|
'```', // '`'
|
|
|
|
'',
|
|
|
|
];
|
|
|
|
this._errorMarkdown = lines.join('\n');
|
|
|
|
this._actionGroup.lookup('copy-error').enabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
_initActions() {
|
|
|
|
let action;
|
|
|
|
|
|
|
|
action = new Gio.SimpleAction({
|
|
|
|
name: 'copy-error',
|
|
|
|
enabled: false,
|
|
|
|
});
|
|
|
|
action.connect('activate', () => {
|
|
|
|
const clipboard = Gtk.Clipboard.get_default(this.get_display());
|
|
|
|
clipboard.set_text(this._errorMarkdown, -1);
|
|
|
|
});
|
|
|
|
this._actionGroup.add_action(action);
|
|
|
|
|
|
|
|
action = new Gio.SimpleAction({
|
|
|
|
name: 'show-url',
|
|
|
|
enabled: this._url !== '',
|
|
|
|
});
|
|
|
|
action.connect('activate', () => {
|
|
|
|
Gio.AppInfo.launch_default_for_uri(this._url,
|
|
|
|
this.get_display().get_app_launch_context());
|
|
|
|
});
|
|
|
|
this._actionGroup.add_action(action);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2012-01-19 02:21:56 +00:00
|
|
|
function initEnvironment() {
|
|
|
|
// Monkey-patch in a "global" object that fakes some Shell utilities
|
|
|
|
// that ExtensionUtils depends on.
|
|
|
|
window.global = {
|
2019-02-12 11:24:30 +00:00
|
|
|
log(...args) {
|
|
|
|
print(args.join(', '));
|
2012-01-19 02:21:56 +00:00
|
|
|
},
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
logError(s) {
|
2020-02-14 15:10:34 +00:00
|
|
|
log('ERROR: %s'.format(s));
|
2012-01-19 02:21:56 +00:00
|
|
|
},
|
|
|
|
|
2019-08-20 21:43:54 +00:00
|
|
|
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']),
|
2012-01-19 02:21:56 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function main(argv) {
|
|
|
|
initEnvironment();
|
2020-03-19 19:38:16 +00:00
|
|
|
Package.initGettext();
|
2012-01-19 02:21:56 +00:00
|
|
|
|
2019-05-28 21:22:37 +00:00
|
|
|
new Application().run(argv);
|
2012-01-19 02:21:56 +00:00
|
|
|
}
|