Skip to content

feat(wayland): auto-detect Wayland session and start aw-watcher-window-wayland - #142

Merged
ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:feat/wayland-autodetect
Oct 18, 2026
Merged

ErikBjare merged 2 commits into
ActivityWatch:masterfrom
TimeToBuildBob:feat/wayland-autodetect

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Summary

On Wayland, aw-watcher-window and aw-watcher-afk do not work — they rely on X11/xcb APIs. aw-watcher-window-wayland already handles both roles (it writes to both the aw-watcher-window and aw-watcher-afk buckets), but users had to manually disable the X11 watchers and start the Wayland one themselves.

This PR makes aw-qt handle the swap transparently:

  • _is_wayland(): detects Wayland by checking WAYLAND_DISPLAY or XDG_SESSION_TYPE=wayland
  • _apply_wayland_substitutions(): when on Wayland and aw-watcher-window-wayland is installed, drops aw-watcher-window and aw-watcher-afk from the autostart list and inserts aw-watcher-window-wayland in their place
  • The default autostart_modules config is unchanged — the swap happens at runtime in Manager.autostart()
  • If aw-watcher-window-wayland is not installed, the original list is returned with a warning (graceful degradation)

Addresses the concern raised by Erik in ActivityWatch/activitywatch#92: system package managers on Wayland-first distros may only list the Tauri distribution if aw-qt is broken on Wayland. With this fix, aw-qt works on Wayland when aw-watcher-window-wayland is installed.

Test plan

  • 12 new unit tests covering _is_wayland() and _apply_wayland_substitutions() — all pass
  • 162 existing tests still pass (run make test)
  • Manual test: run aw-qt on a Wayland session, verify aw-watcher-window-wayland starts instead of the X11 watchers
  • Manual test: run aw-qt on X11, verify original behavior unchanged

Co-Authored-By: Bob timetobuildBob@gmail.com

On Wayland, aw-watcher-window and aw-watcher-afk do not work (they rely
on X11/xcb). aw-watcher-window-wayland handles both roles via Wayland
protocols (wlr-foreign-toplevel-management-unstable-v1 + ext-idle-notify-v1).

Add _is_wayland() which checks WAYLAND_DISPLAY and XDG_SESSION_TYPE, and
_apply_wayland_substitutions() which swaps the two X11 modules for
aw-watcher-window-wayland when the Wayland watcher is installed. The
substitution is transparent: the default autostart_modules config is
unchanged, the swap happens at runtime in Manager.autostart().

When aw-watcher-window-wayland is not installed, the original list is
returned with a warning — no breakage, just no window/AFK tracking.

Closes ActivityWatch/activitywatch#92 (Wayland support in aw-qt)

Git-Session-Id: 2a88ce4d-a37f-436a-bbf8-48c828da3b4d
Comment thread tests/test_wayland.py Fixed
Comment thread tests/test_wayland.py Fixed
@greptile-apps

greptile-apps Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] Auto-detects Wayland and swaps window tracking modules.

Preserve the user's choice to disable startup before merging.

Findings

  1. P1 Disabled tracking starts anyway ▶
  2. P2 Tests silently use fake Qt ▶

Summary

Adds Wayland detection and replaces the X11 watchers with an installed aw-watcher-window-wayland during startup.

  • aw-qt starts the Wayland watcher in place of its X11 watchers.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Configured or command-line module list] --> B{Wayland session?}
    B -- No --> F[Validate and remove duplicates]
    B -- Yes --> C{Wayland watcher installed?}
    C -- No --> F
    C -- Yes --> D[Replace selected X11 watchers]
    D --> E[Also append watcher when none selected]
    E --> F
    F --> G[Start selected server first]
    G --> H[Start remaining modules]
Loading

Reviews (1) · Last reviewed commit: "feat(wayland): auto-detect Wayland and s..." · Reviewed by Greptile

Comment thread aw_qt/manager.py Outdated
Comment thread tests/test_wayland.py Outdated
Greptile P1: the substitution helper appended aw-watcher-window-wayland even
when autostart_modules was empty (--autostart-modules none) or server-only,
overriding an explicit choice to disable tracking.

Only replace modules the user actually selected; leave empty and server-only
lists untouched. Add regression tests for the empty and server-only cases.

