extensionPrefs: Split user and system extensions

Until now, it didn't matter whether an extension was installed in the
user's home or system-wide. However with support for uninstallation,
there is now a significant different, as that action is only available
for user extensions.

Account for that by separating extensions by type, so that users don't
have to second-guess which extensions can be fully-managed and which
appear as part of the system.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1968
This commit is contained in:
Florian Müllner 2019-11-30 08:08:05 +01:00
parent db69ad876a
commit f1bd94a367
2 changed files with 70 additions and 12 deletions

View File

@ -80,7 +80,8 @@ var ExtensionsWindow = GObject.registerClass({
GTypeName: 'ExtensionsWindow', GTypeName: 'ExtensionsWindow',
Template: 'resource:///org/gnome/shell/ui/extensions-window.ui', Template: 'resource:///org/gnome/shell/ui/extensions-window.ui',
InternalChildren: [ InternalChildren: [
'extensionsList', 'userList',
'systemList',
'killSwitch', 'killSwitch',
'mainBox', 'mainBox',
'mainStack', 'mainStack',
@ -106,8 +107,11 @@ var ExtensionsWindow = GObject.registerClass({
this._killSwitch, 'active', this._killSwitch, 'active',
Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN); Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
this._extensionsList.set_sort_func(this._sortList.bind(this)); this._userList.set_sort_func(this._sortList.bind(this));
this._extensionsList.set_header_func(this._updateHeader.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));
this._shellProxy.connectSignal('ExtensionStateChanged', this._shellProxy.connectSignal('ExtensionStateChanged',
this._onExtensionStateChanged.bind(this)); this._onExtensionStateChanged.bind(this));
@ -152,11 +156,8 @@ var ExtensionsWindow = GObject.registerClass({
if (this._prefsDialog) if (this._prefsDialog)
return false; return false;
let row = this._extensionsList.get_children().find(c => { let row = this._findExtensionRow(uuid);
return c.uuid === uuid && c.hasPrefs; if (!row || !row.hasPrefs)
});
if (!row)
return false; return false;
let widget; let widget;
@ -346,13 +347,24 @@ var ExtensionsWindow = GObject.registerClass({
} }
_findExtensionRow(uuid) { _findExtensionRow(uuid) {
return this._extensionsList.get_children().find(c => c.uuid === uuid); return [
...this._userList.get_children(),
...this._systemList.get_children(),
].find(c => c.uuid === uuid);
} }
_onExtensionStateChanged(proxy, senderName, [uuid, newState]) { _onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
let extension = ExtensionUtils.deserializeExtension(newState); let extension = ExtensionUtils.deserializeExtension(newState);
let row = this._findExtensionRow(uuid); let row = this._findExtensionRow(uuid);
// 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;
}
if (row) { if (row) {
if (extension.state === ExtensionState.UNINSTALLED) if (extension.state === ExtensionState.UNINSTALLED)
row.destroy(); row.destroy();
@ -384,11 +396,18 @@ var ExtensionsWindow = GObject.registerClass({
_addExtensionRow(extension) { _addExtensionRow(extension) {
let row = new ExtensionRow(extension); let row = new ExtensionRow(extension);
row.show_all(); row.show_all();
this._extensionsList.add(row);
if (row.type === ExtensionType.PER_USER)
this._userList.add(row);
else
this._systemList.add(row);
} }
_extensionsLoaded() { _extensionsLoaded() {
if (this._extensionsList.get_children().length > 0) 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'; this._mainStack.visible_child_name = 'main';
else else
this._mainStack.visible_child_name = 'placeholder'; this._mainStack.visible_child_name = 'placeholder';

View File

@ -116,8 +116,47 @@
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="margin">36</property> <property name="margin">36</property>
<property name="spacing">12</property>
<child> <child>
<object class="GtkListBox" id="extensionsList"> <object class="GtkLabel">
<property name="visible"
bind-source="userList"
bind-property="visible"
bind-flags="sync-create"/>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Manually Installed</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkListBox" id="userList">
<property name="visible">True</property>
<property name="selection_mode">none</property>
<property name="margin_bottom">24</property>
<style>
<class name="frame"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible"
bind-source="systemList"
bind-property="visible"
bind-flags="sync-create"/>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Built-In</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkListBox" id="systemList">
<property name="visible">True</property> <property name="visible">True</property>
<property name="selection_mode">none</property> <property name="selection_mode">none</property>
<style> <style>