Commit Graph
4 Commits
Author SHA1 Message Date
gitops 49d5f8b20e cosmic-conf: a fixed set of workspaces, with no compositor change
COSMIC's workspaces are dynamic and there is no setting that turns that
off. ensure_last_empty keeps exactly one trailing empty workspace and
collects every other empty one the moment its last window closes, so
"workspace 4 is the browser" is only true while the browser is open.

The primitive that fixes it already exists. can_auto_remove is

    is_empty() && !has_activation_token() && !pinned

and pinned_workspaces is an existing persisted CosmicCompConfig key that
Workspaces::add_output drains into the first output to appear. So this is
a projection and nothing else: no cosmic-comp patch, no new config key,
and the fast cosmic-conf CI job covers all of it rather than a 2.5 hour
package build per distro.

    workspace = 1, name:term
    workspace = 2, name:web
    workspace = 3, name:code

Three things about the restore path shaped the module.

Restore is positional. PinnedWorkspace has no index field -- the order of
the Vec becomes the order of the workspaces -- so `workspace = 4` cannot
emit one entry. It emits four, with 1..3 unnamed, or the browser
workspace comes back as workspace 1. That is why there is a cap: without
one, `workspace = 1000` is a typo that silently creates a thousand
workspaces rather than a diagnostic.

The dynamic workspace survives. Pinned workspaces are pushed into an
empty WorkspaceSet and ensure_last_empty then appends the usual empty
one, so declaring four gives 1-4 always present and a fifth appearing
when you use it. That is Hyprland's behaviour and not a compromise
either way.

It lands at the next login. Workspaces::new reads the key once at
compositor start and there is no reload path for it, while cosmic-conf
watch is started from the autostart file after COSMIC's own components.
Every other key in this file is live, so the one that is not is worth
saying out loud in cosmic.conf rather than leaving to be discovered.

Ids are generated rather than random

random_workspace_id is format!("{:x}", rand(0..2<<24)), at most seven hex
digits. Ours are FNV-1a of the index with the high nibble forced on, so
always eight -- a collision with a compositor-generated id is impossible
by construction rather than unlikely. FNV is written out rather than
reaching for DefaultHasher, which is explicitly not stable across Rust
releases: the id is what ties a window's saved workspace to the
workspace it reappears on, so it changing under a toolchain bump is a
bug that would be very hard to attribute.

monitor: is refused, not ignored

Hyprland's monitor: is the parameter a user reaches for first and the one
COSMIC cannot honour. output_matches compares the EDID before the name,
so an OutputMatch with edid: None is rejected outright against any output
that reports one, and only falls through to the name when neither side
has an EDID. Every real panel reports one, so a name-only match would
work on a VM and nowhere else. cosmic.conf cannot supply an EDID -- it is
a manufacturer triple, product id, serial and manufacture date read off
the wire by the DRM backend.

So the parameter fails with that explanation, the same way follow_mouse =
2 does. Accepting it and quietly doing nothing was the third option and
the worst of the three. The emitted OutputMatch is empty, which is not a
placeholder: an unmatchable match is how a workspace says it has no
output preference, which is the only thing this file can truthfully say.

tiling: defaults to general:autotile

A PinnedWorkspace carries its own tiling_enabled. Defaulting it to false
would have meant that turning workspaces on quietly turned tiling off for
someone whose whole reason for editing the file was autotile = true, so
resolve reads the folded autotile write and passes it through.

CI

The assets job syntax-checked two of the four shell scripts;
hyprcosmic-fan and hyprcosmic-keybinds were added in fc8c2a7 and never
registered. Both are now checked and shellchecked, and each is checked
with the shell its shebang names -- hyprcosmic-fan is POSIX sh on
purpose, and `bash -n` would accept a bashism that fails where /bin/sh is
dash. All four are clean today, so the list stays a ratchet.

Verified

