fix(power): only the backlight class is a screen brightness #81

Merged
Breadway merged 2 commits from fix/bset-73-backlight-class into main 2026-10-14 13:58:36 +08:00
Owner

Closes BSET-73
Closes #74

What

Plain brightnessctl acts on the first device it finds. On desktops, VMs and external-monitor setups that is a keyboard LED (input1::numlock), so the Power page showed a Brightness slider at 0% that drove the Num Lock light.

  • power.rs: reads and writes use brightnessctl --class=backlight --machine-readable, parsed by parse_backlight. With no backlight, the Brightness row is hidden (the existing brightness_pct === null path).
  • power_settings.rs: the hypridle dim action is brightnessctl -c backlight -s set 10% with -c backlight -r on resume. The old skel lines (brightnessctl -s set 10% and brightnessctl -r) are migrated on read and save, like the existing dpms migration.

Tests

  • New: only_backlight_class_is_a_screen (LED lines ignored, first backlight wins) and dim_targets_the_backlight_and_migrates_old_lines (timeout read from the old line, rewrite, idempotent).
  • On top of current main: cargo test (181), clippy, fmt, svelte-check 0/0, npm test, build.
  • Live BOS VM (no backlight): the Brightness row is gone and "Dim the screen after" still reads 5 minutes from the skel config.

Capability changes

None on machines with a backlight. On machines without one, the Brightness row no longer appears.

Follow-up outside this repo: BOS skel hypridle.conf still ships the unscoped line. It gets migrated the first time Power settings are saved.

Closes BSET-73 Closes #74 ## What Plain `brightnessctl` acts on the first device it finds. On desktops, VMs and external-monitor setups that is a keyboard LED (`input1::numlock`), so the Power page showed a Brightness slider at 0% that drove the Num Lock light. - `power.rs`: reads and writes use `brightnessctl --class=backlight --machine-readable`, parsed by `parse_backlight`. With no backlight, the Brightness row is hidden (the existing `brightness_pct === null` path). - `power_settings.rs`: the hypridle dim action is `brightnessctl -c backlight -s set 10%` with `-c backlight -r` on resume. The old skel lines (`brightnessctl -s set 10%` and `brightnessctl -r`) are migrated on read and save, like the existing dpms migration. ## Tests - New: `only_backlight_class_is_a_screen` (LED lines ignored, first backlight wins) and `dim_targets_the_backlight_and_migrates_old_lines` (timeout read from the old line, rewrite, idempotent). - On top of current main: cargo test (181), clippy, fmt, svelte-check 0/0, npm test, build. - Live BOS VM (no backlight): the Brightness row is gone and "Dim the screen after" still reads 5 minutes from the skel config. ## Capability changes None on machines with a backlight. On machines without one, the Brightness row no longer appears. Follow-up outside this repo: BOS skel `hypridle.conf` still ships the unscoped line. It gets migrated the first time Power settings are saved.
fix(power): only the backlight class is a screen brightness
All checks were successful
check / check (push) Successful in 2m57s
31cadc6e7b
Plain brightnessctl acts on the first device it finds, which on desktops,
VMs and external-monitor setups is a keyboard LED (input1::numlock), so the
Power page showed a Brightness slider at 0% that drove the Num Lock light.
Reads and writes now use brightnessctl --class=backlight -m; with no
backlight the row is hidden. The idle dim action is written with -c
backlight too, and the old skel line is migrated on read and save.

Verified in a BOS VM (no backlight): the Brightness row is gone and the
existing dim timeout still reads 5 minutes.
Merge remote-tracking branch 'origin/main' into fix/bset-73-backlight-class
All checks were successful
check / check (push) Successful in 6m31s
e1aa6dd27d
Author
Owner

Closes #74 (BSET-73)

Closes #74 (BSET-73)
Author
Owner

Review of BSET-73, reviewed head e1aa6dd27d (base d432319): PASS.

