feat(qtile): shared widget-anchored Emacs popup UI and notification backend #138

Open
lost-rob0t wants to merge 5 commits from rage/108-emacs-ui-notifications into master
lost-rob0t commented 2026-08-24 00:27:31 +00:00 (Migrated from github.com)

Consumes #108 (control-plane follow-up slice).

What

  • emacs_ui.py: widget-relative popup geometry (left/center/right under the clicked widget's bar, clamped to its physical screen incl. non-zero origins), structured shell-free emacsclient argv, worker-thread launch. No alternate editor: a missing Emacs server fails in the worker and raises a desktop notification — it can never spawn a second full-size window (root cause of the live two-window bug).
  • lisp/qtile/qtile-ui.el + qtile-ui-org.el: one shared frame lifecycle — stable popup IDs, registry with restart rediscovery via frame parameter, chrome-free undecorated frames, user-position geometry, q/Escape dismissal, Org dashboard faces.
  • Notification backend: persistent dmenu/emacs setting with atomic writes (ui-settings.json); Dmenu UI preserved; both backends consume one Dunst history adapter (dunst_history.py) that surfaces errors and keeps every record.
  • SERVICES dashboard: real fourth-dropdown example (systemd user units, two-step restart).
  • Workflow picker re-anchored to its widget through the shared launcher; JSON vectors converted for completing-read.
  • qtile_system.py: root free space + root disk I/O rates resolved from the / mount through sysfs slaves/partition relationships (no hardcoded device names — verified with arbitrary-name fixtures); fixed-width telemetry icon cells (compact disk cell).
  • NetIORate replaces the stock widget.Net showing 'auto not found'; the verified combined graph and OpenRouter renderer are untouched except display-column-aware long-range aggregation that preserves genuine gaps.
  • Floating rules for all qtile-* popup titles so frames render as dropdowns, not tiled windows.

Verification

  • 185 Qtile Python tests + 8 ERT tests green; py_compile; qtile check; literate parity (check-literate-sync + literate-sync.sh); shell suites; nix flake check --no-build; all four Home Manager profiles evaluate.
  • Live: reloaded on the running session; bar rebuilt (NetIORate, disk cluster); no Emacs respawn without a server; popup geometry derived from clicked widget confirmed in generated expression.

Docs

  • docs/qtile-emacs-ui.org: ownership boundaries, public Python/Elisp APIs, positioning/lifecycle, debugging, SERVICES example.
Consumes #108 (control-plane follow-up slice). ## What - **emacs_ui.py**: widget-relative popup geometry (left/center/right under the clicked widget's bar, clamped to its physical screen incl. non-zero origins), structured shell-free emacsclient argv, worker-thread launch. **No alternate editor**: a missing Emacs server fails in the worker and raises a desktop notification — it can never spawn a second full-size window (root cause of the live two-window bug). - **lisp/qtile/qtile-ui.el + qtile-ui-org.el**: one shared frame lifecycle — stable popup IDs, registry with restart rediscovery via frame parameter, chrome-free undecorated frames, user-position geometry, q/Escape dismissal, Org dashboard faces. - **Notification backend**: persistent dmenu/emacs setting with atomic writes (ui-settings.json); Dmenu UI preserved; both backends consume one Dunst history adapter (dunst_history.py) that surfaces errors and keeps every record. - **SERVICES dashboard**: real fourth-dropdown example (systemd user units, two-step restart). - **Workflow picker** re-anchored to its widget through the shared launcher; JSON vectors converted for completing-read. - **qtile_system.py**: root free space + root disk I/O rates resolved from the / mount through sysfs slaves/partition relationships (no hardcoded device names — verified with arbitrary-name fixtures); fixed-width telemetry icon cells (compact disk cell). - **NetIORate** replaces the stock widget.Net showing 'auto not found'; the verified combined graph and OpenRouter renderer are untouched except display-column-aware long-range aggregation that preserves genuine gaps. - Floating rules for all qtile-* popup titles so frames render as dropdowns, not tiled windows. ## Verification - 185 Qtile Python tests + 8 ERT tests green; py_compile; qtile check; literate parity (check-literate-sync + literate-sync.sh); shell suites; nix flake check --no-build; all four Home Manager profiles evaluate. - Live: reloaded on the running session; bar rebuilt (NetIORate, disk cluster); no Emacs respawn without a server; popup geometry derived from clicked widget confirmed in generated expression. ## Docs - docs/qtile-emacs-ui.org: ownership boundaries, public Python/Elisp APIs, positioning/lifecycle, debugging, SERVICES example.
This pull request has changes conflicting with the target branch.
  • .config/qtile/config.py
  • .config/qtile/emacs_ui.py
  • .config/qtile/qtile-ai.org
  • .config/qtile/qtile-desktop.el
  • .config/qtile/qtile-openrouter.org
  • .config/qtile/qtile-workflow.el
  • .config/qtile/qtile.org
  • .config/qtile/qtile_control.py
  • .config/qtile/qtile_openrouter.py
  • .config/qtile/tests/test_emacs_ui.py
  • .config/qtile/tests/test_groupbox_navigation.py
  • .config/qtile/tests/test_qtile_control.py
  • .config/qtile/tests/test_qtile_emacs_server.py
  • .config/qtile/tests/test_qtile_workflow.py
  • docs/qtile-emacs-ui.org
  • docs/wiki/index.org
  • lisp/qtile/qtile-ui-test.el
  • lisp/qtile/qtile-ui.el
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin rage/108-emacs-ui-notifications:rage/108-emacs-ui-notifications
git switch rage/108-emacs-ui-notifications

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch master
git merge --no-ff rage/108-emacs-ui-notifications
git switch rage/108-emacs-ui-notifications
git rebase master
git switch master
git merge --ff-only rage/108-emacs-ui-notifications
git switch rage/108-emacs-ui-notifications
git rebase master
git switch master
git merge --no-ff rage/108-emacs-ui-notifications
git switch master
git merge --squash rage/108-emacs-ui-notifications
git switch master
git merge --ff-only rage/108-emacs-ui-notifications
git switch master
git merge rage/108-emacs-ui-notifications
git push origin master
Sign in to join this conversation.
No description provided.