Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions linux-features/appshots/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Linux AppShots

`linux-features/appshots` exposes the upstream AppShots composer entry on
Linux. It attaches the focused window screenshot plus best-effort AT-SPI text
to the composer.
Linux. It attaches a selected window screenshot plus best-effort AT-SPI text to
the composer.

This feature is disabled by default. Enable it before building:

Expand Down Expand Up @@ -31,9 +31,37 @@ Privacy and correctness constraints:

- The feature may briefly create a full-screen temporary screenshot before
cropping it to the focused window.
- Capture fails closed when no focused window or usable bounds are available.
- Opening the composer menu focuses ChatGPT. On Hyprland, the feature offers a
generic window attachment and opens an installed Hyprland share picker after
the user activates it. It prefers `hyprland-preview-share-picker`, falls back
to `hyprland-share-picker`, and accepts an explicit executable through
`CODEX_LINUX_APPSHOT_PICKER`; these use the picker protocol shipped by
`xdg-desktop-portal-hyprland`. The preview picker is a Wayland layer-shell
overlay rather than a tiled Hyprland client. For that preview picker only,
AppShots opens its window page using a temporary derived config, preserving
and never modifying the user's picker config. Legacy and explicitly supplied
custom pickers receive no preview-only command-line arguments and retain
their own default page. AppShots also forces the picker to use native GTK and
Qt Wayland backends so a launcher-level X11 compatibility setting cannot turn
that layer-shell overlay into a tiled XWayland client. Because ordinary
screenshot CLIs can only read the visible
workspace, the selected window is activated briefly. Its identity, focus,
visibility, and stable bounds are verified before and after pixel capture,
and ChatGPT restoration is verified before any attachment is delivered. The
feature resolves the active Hyprland instance from the runtime directory when
the Electron environment does not inherit `HYPRLAND_INSTANCE_SIGNATURE`. On
EWMH-compatible X11 window managers, the feature selects the topmost external
window in stacking order. Both paths skip ChatGPT and desktop portal windows.
Other backends fail closed when they cannot provide a safe target.
- Capture fails closed when no selected window or usable bounds are available.
- Capture fails closed when no screenshot tool is available or the crop does not
intersect the captured image.
intersect the captured image. The portal picker also exposes Output and
Region pages, but this window-attachment integration accepts only an explicit
Window selection and fails closed for the other result types.
- Window pixels and best-effort accessibility text are collected concurrently.
ChatGPT is restored as soon as both inputs have been acquired, before the PNG
and metadata are sent back to the composer. Capture transactions are
serialized so two requests cannot race compositor focus or exchange targets.
- Global hotkeys remain disabled on Linux because the current upstream package
no longer includes the AppShots hotkey settings surface.
- Previously saved `Alt + Alt` and `Shift + Shift` choices are backed by a feature-local
Expand Down
2 changes: 1 addition & 1 deletion linux-features/appshots/feature.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "appshots",
"title": "Linux AppShots",
"description": "Opt-in AppShots composer integration that captures and crops the focused Linux window without core AppShots backend changes.",
"description": "Opt-in AppShots composer integration that captures and crops a selected Linux window without core AppShots backend changes.",
"defaultEnabled": false,
"entrypoints": {
"patchDescriptors": "./patch.js"
Expand Down
Loading