Criteria

  • Detection/get use only the backlight class: power.rs:116-150 runs brightnessctl --class=backlight --machine-readable; parse_backlight requires class == "backlight". Test only_backlight_class_is_a_screen covers LED-only (None), LED then backlight (backlight wins), empty, and the real laptop line amdgpu_bl1,backlight,325805,81%,400000.
  • Set: set_brightness (power.rs:421-434) targets the device name resolved from the backlight class, so no keyboard LED is driven. Non-blocking nit: it passes --device <name> without -c backlight, so a leds device with an identical name could in theory match. Not realistic; optional follow-up to add --class=backlight.
  • No backlight hides the row: brightness_pct returns None, so Power.svelte:186 hides it (matches the coordinator's VM evidence).
  • hypridle: DIM/UNDIM are brightnessctl -c backlight -s set 10% / -c backlight -r. Legacy lines are migrated in migrate_dpms, which timeout_of and render_idle both call. Neither legacy string is a substring of the new one, so the migration is idempotent. Test dim_targets_the_backlight_and_migrates_old_lines covers timeout read from the old line (300), rewrite to 120, no old on-timeout left, idempotent re-render, and fresh render resume line.
  • Backlight machines unchanged: same slider, polling (get_brightness) and set paths, with the same device name.
  • -m format: brightnessctl.c print_device uses "%s,%s,%d,%d%%,%d\n" = id,class,current,percent%,max, matching the parser. With -c <class> and no op it prints info for every device in that class.

Checks on the exact head (clean detached worktree)

  • frontend: npm ci, npm run check (0 errors, 0 warnings), npm test, npm run build: all pass
  • src: cargo fmt --check OK, cargo clippy --locked --all-targets -D warnings OK, cargo test --locked: 181 passed, 0 failed (both new tests ran)
  • Forgejo CI "check / check (push)" on e1aa6dd: success
  • No outstanding reviews or change requests; PR mergeable.
Review of BSET-73, reviewed head e1aa6dd27d1c6f6e5dd082f2480c13b46fcc96a4 (base d432319): PASS. Criteria - Detection/get use only the backlight class: power.rs:116-150 runs `brightnessctl --class=backlight --machine-readable`; parse_backlight requires class == "backlight". Test only_backlight_class_is_a_screen covers LED-only (None), LED then backlight (backlight wins), empty, and the real laptop line amdgpu_bl1,backlight,325805,81%,400000. - Set: set_brightness (power.rs:421-434) targets the device name resolved from the backlight class, so no keyboard LED is driven. Non-blocking nit: it passes `--device <name>` without `-c backlight`, so a leds device with an identical name could in theory match. Not realistic; optional follow-up to add `--class=backlight`. - No backlight hides the row: brightness_pct returns None, so Power.svelte:186 hides it (matches the coordinator's VM evidence). - hypridle: DIM/UNDIM are `brightnessctl -c backlight -s set 10%` / `-c backlight -r`. Legacy lines are migrated in migrate_dpms, which timeout_of and render_idle both call. Neither legacy string is a substring of the new one, so the migration is idempotent. Test dim_targets_the_backlight_and_migrates_old_lines covers timeout read from the old line (300), rewrite to 120, no old on-timeout left, idempotent re-render, and fresh render resume line. - Backlight machines unchanged: same slider, polling (get_brightness) and set paths, with the same device name. - -m format: brightnessctl.c print_device uses "%s,%s,%d,%d%%,%d\n" = id,class,current,percent%,max, matching the parser. With `-c <class>` and no op it prints info for every device in that class. Checks on the exact head (clean detached worktree) - frontend: npm ci, npm run check (0 errors, 0 warnings), npm test, npm run build: all pass - src: cargo fmt --check OK, cargo clippy --locked --all-targets -D warnings OK, cargo test --locked: 181 passed, 0 failed (both new tests ran) - Forgejo CI "check / check (push)" on e1aa6dd: success - No outstanding reviews or change requests; PR mergeable.
Author
Owner

Merged with a merge commit as 283ba6b20e (head e1aa6dd on base 9b07bcf). Main moved twice during review (#79, #82, neither touching power code). Before merging I re-verified the PR head merged onto the new main in a scratch worktree: frontend check, test and build pass, cargo fmt, clippy and test pass (182 tests). BSET-73 now awaits verification on a machine with a backlight and in a no-backlight VM using the integrated build. Not marked done.

Merged with a merge commit as 283ba6b20ecb679df5830511914859653c9d7ee8 (head e1aa6dd on base 9b07bcf). Main moved twice during review (#79, #82, neither touching power code). Before merging I re-verified the PR head merged onto the new main in a scratch worktree: frontend check, test and build pass, cargo fmt, clippy and test pass (182 tests). BSET-73 now awaits verification on a machine with a backlight and in a no-backlight VM using the integrated build. Not marked done.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Breadway/bos-settings!81
No description provided.