Also drop the sys.modules PyQt6 stubs from the tests (PyQt6 imports fine
without a display, and the stubs leaked MagicMock modules into other tests)
and remove the unused imports CodeQL flagged.

Git-Session-Id: 98c07e2a-30f9-5f17-a998-4fb560a3876e
@TimeToBuildBob

TimeToBuildBob commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 AI code review

Safe to merge — 1 P1 disposed (accepted-tradeoff)

Updated after inline dispositions on finding threads — this is the current state; the verdict below is frozen at review time and is kept as the historical record of that pass.

Finding disposition
Finding Severity State
aw_qt/manager.py:84 P1 accepted-tradeoff

Adds Wayland session detection (_is_wayland) and a substitution helper (_apply_wayland_substitutions) that swaps aw-watcher-window/aw-watcher-afk for aw-watcher-window-wayland in the autostart list when running under Wayland and the watcher is installed. Wires the helper into Manager.autostart() before module validation, and adds a new test module covering detection and substitution.

Not safe to merge — 1 P1 open

Confidence 3/5

1 finding · ❌ 1 P1

❌ P1 high — aw_qt/manager.py:84

When only one of the two X11 watchers is in the autostart list, the substitution still inserts aw-watcher-window-wayland, which reports to both the aw-watcher-window and aw-watcher-afk buckets. For example autostart_modules=['aw-server','aw-watcher-window'] on Wayland with the wayland watcher installed becomes ['aw-server','aw-watcher-window-wayland'], silently enabling AFK tracking the user deliberately omitted. This contradicts the docstring's claim that only modules the user actually selected are replaced; the pair is treated as atomic. Observable consequence: users who disabled AFK tracking for privacy will have AFK data collected after switching to Wayland.

else:
            if name == WAYLAND_WATCHER:
                inserted = True
            result.append(name)

How this was verified: Traced the loop for modules = ["aw-server", "aw-watcher-window"] with _is_wayland True and available_names containing the wayland watcher: it inserts WAYLAND_WATCHER and drops aw-watcher-window, leaving only the combined watcher. The PR description states this watcher reports to both buckets.

Consensus: 3/3 passes agreed
Distinct keys: 1 (general)

Files changed (2) — the diff as I read it
  • aw_qt/manager.py — Adds _is_wayland(), _apply_wayland_substitutions(), and calls the substitution from Manager.autostart() before validating the module list.
  • tests/test_wayland.py — Adds unit tests for Wayland detection and substitution, covering environment variables, X11/Wayland replacement, missing watcher, and empty/server-only lists.

Reviewed 0d31fc75e2bf · openrouter/deepseek/deepseek-v4-flash-0731 · llm engine · 527s · about this reviewer

Maintainer commands

@TimeToBuildBob review (own line) — fresh review · @TimeToBuildBob fix — a worker acts on the findings. Once per comment; 👀 = received.

Comment thread aw_qt/manager.py
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Merge recommendation

Fixed this cycle (head 0d31fc75e2bf):

  • Greptile P1 — substitution no longer overrides an explicit "no tracking" choice: empty and server-only autostart lists are returned unchanged (regression tests added).
  • Greptile P2 — PyQt6 sys.modules MagicMock stubs removed from tests (leaked into other test modules); unused imports CodeQL flagged dropped.

Remaining (non-blocking):

  • AI-review P1 (partial selection): selecting only one of aw-watcher-window/aw-watcher-afk still substitutes the combined Wayland watcher, which reports to both buckets. Disposition: accepted trade-off — on Wayland the X11 watcher cannot capture, so this is the only way to deliver the tracking the user selected; not substituting would silently disable tracking entirely. The AFK side effect is documented in the helper docstring. Flagged below as a domain decision.

Verified against: head 0d31fc75e2bf547424298e66c14497819a404c5e.

CI: all green (Test ubuntu-22.04 / macos-14 / windows-latest, Analyze, CodeQL).

Domain risk for maintainer judgment: the partial-selection AFK-bucket semantics above — if you consider silently enabling AFK collection for a user who deliberately omitted aw-watcher-afk worse than silently losing window tracking on Wayland, the substitution should be restricted to selections containing both modules.

Convergence: detector verdict converged — 0 stable rounds required; all P1/P2 findings resolved or explicitly dispositioned.

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.

3 participants