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.
config/autostart now sets the wallpaper through the `current` symlink that
`cosmic-conf import-theme --assets` maintains, rather than naming a file
inside the theme directory. The test still asserted the old path and failed.
The hazard it was written for is gone with it: the path no longer contains a
space, because it no longer contains a theme name. That case is still covered
on synthetic input by quotes_hold_arguments_containing_spaces_together, so
this one now asserts what actually matters here -- that the script arrives as
a single argument, that it names the link rather than one of the copies beside
it, and that it waits for the daemon before setting an image.
11 profile tests pass.
/usr/bin/start-hyprcosmic gained this during the blank-screen debugging and
the versioned copy never did, so the next install from this repository would
have silently removed it. Found by diffing the two while writing an installer;
the installer's --check exists so that the next one is not found by hunch.
What it does, unchanged from the copy that has been running: redirect the
session's own output to ~/.cache/hyprcosmic/session.log. A session that fails
drops you at the greeter taking its stderr with it, and by then the journal
cannot be read from inside a session that no longer exists.
A plain redirect rather than tee into a process substitution -- tee would be a
child the session writes through, so its death would deliver SIGPIPE, and
nothing about diagnostics should be able to kill the desktop. Every step is
guarded, so a failure here starts the session with no log rather than refusing
to log in. The previous log is kept as .1 so a second attempt does not erase
the evidence from the first.
The template is mostly prose, and `#` starts a comment wherever a word would
start -- so a comment marker landing in the wrong column drops a command
silently rather than failing. Parsing the real file in a test means editing
the explanatory text around a command cannot quietly disable it.
Tests only; no behaviour change, so the installed session binary is unaffected.
Two defects in the previous commit, both of which would have failed silently
at the greeter rather than loudly at build time.
`start_component` passes its whole string to `Process::with_executable`, which
treats it as the program name. An autostart line like `waybar -c <path>` was
therefore looked up as a binary literally called "waybar -c <path>", and the
bar would simply never appear. The unit test asserting that "rofi -show drun"
parses as one entry implied arguments worked; they did not. Extras are now
split into argv and spawned through a `start_process` helper, which is
upstream's `start_component` body with args threaded through --
`start_component` keeps its signature so no upstream call site changes.
The splitter honours quoting, because config paths contain spaces, and treats
`#` as a comment only where a word would start, so `--color=#1a1b26` survives.
It expands nothing else: no variables, globs or command substitution, so a
file that names programs cannot be escalated into running arbitrary shell.
`start-hyprcosmic` also defaulted HYPRCOSMIC_SESSION_BIN to
/usr/bin/cosmic-session -- the stock binary, which has no profile module. The
session would have come up as ordinary COSMIC with the gating apparently doing
nothing. It now points at /usr/libexec/hyprcosmic, so the fork installs
alongside the packaged COSMIC instead of over it, a dnf update cannot clobber
it, and the stock entry stays as the escape hatch. It fails loudly with a
pointer back to that entry if the binary is missing.
Verified: 9 unit tests, including a regression test for the argv defect and
one asserting nothing is expanded; `cargo build -j1` clean.
Upstream hardcodes the set of cosmic-* components a session launches.
HyprCosmic needs cosmic-comp for window management but waybar and rofi in
place of cosmic-panel and cosmic-launcher, so `profile` gates that set.
The default profile is upstream behaviour exactly, and it is what an
unconfigured build gets; the alternate set is opt-in through
HYPRCOSMIC_PROFILE, which only the new session entry sets. So installing
this fork cannot change how the stock session boots, and a broken
HyprCosmic config is always one logout away from being escaped.
Gating lives at the single definition of `start_component` rather than at
its call sites, keeping the diff against upstream small enough to rebase
against a fast-moving tree. cosmic-panel and cosmic-notifications are the
exception: they are started as a coupled pair sharing notification fds and
cannot go through that path, so they are gated where they are spawned
(hence the re-indentation in the diff).
cosmic-greeter is deliberately never disabled - a display manager is the
easiest thing to lock yourself out of. cosmic-osd and cosmic-idle stay too,
since HyDE's equivalents are separate programs a user may not have and
neither competes with waybar for layer-shell space.
Verified: 5 unit tests over profile selection and extras parsing; `cargo
check -j1` and `cargo build -j1` clean.
NOT verified: the gating has never been observed at runtime. Two attempts
to run this session nested inside the live desktop logged the developer out
instead, so runtime confirmation is deferred to logging into the
hyprcosmic.desktop entry from the greeter. Two hazards found along the way
and worth recording: name-matching (pkill/pgrep) cannot distinguish this
fork's processes from the live session's, and a nested cosmic-session steals
the well-known D-Bus name com.system76.CosmicSession from the running
session unless it is given a private bus.