GNOME Shell extension (Vitals@CoreCoding.com) that polls hardware sensors asynchronously and shows them in the top bar. Runtime is GJS ES modules (Shell 45–50). Official getting-started and practices: Creating an extension, Anatomy, Imports, Debugging, Best practices.
The install directory must match metadata.json uuid. User install: ~/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/.
Required: metadata.json, extension.js. This repo also uses prefs.js, stylesheet.css, schemas/, locale/, helpers, and icons.
Required metadata: uuid, name, description, shell-version, url. This project also sets settings-schema, gettext-domain, version, and donations. Do not invent a version bump for EGO; that site owns submission versioning.
extension.jsdefault-exports a subclass ofExtensionwithenable()/disable().prefs.jsdefault-exports a subclass ofExtensionPreferences.- Platform libs:
import St from 'gi://St'(prefs: pin GTK 4, e.g.gi://Gtk?version=4.0). - Shell modules:
resource:///org/gnome/shell/...in the shell process; prefs useresource:///org/gnome/Shell/Extensions/js/.... - Local files: relative paths (
./sensors.js). Noimports./this.imports.
Shared helpers must not import St/Clutter and Gtk/Adw/Gdk. Shell and prefs are different processes.
Constructor runs once on load. Do not create GObjects, connect signals, add timeouts, or change the Shell there.
enable(): build UI, connect, add sources,Main.panel.addToStatusArea(...).disable(): undo everything fromenable(). Destroy widgets, disconnect, remove sources even if they would later returnSOURCE_REMOVE, then null references. Screen lock also callsdisable(). This is the usual EGO rejection reason.
Keep enable() / disable() next to each other and small. Timeout create/remove stay adjacent; do not wrap destroy() / GLib.Source.remove() in try/catch.
| File | Process | Toolkit |
|---|---|---|
extension.js and shell modules |
gnome-shell |
Clutter / St |
prefs.js |
separate GTK app | GTK 4 / Adwaita |
A crash in the shell process can take down the desktop. Prefer async I/O (this project’s design). Do not block the main loop.
stylesheet.css applies only to Shell UI, not prefs.
Settings: schema id lives in metadata; entry points use this.getSettings() with no argument.
GJS caches loaded modules. Code changes require a new gnome-shell process, not just disable/enable.
- Wayland:
dbus-run-session gnome-shell --devkit --wayland(GNOME 49+; needsmutter-devkit). GNOME 48 and earlier:--nested --wayland. Thengnome-extensions enable Vitals@CoreCoding.cominside that session. - X11: Alt+F2 →
restart, then enable. Wayland sessions cannot restart in-place; log out. - Logs:
journalctl -f -o cat /usr/bin/gnome-shell. Useconsole.debug/warn/error; keep volume low (journal is system-wide).SHELL_DEBUG=backtrace-warningsadds JS stacks. Looking Glass: Alt+F2 →lg.
Local clone: compile schemas after schema edits (glib-compile-schemas --strict schemas/). See README for develop-branch install.
- Do not poll or format on the main thread; keep
Gio.File.load_contents_async/ subprocess patterns. - Gettext:
_()from the Extension/prefs import, domainvitals. - GObject subclasses:
GObject.registerClass+ uniqueGTypeName. - Icons:
St.Icon/Gtk.Image, not emoji. - Line length: stay under ~200 characters (EGO review UI).