The RON shape was taken from the struct definitions rather than guessed:
PinnedWorkspace has no serde defaults, so all four fields are emitted,
and the (field: value) / None / Some(x) spelling matches what COSMIC
itself wrote to this machine's xkb_config. 19 unit tests in the new
module and 6 in resolve cover the gap-filling, the id range, the
inherited tiling default, the duplicate-index diagnostic, and that a
quote in a name cannot break out of the RON.

Not verified: nothing was compiled here. cargo test, clippy -D warnings
and the release build run in the cosmic-conf job.
2026-08-11 08:02:41 +07:00
gitops 63610d57df ci: give this workflow a name of its own, so it stops cancelling upstream's
Both files said `name: CI`. The concurrency group is built from
${{ github.workflow }}, which is that name, so the two workflows shared a group
and cancelled each other on every push -- whichever started second would be the
only one that ever reported a result. The compositor and session forks already
say HyprCosmic for the same reason; this one was missed when it was renamed.
2026-08-10 17:32:05 +07:00
gitops c6150755d2 Fetch the two forks over HTTPS, and stop cloning 29 submodules to lint CSS
Two consequences of becoming the meta-repo, neither of which the merge itself
could have caught.

The submodule URLs were written as [email protected]: because that is how they are
pushed from here. That is a working copy's business, not the repository's:
upstream names all 29 over HTTPS, a clone with no key configured is the normal
case, and CI has no key at all. The URLs are now HTTPS; each submodule's own
origin stays SSH, which is where it belongs.

The assets job asked for `submodules: recursive` back when this repository had
two of them. It now names 29, and 27 are the rest of COSMIC -- several gigabytes
fetched per run to check that some CSS is in step with its generator. It fetches
the one it needs instead.

That one is cosmic-session, because install-assets.sh also places the session
entry point that lives in that fork. The script skips those two files with a
warning when the checkout is absent rather than failing, so a fetch that
silently stopped working would quietly reduce what the job covers instead of
turning it red. Hence the `test -f` after it.
2026-08-10 17:30:45 +07:00
gitops c0ae1350f3 Merge pop-os/cosmic-epoch: become the meta-repo, with two submodules swapped
HyprCosmic started as a repository beside COSMIC holding a config compiler and a
pile of theme assets, with the two modified components hanging off it. That had
the relationship backwards. COSMIC already has a meta-repo whose whole job is to
name every component and build the desktop from them, so the honest shape for a
fork is to be that meta-repo with the components we changed pointing at our
copies -- not a separate tree that assumes the rest of COSMIC arrived some other
way.

So this merges cosmic-epoch in and repoints exactly two of its 29 submodules:

    cosmic-comp     -> outbackdingo/hyprcosmic-comp
    cosmic-session  -> outbackdingo/hyprcosmic-session

The other 27 stay on pop-os. Nothing about them needs to change, and pinning
them to copies we do not maintain would be a promise to keep 27 forks current.

`just build` and `just install` now build and install the whole desktop with our
compositor and session in it, which is what "fork COSMIC" ought to mean. The two
forks still install into /usr/libexec/hyprcosmic rather than over /usr/bin, so a
system that already has COSMIC from its distribution keeps that session on the
greeter's menu alongside this one.

Conflict resolutions worth stating:

  .github/workflows/ci.yml   upstream's kept as-is. It builds the entire desktop
                             on Arch through `just sysext`, which is precisely
                             the check a meta-repo wants and is not made less
                             useful by forking. Our per-distribution workflow
                             moved to hyprcosmic.yml beside it, the same way it
                             did in the compositor fork.

  .gitmodules                upstream's 29 entries, then two URLs rewritten.

  cosmic-comp, cosmic-session
                             ours. Git reports "no merge base" because they are
                             unrelated to the pop-os commits recorded here,
                             which is expected: they are different repositories,
                             not newer commits of the same one.

  .gitignore                 both sides, plus a note that the two forks are
                             deliberately no longer ignored.
2026-08-10 17:22:10 +07:00