429 lines
18 KiB
Markdown
429 lines
18 KiB
Markdown
|
|
# NeoCDE — Technical Architecture Plan
|
||
|
|
|
||
|
|
A modernized CDE (Common Desktop Environment) for Wayland, built on the WayRay compositor (`wrsrvd`) with its pluggable WM protocol.
|
||
|
|
|
||
|
|
## System Architecture
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────┐
|
||
|
|
│ wrsrvd (WayRay Compositor) │
|
||
|
|
│ • Rendering / encoding │
|
||
|
|
│ • Input dispatch │
|
||
|
|
│ • wayray_wm_v1 protocol server │
|
||
|
|
│ • wlr-layer-shell server │
|
||
|
|
│ • SSD decoration rendering (5.1) │
|
||
|
|
│ • Reads wrsrvd-theme.ron │
|
||
|
|
└──────┬──────────┬───────────────────┘
|
||
|
|
│ │
|
||
|
|
WM Protocol │ Layer-shell / xdg-shell
|
||
|
|
│ │
|
||
|
|
┌──────▼──────┐ ┌─▼──────────────────────────┐
|
||
|
|
│ neocde-wm │ │ NeoCDE Shell + Apps │
|
||
|
|
│ (wm client) │ │ • Front Panel (layer-shell) │
|
||
|
|
│ │ │ • Taskbar (layer-shell) │
|
||
|
|
│ • Layout │ │ • App Drawer (layer-shell) │
|
||
|
|
│ • Focus │ │ • File Manager (xdg-shell) │
|
||
|
|
│ • Keybinds │ │ • Terminal (xdg-shell) │
|
||
|
|
│ • Decor │ │ • Settings (xdg-shell) │
|
||
|
|
│ policy │ │ • Style Mgr (xdg-shell) │
|
||
|
|
└─────────────┘ └─────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
## Toolkit Decision: Slint + layer-shika
|
||
|
|
|
||
|
|
### Primary Stack
|
||
|
|
|
||
|
|
| Component | Technology |
|
||
|
|
|--------------------|-------------------------------------|
|
||
|
|
| Compositor | wrsrvd (WayRay — Smithay-based) |
|
||
|
|
| WM Client | Pure Rust: wayland-client + wayray-wm-protocol |
|
||
|
|
| Shell Components | Slint + layer-shika (SCTK-based) |
|
||
|
|
| Desktop Apps | Slint (standard xdg-shell via winit)|
|
||
|
|
| Design Tokens | TOML → codegen → .slint + .ron |
|
||
|
|
| Event Loop | calloop (via layer-shika) |
|
||
|
|
| GPU Rendering | femtovg (OpenGL ES 2.0) via layer-shika |
|
||
|
|
|
||
|
|
### Why Slint
|
||
|
|
|
||
|
|
1. **Design/code separation**: `.slint` markup files are a declarative DSL purpose-built for separating UI design from business logic. Designer AIs edit `.slint` files; code AIs edit `.rs` files. Hard boundary.
|
||
|
|
2. **Hot reload**: `slint-viewer --auto-reload` for design iteration without recompilation.
|
||
|
|
3. **Runtime interpreter**: `slint-interpreter` crate loads `.slint` files at runtime — AI can iterate on designs without triggering a build.
|
||
|
|
4. **Design token globals**: Slint's `export global Theme { ... }` maps directly to our Pencil design variables.
|
||
|
|
5. **Rust-native**: First-class Rust API, no C FFI or GObject complexity.
|
||
|
|
6. **License**: Royalty-free for desktop applications at no cost.
|
||
|
|
|
||
|
|
### Why Not Alternatives
|
||
|
|
|
||
|
|
- **libcosmic (COSMIC DE toolkit)**: Proven for desktop environments but tightly coupled to COSMIC's design system. No external design file separation — styling is in Rust code. Forking an entire DE toolkit to make it look like CDE is more work than building on Slint.
|
||
|
|
- **GTK4-rs / Relm4**: LGPL licensing requires dynamic linking. C-based with GObject complexity. CSS is looser than `.slint` for AI-driven design. GTK is opinionated about HIG — CDE aesthetics fight its design philosophy.
|
||
|
|
- **iced (vanilla)**: No built-in external style file system. Styling is entirely code-based.
|
||
|
|
- **egui**: Immediate-mode paradigm is wrong for persistent desktop shell UI.
|
||
|
|
- **Xilem/Masonry**: Pre-alpha, 1-2 years from production readiness.
|
||
|
|
|
||
|
|
## WM Architecture (neocde-wm)
|
||
|
|
|
||
|
|
The WM is a **pure protocol client** with zero GUI dependencies. It connects to `wrsrvd` via the `wayray_wm_v1` Wayland protocol.
|
||
|
|
|
||
|
|
**Dependencies**: `wayland-client`, `wayray-wm-protocol` only. No rendering libraries.
|
||
|
|
|
||
|
|
**Decoration policy**: The WM sends `use_ssd` to tell the compositor to render server-side decorations. The actual CDE Motif-style title bar/border rendering is 100% the compositor's responsibility (`wrsrvd` Phase 5.1). The WM never renders pixels.
|
||
|
|
|
||
|
|
**Two-phase transaction model** (from wayray_wm_v1):
|
||
|
|
- **Phase 1 — Manage**: Compositor sends `manage_start` → WM responds with `propose_dimensions`, `set_focus`, decoration choices, fullscreen grant/deny → WM calls `manage_done`
|
||
|
|
- **Phase 2 — Render**: After apps commit → compositor sends `render_start` → WM sends `set_position`, `set_z_top/bottom`, `show`/`hide` → WM calls `render_done` → atomic frame apply
|
||
|
|
|
||
|
|
**CDE-specific WM behaviors**:
|
||
|
|
- Click-to-focus, raise-on-focus
|
||
|
|
- CDE floating layout with centered initial placement
|
||
|
|
- Virtual desktops (workspace switching mapped to Front Panel buttons)
|
||
|
|
- Alt+F4 close, Alt+Tab window cycling
|
||
|
|
- Interactive move/resize via `wayray_wm_seat_v1`
|
||
|
|
|
||
|
|
## Shell Components (layer-shika)
|
||
|
|
|
||
|
|
Shell components are **layer-shell Wayland clients** rendered by Slint via layer-shika's SCTK-based platform backend.
|
||
|
|
|
||
|
|
### layer-shika (v0.3.1, Feb 2026)
|
||
|
|
|
||
|
|
Architecture:
|
||
|
|
- **domain**: Core models, port traits, zero external deps
|
||
|
|
- **adapters**: SCTK for Wayland, femtovg + EGL for rendering, Slint platform integration
|
||
|
|
- **composition**: Public API with builder patterns
|
||
|
|
|
||
|
|
Capabilities:
|
||
|
|
- Multi-surface layer shell windows (Front Panel + Taskbar = separate surfaces)
|
||
|
|
- Per-monitor instances (panel on every output)
|
||
|
|
- xdg-popup protocol (menus, tooltips)
|
||
|
|
- ext-session-lock-v1 (lock screen)
|
||
|
|
- HiDPI / fractional scaling
|
||
|
|
- Runtime `.slint` compilation via slint-interpreter
|
||
|
|
|
||
|
|
**License**: AGPL-3.0. NeoCDE shell components must be AGPL-3.0 compatible, or negotiate with the author, or write a custom SCTK-based Slint platform backend (~500 lines following their architecture).
|
||
|
|
|
||
|
|
### Shell Surfaces
|
||
|
|
|
||
|
|
| Component | Layer | Purpose |
|
||
|
|
|---------------|----------|--------------------------------------|
|
||
|
|
| Front Panel | bottom | Workspace buttons, app launchers, clock |
|
||
|
|
| Taskbar | top | Window list (via wlr-foreign-toplevel) |
|
||
|
|
| App Drawer | overlay | Application launcher grid |
|
||
|
|
| Lock Screen | overlay | ext-session-lock-v1 |
|
||
|
|
| Notifications | top | Desktop notifications |
|
||
|
|
|
||
|
|
## Design Token Pipeline
|
||
|
|
|
||
|
|
```
|
||
|
|
Pencil (.pen) ←── Designer AI / Pencil MCP edits here
|
||
|
|
│
|
||
|
|
│ export (pen-to-toml tool)
|
||
|
|
▼
|
||
|
|
tokens.toml ←── Canonical source of truth
|
||
|
|
│
|
||
|
|
├── build.rs codegen ──► theme.slint (shell + apps consume)
|
||
|
|
│
|
||
|
|
└── build.rs codegen ──► wrsrvd-theme.ron (compositor SSD rendering)
|
||
|
|
```
|
||
|
|
|
||
|
|
### tokens.toml (canonical format)
|
||
|
|
|
||
|
|
Maps directly from Pencil's 70+ design variables:
|
||
|
|
|
||
|
|
```toml
|
||
|
|
[metadata]
|
||
|
|
name = "neocde-glassy-workstation"
|
||
|
|
is_dark = true
|
||
|
|
|
||
|
|
[colors]
|
||
|
|
window-bg = "#1E2A3AE6"
|
||
|
|
window-bg-solid = "#1E2A3AFF"
|
||
|
|
window-border = "#3A5068FF"
|
||
|
|
surface-glass = "#1E2E4280"
|
||
|
|
surface-dark = "#0E1620FF"
|
||
|
|
surface-medium = "#1A2838FF"
|
||
|
|
surface-light = "#2A3E52FF"
|
||
|
|
title-bar-bg = "#2A3E55E6"
|
||
|
|
title-bar-text = "#B0C8DCFF"
|
||
|
|
color-primary = "#4A8B82FF"
|
||
|
|
color-primary-hover = "#5BB0A4FF"
|
||
|
|
accent = "#4A8A90FF"
|
||
|
|
accent-hover = "#5AA0A8FF"
|
||
|
|
color-accent = "#C16B58FF"
|
||
|
|
color-background = "#15171AFF"
|
||
|
|
color-frame = "#24282DFF"
|
||
|
|
color-terminal-bg = "#0D0E11FF"
|
||
|
|
color-input-bg = "#0D0E11E6"
|
||
|
|
text-primary = "#C8DDE8FF"
|
||
|
|
text-secondary = "#8AA4B8FF"
|
||
|
|
text-muted = "#5A7A90FF"
|
||
|
|
color-muted = "#8B949EFF"
|
||
|
|
color-text = "#E4E7EBFF"
|
||
|
|
button-bg = "#2A3E55CC"
|
||
|
|
button-border = "#3A5A78FF"
|
||
|
|
button-hover = "#3A5068CC"
|
||
|
|
taskbar-bg = "#141E2CE6"
|
||
|
|
color-panel-bg = "#202428A6"
|
||
|
|
color-surface = "#202428A6"
|
||
|
|
danger = "#C85050FF"
|
||
|
|
success = "#50A868FF"
|
||
|
|
color-folder = "#C8A868FF"
|
||
|
|
color-folder-shadow = "#8A7040FF"
|
||
|
|
color-divider = "#2A3040FF"
|
||
|
|
desktop-bg = "#0A1018FF"
|
||
|
|
scrollbar-thumb = "#3A5A78FF"
|
||
|
|
scrollbar-bg = "#1A2838FF"
|
||
|
|
input-bg = "#0E1A28E6"
|
||
|
|
input-border = "#2A4058FF"
|
||
|
|
divider = "#2A4058FF"
|
||
|
|
color-selection = "#4A8B8233"
|
||
|
|
color-highlight-border = "#FFFFFF0D"
|
||
|
|
color-shadow-inset-dark = "#00000066"
|
||
|
|
color-shadow-inset-light = "#FFFFFF0D"
|
||
|
|
color-scrollbar-thumb = "#4A8B82FF"
|
||
|
|
color-scrollbar-track = "#24282DFF"
|
||
|
|
|
||
|
|
[spacing]
|
||
|
|
xs = 4
|
||
|
|
sm = 8
|
||
|
|
md = 12
|
||
|
|
lg = 16
|
||
|
|
xl = 24
|
||
|
|
|
||
|
|
[corner-radii]
|
||
|
|
sm = 3
|
||
|
|
md = 6
|
||
|
|
lg = 8
|
||
|
|
panel = 16
|
||
|
|
inner = 0
|
||
|
|
outer = 4
|
||
|
|
window = 8
|
||
|
|
|
||
|
|
[typography]
|
||
|
|
font-ui = "IBM Plex Sans"
|
||
|
|
font-mono = "IBM Plex Mono"
|
||
|
|
font-main = "IBM Plex Mono"
|
||
|
|
|
||
|
|
[typography.sizes]
|
||
|
|
xs = 12
|
||
|
|
sm = 14
|
||
|
|
md = 13
|
||
|
|
body = 15
|
||
|
|
lg = 20
|
||
|
|
xl = 28
|
||
|
|
clock = 14
|
||
|
|
|
||
|
|
[dimensions]
|
||
|
|
title-bar-height = 32
|
||
|
|
front-panel-height = 80
|
||
|
|
menu-bar-height = 28
|
||
|
|
status-bar-height = 24
|
||
|
|
icon-size = 64
|
||
|
|
scrollbar-width = 16
|
||
|
|
border-width = 1
|
||
|
|
border-thick = 8
|
||
|
|
```
|
||
|
|
|
||
|
|
### Generated theme.slint
|
||
|
|
|
||
|
|
```slint
|
||
|
|
// Auto-generated from tokens.toml — do not hand-edit
|
||
|
|
export global Theme {
|
||
|
|
// Colors
|
||
|
|
in-out property<color> window-bg: #1E2A3AE6;
|
||
|
|
in-out property<color> surface-glass: #1E2E4280;
|
||
|
|
in-out property<color> title-bar-bg: #2A3E55E6;
|
||
|
|
in-out property<color> title-bar-text: #B0C8DCFF;
|
||
|
|
in-out property<color> color-primary: #4A8B82FF;
|
||
|
|
in-out property<color> text-primary: #C8DDE8FF;
|
||
|
|
in-out property<color> text-secondary: #8AA4B8FF;
|
||
|
|
in-out property<color> button-bg: #2A3E55CC;
|
||
|
|
in-out property<color> button-border: #3A5A78FF;
|
||
|
|
// ... all color tokens
|
||
|
|
|
||
|
|
// Spacing
|
||
|
|
in-out property<length> spacing-xs: 4px;
|
||
|
|
in-out property<length> spacing-sm: 8px;
|
||
|
|
in-out property<length> spacing-md: 12px;
|
||
|
|
in-out property<length> spacing-lg: 16px;
|
||
|
|
in-out property<length> spacing-xl: 24px;
|
||
|
|
|
||
|
|
// Corner radii
|
||
|
|
in-out property<length> corner-sm: 3px;
|
||
|
|
in-out property<length> corner-md: 6px;
|
||
|
|
in-out property<length> corner-lg: 8px;
|
||
|
|
in-out property<length> corner-panel: 16px;
|
||
|
|
in-out property<length> corner-window: 8px;
|
||
|
|
|
||
|
|
// Dimensions
|
||
|
|
in-out property<length> title-bar-height: 32px;
|
||
|
|
in-out property<length> front-panel-height: 80px;
|
||
|
|
in-out property<length> menu-bar-height: 28px;
|
||
|
|
in-out property<length> status-bar-height: 24px;
|
||
|
|
in-out property<length> icon-size: 64px;
|
||
|
|
in-out property<length> scrollbar-width: 16px;
|
||
|
|
|
||
|
|
// Typography
|
||
|
|
in-out property<string> font-ui: "IBM Plex Sans";
|
||
|
|
in-out property<string> font-mono: "IBM Plex Mono";
|
||
|
|
in-out property<length> font-size-xs: 12px;
|
||
|
|
in-out property<length> font-size-sm: 14px;
|
||
|
|
in-out property<length> font-size-md: 13px;
|
||
|
|
in-out property<length> font-size-body: 15px;
|
||
|
|
in-out property<length> font-size-lg: 20px;
|
||
|
|
in-out property<length> font-size-xl: 28px;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Generated wrsrvd-theme.ron (for compositor SSD)
|
||
|
|
|
||
|
|
```ron
|
||
|
|
NeoCdeDecorations((
|
||
|
|
title_bar: (
|
||
|
|
height: 32,
|
||
|
|
bg: (red: 0.165, green: 0.243, blue: 0.333, alpha: 0.902),
|
||
|
|
text: (red: 0.690, green: 0.784, blue: 0.863, alpha: 1.0),
|
||
|
|
font: "IBM Plex Sans",
|
||
|
|
font_size: 13,
|
||
|
|
),
|
||
|
|
border: (
|
||
|
|
color: (red: 0.227, green: 0.353, blue: 0.471, alpha: 1.0),
|
||
|
|
width: 1,
|
||
|
|
corner_radius: 8,
|
||
|
|
),
|
||
|
|
buttons: (
|
||
|
|
close: (bg: (red: 0.784, green: 0.314, blue: 0.314, alpha: 1.0)),
|
||
|
|
minimize: (bg: (red: 0.165, green: 0.243, blue: 0.333, alpha: 0.8)),
|
||
|
|
maximize: (bg: (red: 0.165, green: 0.243, blue: 0.333, alpha: 0.8)),
|
||
|
|
),
|
||
|
|
))
|
||
|
|
```
|
||
|
|
|
||
|
|
## AI Workflow Model
|
||
|
|
|
||
|
|
### Separation of Concerns
|
||
|
|
|
||
|
|
```
|
||
|
|
Designer AI (Pencil MCP, Slint editor) Code AI (Rust)
|
||
|
|
───────────────────────────────────── ──────────────────────
|
||
|
|
Edits: Edits:
|
||
|
|
designs/*.pen */src/**/*.rs
|
||
|
|
tokens/tokens.toml Cargo.toml, Cargo.lock
|
||
|
|
*/ui/**/*.slint build.rs
|
||
|
|
|
||
|
|
Never touches: Never touches:
|
||
|
|
*.rs *.slint
|
||
|
|
Cargo.toml *.pen
|
||
|
|
tokens.toml
|
||
|
|
```
|
||
|
|
|
||
|
|
### Two Runtime Modes
|
||
|
|
|
||
|
|
| Mode | Use Case | How .slint is loaded | Trade-off |
|
||
|
|
|------|----------|---------------------|-----------|
|
||
|
|
| **Compiled** (production) | Release builds | `build.rs` → `slint_build::compile()` → `slint::include_modules!()` | Type-safe, fast startup, AOT |
|
||
|
|
| **Interpreted** (design iteration) | AI design workflow | `slint_interpreter::Compiler::build_from_path()` | Hot reload, no recompilation, string-keyed properties |
|
||
|
|
|
||
|
|
## Wayland Protocols Required
|
||
|
|
|
||
|
|
| Protocol | Purpose | Priority |
|
||
|
|
|------------------------------------|--------------------------------|----------|
|
||
|
|
| wayray_wm_v1 | WM ↔ compositor (custom) | Critical |
|
||
|
|
| wlr-layer-shell-v1 | Panel, taskbar, overlays | Critical |
|
||
|
|
| xdg-shell | Application windows | Critical |
|
||
|
|
| xdg-decoration | Server-side CDE window chrome | Critical |
|
||
|
|
| wlr-foreign-toplevel-management | Taskbar window list | Critical |
|
||
|
|
| ext-session-lock-v1 | Lock screen | High |
|
||
|
|
| wlr-output-management | Display settings | High |
|
||
|
|
| wp-fractional-scale | HiDPI support | High |
|
||
|
|
| xdg-activation-v1 | Focus management | Medium |
|
||
|
|
| wp-idle-inhibit | Screensaver prevention | Medium |
|
||
|
|
| wlr-data-control | Clipboard manager | Medium |
|
||
|
|
| ext-idle-notify | Screensaver triggering | Low |
|
||
|
|
|
||
|
|
## Dependencies (target versions, early 2026)
|
||
|
|
|
||
|
|
| Crate | Version | Used By |
|
||
|
|
|---------------------------|---------------|-------------------|
|
||
|
|
| slint | 1.14+ | Shell + Apps |
|
||
|
|
| slint-interpreter | 1.14+ | AI design workflow|
|
||
|
|
| slint-build | 1.14+ | build.rs codegen |
|
||
|
|
| layer-shika | 0.3+ (git) | Shell surfaces |
|
||
|
|
| smithay-client-toolkit | 0.20 | Wayland protocols |
|
||
|
|
| wayland-client | 0.31+ | WM client |
|
||
|
|
| calloop | 0.14+ | Event loop |
|
||
|
|
| toml | 0.8+ | Token parsing |
|
||
|
|
| ron | 0.8+ | RON generation |
|
||
|
|
| serde | 1.x | Serialization |
|
||
|
|
|
||
|
|
## Project Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
neocde/
|
||
|
|
├── designs/
|
||
|
|
│ └── untitled.pen # Pencil source of truth
|
||
|
|
├── images/
|
||
|
|
│ └── *.png # Reference imagery
|
||
|
|
├── tokens/
|
||
|
|
│ ├── tokens.toml # Canonical design tokens
|
||
|
|
│ ├── pen-to-toml/ # Tool: .pen export → tokens.toml
|
||
|
|
│ │ ├── Cargo.toml
|
||
|
|
│ │ └── src/main.rs
|
||
|
|
│ └── token-codegen/ # Shared codegen library
|
||
|
|
│ ├── Cargo.toml
|
||
|
|
│ └── src/lib.rs # generate_slint(), generate_ron()
|
||
|
|
├── neocde-wm/ # WM client (zero GUI deps)
|
||
|
|
│ ├── Cargo.toml # wayland-client, wayray-wm-protocol
|
||
|
|
│ └── src/
|
||
|
|
│ ├── main.rs
|
||
|
|
│ ├── layout.rs # CDE floating layout
|
||
|
|
│ ├── focus.rs # Click-to-focus, raise-on-focus
|
||
|
|
│ ├── keybinds.rs # Alt+F4, Alt+Tab, workspaces
|
||
|
|
│ ├── workspaces.rs # Virtual desktops
|
||
|
|
│ └── config.rs # WM config (TOML)
|
||
|
|
├── neocde-shell/ # Shell (layer-shika + Slint)
|
||
|
|
│ ├── Cargo.toml # slint, layer-shika, sctk
|
||
|
|
│ ├── build.rs # tokens.toml → theme.slint
|
||
|
|
│ ├── ui/ # DESIGNER AI TERRITORY
|
||
|
|
│ │ ├── theme.slint # Generated from tokens
|
||
|
|
│ │ ├── components/
|
||
|
|
│ │ │ ├── button.slint
|
||
|
|
│ │ │ ├── window-chrome.slint # CSD fallback
|
||
|
|
│ │ │ ├── input.slint
|
||
|
|
│ │ │ ├── tab-bar.slint
|
||
|
|
│ │ │ ├── menu-bar.slint
|
||
|
|
│ │ │ ├── scrollbar.slint
|
||
|
|
│ │ │ └── status-bar.slint
|
||
|
|
│ │ ├── front-panel.slint # CDE Front Panel
|
||
|
|
│ │ ├── taskbar.slint # Window list + clock
|
||
|
|
│ │ └── app-drawer.slint # App launcher
|
||
|
|
│ └── src/ # CODE AI TERRITORY
|
||
|
|
│ ├── main.rs
|
||
|
|
│ ├── panel.rs
|
||
|
|
│ ├── taskbar.rs
|
||
|
|
│ ├── clock.rs
|
||
|
|
│ └── launcher.rs
|
||
|
|
├── neocde-filemanager/ # App (Slint, xdg-shell)
|
||
|
|
│ ├── Cargo.toml
|
||
|
|
│ ├── build.rs
|
||
|
|
│ ├── ui/
|
||
|
|
│ │ └── file-manager.slint
|
||
|
|
│ └── src/
|
||
|
|
│ ├── main.rs
|
||
|
|
│ └── filesystem.rs
|
||
|
|
├── neocde-terminal/ # App (custom GPU or Slint)
|
||
|
|
├── neocde-settings/ # App (Slint)
|
||
|
|
│ ├── ui/
|
||
|
|
│ │ └── style-manager.slint
|
||
|
|
│ └── src/
|
||
|
|
└── Cargo.toml # Workspace root
|
||
|
|
```
|
||
|
|
|
||
|
|
## Build Order
|
||
|
|
|
||
|
|
1. **token-codegen** — build.rs library: tokens.toml → theme.slint + wrsrvd-theme.ron
|
||
|
|
2. **neocde-shell (Front Panel only)** — proves: Pencil tokens → TOML → Slint → layer-shell → WayRay
|
||
|
|
3. **neocde-wm** — connect to wrsrvd, CDE floating layout, `use_ssd`
|
||
|
|
4. **neocde-shell (Taskbar)** — second layer-shika surface, foreign-toplevel window list
|
||
|
|
5. **neocde-filemanager** — first standard Slint app (xdg-shell)
|
||
|
|
6. **neocde-settings / Style Manager** — theme editor that writes back to tokens.toml
|
||
|
|
7. **neocde-terminal** — may need custom renderer for terminal grid performance
|