Skip to content

feat(screenshot): snap to active popouts & modals in region mode - #3618

Merged
bbedward merged 3 commits into
duxlabs-dev:masterfrom
hthienloc:feat/screenshot-popout
Sep 29, 2026
Merged

bbedward merged 3 commits into
duxlabs-dev:masterfrom
hthienloc:feat/screenshot-popout

Conversation

@hthienloc

Copy link
Copy Markdown
Member

What

Adds snap-to-surface behavior in region screenshot mode (dms screenshot):

  • Exposes screenshot.getSurfaces shell IPC endpoint querying visible DankPopout and DankModal bounding boxes.
  • Hovering over an open popout or modal highlights its perimeter and shows [<surface-name>] <W>x<H>.
  • Clicking or pressing Return/Space while hovering locks the selection to the surface bounds.
  • Allows dragging away (>5px) to cancel snap and switch back to freeform rectangle drawing.
  • Preserves hover snapping even when a pre-selected region exists (~/.cache/dms/screenshot-state.json).
  • Degenerate (1×1) clicks reset the selection state so users can re-select without relaunching the CLI.

Why

Capturing open shell popouts (Control Center, App Launcher, Clipboard, Wi-Fi password modal, etc.) required manual pixel-precise dragging. Snapping automatically aligns to the exact window bounding box.

recording_2026-09-29_13-19-29.mp4

Allow region screenshot selector to detect and snap to visible shell
popouts and modals on hover and click or keyboard confirmation.

- PopoutManager.qml: add getActiveSurfaces() collecting visible
  DankPopout and DankModal global bounding boxes
- DMSShellIPC.qml: add screenshot.getSurfaces IPC endpoint
- core: fetch snap targets from shell IPC during region screenshot init
- selector: highlight snap targets on hover with surface name and dimensions
- selector: click or Enter/Space on hovered target locks selection to surface bounds
- selector: allow hover snap over pre-selection (SelectionState.fromPreSelect)
- selector: reset selection on degenerate (1x1) click release for quick re-selection
- unit tests for display name formatting, hover detection, and render bounds
@hthienloc

Copy link
Copy Markdown
Member Author

/claude review

Comment thread core/internal/screenshot/region_input.go
Comment thread core/internal/screenshot/region_input.go Outdated
@claude

claude Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Claude review

Two bugs in the snap logic need fixing before merge.

  • Dragging away from a snap target with no pre-selection never sets hasSelection, so nothing is drawn or captured. core/internal/screenshot/region_input.go:89
  • Snapped region captures one extra device pixel on the right and bottom (a 420×580 popout comes out 421×581). core/internal/screenshot/region_input.go:177
    Checked: region input, render and hover logic, qsipc snap-target fetch, the PopoutManager/DMSShellIPC getSurfaces endpoint, and the Go/QML protocol match. Model: claude-opus-5-5.

- region_input: fix drag-away snap cancellation by setting hasSelection=true
  and clearing preSelect so freeform dragging renders and is not discarded
- region_input: add snapToTarget helper subtracting 1 device pixel (devPxX/Y)
  from currentX/currentY to prevent inclusive coordinate off-by-one (420x580 -> 420x580)
- region_render: compute hover bounds with w = round(width * scaleX) and
  x2 = x1 + w - 1 to eliminate +1 device pixel in render bounds
- region_snap_test: assert exact 420x580 bounds for both hover and snapped states
@hthienloc

Copy link
Copy Markdown
Member Author

/claude review

@claude

claude Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Claude review

No issues found. Both earlier findings are fixed: dragging away from a snap target now draws and keeps the selection, and the snapped capture subtracts one device pixel so it matches the target size.
Checked: pointer and key handling for snap, drag-away, the degenerate-click reset and pre-selection, hover rendering, the qsipc calls (they have a 2s timeout and the selector hook runs in a goroutine), and that the PopoutManager getActiveSurfaces fields exist on DankPopoutHost and DankModal and match the Go SnapTarget JSON. Model: claude-opus-5-5.

@bbedward
bbedward merged commit 34e0ed2 into duxlabs-dev:master Sep 29, 2026
4 checks passed
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