Skip to content

Add a PyQt6 GUI frontend (vrgb-gui) with FN-key brightness sync, tray, and profiles#6

Open
mrw1986 wants to merge 5 commits into
vrgb-dev:mainfrom
mrw1986:feat/gui
Open

Add a PyQt6 GUI frontend (vrgb-gui) with FN-key brightness sync, tray, and profiles#6
mrw1986 wants to merge 5 commits into
vrgb-dev:mainfrom
mrw1986:feat/gui

Conversation

@mrw1986
Copy link
Copy Markdown

@mrw1986 mrw1986 commented Jun 3, 2026

Summary

Adds a PyQt6 desktop GUI (vrgb-gui) for VRGB — covering the "simple GUI frontend / color picker / brightness control / profile management" items listed under Future Development in the README.

It's a thin frontend, not a reimplementation: the GUI imports the vrgb script as a module (importlib) and calls its existing functions in-process, so the HID protocol, report-id mapping and config logic are shared with the CLI — no duplicated device code.

What's included

  • vrgb-gui.py — the GUI:
    • HS color wheel + value slider, hex entry, preset swatches (live preview while dragging, persisted on release)
    • Unified brightness slider tied to FN+F4 / FN+F3. The keyboard has two brightness layers that multiply — the firmware backlight (asus::kbd_backlight, 0..max, set via logind) and vrgb's HID intensity byte. The slider exposes a single brightness B and decomposes it into a firmware step F and HID intensity I such that (F/max)·(I/255) = B, so the two layers never double-dim. A poll mirrors hardware FN-key changes back into the slider. Falls back to pure-HID brightness when the LED node / logind is unavailable.
    • Power on/off, firmware/autonomous toggle, OEM rainbow (auto-disabled on mappings where rainbow_supported is false)
    • Profile manager (save / load / delete)
    • System-tray applet (on/off, brightness-step submenu, color submenu + full dialog, profiles); closing the window hides to tray
    • In-GUI "Start at login" toggles that create/remove the XDG autostart entries (opt-in per user)
    • All device I/O runs on a worker thread; if the vrgb group isn't active in the session yet, persisting actions fall back to pkexec (Polkit) — and only ever run the root-owned /usr/local/bin/vrgb, never a user-writable script.
  • install-gui.sh, vrgb-gui.desktop — installer + launcher.
  • vrgb.py: get_real_home() now also honors PKEXEC_UID, so a pkexec-elevated CLI run reads/writes the invoking user's ~/.config/vrgb instead of /root's.
  • README updated with a GUI section.

Notes

  • Developed and tested on an ASUS Vivobook S16 (M5606WA), ITE5570 0B05:5570 mapping, on Fedora/KDE.
  • Requires PyQt6 (sudo dnf install python3-pyqt6 on Fedora).
  • KDE tray menus render over DBusMenu, which can't host embedded widgets, so the tray uses submenus (brightness steps / color swatches) rather than an inline slider.

🤖 Generated with Claude Code

mrw1986 and others added 5 commits June 2, 2026 21:37
A desktop frontend that imports the vrgb CLI as a module and drives the
keyboard in-process (shared HID protocol + config logic, no duplication).
Device I/O runs on a worker thread; persisting actions fall back to
pkexec when the vrgb group is not yet active in the session.

Features:
- HS color wheel + value slider, hex entry, preset swatches
- Live throttled preview, persisted on release
- Brightness slider, power toggle, firmware/autonomous toggle
- OEM rainbow toggle (auto-disabled on unsupported device mappings)
- Profile save/load/delete
- System-tray applet (quick on/off, brightness, profiles); close-to-tray

Adds install-gui.sh, vrgb-gui.desktop, and README docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Critical:
- pkexec only ever runs the root-owned /usr/local/bin/vrgb; never a
  user-writable script (removes a local privesc primitive)
- vrgb.py get_real_home() now honors PKEXEC_UID, so a pkexec'd CLI writes
  the invoking user's ~/.config/vrgb instead of /root's
- parent all tray QActions to self so 'Quit' is not garbage-collected

High:
- clear _interacting on brightness commit (UI refresh no longer freezes)
- only set quitOnLastWindowClosed(False) when a tray exists, else closing
  the window exits instead of orphaning a headless process
- track + kill the pkexec subprocess on shutdown; add a 120s timeout; drain
  the worker (wait/terminate) before quitting so the QThread isn't destroyed
  while running

Medium/low:
- stop mutating process-global sys.stdout/stderr from the worker thread
- process the op queue strictly FIFO (drop racy _coalesce reordering)
- brightness applies the on-screen color (slider routes through the color path)
- gate all device-dependent widgets on detection
- 'Save current' commits on-screen state before snapshotting
- emit deep-copied config snapshots across the thread boundary
- clamp hue for gray colors; guard zero-radius wheel geometry

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The keyboard has two brightness layers that multiply: the firmware backlight
(FN keys -> asus::kbd_backlight, 0..max) and vrgb's HID intensity byte. They
were independent, so the slider and the FN keys ignored each other.

The slider now exposes a single unified brightness B (0..100%), decomposed into
a firmware step F and HID intensity I such that (F/max)*(I/255) == B — smooth and
no double-dimming. Firmware writes go through logind SetBrightness (passwordless
for the active session). A 300ms poll watches the firmware level so FN+F4/F3 move
the slider and the HID intensity too, with a settle window to ignore self-induced
changes. Degrades to pure-HID brightness when the LED node / logind is absent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 'Start at login' section in the window with two checkboxes that create/remove
  the user XDG autostart entries (restore lighting / start tray), reflecting their
  current state — so autostart is opt-in per user, not forced by the installer.
- Tray menu now embeds a live brightness slider and a color-swatch row plus a
  'More colors…' QColorDialog. They drive the main window's controls, reusing the
  firmware decomposition, preview throttling and persistence. The tray slider
  re-syncs to the current brightness each time the menu opens.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
KDE renders system-tray menus over DBusMenu, which silently drops QWidgetAction
embedded widgets — the brightness slider, color swatch row and captions showed up
blank. Replace them with standard, DBusMenu-renderable items:

- Brightness submenu of discrete steps (10/25/50/75/100%), exclusive + checkable,
  with the step nearest the current brightness ticked on open.
- Color submenu of preset swatches (colored QIcon) plus a 'More colors…' dialog.

Both still route through the main window's controls (set_brightness_external /
_apply_hex), so the firmware decomposition, preview and persistence are reused.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vrgb-dev
Copy link
Copy Markdown
Owner

vrgb-dev commented Jun 5, 2026

Thanks for the work. I'll review over the weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants