Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
application ID or a regular expression on the window title).
- Build tooling: `Makefile` (build/lint/pot/pack/install/nested), ESLint config,
GitHub Actions CI, and gettext translation scaffolding (`po/`).
- External control: writing `active-profile` from outside the extension now applies
that profile. Previously only the preferences process listened to the key, and only
to refresh its own UI, so an external writer changed nothing on screen. This makes
`gsettings` a supported way for another program to drive the borders without
duplicating the calibration.
- `CONTRIBUTING.md` and this changelog.
- Brazilian Portuguese translation.

Expand Down
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ for laptop users who need extra illumination without external gear.
- **Multi-monitor support**: Show on the primary monitor or all screens.
- **Seamless integration**: Native GNOME Shell feel with a toggle in the top bar.
- **Convenient shortcut**: `Ctrl + Alt + L` opens the preferences.
- **Scriptable**: apply a profile or toggle the light from any other program by
writing the extension's GSettings keys — see [Controlling Lighter from another
program](#controlling-lighter-from-another-program).

## Requirements

Expand Down Expand Up @@ -74,6 +77,51 @@ match rule — an application ID (e.g. `firefox.desktop`) and/or a window title
matches, the optional *default profile* is applied. Manual selection always works and
takes effect immediately.

### Controlling Lighter from another program

Every appearance setting lives in GSettings, and the extension reacts to external
writes. That makes `gsettings` a supported entry point: another program can drive the
borders without reimplementing them, and without knowing how your borders are
calibrated.

The schema is not in the default search path, so `--schemadir` is required:

```bash
SCHEMA_DIR="$HOME/.local/share/gnome-shell/extensions/lighter@gnome-shell-extensions.ferrete.com/schemas"
SCHEMA=org.gnome.shell.extensions.lighter

# Turn the light on and off
gsettings --schemadir "$SCHEMA_DIR" set $SCHEMA enabled true
gsettings --schemadir "$SCHEMA_DIR" set $SCHEMA enabled false

# Apply a saved profile by its id
gsettings --schemadir "$SCHEMA_DIR" set $SCHEMA active-profile '<profile-id>'
```

**Look profile ids up by name, never hardcode them.** They are UUIDs generated when
the profile is created, so a hardcoded id breaks as soon as you recreate the profile.
The `profiles` key holds a JSON document shaped like
`{"version": 1, "profiles": [{"id": "…", "name": "Meet", "settings": {…}}]}`:

```bash
gsettings --schemadir "$SCHEMA_DIR" get $SCHEMA profiles \
| sed "s/^'//; s/'$//" \
| jq -r '.profiles[] | select(.name == "Meet") | .id'
```

Writing `active-profile` applies the profile, including turning the light on. The
appearance keys (`thickness-*`, `opacity`, `color`, `temperature`, `multi-monitor`,
`maximize-brightness`) can also be set individually and take effect immediately.

Two things worth knowing:

- **Turn off *Auto-switch profiles* while an external program is in charge**, or the
window watcher will apply its own profile on the next focus change and overwrite
what your program just did. The two are independent controllers of the same state.
- **Changes to the extension's own code need a logout/login on Wayland**, because the
GNOME Shell cannot reload an extension there. Changes to *settings* apply
immediately — only code changes need the session restart.

## Development

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide. Quick start:
Expand Down
23 changes: 23 additions & 0 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ export default class LighterExtension extends Extension {
if (SYNC_KEYS.includes(key))
this._sync();
});

// Applying a profile by writing `active-profile` from outside.
//
// Only the preferences process listened to this key before, and only
// to refresh its own UI — so an external writer could set it and
// nothing would happen on screen. Wiring it here makes the key a
// real entry point: `gsettings set ... active-profile <id>` applies
// the profile, which lets another program drive the borders without
// knowing the nine appearance keys or duplicating the calibration.
//
// No feedback loop: `applyProfile` writes `active-profile` back with
// the same value, and GSettings does not emit `changed` when the
// value is unchanged.
this._activeProfileId = this._settings.connect('changed::active-profile', () => {
const id = this._settings.get_string('active-profile');
if (id)
this._profiles.applyProfile(id);
});
this._monitorsChangedId = Main.layoutManager.connect(
'monitors-changed', () => this._sync());

Expand All @@ -73,6 +91,11 @@ export default class LighterExtension extends Extension {
this._settingsId = 0;
}

if (this._activeProfileId) {
this._settings.disconnect(this._activeProfileId);
this._activeProfileId = 0;
}

if (this._monitorsChangedId) {
Main.layoutManager.disconnect(this._monitorsChangedId);
this._monitorsChangedId = 0;
Expand Down
Loading