Files
Nebula-OS/shells/desktop/README.md
T
andrew b0c95b9e78 Add desktop app service and VM dev session tooling
Introduces a new `core/applications` QML/C++ module (`Nebula.Applications`) to discover `.desktop` entries, expose filterable application models, and launch installed apps safely from the shell. The desktop launcher now uses real installed apps with themed icon loading and fallback glyphs, adds output-aware surface sizing via `OutputTracker`, and wires in image/icon providers. It also adds VMware-focused Sway/shell wrapper scripts, updates Sway config/session env defaults, and refreshes README docs to document the new development flow and Desktop 0.1 behavior.
2026-08-26 17:19:30 +12:00

278 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nebula Desktop
Production shell for the mouse-and-keyboard NebulaOS desktop. This is Nebula Desktop **0.1**: a usable session foundation, not only a visual prototype.
The user can enter the development session, use the full output, open the Nebula launcher, and start real installed applications (including Foot) without Sway keyboard shortcuts.
## Architecture
Nebula Desktop is a **Qt Quick / QML** Wayland shell. It draws system chrome only. It does not host application or game windows.
```text
Ubuntu
Wayland
Sway
temporary compositor
Nebula Shell
C++20 + Qt 6 + Qt Quick/QML + LayerShellQt
```
Eventual target:
```text
Ubuntu/Linux
Wayland
Nebula compositor
Nebula Shell
Qt Quick/QML
```
Normal applications remain ordinary Wayland / XWayland clients of the compositor:
```text
Nebula Launcher
ApplicationService
application process
Wayland / XWayland
Sway
```
Games, browsers, terminals, and other apps never pass through Qt Quick.
## Production stack
| Piece | Technology |
|-------|------------|
| Language | C++20 |
| UI | Qt 6, Qt Quick, QML |
| Layer surfaces | LayerShellQt |
| Installed apps | `core/applications` (`import Nebula.Applications`) |
| Build | CMake |
| Shared design system | `packages/nebula-ui` (`import Nebula.UI`) |
The executable is `nebula-shell`.
QML module URI: `Nebula.Shell`.
## Surfaces
Independent Wayland layer-shell windows:
| Surface | Layer | Role |
|---------|-------|------|
| Desktop | `BACKGROUND` | Fills the current output, no exclusive zone, no keyboard focus |
| Top Bar | `TOP` | 40 logical pixels, exclusive zone, spans the output width |
| Launcher | `OVERLAY` | Covers the output below the top bar while open; hidden otherwise |
Stacking:
```text
OVERLAY
Nebula Launcher
TOP
Nebula Top Bar
NORMAL WAYLAND WINDOWS
Foot, Firefox, applications, games, …
BACKGROUND
Nebula Desktop
```
Surfaces follow the live Wayland output geometry from Qt (`OutputTracker`). They do not assume 1920×1080 or other fixed desktop sizes. If VMware resizes the display, the shell updates.
## Applications
`core/applications` discovers freedesktop `.desktop` entries from XDG data directories:
1. `$XDG_DATA_HOME/applications` (default `~/.local/share/applications`)
2. `$XDG_DATA_DIRS/applications` (default `/usr/local/share:/usr/share`)
Launcher-visible apps respect `Hidden=true`, `NoDisplay=true`, `OnlyShowIn` / `NotShowIn`, and `TryExec` when present. Localized `Name` values are used when available.
Launching uses `QProcess::startDetached` after `QProcess::splitCommand`. Exec field codes (`%f`, `%F`, `%u`, `%U`, `%i`, `%c`, `%k`, `%%`, …) are handled for launches without file arguments. Desktop-entry strings are never passed to a shell.
Search matches name, generic name, comment, and categories. Searching `term` should find Foot (`GenericName=Terminal`). Searching `firefox` should find Firefox if it is installed.
Application icons use the system icon theme through Qt (`QIcon::fromTheme`). Unresolved icons use a Nebula fallback glyph, not a broken-image placeholder.
The top-bar context text stays **Desktop** in this milestone. Launching an app is not treated as focus; real window tracking comes next.
Mock launcher data remains only as a fallback when no installed applications are discovered.
## Layout
```text
shells/desktop/
├── README.md this file
├── shell/ production Qt/QML shell
│ ├── CMakeLists.txt
│ ├── src/
│ └── qml/
└── prototype-react/ archived design reference only
```
Shared visual language lives in `packages/nebula-ui`. Application discovery lives in `core/applications`.
## Linux build
This project will not compile on Windows. LayerShellQt is a Wayland API and is not stubbed.
On the Ubuntu NebulaOS VM:
```bash
sudo apt install \
qt6-base-dev \
qt6-declarative-dev \
qt6-wayland \
liblayershellqtinterface-dev \
qml6-module-org-kde-layershell \
qml6-module-qtquick \
qml6-module-qtquick-window \
adwaita-icon-theme \
cmake \
build-essential
```
Qt 6.4 or newer is required. `loadFromModule` is used on Qt 6.5+.
```bash
cd shells/desktop/shell
rm -rf build
cmake -S . -B build
cmake --build build -j$(nproc)
```
The production binary is `shells/desktop/shell/build/nebula-shell`. It does **not** force `QT_QUICK_BACKEND=software`. GPU-accelerated Qt Quick is the production default.
### QML lint
If the installed Qt provides `qmllint`:
```bash
qmllint \
shells/desktop/shell/qml/*.qml \
shells/desktop/shell/qml/surfaces/*.qml \
shells/desktop/shell/qml/components/*.qml \
shells/desktop/shell/qml/mock/*.qml \
packages/nebula-ui/qml/Nebula/UI/*.qml
```
Do not use ESLint or Oxlint on the production Qt shell.
## Development session (VMware)
From the repository root, the intended flow is:
```bash
sway -c compositor/sway/nebula-sway.conf
```
or, recommended on the VM (sets cursor env and starts Sway from the repo root):
```bash
./compositor/sway/dev/run-sway-vm.sh
```
That should:
1. start Sway without a Sway bar
2. autostart `nebula-shell` through `scripts/run-nebula-vm.sh`
3. fill the current output
4. show a normal Adwaita 24px cursor
5. let the Nebula launcher start Foot and other installed apps
Skip autostart while debugging the compositor:
```bash
NEBULA_SHELL_AUTOSTART=0 sway -c compositor/sway/nebula-sway.conf
```
### VMware software rendering
The VMware virtual GPU currently cannot run the Qt Quick accelerated path correctly. The **development wrapper** therefore sets:
```bash
QT_QUICK_BACKEND=software
```
That variable is not a production default. `scripts/run-nebula-vm.sh` is the only place that sets it automatically. Production `nebula-session` / `nebula-shell` must run GPU-accelerated.
Manual equivalent, if you start the shell yourself:
```bash
QT_QUICK_BACKEND=software ./build/nebula-shell
```
### Output / resolution
The development Sway config requests `1920x1080` at scale `1` when that mode exists. If the VM does not advertise it, Sway keeps the preferred mode. This is a development default, not a production requirement.
Inspect outputs and modes:
```bash
swaymsg -t get_outputs
```
Set a mode explicitly if needed:
```bash
swaymsg output <name> mode 1920x1080
swaymsg output <name> scale 1
```
In VMware, also set the guest display (or Autofit Guest) so the advertised modes match the host window.
### Cursor
Sway owns the cursor:
```text
XCURSOR_THEME=Adwaita
XCURSOR_SIZE=24
seat * xcursor_theme Adwaita 24
```
Install `adwaita-icon-theme` if the theme is missing. A branded Nebula cursor is a later task. `WLR_NO_HARDWARE_CURSORS=1` is set only by the VMware Sway wrapper.
### Emergency shortcuts
These remain for development fallback. They are not the normal UX once the GUI launcher works.
| Shortcut | Action |
|----------|--------|
| Super+Enter | open Foot |
| Super+Shift+E | exit Sway |
| Super+Shift+C | reload Sway config |
## Design reference
`prototype-react/` is an archived React/Vite UI. It is **not** the production shell. Keep it until the Qt shell reaches visual and behavioural parity, then remove it in a later cleanup.
## Out of scope
Not implemented in this milestone:
- Sway IPC / focused-window tracking
- workspaces, window overview, dock
- PipeWire, NetworkManager, BlueZ, UPower
- notifications, XDG portals, Polkit
- login/lock screen, greetd
- a custom Nebula compositor
- Nebula Bigscreen
- Gamescope
Those come later. Bigscreen is expected to reuse `Nebula.UI` and `Nebula.Applications`.