Skip to content

feat: add per-window capture source selection - #136

Closed
Gaming-RF wants to merge 1 commit into
eklonofficial:mainfrom
Gaming-RF:feature/window-capture-source
Closed

feat: add per-window capture source selection#136
Gaming-RF wants to merge 1 commit into
eklonofficial:mainfrom
Gaming-RF:feature/window-capture-source

Conversation

@Gaming-RF

Copy link
Copy Markdown

Summary

Allow users to record a specific application window instead of the entire desktop. Adds a unified Capture source selector in Settings that lists both monitors and application windows.

What changed

Backend — Source Enumeration (active_window.py)

  • New list_capture_windows() enumerates visible windows for X11 (wmctrl/xdotool), Hyprland (hyprctl clients -j), and Sway (swaymsg tree walk)
  • Filters out system-level windows (panels, docks, trays, notification popups)
  • Returns window ID, title, app name, and PID for each capture-eligible window

Backend — Recording Pipeline (recorder.py)

  • New list_capture_sources() combines monitors + windows into a unified list with kind field
  • New list_gsr_windows() parses gpu-screen-recorder's --list-capture-options for window entries
  • New _resolve_capture_source() handles the unified capture_source config format
  • Updated _gsr_capture_target() to pass window IDs to GSR's -w flag
  • Updated _ffmpeg_x11_input_args() to capture specific windows by geometry via xwininfo
  • Added window capture warning for wf-recorder (not natively supported — GSR recommended)
  • Added _x11_window_geometry() for window dimension detection

Config (config.py)

  • New capture_source field on RecordingConfig — format: "display:<id>", "window:<id>", "window:focused", or null for auto
  • Backward compatible: existing display field still works when capture_source is not set

API (share.py)

  • New GET /api/capture-sources endpoint returning monitors + windows with kind and label

UI (index.html, settings.js, state.js, settings.css)

  • "Display" selector renamed to "Capture source" with two <optgroup> sections: "Displays" and "Application Windows"
  • "Focused window (auto-follow)" option for tracking the active window
  • Refresh button to re-scan for available windows
  • Backward compatible with existing display config values

Edge cases handled

  • wf-recorder + window source: Logs a warning and falls back to full display capture
  • Window closed during recording: GSR reports error on stderr (captured by existing watchdog)
  • No windows detected: Shows "No application windows detected" with graceful fallback
  • Compositor unsupported: Shows appropriate message per backend
  • Resolution: Auto-detects window dimensions via xwininfo for ffmpeg; GSR handles internally

Testing

All 200 existing tests pass (151 recorder + 49 UI static).

Screenshots

The Capture source dropdown in Settings:

  • "Auto (current display)" — default
  • "Focused window (auto-follow)" — tracks active window
  • Displays optgroup — list of monitors
  • Application Windows optgroup — list of visible app windows

Closes #

Allow users to record a specific application window instead of the
entire desktop. Adds a unified 'Capture source' selector in Settings
that lists both monitors and application windows.

Backend changes:
- Add list_capture_windows() to active_window.py for X11, Hyprland,
  and Sway window enumeration with title, app name, and window ID
- Add list_capture_sources() to recorder.py combining monitors + windows
- Add list_gsr_windows() parsing gpu-screen-recorder --list-capture-options
- Add _resolve_capture_source() for unified capture_source config format
- Add _x11_window_geometry() for window dimension detection
- Update GSR, wf-recorder, and ffmpeg backends to use capture_source
- Add window capture warning for wf-recorder (unsupported)

Config:
- Add capture_source field to RecordingConfig (format: display:<id>,
  window:<id>, window:focused, or null for auto)

API:
- Add GET /api/capture-sources endpoint returning monitors + windows

UI:
- Replace Display selector with Capture source grouped dropdown
  (Displays optgroup + Application Windows optgroup)
- Add Focused window (auto-follow) option
- Add refresh button to re-scan for windows
- Add .capture-source-row CSS layout

All 200 existing tests pass.
@eklonofficial

Copy link
Copy Markdown
Owner

Thanks for this, and sorry it sat so long.

I'm going to close it, but I want to be specific about why, because two of the criticisms floating around aren't accurate and I don't want them attached to your work. This PR does not touch games.json and does not delete any tests. It's branched off v2.5.0, so a diff against current main makes it look that way. That isn't on you.

The two things that are real:

-w focused will crash gpu-screen-recorder. The man page says focused has to be used together with -s, and -s never gets passed here. _detect_window_resolution() is defined but nothing calls it, so anyone picking "Focused window" without also setting a manual resolution gets a recorder that dies on start.

It would take follow-my-mouse down with it. 2.6.0 added a display override that runs through _resolve_display_option(rc, backend, override) and _gsr_capture_target(rc, override). This PR rewrites both with the older single-argument signature. It's 9 conflict blocks across 6 files now, and resolving them naively silently removes that feature.

Neither is a design problem, they're both "this needs a rebase onto 2.6.0" problems. But there's also #157 now covering the same ground, and its approach is better in one way that matters: instead of GSR's -w focused, it matches the focused window against games.json first and pins to that window id, so alt-tabbing to Discord mid-game doesn't move the capture onto Discord. -w focused follows raw input focus, which for a replay-buffer recorder is the wrong thing.

I'd rather land one implementation than merge two half-overlapping ones, so I'm consolidating on #157. Your list_capture_windows() enumeration across X11, Hyprland and Sway is more thorough than anything there, and the explicit source picker is genuinely useful beyond auto-detection. If you want to bring that part over as a smaller PR on top, I'd take it.

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