Hand the session's identity to systemd --user, so portals work

Pressing PrtScr said "COSMIC screenshot crashed". cosmic-screenshot was
aborting on an unwrap, because org.freedesktop.portal.Screenshot had no
implementation behind it.

start-hyprcosmic exported XDG_CURRENT_DESKTOP=COSMIC, and the compositor had
it. But an export only reaches processes started by this script, and the
portal is not one of them: xdg-desktop-portal is launched by `systemd --user`,
which is older than the session and carries its own environment block. Its
copy had XDG_SESSION_TYPE and nothing else.

xdg-desktop-portal chooses a backend by matching the `UseIn=` line of
/usr/share/xdg-desktop-portal/portals/*.portal against XDG_CURRENT_DESKTOP.
Unset, `UseIn=COSMIC` never matched, no backend loaded, and the Screenshot
interface was never exported. Nothing anywhere logged a missing portal. The
crash was the only symptom, and it pointed at the screenshot tool.

`systemctl --user import-environment` fixes it, which is what start-cosmic has
always done and this script had not. Ordering works out: the portal unit is
`After=` and `Requisite=graphical-session.target`, which cosmic-session brings
up later, so it cannot start ahead of the import.

dbus-update-activation-environment as well, for any backend whose .service
file has no `SystemdService=` line -- but only when a bus already exists,
since in the dbus-run-session branch the bus is created after this point.
Everything is `||:`. Losing a portal is bad; refusing to log in is worse.

Verified by clearing all three variables out of the user manager, running the
script's environment block, restarting xdg-desktop-portal, and watching the
Screenshot interface come back and cosmic-screenshot exit 0 with a real PNG.
This commit is contained in:
2026-08-10 12:58:28 +07:00
parent 6400f64791
commit 22e894330e
+38
View File
@@ -66,6 +66,7 @@ export HYPRCOSMIC_PROFILE=hyprcosmic
# key off this, and the compositor underneath really is COSMIC. # key off this, and the compositor underneath really is COSMIC.
export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-COSMIC}" export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-COSMIC}"
export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-hyprcosmic}" export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-hyprcosmic}"
export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:-wayland}"
# Same hygiene as start-cosmic: a failed unit left by a previous graphical # Same hygiene as start-cosmic: a failed unit left by a previous graphical
# session will otherwise block this one from starting. # session will otherwise block this one from starting.
@@ -79,6 +80,43 @@ if command -v systemctl >/dev/null; then
fi fi
done done
done done
# Hand the session's identity to `systemd --user`, which is what actually
# launches the portal.
#
# Exporting XDG_CURRENT_DESKTOP above only reaches processes started *by
# this script*. The user manager is older than the session and has its own
# environment block, so anything it activates -- xdg-desktop-portal, and
# through it xdg-desktop-portal-cosmic, which is `SystemdService=` in its
# D-Bus service file -- never saw the variable.
#
# xdg-desktop-portal picks a backend by matching the `UseIn=` line of
# /usr/share/xdg-desktop-portal/portals/*.portal against
# XDG_CURRENT_DESKTOP. With the variable unset, `UseIn=COSMIC` did not
# match, no backend loaded, and org.freedesktop.portal.Screenshot was never
# exported -- so pressing PrtScr made cosmic-screenshot unwrap an error and
# abort with "COSMIC screenshot crashed". Nothing logged a missing portal;
# the only symptom was the crash.
#
# Ordering is fine: xdg-desktop-portal.service is `After=` and
# `Requisite=graphical-session.target`, which cosmic-session brings up
# later, so the portal cannot start before this import.
#
# `||:` throughout -- losing a portal is bad, refusing to log in is worse.
systemctl --user import-environment \
XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE ||:
fi
# Same variables again for dbus-daemon's own activation environment, which
# covers any backend whose .service file has no `SystemdService=` line.
#
# Only when a bus already exists. In the dbus-run-session branch below the bus
# is created *after* this point, so calling it here would talk to the wrong bus
# or none at all. That branch is the fallback path anyway; a normal graphical
# login arrives with DBUS_SESSION_BUS_ADDRESS already set.
if [[ -n "${DBUS_SESSION_BUS_ADDRESS}" ]] && command -v dbus-update-activation-environment >/dev/null; then
dbus-update-activation-environment \
XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE ||:
fi fi
# cosmic-session takes the compositor to launch as its first argument # cosmic-session takes the compositor to launch as its first argument