Commit Graph
8 Commits
Author SHA1 Message Date
gitops ce3083fad2 Patch D: install beside COSMIC, not over it
The binary went to $(bindir)/cosmic-comp, which is the distro's own
cosmic-comp. Installing this fork there replaces the compositor the stock
COSMIC session runs, and that makes installing HyprCosmic a one-way door: if
the fork fails to start, the session you would log into to fix it is now
running the same broken binary. It goes to $(libexecdir)/hyprcosmic instead,
which is where the hand-installed copy has been living all along -- this
teaches the Makefile the layout rather than inventing one.

Both sessions are meant to coexist. /usr/share/wayland-sessions holds
cosmic.desktop and hyprcosmic.desktop side by side, and the greeter offers
both; that only stays true while the two compositors occupy different paths.

The two .ron files move out of `install` for a related reason. They are
COSMIC's shared defaults, at paths the distro's cosmic-comp package already
owns, so a HyprCosmic package installing them would conflict with that package
over two files it has no reason to change -- and `uninstall` would have deleted
the stock session's keybindings on the way out. The fork reads the stock copies,
which costs nothing: a HyprCosmic session already needs the rest of COSMIC for
the greeter, the portals and the settings daemon. `install-defaults` keeps them
reachable for anyone building this fork without a COSMIC install to borrow from.

