Pod maską
Architektura
Sześć crate'ów, jeden kierunek zależności i jeden kontrakt rysowania. libLuna nie próbuje odtworzyć GTK — próbuje być wystarczająco mała, żeby dało się ją objąć wzrokiem i naprawić.
Nazwy warstw
| Warstwa | Odpowiednik GNOME | Odpowiednik KDE | Luna |
|---|---|---|---|
| Toolkit | GTK | Qt | libLuna |
| Środowisko / powłoka | GNOME | KDE Plasma | Luna |
| Kompozytor Wayland | Mutter | KWin | Selene |
Dokumentacja dotyczy libLuny, ale architektura całego projektu ma sens tylko razem: aplikacja rysuje libLuną, mówi standardowym Waylandem, a Selene przyjmuje okna i zarządza ekranem.
Mapa crate'ów
libluna
re-eksport warstw + prelude
libluna-core
geometria · kolor · zdarzenia · motyw · tokeny
libluna-render
scena · tekst · SVG · backend CPU
libluna-platform
Wayland · okna · wejście · schowek
libluna-widgets · libluna-i18n
77 widgetów · layout · tłumaczenia
Zależności idą tylko w dół. Widgety nie wiedzą, jak działa DRM. Platforma nie wie, jak narysować przycisk. Motyw nie wie, kto go używa.
Rysowanie i tekst
Graf sceny
libluna-render::scene to lista DrawCommand niezależna od backendu. Widgety budują scenę, nie dotykając pikseli.
Backend CPU
tiny-skia rasteryzuje kształty z antyaliasingiem; bufor RGBA8888 trafia przez wl_shm.
Tekst
fontdue + font systemowy. Dziś bez kerningu i pism złożonych; docelowo cosmic-text bez zmiany kontraktu.
Ikony
SVG rasteryzowane przez resvg (bez tekstu i rastrów) oraz zestaw pastelowych ikon wektorowych.
Rozdzielenie sceny od backendu pozwala dodać GPU (EGL/dmabuf) bez zmian w widgetach. To także powód, dla którego testy można robić bez okna: scenę da się porównać lub wyrenderować do PNG.
Model widgetu
Docelowy model jest retencyjny, ale kontrakt rysowania pozostaje immediate:
Widget:
measure(constraints) -> Size // ile chce
allocate(rect) // gdzie trafia
paint(scene, theme) // rysowanie
hit(event) -> Handled | Propagate // wejście
focus / grab / hover
Dziś layout jest osobnym drzewem Node z dwoma przebiegami measure/allocate, a widgety pozostają liśćmi z metodami paint i *_at. Dzięki temu można używać ich ręcznie (jak w demo) albo przez layout.
Komunikacja z kompozytorem
| Przypadek | Protokół | W libLunie |
|---|---|---|
| Zwykłe okno aplikacji | xdg-shell + CSD | AppConfig::new(...), własny HeaderBar. |
| Panel / dock / tło | wlr-layer-shell | AppConfig::layer(LayerConfig::top_panel(...)). |
| OSD / powiadomienia | wlr-layer-shell overlay | LayerConfig::overlay(...), przezroczystość. |
| Ekran blokady | overlay + klawiatura wyłączna | LayerConfig::lock_screen(...). |
| Schowek | wl_data_device | Frame::copy_to_clipboard / paste_from_clipboard. |
Brak backendu X11 po stronie klienta. XWayland obsługuje okna aplikacji X11 w Selene, ale nowa aplikacja libLuny mówi natywnie Waylandem.
Motywowanie
Tokeny są w libluna-core::style: spacing, radius, typografia, metryki kontrolek i paleta. Widgety czytają je w paint i layout, więc styl zmienia geometrię, nie tylko kolory.
// 1. wariant
frame.set_preference(ThemePreference::Dark);
// 2. akcent
frame.set_accent(Accent::Teal);
// 3. styl z pliku (kolory + geometria)
frame.set_style(Some("nord".into()));
Szczegóły: Motywy i tokeny.
Świadomie odłożone
Dostępność AT-SPI
Ważna dla realnego pulpitu, ale wymaga mostka D-Bus i drzewa dostępności. Zaplanowana później.
IME / text-input-v3
Wygodne wpisywanie CJK i klawiatura wirtualna. Dziś podstawowe zdarzenia tekstowe działają.
GPU / dmabuf
Zero-copy dla klientów Vulkan/EGL. Dziś render jest CPU, ale kontrakt sceny pozostaje.
Fractional scaling
HiDPI bez rozmycia. Skala jest już w Frame::scale i Scale.
Drag & drop
Schowek działa; DnD między aplikacjami jest późniejszy.
xdg_activation
Nowe okno czasem trzeba znaleźć za innym. Protokół jest w planach Selene.
Repozytorium i budowanie
# cały projekt
make build
make test
# tylko libLuna
cd libluna
cargo test --workspace
cargo doc --no-deps
# demo i galeria
cargo run --manifest-path apps/luna-demo/Cargo.toml --bin gallery
cargo run --manifest-path apps/luna-demo/Cargo.toml --bin render -- docs/images/out.png
Każdy katalog jest osobnym workspace'em Cargo z własnym Cargo.lock. Meta-repo tylko orchestruje build. Więcej o wydaniach: docs/repositories.md.