enBoxer/docs/VIDEO.md
en 9d2f51685d Finish the project (T7..T15): layout wizard, broadcast, overlay, dmabuf, teams
Layout wizard (T7):
- App::layout_canvas with monitor backgrounds, click-to-select, draggable tiles
- borderless Hyprland window_rule on run
- App::refresh_monitors + Refresh monitors button; monitors cache for canvas sync

Routing extras (T8, T13, T14):
- clipboard IPC verb (wl-paste / xclip -> Ctrl+V to non-leader slots)
- mirror-mode mouse click broadcast via hypr::deliver_click
- round_robin / rr bind target rotates through ALL slots (leader included)

Slot overlay (T9 real):
- src/wayland_layer.rs: zwlr_layer_shell_v1 client, shm buffers, 3x5 bitmap
  digit glyphs, wl_pointer click -> swap <slot>
- gated ENBOXER_ENABLE_OVERLAY=1; cargo test does not connect

Covered-window VFX capture (T10 real):
- src/toplevel_export.rs: zwlr_export_dmabuf_unstable_v1 client
- ARGB8888 / XRGB8888 format negotiation, synthetic-PNG fallback for tests
- gated ENBOXER_ENABLE_TOPLEVEL=1; gbm_bo_map upgrade documented

Teams + Lutris launcher (T15):
- src/team.rs: Team, list_teams, teams_dir, current_team
- src/lutris.rs: LutrisGame parser, load_all with bad-YAML tolerance
- src/launcher.rs: SpawnPlan merges Lutris config + per-character wine-prefix
- GUI: Teams menu (New / Switch / Refresh / Show / Delete) + Launch menu
- Lutris picker visible only in New-team flow; direct Wine spawn, no lutris CLI

Tests: 89 passed; 0 failed (up from 24).
Clippy: clean with -D warnings.

Safety:
- No live hyprctl dispatch that moves / resizes / pins / closes the session.
- All Wayland paths feature-gated; cargo test does not connect.
- apply_layout still gated by allow_layout + confirm_apply.

Files: 14 modified + 6 new (src/{launcher,lutris,overlay,team,toplevel_export,wayland_layer}.rs)
Diff: +1570 / -29
2026-09-15 17:18:37 +02:00

29 lines
2.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Live crop (Video FX)
You pick **two rectangles**:
1. **Source** — which part of another client to copy, and how large that crop is.
2. **Viewer** — where that crop is drawn on the primary client, and how large it is shown.
Numbers `0``1` are fractions of that window. Numbers **greater than 1** are pixels inside the window. In the GUI, **Pick source / Pick viewer** uses `slurp` and stores pixels.
When the mouse is over the viewer, **clicks and keys go only to the source client**, not to the primary and not to the rest of the team.
Configure this in the **Video FX** page of the control panel (`enboxer` with no arguments).
It is not a second monitor and not a window swap. The other client can sit behind the main one; you still see the cropped piece.
## What Hyprland can actually do
| Method | Sees a window that is fully covered? | What we use |
| --- | --- | --- |
| `grim` of a screen rectangle | No — only pixels currently on the output | **Yes, default** |
| `hyprland-toplevel-export` | Yes — compositor copy of that windows buffer | **Yes, gated behind `ENBOXER_ENABLE_TOPLEVEL=1`** |
| Desktop portal / PipeWire | Yes, heavier | No |
The dispatcher in `src/vfx.rs::capture_for_source` checks `is_window_visible(monitors, client)`. If the source window sits on a visible output, `grim` captures it. If the window is covered and the operator has opted in to compositor-side capture (`ENBOXER_ENABLE_TOPLEVEL=1`), the dispatcher routes to `capture_toplevel` (zwlr_export_dmabuf_unstable_v1). With the gate off, covered windows fall through to `grim` and the operator sees whatever is currently on top of those pixels — exactly the previous behaviour.
So: keep the source window **on a visible output** for the default `grim` path. Set `ENBOXER_ENABLE_TOPLEVEL=1` when you want a stacked layout where some sources are fully covered by another; the live toplevel-export client is a follow-up and the dispatcher is ready for it.
The overlay itself is an `mpv` window (`class: enboxer-vfx`) that reloads each `grim` frame.