nandi/jolt-nativepublic Fork 0
98daca12963d585049dc7c4cd5d6032343cc2be8
Commits
Clone
git clone https://git.rickub.com/nandi/jolt-native.git
git clone ssh://git@rickub.com/nandi/jolt-native.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Paint the rest of frq's tags in glimmer-cosmic 7703c75 · on 98daca12963d585049dc7c4cd5d6032343cc2be8 · nandi · 8d ago
README.md · 65 lines · 3.3 KBmarkdown
Blame HistoryOpen raw

glimmer-cosmic

The libcosmic backend for glimmer — a spike. The same hiccup that
glimmer-vidya paints with egui and glimmer-tui
paints in a terminal, painted with COSMIC's widgets and theme through
crates/jolt-cosmic.

cargo build --release -p jolt-cosmic
LD_LIBRARY_PATH=../../target/release jolt counter
LD_LIBRARY_PATH=../../target/release jolt smoke    # non-interactive, quits itself

What is the same

The tree half is glimmer-vidya's. Nodes are integer handles in a Rust arena,
props are written across by name, handlers stay on the jolt side and are found
by node id when an event comes back, and a widget writes its new value into its
own props so a control that ignores its event still works.

What is not: who owns the loop

egui lets its caller drive frames. libcosmic does not: cosmic::app::run takes
the main thread (winit insists) and keeps it until the window closes. So the
loop is inverted:

main thread      cosmic_run ──────────────────────────────────── returns on close
                     ▲ wake(tree)              │ click / change / toggled
worker (future)  mount → commit → wait ─ drain, dispatch, timers → commit → wait …
  • The reconciler runs on a worker, which is the "UI thread" as glimmer sees it:
    schedule queues onto it, handlers and timers run on it.
  • Its edits land in the arena under a mutex, but libcosmic paints a snapshot
    taken at cosmic_tree_commit, once per pass. A reconcile half-way through a
    patch is never on screen, and a pass that changed nothing commits nothing.
  • The worker sleeps in cosmic_wait until there is an event, a schedule, a
    due timer or a close — an idle window costs neither side anything.
  • Every call but cosmic_run is safe from any thread, which is not true of
    libvidya.

Spike limits

  • Tags: :window :box/:hbox/:vbox :page :card :frame :scroll
    :label :title :title-2 :dim-label :button :link :checkbutton
    :entry :separator :spacer :progress :status :spinner :image
    :avatar :emoji :reaction. Anything else paints as a column.
  • Layout follows glimmer-jvui: a container fills its parent's cross axis,
    :fill-height takes what is left, :width-request 0 is no request, and
    :margin/:margin-top:spacing :align are read.
  • :scroll fills both ways, follows new rows while :stick-to-bottom and the
    reader is at the end, jumps when :scroll-to-bottom changes, keeps its place
    by :scroll-key across a remount, reports "end"/"away" on :on-change,
    and moves to a row that sets :scroll-here — by the row's index, since there
    is no layout to ask, so it is close rather than exact in a list of rows of
    different heights.
  • Events: click, toggled, change, activate, hover, unhover.
  • Not yet: :image {:feed …} (live frames; the slot is drawn empty), a
    wrapping :hbox {:wrap true}, :on-rows :on-paste-empty :on-key on an
    entry, :max-rows (the entry is one line).
  • One window per process — winit cannot make a second event loop — so there is
    no REPL start!/stop! yet, and no headless test beyond the arena's own
    Rust tests.
  • libcosmic is MPL-2.0 and a git dependency; see crates/jolt-cosmic/Cargo.toml.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# glimmer-cosmic

The **libcosmic** backend for glimmer — a spike. The same hiccup that
[glimmer-vidya](../glimmer-vidya) paints with egui and [glimmer-tui](../glimmer-tui)
paints in a terminal, painted with COSMIC's widgets and theme through
[`crates/jolt-cosmic`](../../crates/jolt-cosmic).

```bash
cargo build --release -p jolt-cosmic
LD_LIBRARY_PATH=../../target/release jolt counter
LD_LIBRARY_PATH=../../target/release jolt smoke    # non-interactive, quits itself
```

## What is the same

The tree half is glimmer-vidya's. Nodes are integer handles in a Rust arena,
props are written across by name, handlers stay on the jolt side and are found
by node id when an event comes back, and a widget writes its new value into its
own props so a control that ignores its event still works.

## What is not: who owns the loop

egui lets its caller drive frames. libcosmic does not: `cosmic::app::run` takes
the main thread (winit insists) and keeps it until the window closes. So the
loop is inverted:

```
main thread      cosmic_run ──────────────────────────────────── returns on close
                     ▲ wake(tree)              │ click / change / toggled
worker (future)  mount → commit → wait ─ drain, dispatch, timers → commit → wait …
```

* The reconciler runs on a worker, which is the "UI thread" as glimmer sees it:
  `schedule` queues onto it, handlers and timers run on it.
* Its edits land in the arena under a mutex, but libcosmic paints a snapshot
  taken at `cosmic_tree_commit`, once per pass. A reconcile half-way through a
  patch is never on screen, and a pass that changed nothing commits nothing.
* The worker sleeps in `cosmic_wait` until there is an event, a `schedule`, a
  due timer or a close — an idle window costs neither side anything.
* Every call but `cosmic_run` is safe from any thread, which is not true of
  libvidya.

## Spike limits

* Tags: `:window` `:box`/`:hbox`/`:vbox` `:page` `:card` `:frame` `:scroll`
  `:label` `:title` `:title-2` `:dim-label` `:button` `:link` `:checkbutton`
  `:entry` `:separator` `:spacer` `:progress` `:status` `:spinner` `:image`
  `:avatar` `:emoji` `:reaction`. Anything else paints as a column.
* Layout follows glimmer-jvui: a container fills its parent's cross axis,
  `:fill-height` takes what is left, `:width-request 0` is no request, and
  `:margin`/`:margin-top``:spacing` `:align` are read.
* `:scroll` fills both ways, follows new rows while `:stick-to-bottom` and the
  reader is at the end, jumps when `:scroll-to-bottom` changes, keeps its place
  by `:scroll-key` across a remount, reports `"end"`/`"away"` on `:on-change`,
  and moves to a row that sets `:scroll-here` — by the row's index, since there
  is no layout to ask, so it is close rather than exact in a list of rows of
  different heights.
* Events: `click`, `toggled`, `change`, `activate`, `hover`, `unhover`.
* Not yet: `:image {:feed …}` (live frames; the slot is drawn empty), a
  wrapping `:hbox {:wrap true}`, `:on-rows` `:on-paste-empty` `:on-key` on an
  entry, `:max-rows` (the entry is one line).
* One window per process — winit cannot make a second event loop — so there is
  no REPL `start!`/`stop!` yet, and no headless test beyond the arena's own
  Rust tests.
* libcosmic is MPL-2.0 and a git dependency; see `crates/jolt-cosmic/Cargo.toml`.