Start singularity-session.target so graphical-session.target actually activates - #6
Conversation
… actually activates graphical-session.target is systemd-hardened against direct manual start (RefuseManualStart) -- it needs a unit that BindsTo= it, which is what labwc's own docs/autostart recommends (start labwc-session.target). That unit is not installed by this build, so add our own with the same shape: BindsTo=graphical-session.target, Wants=graphical-session-pre.target. Without something starting it, every systemd --user unit declaring WantedBy=graphical-session.target -- our xdg-desktop-portal-singularity service among them, plus foot-server -- sits enabled but never runs. Root-caused on real O6N 2026-08-27: xdg-desktop-portal correctly routed Screenshot requests to the singularity backend, but the backend process itself never started because nothing had ever activated graphical-session.target on this system. Confirmed fixed end-to-end after a clean session restart (with the matching cix-installer bridge that puts this target where systemd --user actually looks) -- both the portal-mediated Screenshot call and the native singularity-screenshot binary produced real PNGs.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b1d95bad61
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # own xdg-desktop-portal-singularity.service among them) launch at all. | ||
| install_data( | ||
| 'config/systemd-user/singularity-session.target', | ||
| install_dir: get_option('prefix') / 'lib' / 'systemd' / 'user', |
There was a problem hiding this comment.
Install the target into a systemd user-unit search path
For the advertised /opt/local installation, this places the target in /opt/local/lib/systemd/user, so the new systemctl call cannot find it and silently continues without activating the graphical services. Checked with systemd-analyze --user unit-paths: the standard paths include /usr/local/lib/systemd/user and /usr/lib/systemd/user, but not arbitrary ${prefix}/lib/systemd/user; use the configured systemd user-unit directory or otherwise install the file into a searched location.
Useful? React with 👍 / 👎.
| # the same role: BindsTo=graphical-session.target, | ||
| # Wants=graphical-session-pre.target, so starting it gets the pre-target | ||
| # sequencing for free too. | ||
| systemctl --user --no-block start singularity-session.target 2>/dev/null || true |
There was a problem hiding this comment.
Stop the session target when the compositor exits
When the user manager survives logout—such as with lingering enabled or another concurrent login—this start has no matching stop, so singularity-session.target remains active after labwc terminates. Because it keeps the StopWhenUnneeded=yes graphical target needed, graphical-session services such as the portal backend and foot server continue running outside the desktop session; add teardown tied to the launcher/compositor lifetime.
Useful? React with 👍 / 👎.
graphical-session.target refuses direct manual start (systemd hardening) — it needs a bound unit to pull it in. Nothing did, so every WantedBy=graphical-session.target unit (xdg-desktop-portal-singularity, foot-server) was enabled but never ran.
Adds singularity-session.target (BindsTo=graphical-session.target, matching what labwc's own docs recommend starting) and starts it from the session launcher.
Validated on real O6N: root-caused live, fixed, then confirmed clean from a full session restart — both the portal-mediated Screenshot call and the native singularity-screenshot binary produced real PNGs.