Commit graph

12 commits

Author SHA1 Message Date
roberts
36eff81111 Add bidirectional clipboard sync between Xvfb and browser
X11 → Browser:
- Background task polls xclip every 500ms for clipboard changes
- When content changes, sends {"type":"clipboard","data":"..."} via WS
- Browser receives and writes to navigator.clipboard

Browser → X11:
- Ctrl+V reads navigator.clipboard.readText() first
- Sends clipboard content to backend via WS message
- Backend writes to X11 clipboard via xclip -selection clipboard
- Then forwards the Ctrl+V keystroke so the app pastes

This allows copying links/text from GUI apps (like Nextcloud auth URLs)
and pasting content from the host browser into the GUI app.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:26:42 -05:00
roberts
a5a7b01fd9 Complete rewrite of input forwarding — fix mouse and keyboard events
Root causes fixed:
- _focused was a stray class annotation in @dataclass, causing field
  ordering issues — moved to proper dataclass field
- xdotool type --window WID not supported on all versions — removed
  --window flag, use focused window instead
- xdotool commands with --window may fail silently — switched to
  absolute coordinates (window is at 0,0 filling the display)
- All xdotool errors were silently swallowed — now logged with stderr

Mouse events:
- Use absolute mousemove + click (no --window) since window fills display
- Separate mousemove and click into two calls for reliability
- Fire-and-forget for mousemove to reduce latency

Keyboard events:
- xdotool type (no --window) for printable characters
- xdotool key (no --window) for special keys and modifier combos
- Window focused once via _ensure_focus, not per-event

Diagnostics:
- Backend logs first 5 input events received per WebSocket session
- Backend logs xdotool stderr on failure
- Frontend logs first 10 input events sent + WS state warnings
- Frontend uses capture phase for keyboard events

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:22:59 -05:00
roberts
8d2a228599 Fix input forwarding: special chars, mouse events, and typing latency
Keyboard:
- Use xdotool type for printable characters (handles @, #, !, etc.)
- Use xdotool key only for non-printable keys and modifier combos
- Remove --sync from every keystroke — focus set once, not per-event
- Skip release events (xdotool key already handles press+release)

Mouse:
- Remove windowactivate --sync from every click — focus set once
- Fire-and-forget for mousemove events to reduce latency
- Add _xdotool_fire() for non-blocking subprocess calls

Performance:
- _ensure_focus() activates window once, skips on subsequent calls
- Eliminated redundant --sync flags that added 100-300ms per event
- Added _reap() helper to prevent zombie processes from fire-and-forget

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:14:21 -05:00
roberts
12c10d69f0 Maximize GUI app window and fix input forwarding
- After window discovery, activate, move to (0,0), and resize to
  fill the 1280x1024 Xvfb display so the app is fullscreen
- Add windowactivate --sync before click events so the window
  receives focus in X11 before mouse input
- Add windowfocus --sync before key events so keyboard input
  goes to the correct window
- Make canvas fill the entire app panel area (width/height 100%)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:09:58 -05:00
roberts
1467d07bc4 Improve window discovery, add app context menu with Start/Stop/Restart
Window discovery:
- Add display-wide search as final fallback (any window on the Xvfb)
- Also search by WM_CLASS for Electron apps
- Increase timeout to 60s, log progress and early crashes
- Add restart endpoint POST /api/display/apps/{id}/restart

Panel apps:
- Replace play/stop button with ⋮ context menu (Start, Stop, Restart)
- LED indicator: green=running, amber pulsing=starting, red=stopped/error
- Add status field to app API response

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:05:19 -05:00
roberts
da8f0326f8 Fix window discovery for Electron/forking apps like Nextcloud
xdotool search --pid only matches the exact launched PID, but
Electron apps fork into child processes that own the actual window.
Now tries: direct PID → descendant PIDs via /proc → window name match.
Also increases retry timeout to 30s for heavy apps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 00:58:28 -05:00
roberts
6a0c8757f8 Run terminals and GUI apps as the authenticated user, not root
Atlus runs as root (systemd) but user-facing processes must run under the
authenticated user's identity. Added privilege-dropping via preexec_fn
(os.setgid + os.initgroups + os.setuid) to both terminal PTY spawning
and GUI app launching. System admin operations (services, packages,
network, updates) intentionally remain root.

Autostart apps now support a configurable default_user; without one set,
autostart defers until the first user logs in and runs as that user.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 00:35:52 -05:00
roberts
8d48e3eeb8 App exit diagnostics, desktop file discovery, WiFi wpa_supplicant fix
- Capture stderr from GUI apps and show meaningful exit reasons (signal names,
  error messages) instead of generic "Application exited"
- Add /api/display/discover-apps endpoint that scans .desktop files for
  installed GUI apps, replacing manual-only app configuration
- Settings > Applications now shows discoverable apps with one-click Add,
  with manual form available as fallback
- Fix WiFi: start wpa_supplicant before bringing interface up, handle rfkill
  blocks, add retry logic and error messages to scan results
- Fix WiFi scan frontend bug: response is {networks:[...]} not a bare array
- Add iw and wpasupplicant to install.sh dependencies

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 00:03:13 -05:00
roberts
23e4906d08 Replace panel services with docked apps, add autostart and update scanner settings
Panel: SERVICES section becomes APPLICATIONS — shows configured GUI apps with
status dots, launch/stop controls, and "+ Add" button linking to Settings.

Backend: DisplayManager.autostart_apps() launches autostart-enabled GUI apps on
service startup (always-on desktop session). Lifespan calls it before yield.

Settings: new Applications section for managing GUI apps (add/remove/autostart
toggle). General section gains update scanner interval + enable/disable toggle.
Config adds update_check_enabled and update_check_interval fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 23:40:44 -05:00
roberts
a73b515258 Add native GUI app support via per-window frame streaming
Each configured GUI app (e.g. Nextcloud) gets its own dock icon and
opens as a regular Atlus tab. Under the hood: Xvfb virtual display,
ImageMagick captures individual window pixmaps as JPEG, streams over
WebSocket to a canvas element, with xdotool forwarding mouse/keyboard
input back to the X11 window. Apps persist in background when tab is
closed, and streaming pauses when no viewers are attached.

New files: backend/display.py (DisplayManager + ManagedGuiApp),
backend/routers/display.py (WebSocket + REST), frontend display.js/css.
Config: gui_apps array in settings for registered applications.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 23:09:15 -05:00
roberts
6b407a056b Remove X11/noVNC display feature entirely
The Xvfb + x11vnc + websockify + noVNC approach defeats the purpose
of a native web desktop environment. Removed all related backend
(display.py, routers/display.py), frontend (xdisplay.js/css, panel
tray polling), and installer (X11 deps) code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 22:45:18 -05:00
roberts
a88e7bbb06 Fixed polling agent and status bars. 2026-03-14 22:41:00 -05:00