Verified by staging into a DESTDIR: the result is byte-identical to the copy
currently running from /usr/libexec/hyprcosmic/cosmic-comp.
2026-08-10 16:38:38 +07:00
gitops 6390f85eb6 Patch C: open a new window beside the focused one, not inside it
COSMIC's tiling tree is already N-ary -- `Data::Group` holds a `sizes:
Vec<i32>` and `add_window` divides by `sizes.len() + 1`, so three panes in
a row is perfectly representable. You just cannot get there by opening
windows. `map_to_tree` always wraps the focused window in a *new* group
whose orientation comes from that window's aspect ratio, so the second
window splits the screen into two columns, and the third one -- opening
into a column that is now taller than wide -- splits that column
horizontally. Quadrants. The limit was the insertion rule, not the shape
of the tree.

`preserve_split` makes the new window join the group the focused window
is already in, at the index right after it, keeping that group's
direction. Three windows land as three panes in a row, which is what
Hyprland's dwindle layout does with the option of the same name.

The insert is `move_current_node`'s idiom, minus the move: children and
`sizes` are positional, so the node goes in at `idx + 1` and
`add_window(idx + 1)` puts the size at the matching slot. Get those out
of step and every window in the group draws one slot over.

Off by default, so an unconfigured build still lays out like COSMIC.
HyprCosmic turns it on in cosmic.conf. It only affects where the next
window is inserted, never existing windows, so the config watcher just
pushes the flag down through `update_config` -- there is nothing to
retile.
2026-08-10 14:53:21 +07:00
gitops d58c55355c Patch B: name the sockets what clients open, and accept dispatch
The sockets were created as `.socket` and `.socket2`. Hyprland's are
`.socket.sock` and `.socket2.sock`, and every real client hardcodes those
names: waybar's hyprland/* modules, hyprctl, eww, ags. None of them fall back
and none of them say much when they fail -- waybar reports "Couldn't connect
to ... (3)" once at startup and then disables the module, so the whole symptom
is a bar with a workspace widget that never appears. The IPC was correct and
unreachable, which is the worst of both.

With the names fixed the read side is reachable, but a workspace you can see
and cannot click is only half a bar. So: a `dispatch` verb, deliberately the
smallest one that makes the bar work. `dispatch workspace N` switches, and
everything else is refused.

That refusal is the point. This socket is the surface any process able to open
it can use to drive the compositor, so the parser rejects rather than guesses:
`dispatch exec` is not implemented and never will be here, `killactive` is
not implemented, and an unparsed request gets no answer rather than being
treated as something near it.

Which is how the test earned its keep. `dispatch workspace +1` means "one to
the right" in Hyprland, and it was coming through as absolute workspace 1 --
because `u32::from_str` accepts a leading `+`. On workspace 1 that looks like
it worked. The target is now checked for digits before it is parsed, so every
relative form is rejected instead of silently mistranslated.
2026-08-10 12:58:15 +07:00
gitops 79834620ad Ignore .omc/ operational artifacts
Matches the parent repo and the cosmic-session fork. These are runtime
scratch files; one was committed by accident earlier in this project.
2026-08-10 08:26:02 +07:00
gitops 09eb1717c4 Patch B: drive the .socket2 event stream
Emits openwindow/closewindow/activewindow/workspace by diffing a state
snapshot from lib.rs's existing throttled refresh, rather than instrumenting
window map/unmap and focus-change sites across shell/. One call plus one new
file, so the fork stays rebasable against the ~46 upstream commits a month
those files see.

The snapshot walk is skipped entirely when nothing is subscribed to .socket2,
which is every tick when no bar is running. The baseline is still updated so
a newly-connected client does not receive a burst of openwindow events for
windows that were already open.

Ordering follows Hyprland: openwindow before the activewindow that usually
accompanies it, closewindow after, so a client tracking windows by address
never sees an activewindow for one it has not been told about.

Known trade-off: a window opening and closing inside one 150ms tick produces
no events. Hyprland would emit both.

9 new tests driving a real socketpair through the actual broadcast path.
22 hypr_ipc tests pass.

Runtime-verified nested: subscribing to .socket2 and opening a window yields
  openwindow>>1,1,foot,foot / activewindow>>foot,foot
  activewindow>>, / closewindow>>1
2026-08-10 07:59:08 +07:00
gitops 1de9027b07 Patch B: Hyprland-compatible IPC socket
Binds .socket (request/response) and .socket2 (event stream) under
$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE, so waybar's
hyprland/workspaces and hyprland/window modules work unmodified. Both
listeners register on the existing calloop loop following session.rs's
run_socket pattern; nothing spawns a thread touching compositor state.

Wiring the agent documented but did not apply:
  - lib.rs calls hypr_ipc::init before announcing readiness, so the signature
    is exported in time for get_env to pass it to children. Failure is
    non-fatal; only waybar's hyprland/* modules go dark.
  - Common gains an Option<HyprIpcHandle>, None until the sockets bind.
  - session.rs get_env forwards HYPRLAND_INSTANCE_SIGNATURE alongside
    WAYLAND_DISPLAY, which is how waybar finds the socket.

cargo check passes clean; 13 hypr_ipc unit tests pass, covering the JSON
field names, event-line formats and command parsing. Full lib suite: 14
passed, 0 failed.

NOT runtime-verified — no Wayland session available here, so nothing confirms
waybar actually consumes these sockets.

Event notifications are inert until notify_* is called from focus-change
sites; request/response works without that.
2026-08-10 07:44:29 +07:00
gitops 84bdd3b9df Patch A: zwlr_foreign_toplevel_management_v1
Implements the wlr foreign-toplevel management protocol on top of the
existing ToplevelInfoState/ToplevelManagementHandler, so waybar's wlr/taskbar
module works. cosmic-comp previously shipped only ext-foreign-toplevel-list,
which enumerates but cannot activate or close.

The wlr manager state is constructed alongside ForeignToplevelListState and
driven from the same new_toplevel/remove_toplevel/refresh hooks, so no
separate registration in state.rs is needed.

Accessors global_id and registered_toplevels moved to an unbounded impl
block: adding the wlr dispatch bounds to the shared impl made them viral and
broke overlap_notify.rs, which needs neither.

cargo check passes clean. NOT runtime-verified — no Wayland session here.
2026-08-09 23:07:10 +07:00
d 6ce5e75b0b Fork of pop-os/cosmic-comp @ upstream 2026-08-09 22:37:21 +07:00