Skip to content

Fix AppShots external target selection - #1384

Open
brianmsm wants to merge 4 commits into
ilysenko:mainfrom
brianmsm:fix/appshots-external-target
Open

Fix AppShots external target selection#1384
brianmsm wants to merge 4 commits into
ilysenko:mainfrom
brianmsm:fix/appshots-external-target

Conversation

@brianmsm

@brianmsm brianmsm commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

mise ~/.config/mise/config.toml tools: gh@2.98.0

Summary

Fixes #1383.

Opening the composer attachment menu focuses ChatGPT Community before AppShots queries the Linux window backend. An explicit picker is required, but selection alone is insufficient on Hyprland: ordinary screenshot CLIs capture the visible workspace, so cropping that image with bounds from another workspace can attach the wrong pixels.

This disabled-by-default appshots feature now:

  • opens the installed Hyprland share picker only after the user activates the generic window entry;
  • uses a temporary Windows-page config only for hyprland-preview-share-picker;
  • leaves legacy and explicitly configured custom pickers argument-free;
  • forces native GTK and Qt Wayland backends for the picker child process;
  • resolves a live Hyprland instance from $XDG_RUNTIME_DIR/hypr when Electron did not inherit HYPRLAND_INSTANCE_SIGNATURE;
  • requires a valid, visible ChatGPT return target before changing workspaces;
  • activates the selected window and waits for stable identity, focus, visibility, and bounds;
  • adds a render-settle interval and repeats the stable-state check before capture;
  • revalidates identity, focus, visibility, and bounds after pixel acquisition;
  • captures pixels and accessibility data concurrently;
  • verifies ChatGPT focus restoration before delivering any renderer message;
  • serializes capture transactions so requests cannot race compositor focus;
  • keeps the EWMH stacking fallback for X11; and
  • fails closed when any target, capture, or restoration invariant cannot be proven.

It prefers hyprland-preview-share-picker, falls back to hyprland-share-picker, and supports CODEX_LINUX_APPSHOT_PICKER as an explicit executable override.

User-visible behavior

On Hyprland, the composer offers a generic Attach window... entry. Activating it opens the preview selector directly on Windows even when its persistent config defaults to Outputs or Region. Selecting a window on another workspace briefly displays that workspace while AppShots captures it, then restores ChatGPT Community before the attachment is delivered.

The preview selector is a centered native Wayland layer-shell overlay, not a normal tiled client. Output and Region selections remain intentionally fail-closed because the current AppShots contract accepts only a Window target.

Scope and compatibility

  • Hyprland native Wayland: explicit picker and verified focus/capture/restore transaction.
  • EWMH-compatible X11 window managers: stacking-order fallback with synthetic coverage.
  • Other Wayland compositors: unchanged safe failure; no compositor-specific target is guessed.
  • Architectures and package formats: no architecture-specific or format-specific feature payload.

Validation

Passed on the rebased branch:

node --test linux-features/appshots/test.js
# 24 passed

