Skip to main content

gnome-shell-extension-development

Applies when building, reviewing or shipping a GNOME Shell extension in GJS, including GTK/libadwaita preferences, account connectors, notifications, native popup effects, stale controls, session coordination failures, package updates or installed-versus-loaded code mismatches.

Informations de source

Dépôt
dandgabr/Coacus
Dernière activité de la source
8 octobre 2026 à 23:56
Langue détectée de SKILL.md
anglais
Étoiles
9
Forks
5

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
6 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
gnome-shell-extension-development
description
Applies when building, reviewing or shipping a GNOME Shell extension in GJS, including GTK/libadwaita preferences, account connectors, notifications, native popup effects, stale controls, session coordination failures, package updates or installed-versus-loaded code mismatches.
tags
["gnome-shell","gjs","extension","notifications","testing"]
# GNOME Shell extension development Treat the desktop process as the failure boundary: verify module loading, reclaim owned resources and respect platform lock-screen and Do Not Disturb behavior. Consult [the verified notes](references/gnome-shell-50-notes.md) for version-specific API facts and re-verify native names and behavior on another Shell version. Read the branch-specific account, rendering and delivery references below when relevant. ## 1. Split by process and by layer - **A pure core** holds every rule and every sentence the user reads: no GObject import, so it runs under the plain interpreter and the unit tests cover it. - **Services** hold the I/O (timers, files, the keyring, the system bus). **The interface layer** only draws. **The preferences window is another process** (GTK and libadwaita); shell code never imports GTK, and the preferences never import the shell's toolkit. - Enforce the split with a structure test that reads the imports: the core imports nothing outside itself, the shell toolkit stays in the interface layer, the notification API stays there too, and the system bus stays in the services. - **Separate state from drawing.** A controller owns the state and the actions, and takes everything that touches the system as injected dependencies; each screen is a thin view over it. Two screens that sign in the same account then share one implementation, one sign-in at a time and one place to review, and the controller is testable with fakes: no keyring, no port, no browser. ## 2. Gates for what unit tests cannot import The interface modules need the shell, so no unit test loads them. A name declared twice, or not defined, is invisible until the extension is enabled, and then it simply fails to load. 1. Check the **syntax of every module**. 2. **Enable the extension in a throwaway headless shell** and read its state and its error: the state must be enabled and the error empty. This is the gate that catches an undefined name. 3. **Look at it**: drive the interface in a throwaway shell and capture the screen. A passing gate does not say the icon is the right size. A gate that has never failed is a hypothesis. Seed a defect (a name declared twice, a name that does not exist), watch the gate fail, then restore the file and confirm the diff is empty. Make the check script build its generated inputs first (the compiled settings schema, the translation catalogs): a test that reads a stale build fails for a setting it has never heard of. ## 3. Verify the shell API against a live shell The shell's own scripts are compiled into its binary and cannot be listed or read. An API recalled from an older version is a guess. In a throwaway shell with the evaluation channel on, enumerate the prototypes, the GObject properties and the enum values of what you are about to use, write against what you saw, and record the version and the date. Confirm at least: the constructors and properties of the notification classes, the urgency and privacy-scope values, how the session mode reports a locked screen and where the notification settings live. ## 4. Lifecycle, the lock screen and suspend - **Create after enabling, destroy when disabling**: sources, notifications, timers, signal handlers, bus subscriptions. A late event after disabling must create nothing, so the notifier keeps a destroyed flag. - **Without the `unlock-dialog` session mode the shell disables the extension while the screen is locked.** Nothing of yours can then be on a lock screen, no alert is raised while locked, and a notification that was not read is gone after unlocking. Do not add a setting for what the platform already decides: a switch for details on the lock screen did nothing and was removed. - The extension comes back on unlock, so what it needs to remember (what it already announced) lives on disk, and its memory must be longer than the longest lock: a quota that crossed its threshold during the lock is announced on the first look afterwards. - **After suspend every timer is late at once** (they use the monotonic clock) and the data looks old. Subscribe to the login manager's sleep signal, hold connection alerts for a grace window, then refresh with jitter. ## 5. Notifications - Use **a source of your own**; keep one notification per provider and kind and replace the old one rather than stacking. - Urgency is **normal or high, never critical**: only critical bypasses Do Not Disturb. With it on, the banner is held for normal and high alike and the notification waits in the list. Actions do nothing while the screen is locked. - **Text comes only from fixed, translated templates**, names from a registry and clamped numbers. Nothing a provider or a user typed reaches a notification or a tooltip: strip controls and bidirectional overrides, cap the length, turn markup off. - **Quiet by construction.** Announce a crossing once and re-arm only after the value falls by a margin or the window resets; never announce the first reading; cap the number an hour and fold the rest into one summary; one connection alert per outage. A connection alert measured in time needs a clock, because a rejected sign-in is polled no more. Announce nothing until the set of providers is known. - Offer a **test button** in the preferences that raises a counter the shell consumes. The assistant never sends a notification on its own. ## 6. Settings and the preferences window - **Classify every settings key** as restored or kept by Restore defaults, in one list, with a test that fails for an unclassified key: a new setting must be decided about when it is added. Never reset what belongs to the user's accounts. - **Reset in one batch** (delay then apply): the shell reacts to every key, and eighteen writes are eighteen rebuilds. - A combo row must **not write back a value it only read**, or following a reset gives the key a user value again and the shell reacts twice. - Read a setting once and refresh it on change, and **re-check it where it is used**: the user can edit it by hand. - Dim a control when its master switch is off instead of blocking it, so the value stays visible. Show the current value in the row, not only inside it. - A danger or terms confirmation has **one code path** used by every screen, with the safe response as the default. ## 7. Internationalization - **Follow the session language.** Never change the locale of the process: it would translate the shell itself. A language without a catalog shows the source text. - The extraction tool only sees **literal strings** inside the translation calls: a table of texts built outside them is invisible, so write the texts where they are translated. Keep the percent sign in the template (`%d%%`), because the language decides the spacing. - A plain interpreter has no `String.format`: use a small printf, so the same code runs under the tests. ## 8. Checking a change See [the verified notes](references/gnome-shell-50-notes.md) for the recipes: the evaluation scope lacks the toolkit, a fresh shell opens a welcome dialog, a virtual pointer that starts in the corner triggers the hot corner, an icon needs a size, and one preferences page can be shown alone with a small harness and an in-memory settings backend. ## 9. Accounts, visual effects and delivery Read the relevant reference before changing these boundaries: - [Accounts and API reporting](references/accounts-and-api-reporting.md): distinguish a saved connector from an authenticated account; preserve identity through deletion, delayed credential operations, session turnover and monetary reporting. - [Native preferences lifecycle](references/native-preferences-lifecycle.md): bind subscriptions to navigation lifetime and verify both stored settings and visible controls after user actions, including actual signal disconnection. - [Native layout and theme effects](references/native-layout-and-effects.md): keep decorations outside reading layout, describe theme defaults rather than supported overrides, and verify materials and numeric stability on rendered frames. - [Verification and release](references/verification-and-release.md): reject false native evaluation results, isolate tests from the desktop, audit the actual ZIP, and distinguish installed files from code already loaded in the session. These are reusable practices derived from a shipped extension, not permission to read real credentials, publish a release or restart the user's desktop.
Voir sur GitHub