Preferences
Our preferences dialog will be written in Gtkopen in new window, which gives us a lot of options for how we present settings to the user. You may consider looking through the GNOME Human Interface Guidelines for ideas or guidance.
GSettings
GSettingsopen in new window provides a simple, extremely fast API for storing application settings, that can also be used by GNOME Shell extensions.
Creating the schema
Schema files describe the types and default values of a particular group of settings, using the same type format as GVariantopen in new window. The first thing to do is create a subdirectory for your settings schema and open the schema file in your editor:
$ mkdir schemas/
$ gedit schemas/org.gnome.shell.extensions.example.gschema.xml
2
Then using your edit, create a schema describing the settings for your extension:
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema id="org.gnome.shell.extensions.example" path="/org/gnome/shell/extensions/example/">
<!-- See also: https://docs.gtk.org/glib/gvariant-format-strings.html -->
<key name="show-indicator" type="b">
<default>true</default>
</key>
</schema>
</schemalist>
2
3
4
5
6
7
8
9
In the case of GSchema IDs, it is convention to use the above id
and path
form so that all GSettings for extensions can be found in a common place.
Compiling the schema
Once you are done defining you schema, you must compile it before it can be used.
If you use gnome-extension pack
to package your extension, the schemas in the schemas
directory will automatically be compiled.
To manually compile your schema:
$ glib-compile-schemas schemas/
$ ls schemas
example.gschema.xml gschemas.compiled
2
3
Integrating GSettings
Now that our GSettings schema is compiled and ready to be used, we'll integrate it into our extension:
const Gio = imports.gi.Gio;
const St = imports.gi.St;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
class Extension {
constructor() {
this._indicator = null;
}
enable() {
log(`enabling ${Me.metadata.name}`);
this.settings = ExtensionUtils.getSettings(
'org.gnome.shell.extensions.example');
let indicatorName = `${Me.metadata.name} Indicator`;
// Create a panel button
this._indicator = new PanelMenu.Button(0.0, indicatorName, false);
// Add an icon
let icon = new St.Icon({
gicon: new Gio.ThemedIcon({name: 'face-laugh-symbolic'}),
style_class: 'system-status-icon'
});
this._indicator.add_child(icon);
// Bind our indicator visibility to the GSettings value
//
// NOTE: Binding properties only works with GProperties (properties
// registered on a GObject class), not native JavaScript properties
this.settings.bind(
'show-indicator',
this._indicator,
'visible',
Gio.SettingsBindFlags.DEFAULT
);
Main.panel.addToStatusArea(indicatorName, this._indicator);
}
disable() {
log(`disabling ${Me.metadata.name}`);
this._indicator.destroy();
this._indicator = null;
}
}
function init() {
log(`initializing ${Me.metadata.name}`);
return new Extension();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Now save extension.js
and restart GNOME Shell to load the changes to your extension.
Preferences Window
Now that we have GSettings for our extension, we will give the use some control by creating a simple preference dialog. Start by creating the prefs.js
file and opening it in your text editor:
$ gedit prefs.js
Then we'll create a simple preferences row with a switch to control our settings:
'use strict';
const { Adw, Gio, Gtk } = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
function init() {
}
function fillPreferencesWindow(window) {
// Use the same GSettings schema as in `extension.js`
const settings = ExtensionUtils.getSettings(
'org.gnome.shell.extensions.example');
// Create a preferences page and group
const page = new Adw.PreferencesPage();
const group = new Adw.PreferencesGroup();
page.add(group);
// Create a new preferences row
const row = new Adw.ActionRow({ title: 'Show Extension Indicator' });
group.add(row);
// Create the switch and bind its value to the `show-indicator` key
const toggle = new Gtk.Switch({
active: settings.get_boolean ('show-indicator'),
valign: Gtk.Align.CENTER,
});
settings.bind(
'show-indicator',
toggle,
'active',
Gio.SettingsBindFlags.DEFAULT
);
// Add the switch to the row
row.add_suffix(toggle);
row.activatable_widget = toggle;
// Add our page to the window
window.add(page);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
To test the new preferences dialog, you can launch it directly from the command line:
$ gnome-extensions prefs example@shell.gnome.org

The extension should be kept up to date with any changes that happen, because of the binding in extension.js
watching for changes.
Debugging
Because preferences are not run within gnome-shell
but in a separate process, the logs will appear in the gjs
process:
journalctl -f -o cat /usr/bin/gjs