node --test scripts/patch-linux-window-ui.test.js \
  scripts/lib/linux-features.test.js \
  linux-features/*/test.js
# 790 passed, 1 skipped

bash -n install.sh scripts/lib/*.sh launcher/start.sh.template
bash tests/scripts_smoke.sh
# 57 passed

./scripts/ci-local.sh pr
# deb, RPM, and pacman package builds passed

git diff --check

An isolated official-bundle build with only appshots enabled applied exactly its three descriptors against official chatgpt 26.825.32147 amd64 (SHA-256 986d38b690dd0310933ce61175b09c27434001f4e114332bb0f7b6ffdc3ca406).

The updated regression coverage includes binary-aware picker arguments, temporary config cleanup, missing inherited Hyprland instance resolution, invalid return targets, target identity/focus/visibility/bounds drift, pre- and post-capture validation, verified restoration before delivery, restoration failure, concurrent pixel/accessibility acquisition, and serialized capture requests.

Interactive Hyprland validation

Previously confirmed on Omarchy / Hyprland / native Wayland:

  • the preview selector opens once as a centered native layer-shell overlay;
  • windows from multiple apps and workspaces appear;
  • explicit external selections attach that app instead of ChatGPT;
  • ChatGPT regains focus before the thumbnail appears;
  • successful Window selection does not show a failure toast;
  • Output and Region fail closed.

Interactive X11 remains untested; synthetic coverage protects the EWMH fallback.

Review status

The branch is rebased onto current main. I reviewed the complete updated base-to-head diff after the changes above and found no remaining blocker. Local validation and all required GitHub checks are green. The complete updated base-to-head diff was reviewed again before requesting maintainer re-review.

Checklist

  • This pull request is ready for review.
  • I followed CONTRIBUTING.md and kept the change inside the optional feature.
  • Drift-prone bundle anchors fail closed and are covered by tests.
  • Relevant local tests and cross-format local CI pass.
  • I reviewed the final base-to-head diff.
  • Newly triggered required GitHub Actions checks pass.

@brianmsm
brianmsm force-pushed the fix/appshots-external-target branch from 5c0d51a to 863ddf6 Compare August 20, 2026 16:26
@brianmsm
brianmsm marked this pull request as draft August 20, 2026 16:31
@brianmsm
brianmsm force-pushed the fix/appshots-external-target branch 3 times, most recently from 9245b34 to b0a24ea Compare August 20, 2026 17:30
@brianmsm
brianmsm marked this pull request as ready for review August 20, 2026 19:05

@ilysenko ilysenko left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for completing the native Wayland picker work and interactive Hyprland validation. Before this can merge, please address the remaining capture-safety issues:

  • Establish that the selected workspace is actually rendered before capturing, and revalidate the selected window’s identity, focus, visibility, and bounds before accepting the acquired pixels.
  • Serialize capture transactions or add explicit ownership and cancellation so concurrent requests cannot race global compositor focus and attach pixels from another target.
  • Reuse the repository’s Hyprland session/instance resolution for picker execution and focus/restore when the Electron environment lacks HYPRLAND_INSTANCE_SIGNATURE.
  • Require a valid ChatGPT return target before activating another workspace, and fail closed unless restoration is successfully verified before delivering the attachment.
  • Make picker invocation binary-aware. Preview-only config arguments must not be passed to legacy or custom pickers, and the documented Windows-first behavior must match each supported picker.

Please add regression coverage for these failure and concurrency paths.

Verify the updated PR against CONTRIBUTING.md, run the relevant tests locally before pushing the update, and wait for every required CI check to pass. Run the complete updated base-to-head diff through your own code-review model, fix every blocker it finds, rerun the review, and repeat until the model reports no remaining blockers before requesting maintainer re-review.

Open the Hyprland share picker on its window page so users explicitly choose an external window after the composer takes focus. Activate the selected window before capturing the visible workspace, wait for stable current bounds, and restore ChatGPT even when capture fails. Preserve the user picker configuration through a temporary derived override, keep the EWMH stacking fallback for X11, and fail closed when no safe target is available.

Docs: document picker selection, focus transition, and unsupported-backend behavior.
Collect window pixels and accessibility data concurrently, restore ChatGPT before delivering the capture to the renderer, and report failed capture stages with a stable Linux reason. Document the window-only picker contract and cover the new ordering and concurrency behavior.

Docs: document capture ordering and unsupported picker result types.
Force GTK and Qt Wayland backends for the Hyprland picker so launcher-level X11 compatibility settings cannot demote its layer-shell overlay into a tiled client. Add regression coverage for inherited backend variables and document the runtime boundary.\n\nDocs: linux-features/appshots/README.md
@brianmsm
brianmsm force-pushed the fix/appshots-external-target branch from 9d8c962 to eccfb7c Compare August 28, 2026 18:48
@brianmsm

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review. I addressed the requested capture-safety changes in eccfb7c:

  • selected-window identity, focus, visibility, and bounds are stabilized before capture and revalidated after pixel acquisition;
  • capture transactions are serialized;
  • picker and focus/restore paths resolve a live Hyprland instance when the Electron environment lacks the signature;
  • capture now requires a valid visible ChatGPT return target and verified restoration before renderer delivery; and
  • picker invocation is binary-aware, so preview-only config arguments are not passed to legacy or custom pickers.

Regression coverage now includes the failure, drift, restoration, and concurrency paths. The branch is rebased, the complete base-to-head diff was reviewed again with no remaining blockers, local validation passed, and all required CI checks are green. Re-requesting review.

@brianmsm
brianmsm requested a review from ilysenko August 28, 2026 19:22
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.

AppShots composer targets ChatGPT instead of the previous external window

2 participants