Add screensaver instructions

This commit is contained in:
Daniel Demus
2026-04-29 22:49:29 +02:00
parent e139f05513
commit 04cfa4c8a5
2 changed files with 123 additions and 3 deletions
+119
View File
@@ -0,0 +1,119 @@
# Copilot Instructions — blelock
## Environment
- OS: Fedora — use `dnf` to install packages, not `apt-get`.
- Node.js/npm must be installed via `dnf install nodejs npm` if not present.
GNOME Shell 49 extension that locks/unlocks the GNOME session based on the
Bluetooth RSSI of a nearby device. The extension code lives in `generated/`.
## Build, Test, and Install
All commands run from `generated/`.
```sh
cd generated/
npm install # install typescript, @girs types, vitest
make # compile TypeScript → dist/
make install # pack + gnome-extensions install --force
make test # run all vitest tests
npm run test:unit # unit tests only (pure logic, no GI)
npm run test:integration # integration tests with mocked D-Bus
npx vitest run tests/unit/thresholds.test.ts # single test file
```
After any TypeScript change, rebuild with `make` then restart the nested shell.
**Nested-shell testing (GNOME 49):**
```sh
dbus-run-session gnome-shell --devkit --wayland # start nested session
gnome-extensions enable ble-unlock@blelock.github.io
journalctl -f -o cat /usr/bin/gnome-shell # watch logs
gjs tests/gnome-shell/extension.test.js # GJS integration tests (inside nested session)
```
**GSettings schema** must be compiled before installing:
```sh
glib-compile-schemas schemas/ # run from generated/
```
## Architecture
```
generated/
├── thresholds.ts pure logic: classifySignal / shouldLock / shouldUnlock
├── bleMonitor.ts GObject that polls BlueZ RSSI via Gio.DBusProxy
├── quickSettingsMenu.ts Quick Settings toggle + device-list + threshold controls
├── extension.ts Extension enable/disable; wires monitor → indicator
├── prefs.ts GTK4/Adwaita preferences window (separate process)
└── schemas/ GSettings schema (5 keys; see below)
```
**Data flow:**
1. `BleMonitor` polls `org.bluez.Device1.RSSI` (cached D-Bus property) every N seconds.
2. Each poll feeds into `thresholds.ts` pure functions to detect state transitions.
3. On transition, `BleMonitor.onSignalBelowThreshold()` or `onSignalAboveThreshold()` is called — these are **intentionally empty** hooks wired up in `extension.ts`.
4. `BleUnlockMenuToggle` subscribes to `rssi-changed` and `devices-changed` GObject signals to keep the Quick Settings UI current.
**Two-process boundary:**
- Shell process (`extension.ts`, `bleMonitor.ts`, `quickSettingsMenu.ts`): GI libs only — Clutter, St, Meta, Gio, GLib, GObject. **No Gtk/Adw/Gdk.**
- Prefs process (`prefs.ts`): GTK4 + Adwaita + Gio/GLib only. **No Clutter/Meta/St/Shell.**
## Key Conventions
### TypeScript for GJS
- `module: "NodeNext"` in tsconfig — local imports use `.js` extension even though source is `.ts`.
- GObject subclasses use the static-block registration pattern:
```ts
class Foo extends GObject.Object {
static { GObject.registerClass({ GTypeName: 'Foo', Signals: {...} }, this); }
}
```
- `GObject.registerClass(class Foo extends Bar {...})` wrapper is used for Quick Settings UI classes.
- Fields on GObject subclasses are declared with initial values (`private _x: T | null = null`), not `declare`.
### Extension lifecycle rules
- **Nothing** is created in `constructor()` — only in `enable()`.
- `disable()` must stop all GLib timers, disconnect all signals, null all references, and destroy all widgets.
- This extension uses `"session-modes": ["user", "unlock-dialog"]` — `disable()` is **not** called on screen lock. The JSDoc on `disable()` explains this.
### GSettings schema
Schema ID: `org.gnome.shell.extensions.bleunlock`
Path: `/org/gnome/shell/extensions/bleunlock/`
| Key | Type | Default |
|---|---|---|
| `enabled` | boolean | false |
| `device-address` | string | "" |
| `rssi-lock-threshold` | int | -75 |
| `rssi-unlock-threshold` | int | -65 |
| `poll-interval` | int | 3 |
### Testing strategy
- `tests/unit/` — vitest, no GI dependencies; tests `thresholds.ts` pure functions only.
- `tests/integration/` — vitest with GI stubs in `tests/mocks/`; tests BleMonitor state-machine via `MockBleMonitor` that replays the same threshold logic without D-Bus.
- `tests/gnome-shell/` — GJS/Jasmine script; runs **inside** a nested GNOME Shell 49 session.
- Mocks live in `tests/mocks/` (GLib, Gio, GObject, Clutter, St). Extend them when adding new GI API calls.
### GNOME 49 API notes
- Nested testing: `dbus-run-session gnome-shell --devkit --wayland` (not `--nested`).
- `Meta.Window.is_maximized()` — use this, not the removed `get_maximized()`.
- `Mtk.Rectangle` — replaces `Meta.Rectangle` if rectangle types are needed.
- `Meta.WaylandClient.new_subprocess()` — use this on GNOME 49 for any companion subprocess.
- `ExtensionBase.getLogger()` is available (GNOME 48+) but not yet adopted; `console.warn/log` is used instead.
### BlueZ D-Bus
- ObjectManager: `org.bluez` at path `/`, interface `org.freedesktop.DBus.ObjectManager`.
- Adapter: `/org/bluez/hci0`, interface `org.bluez.Adapter1`.
- Device RSSI: property `RSSI` (type `n`, int16) on `org.bluez.Device1`. Read via `get_cached_property('RSSI')` — no extra D-Bus round-trip.
- Discovery is triggered by `StartDiscovery`/`StopDiscovery` on the adapter, then `GetManagedObjects` is called to refresh the device list.
## Skills
Two Copilot skills in `.agents/skills/` provide additional context for extension work:
- **`gjs-gnome-extensions`** — Quick Settings patterns, ESModule imports, lifecycle rules, packaging.
- **`gnome-shell-extension-dev`** — GNOME 47-49 compatibility, subprocess/Wayland, review readiness.
Invoke with `@gjs-gnome-extensions` or `@gnome-shell-extension-dev` when making shell-side or version-sensitive changes.
+4 -3
View File
@@ -1,12 +1,12 @@
## INSTRUCTION
- Generate the gnome-shell 49 extension described under the _EXTENSION DESCRIPTION_ item.
- Place all output in a subdirectory named 'generated' in the working directory. Configure the project for typescript.
- Place a GPL-3.0 LICENSE file in the generated directory.
- Place all output in a subdirectory named 'generated' in the working directory.
- Place a GPL-3.0 LICENSE.md file in the generated directory.
## EXTENSION DESCRIPTION:
- Features:
- The extension is called 'BLE Unlock' and is owned by daniel@demus.dk.
- The extension monitors the signal strength of a bluetooth device in the proximity of the computer and calls functions when the signal strength goes below or above configured thresholds, respectively. Leave the called functions empty.
- The extension monitors the signal strength of a bluetooth device in the proximity of the computer and calls functions when the signal strength goes below or above configured thresholds, respectively. The functions send a dbus message to then org.gnome.ScreenSaver method SetActive with boolean `true` when the RSSI falls over the threshold and boolean `false` when it goes over with a configurable delay, which is 3 seconds by default. Debug log the transitions.
- Include a quick settings item allowing to enable/disable the monitoring functionality and showing some status information including the selected device and current signal strength.
- The dB thresholds and device to monitor are configurable. The item must have a submenu allowing setting the thresholds and selecting which device to monitor, so the quick settings item it should list nearby devices and allow selecting one of them, similarly to the the gnome Bluetooth Settings dialog.
- The extension runs in user and unlock-dialogue session modes.
@@ -15,3 +15,4 @@
- Generate unit tests for all isolatable codepaths.
- Generate integration tests both with mocks and gnome-shell-test-tool as appropriate for the given functionality under test.
- Store any informational output related to the project or further instructions into a README.md file.