Introduce a Linux-only C++20 `nebula-shell` host built with CMake, GTK4, gtk4-layer-shell, and WebKitGTK 6.0. Add a shared `Surface` abstraction and concrete Desktop/TopBar/Launcher surfaces with layer placement, sizing, transparency, and per-surface `?surface=` URL loading. Add `ShellApplication` startup flow that validates `NEBULA_SHELL_DEV_URL`, checks layer-shell support, creates/presents desktop and top bar, and keeps launcher created but hidden for future bridge-driven toggling. Update the native README to document architecture, development setup, dependencies, and current milestone scope.
3.7 KiB
Nebula Desktop native host
nebula-shell hosts the React-based Nebula Desktop chrome as real Wayland Layer Shell surfaces.
It is a C++ process that creates several GTK4 windows, each backed by WebKitGTK 6.0 and placed with gtk4-layer-shell. It does not composite application windows. Those remain ordinary Wayland / XWayland clients of the compositor.
Stack:
- C++20
- GTK4
- gtk4-layer-shell
- WebKitGTK 6.0
- CMake
- Wayland
This host is Linux-only. It will not compile on Windows.
Purpose
Nebula Desktop's React UI is shell chrome only: wallpaper/desktop, top bar, and launcher. nebula-shell maps each of those to a Wayland layer surface so they sit in the compositor like a real desktop environment, not like a browser window.
Normal applications and games never render inside WebKit.
Architecture
Nebula Shell
├── DesktopSurface
│ ├── WebKitGTK
│ ├── ?surface=desktop
│ └── BACKGROUND
│
├── TopBarSurface
│ ├── WebKitGTK
│ ├── ?surface=topbar
│ └── TOP
│
└── LauncherSurface
├── WebKitGTK
├── ?surface=launcher
└── OVERLAY
| Surface | Query | Layer Shell layer | Placement |
|---|---|---|---|
| Desktop | ?surface=desktop |
BACKGROUND |
Anchored to all monitor edges |
| Top Bar | ?surface=topbar |
TOP |
Anchored top/left/right, 40px (matches the React top bar), exclusive zone enabled |
| Launcher | ?surface=launcher |
OVERLAY |
Created at startup, hidden/unmapped until later toggle work |
OVERLAY
Nebula Launcher ← created, currently unmapped
notifications
OSDs
TOP
Nebula Top Bar ← exclusive zone; apps do not go under it
NORMAL APPLICATION WINDOWS
Firefox, Steam, Blender, games, terminals, …
BACKGROUND
Nebula Desktop
wallpaper
React draws shell chrome only. Applications and games render through the compositor, not through WebKit:
App
↓
Wayland / XWayland
↓
Compositor
↓
GPU
Development
The host must not hardcode a Vite host or port. It reads a base origin from the environment and appends the surface query parameter.
Start the React UI (the port is an example, not part of the native architecture):
cd shells/desktop/ui
npm run dev -- --host 127.0.0.1 --port 5174 --strictPort
Point the shell at that origin:
export NEBULA_SHELL_DEV_URL=http://127.0.0.1:5174
That loads:
{NEBULA_SHELL_DEV_URL}/?surface=desktop
{NEBULA_SHELL_DEV_URL}/?surface=topbar
{NEBULA_SHELL_DEV_URL}/?surface=launcher
Build:
cd shells/desktop/native
cmake -S . -B build
cmake --build build -j$(nproc)
Run inside a Wayland compositor such as Sway:
./build/nebula-shell
On startup the desktop and top bar are presented. The launcher is created but left hidden.
A combined browser preview (/?surface=preview, also the default) is for Windows UI work only. The native host loads the three surfaces separately.
Linux packages
Build dependencies (install on the Ubuntu machine, not from this tree):
libgtk-4-dev
libgtk4-layer-shell-dev
libwebkitgtk-6.0-dev
pkg-config
cmake
build-essential
Production
Production loading from bundled shells/desktop/ui/dist files is not implemented yet. This milestone is development-URL loading only.
Shell bridge
Not implemented in this milestone. Each WebKit view will later talk to the host through a JavaScript bridge (shellBridge in the React UI) so the top bar can map and unmap LauncherSurface.
Current development compositor
Sway is the temporary compositor. See compositor/sway/nebula-sway.conf.