Updates desktop shell and application code for cross-Qt compatibility: uses begin/endFilterChange for Qt 6.10+, gates LayerShell usage to Qt < 6.5, and adds include handling for generated QML type registration files so nebula-shell builds reliably. Also fixes qInfo size formatting casts and updates README commands to invoke run-sway-vm.sh via `sh` for more portable execution.
278 lines
7.5 KiB
Markdown
278 lines
7.5 KiB
Markdown
# 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
|
||
sh 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`.
|