git.lucas.co / cce-desktop-portal
Settings and Inhibit portal backends
git clone https://git.lucas.co/cce-desktop-portal.git

commitd292a0b159a7e5f8418701af43b05cde4b72beb9
parent45ea21e6e7
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-07 15:01
CLAUDE.md: the AppChooser backend, its wiring and how to drive it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 CLAUDE.md | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index f5f6f24..bee673f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -6,7 +6,7 @@ rules.
 
 ## What this is
 
-`cce-desktop-portal` is cce's own backend for two portal interfaces that
+`cce-desktop-portal` is cce's own backend for three portal interfaces that
 used to fall to xdg-desktop-portal-gtk through `default=gtk`, plus the
 `org.freedesktop.ScreenSaver` service apps call directly:
 
@@ -35,6 +35,15 @@ used to fall to xdg-desktop-portal-gtk through `default=gtk`, plus the
   connection goes away. Only the portal's idle (8) and suspend (4) flags
   hold anything; logout and user-switch have nothing to hold in cce.
 
+- **`org.freedesktop.impl.portal.AppChooser`** (`src/app_chooser.rs`) — the
+  "Open with…" dialog. The frontend passes the handler IDs; this runs
+  `cce-cloud --choose -p "Open <file> with: " [-s <last_choice>]` with the IDs
+  on stdin (cce-cloud's chooser mode shows each entry's name and icon and
+  prints the picked ID — see its CLAUDE.md) and answers `{choice: <id>}`, or
+  cancelled on Escape. The request's `Close` kills the cce-cloud client; the
+  cce-cloud daemon closes a popup whose client hung up. `UpdateChoices` is
+  only logged. `CCE_CHOOSER_BIN` points a run at another cce-cloud build.
+
 `idle status` names holders as `portal:<who>`.
 
 ## Lifecycle
@@ -56,8 +65,9 @@ does, so the bus activation environment must carry it (startcce imports it).
 - `portals/cce-desktop.portal` → `$XDG_DATA_HOME/xdg-desktop-portal/portals/`
 - `dbus/*.service` → `~/.local/share/dbus-1/services/` (absolute `Exec`)
 - **`~/.config/xdg-desktop-portal/cce-portals.conf`** (user config, not
-  versioned) must say `org.freedesktop.impl.portal.Settings=cce-desktop;gtk`
-  and `org.freedesktop.impl.portal.Inhibit=cce-desktop`.
+  versioned) must say `org.freedesktop.impl.portal.Settings=cce-desktop;gtk`,
+  `org.freedesktop.impl.portal.Inhibit=cce-desktop` and
+  `org.freedesktop.impl.portal.AppChooser=cce-desktop`.
 
 The frontend reads portal files and the conf at startup. Restarting it
 (`systemctl --user restart xdg-desktop-portal`) drops every app's portal
@@ -79,3 +89,12 @@ the live one, run a private `dbus-run-session` with this backend,
 `XDG_CONFIG_HOME` holding a test `cce-portals.conf`, and kill everything
 the private bus activated afterwards (cce-shortcuts-portal attaches to the
 shadow and keeps `dbus-run-session` alive).
+
+The chooser can be driven end to end the same way, never on the live bus:
+a private `dbus-run-session` running this backend with
+`WAYLAND_DISPLAY=<shadow's>` and `CCE_CHOOSER_BIN=<tree cce-cloud>`, a
+`gdbus call … AppChooser.ChooseApplication /test/r/1 app "" "['gimp',…]"
+"{'filename': <'/x/a.pdf'>}"` in the background, then `cce-shadow ctl
+keypress` (108 Down, 28 Enter, 1 Escape) and read gdbus's reply. cce-cloud's
+client socket is keyed by `WAYLAND_DISPLAY`, so a shadow's chooser runs
+standalone (or under a shadow daemon) and never reaches the live one.