dbusServices/extensions: Take over prefs dialog from app
As outlined earlier, in order to turn the Extensions app into a properly sandboxed application, we need to split out the extension prefs dialog and move it elsewhere. With "elsewhere" being the new Extensions D-Bus service, effectively turning it into a shell extensions portal. https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1106
This commit is contained in:
parent
91b7474d5a
commit
34e85342d8
2
js/dbusServices/extensions/css/application.css
Normal file
2
js/dbusServices/extensions/css/application.css
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.expander-frame > * { border-top-width: 0; }
|
||||||
|
.expander-toolbar { border: 0 solid @borders; border-top-width: 1px; }
|
@ -1,7 +1,9 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported ExtensionsService */
|
/* exported ExtensionsService */
|
||||||
|
|
||||||
const { Gio, GLib } = imports.gi;
|
const { Gdk, Gio, GLib, GObject, Gtk } = imports.gi;
|
||||||
|
|
||||||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||||
const { ServiceImplementation } = imports.dbusService;
|
const { ServiceImplementation } = imports.dbusService;
|
||||||
@ -108,10 +110,25 @@ var ExtensionsService = class extends ServiceImplementation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OpenExtensionPrefsAsync(params, invocation) {
|
OpenExtensionPrefsAsync(params, invocation) {
|
||||||
this._proxy.OpenExtensionPrefsRemote(...params, (res, error) => {
|
const [uuid, parentWindow_, options] = params;
|
||||||
|
|
||||||
|
this._proxy.GetExtensionInfoRemote(uuid, (res, error) => {
|
||||||
if (this._handleError(invocation, error))
|
if (this._handleError(invocation, error))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const [serialized] = res;
|
||||||
|
const extension = ExtensionUtils.deserializeExtension(serialized);
|
||||||
|
|
||||||
|
const window = new ExtensionPrefsDialog(extension);
|
||||||
|
|
||||||
|
if (options.modal)
|
||||||
|
window.modal = options.modal.get_boolean();
|
||||||
|
|
||||||
|
window.connect('destroy', () => this.release());
|
||||||
|
this.hold();
|
||||||
|
|
||||||
|
window.show();
|
||||||
|
|
||||||
invocation.return_value(null);
|
invocation.return_value(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -125,3 +142,124 @@ var ExtensionsService = class extends ServiceImplementation {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var ExtensionPrefsDialog = GObject.registerClass({
|
||||||
|
GTypeName: 'ExtensionPrefsDialog',
|
||||||
|
Template: 'resource:///org/gnome/Shell/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.metadata.url || '';
|
||||||
|
|
||||||
|
this._headerBar.title = extension.metadata.name;
|
||||||
|
|
||||||
|
this._actionGroup = new Gio.SimpleActionGroup();
|
||||||
|
this.insert_action_group('win', this._actionGroup);
|
||||||
|
|
||||||
|
this._initActions();
|
||||||
|
this._addCustomStylesheet();
|
||||||
|
|
||||||
|
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 {
|
||||||
|
ExtensionUtils.installImporter(extension);
|
||||||
|
|
||||||
|
// give extension prefs access to their own extension object
|
||||||
|
ExtensionUtils.getCurrentExtension = () => extension;
|
||||||
|
|
||||||
|
const prefsModule = extension.imports.prefs;
|
||||||
|
prefsModule.init(extension.metadata);
|
||||||
|
|
||||||
|
const widget = prefsModule.buildPrefsWidget();
|
||||||
|
this._stack.add(widget);
|
||||||
|
this._stack.visible_child = widget;
|
||||||
|
} catch (e) {
|
||||||
|
this._setError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setError(exc) {
|
||||||
|
this._errorView.buffer.text = `${exc}\n\nStack trace:\n`;
|
||||||
|
// Indent stack trace.
|
||||||
|
this._errorView.buffer.text +=
|
||||||
|
exc.stack.split('\n').map(line => ` ${line}`).join('\n');
|
||||||
|
|
||||||
|
// markdown for pasting in gitlab issues
|
||||||
|
let lines = [
|
||||||
|
`The settings of extension ${this._uuid} had an error:`,
|
||||||
|
'```',
|
||||||
|
`${exc}`,
|
||||||
|
'```',
|
||||||
|
'',
|
||||||
|
'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);
|
||||||
|
}
|
||||||
|
|
||||||
|
_addCustomStylesheet() {
|
||||||
|
let provider = new Gtk.CssProvider();
|
||||||
|
let uri = 'resource:///org/gnome/Shell/Extensions/css/application.css';
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
/* exported main */
|
/* exported main */
|
||||||
|
|
||||||
|
imports.gi.versions.Gdk = '3.0';
|
||||||
|
imports.gi.versions.Gtk = '3.0';
|
||||||
|
|
||||||
|
const { Gtk } = imports.gi;
|
||||||
|
const pkg = imports.package;
|
||||||
|
|
||||||
const { DBusService } = imports.dbusService;
|
const { DBusService } = imports.dbusService;
|
||||||
const { ExtensionsService } = imports.extensionsService;
|
const { ExtensionsService } = imports.extensionsService;
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
|
Gtk.init(null);
|
||||||
|
pkg.initFormat();
|
||||||
|
|
||||||
const service = new DBusService(
|
const service = new DBusService(
|
||||||
'org.gnome.Shell.Extensions',
|
'org.gnome.Shell.Extensions',
|
||||||
new ExtensionsService());
|
new ExtensionsService());
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
<file>dbusService.js</file>
|
<file>dbusService.js</file>
|
||||||
|
|
||||||
<file>misc/config.js</file>
|
<file>misc/config.js</file>
|
||||||
|
<file>misc/extensionUtils.js</file>
|
||||||
<file>misc/fileUtils.js</file>
|
<file>misc/fileUtils.js</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
|
||||||
|
<gresource prefix="/org/gnome/Shell/Extensions">
|
||||||
|
<file>css/application.css</file>
|
||||||
|
<file>ui/extension-prefs-dialog.ui</file>
|
||||||
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
|
@ -9,6 +9,3 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
image.warning { color: @warning_color; }
|
image.warning { color: @warning_color; }
|
||||||
|
|
||||||
.expander-frame > * { border-top-width: 0; }
|
|
||||||
.expander-toolbar { border: 0 solid @borders; border-top-width: 1px; }
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
<file>dbus-interfaces/org.gnome.Shell.Extensions.xml</file>
|
<file>dbus-interfaces/org.gnome.Shell.Extensions.xml</file>
|
||||||
|
|
||||||
<file>ui/extension-prefs-dialog.ui</file>
|
|
||||||
<file>ui/extension-row.ui</file>
|
<file>ui/extension-row.ui</file>
|
||||||
<file>ui/extensions-window.ui</file>
|
<file>ui/extensions-window.ui</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
@ -85,7 +85,6 @@ var ExtensionsWindow = GObject.registerClass({
|
|||||||
_init(params) {
|
_init(params) {
|
||||||
super._init(params);
|
super._init(params);
|
||||||
|
|
||||||
this._prefsDialog = null;
|
|
||||||
this._updatesCheckId = 0;
|
this._updatesCheckId = 0;
|
||||||
|
|
||||||
this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
|
this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
|
||||||
@ -152,16 +151,9 @@ var ExtensionsWindow = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
openPrefs(uuid) {
|
openPrefs(uuid) {
|
||||||
if (this._prefsDialog)
|
this._shellProxy.OpenExtensionPrefsRemote(uuid,
|
||||||
return;
|
'',
|
||||||
|
{ modal: new GLib.Variant('b', true) });
|
||||||
let row = this._findExtensionRow(uuid);
|
|
||||||
this._prefsDialog = new ExtensionPrefsDialog(row);
|
|
||||||
this._prefsDialog.set({ transient_for: this, modal: true });
|
|
||||||
|
|
||||||
this._prefsDialog.connect('destroy', () => (this._prefsDialog = null));
|
|
||||||
|
|
||||||
this._prefsDialog.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_showAbout() {
|
_showAbout() {
|
||||||
@ -467,119 +459,6 @@ var ExtensionRow = GObject.registerClass({
|
|||||||
_canToggle() {
|
_canToggle() {
|
||||||
return this._extension.canChange;
|
return this._extension.canChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
get prefsModule() {
|
|
||||||
// give extension prefs access to their own extension object
|
|
||||||
ExtensionUtils.getCurrentExtension = () => this._extension;
|
|
||||||
|
|
||||||
if (!this._prefsModule) {
|
|
||||||
ExtensionUtils.installImporter(this._extension);
|
|
||||||
|
|
||||||
this._prefsModule = this._extension.imports.prefs;
|
|
||||||
this._prefsModule.init(this._extension.metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._prefsModule;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function initEnvironment() {
|
function initEnvironment() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported GnomeShell, ScreenSaverDBus */
|
/* exported GnomeShell, ScreenSaverDBus */
|
||||||
|
|
||||||
const { Gio, GLib, Meta, Shell } = imports.gi;
|
const { Gio, GLib, Meta } = imports.gi;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||||
@ -315,13 +315,18 @@ var GnomeShellExtensions = class {
|
|||||||
this.OpenExtensionPrefs(uuid, '', {});
|
this.OpenExtensionPrefs(uuid, '', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenExtensionPrefs(uuid, _parentWindow, _options) {
|
OpenExtensionPrefs(uuid, parentWindow, options) {
|
||||||
let appSys = Shell.AppSystem.get_default();
|
Gio.DBus.session.call(
|
||||||
let app = appSys.lookup_app('org.gnome.Extensions.desktop');
|
'org.gnome.Shell.Extensions',
|
||||||
let info = app.get_app_info();
|
'/org/gnome/Shell/Extensions',
|
||||||
let timestamp = global.display.get_current_time_roundtrip();
|
'org.gnome.Shell.Extensions',
|
||||||
info.launch_uris([`extension:///${uuid}`],
|
'OpenExtensionPrefs',
|
||||||
global.create_app_launch_context(timestamp, -1));
|
new GLib.Variant('(ssa{sv})', [uuid, parentWindow, options]),
|
||||||
|
null,
|
||||||
|
Gio.DBusCallFlags.NONE,
|
||||||
|
-1,
|
||||||
|
null,
|
||||||
|
(conn, res) => conn.call_finish(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReloadExtension(uuid) {
|
ReloadExtension(uuid) {
|
||||||
|
@ -4,10 +4,10 @@ data/50-gnome-shell-system.xml
|
|||||||
data/org.gnome.Shell.desktop.in.in
|
data/org.gnome.Shell.desktop.in.in
|
||||||
data/org.gnome.shell.gschema.xml.in
|
data/org.gnome.shell.gschema.xml.in
|
||||||
data/org.gnome.Shell.PortalHelper.desktop.in.in
|
data/org.gnome.Shell.PortalHelper.desktop.in.in
|
||||||
|
js/dbusServices/extensions/ui/extension-prefs-dialog.ui
|
||||||
js/extensionPrefs/data/metainfo/org.gnome.Extensions.metainfo.xml.in
|
js/extensionPrefs/data/metainfo/org.gnome.Extensions.metainfo.xml.in
|
||||||
js/extensionPrefs/data/org.gnome.Extensions.desktop.in.in
|
js/extensionPrefs/data/org.gnome.Extensions.desktop.in.in
|
||||||
js/extensionPrefs/js/main.js
|
js/extensionPrefs/js/main.js
|
||||||
js/extensionPrefs/data/ui/extension-prefs-dialog.ui
|
|
||||||
js/extensionPrefs/data/ui/extension-row.ui
|
js/extensionPrefs/data/ui/extension-row.ui
|
||||||
js/extensionPrefs/data/ui/extensions-window.ui
|
js/extensionPrefs/data/ui/extensions-window.ui
|
||||||
js/gdm/authPrompt.js
|
js/gdm/authPrompt.js
|
||||||
|
Loading…
x
Reference in New Issue
Block a user