diff --git a/CONFIG.md b/CONFIG.md index fe22d5297..67173401c 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -1,18 +1,27 @@ -# Noctalia Configuration +# Configuration -Config file: `$XDG_CONFIG_HOME/noctalia/config.toml` (defaults to `~/.config/noctalia/config.toml`) +Noctalia has two configuration layers: -Changes are hot-reloaded via inotify — no restart required. +- Declarative user config lives in `$XDG_CONFIG_HOME/noctalia/` or `~/.config/noctalia/`. + Noctalia reads every `*.toml` file in that directory, sorted alphabetically, and deep-merges them into one config. + A single `config.toml` is the simplest setup, but splitting config into files such as `bar.toml`, `theme.toml`, + or `widgets.toml` is also supported. +- GUI-managed overrides live in `$XDG_STATE_HOME/noctalia/settings.toml` or + `~/.local/state/noctalia/settings.toml`. This file is written by Noctalia itself for settings changed through the + UI, IPC-backed controls, setup flows, and other runtime actions that need persistence. -A ready-to-use starting config with all defaults is at [`example.toml`](example.toml). +Load order is built-in defaults first, then declarative config files, then `settings.toml`. +Because the state file is applied last, GUI overrides win over matching values in `config.toml`. -Notification daemon toggle: use `[notification].enable_daemon` (documented in [`config/services.md`](config/services.md)). -Weather location visibility toggle: use `[shell].show_location` (documented in [`config/shell.md`](config/shell.md)). -Wallpaper automation: use `[wallpaper.automation]` (documented in [`config/wallpaper.md`](config/wallpaper.md)). -Wallpaper single-color fallback/fill: use `[wallpaper].fill_color` (documented in [`config/wallpaper.md`](config/wallpaper.md)). -Bar creation order: use `[bar].order` (documented in [`config/bar.md`](config/bar.md)). +Use the declarative config directory for hand-authored, dotfile-managed configuration. Treat `settings.toml` as an +app-managed override layer: inspect or delete it when you want to understand or clear GUI changes, but do not rely on +it as the primary place for curated config. Keeping the override file outside `~/.config` also allows the GUI to save +changes when the config directory is read-only, such as on NixOS. ---- +Both layers are watched for changes and hot-reloaded. If neither declarative config nor state overrides exist, +Noctalia falls back to built-in defaults in code. + +A ready-to-use starting config with all defaults is at [example.toml](example.toml). ## Reference @@ -20,9 +29,11 @@ Bar creation order: use `[bar].order` (documented in [`config/bar.md`](config/ba |---------|-------------| | [Bar](config/bar.md) | Bar layout, per-monitor overrides, auto-hide, widget capsule styling | | [Widgets](config/widgets.md) | Widget definitions and all built-in widget types | -| [Dock](config/dock.md) | Application dock — pinned apps, auto-hide, IPC | -| [Desktop Widgets](config/desktop-widgets.md) | Desktop overlay widgets — edit mode, state file format | -| [Wallpaper](config/wallpaper.md) | Wallpaper picker and overview backdrop | -| [Theme](config/theme.md) | Color schemes, modes, wallpaper-derived palettes, app templates | -| [Services](config/services.md) | Audio, Sound cues, Brightness, Night Light, Weather, Idle, Notifications | -| [Shell](config/shell.md) | Global UI settings, OSD, Keybinds, Hooks | +| [Scripted Widgets](config/scripted-widgets.md) | Custom Luau-driven bar widgets | +| [Dock](config/dock.md) | Application dock, pinned apps, auto-hide, IPC | +| [Desktop Widgets](config/desktop-widgets.md) | Desktop overlay widgets, edit mode, state file format | +| [Wallpaper](config/wallpaper.md) | Wallpaper picker, overview backdrop, automation | +| [Theme](config/theme.md) | Color schemes, modes, wallpaper-derived palettes | +| [Theming Templates](config/theming-templates.md) | App theme template generation and export paths | +| [Services](config/services.md) | Audio, sound cues, brightness, night light, weather, idle, notifications | +| [Shell](config/shell.md) | Global UI settings, OSD, keybinds, hooks | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6495c8839 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,175 @@ +Contributing +=== + +This file collects contributor-facing details for Noctalia: design goals, stack notes, code style, source layout, +runtime asset behavior, and debugging helpers. + +For dependencies and normal build commands, start with [README.md](README.md). + +## Design Principles + +- Direct Wayland + OpenGL ES only -- no toolkit overhead +- Minimal scene graph, domain-specific to shell UI +- Packaging should work across all major Linux distros: Arch, NixOS, Fedora, Gentoo, Debian, Void, OpenSuse + +## Stack + +| Layer | Library | +|-------|---------| +| Wayland core | `libwayland-client`, `wayland-scanner`, `wayland-protocols` | +| Surfaces | `xdg-shell`, `zwlr-layer-shell-v1` | +| Multi-monitor | `zxdg-output-unstable-v1` | +| Active window metadata | `zwlr-foreign-toplevel-management-unstable-v1` | +| Workspaces | `ext-workspace-v1`, `dwl-ipc-unstable-v2` | +| Clipboard | `ext-data-control-v1`, `wlr-data-control-unstable-v1` | +| Activation | `xdg-activation-v1` | +| Lockscreen | `ext-session-lock-v1` | +| Idle | `ext-idle-notify-v1`, `idle-inhibit-unstable-v1` | +| Cursor | `wp-cursor-shape-v1` | +| Keyboard | `xkbcommon` | +| Rendering | `EGL`, `OpenGL ES 3`, `wayland-egl` | +| Text | `cairo`, `pango`, `pangocairo`, `freetype`, `fontconfig` | +| Images | `Wuffs` (vendored), `nanosvg` (vendored), `stb_image_resize2` (vendored), `libwebp` | +| IPC | `sdbus-c++` | +| Audio | `libpipewire`, `dr_wav` (vendored) | +| Authentication | `PAM` | +| HTTP | `libcurl` | +| Config | `tomlplusplus` (vendored) | +| JSON | `nlohmann/json` (vendored) | +| Math expressions | `tinyexpr` (vendored) | +| Scripting | `Luau` (vendored) | +| Theme generation | Material Color Utilities (vendored) | + +## Runtime Assets + +`meson install` installs the binary and shipped assets separately using the normal prefix layout: + +```text +/usr/local/bin/noctalia +/usr/local/share/noctalia/assets/... +``` + +With a different Meson `prefix`/`datadir`, the same structure is preserved under that prefix. + +Noctalia needs the `assets/` tree at runtime. Copying only the bare `noctalia` binary is not enough. + +Portable bundle layouts are also supported: + +```text +bundle/ + noctalia + assets/ +``` + +```text +bundle/ + bin/noctalia + share/noctalia/assets/ +``` + +Runtime asset lookup order: + +1. `NOCTALIA_ASSETS_DIR` +2. `assets/` next to the executable +3. `assets/` one level above the executable +4. install-style `../share/noctalia/assets` relative to the executable +5. the compiled install path from Meson (`//noctalia/assets`) +6. the source-tree `assets/` directory as a development fallback + +An asset root is only accepted if it contains the expected shipped files such as `emoji.json`, `fonts/tabler.ttf`, +`templates/builtin.toml`, and `translations/en.json`. + +## Code Style + +This project uses [clang-format](https://clang.llvm.org/docs/ClangFormat.html) for formatting. Run `just format` +before committing. + +### Naming Conventions + +| | Convention | Example | +|---|---|---| +| Files | snake_case | `widget_factory.cpp` | +| Directories | snake_case | `shell/widgets/` | +| Types / Classes | PascalCase | `WidgetFactory` | +| Functions / Methods | camelCase | `createWidget()` | +| Variables / Parameters | camelCase | `busName` | +| Private members | m_camelCase | `m_changeCallback` | +| Macros / Enum values | SCREAMING_SNAKE_CASE | `MAX_SIZE` | + +D-Bus wire-protocol string literals, such as `player["bus_name"]`, stay snake_case because they are wire names, not +C++ identifiers. + +## Project Layout + +```text +src/ + main.cpp Entry point + app/ Application bootstrap, main loop + auth/ PAM authentication (lockscreen) + config/ Configuration and state persistence (TOML) + core/ Logger, timer manager, shared utilities + dbus/ DBus service implementations + debug/ Debug service (runtime log toggling) + idle/ Idle manager and inhibitor + ipc/ IPC client/service (dev.noctalia.* commands) + launcher/ Launcher providers (apps, emoji, math, usage) + net/ HTTP client (libcurl) + notification/ Notification manager + pipewire/ PipeWire audio service and spectrum analyzer + render/ + animation/ Animation manager and easing + core/ EGL/GLES renderer, image decoders + programs/ Shader programs per NodeType + scene/ Scene graph nodes (Rect, Text, Image, Icon, InputArea, ...) + text/ Cairo/Pango text rendering + shell/ + bar/ Bar surface and instance + clipboard/ Clipboard history panel + control_center/ Control center panel and tabs + launcher/ Application launcher panel + lockscreen/ Session lockscreen surface + notification/ Notification popup + osd/ On-screen display (volume, brightness, ...) + overview/ Workspace overview + panel/ Panel base and manager + session/ Session menu (logout, reboot, ...) + tray/ System tray (StatusNotifierItem) + wallpaper/ Wallpaper surface and instance + widget/ Widget base and factory + widgets/ Widget implementations + system/ System monitor (CPU, RAM, temperature) + time/ Time service and polling + ui/ + controls/ Low-level UI building blocks (Button, Input, Label, Flex, ...) + util/ Generic helpers (fuzzy matching, ...) + wayland/ Wayland connection, seat, toplevels, clipboard, ... + compositors/ Compositor-specific workspace backends (ext-workspace, sway, mango, dwl, ...) +third_party/ + tomlplusplus/ TOML parser (vendored) + wuffs/ Raster image decoding (vendored) + nanosvg/ SVG rasterization (vendored) + stb/ Image resizing (vendored) + tinyexpr/ Math expression evaluator (vendored) + nlohmann/ JSON parser (vendored, header-only) + dr_wav/ WAV decoder (vendored) + luau/ Scripted widget runtime (vendored) + material_color_utilities/ Material Design color generation (vendored) +``` + +## Debugging + +All debug commands use the `dev.noctalia.Debug` D-Bus service, available at runtime. + +```sh +# Enable verbose debug logs +gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.SetVerboseLogs true + +# Disable verbose debug logs +gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.SetVerboseLogs false + +# Check current verbose log state +gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.GetVerboseLogs + +# Emit an internal notification (app_name, summary, body, timeout_ms, urgency 0-2) +gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.EmitInternalNotification "Noctalia" "Test" "Hello from debug" 5000 1 +``` diff --git a/README.md b/README.md index 6531529bd..79ace8055 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,9 @@ Noctalia === -A lightweight Wayland shell and bar with no Qt or GTK dependency. +A lightweight Wayland shell and bar built directly on Wayland + OpenGL ES, with no Qt or GTK dependency. -## Design Principles - -- Direct Wayland + OpenGL ES only -- no toolkit overhead -- Minimal scene graph, domain-specific to shell UI -- Packaging should work across all major Linux distros: Arch, NixOS, Fedora, Gentoo, Debian, Void, OpenSuse - -## Stack - -| Layer | Library | -|-------|---------| -| Wayland core | `libwayland-client`, `wayland-scanner`, `wayland-protocols` | -| Surfaces | `xdg-shell`, `zwlr-layer-shell-v1` | -| Multi-monitor | `zxdg-output-unstable-v1` | -| Active window metadata | `zwlr-foreign-toplevel-management-unstable-v1` | -| Workspaces | `ext-workspace-v1`, `dwl-ipc-unstable-v2` | -| Clipboard | `ext-data-control-v1`, `wlr-data-control-unstable-v1` | -| Activation | `xdg-activation-v1` | -| Lockscreen | `ext-session-lock-v1` | -| Idle | `ext-idle-notify-v1`, `idle-inhibit-unstable-v1` | -| Cursor | `wp-cursor-shape-v1` | -| Keyboard | `xkbcommon` | -| Rendering | `EGL`, `OpenGL ES 3`, `wayland-egl` | -| Text | `cairo`, `pango`, `pangocairo`, `freetype`, `harfbuzz`, `fontconfig` | -| Images | `Wuffs` (vendored), `nanosvg` (vendored), `libwebp` | -| IPC | `sdbus-c++` | -| Audio | `libpipewire` | -| Authentication | `PAM` | -| HTTP | `libcurl` | -| Config | `tomlplusplus` (vendored) | -| JSON | `nlohmann/json` (vendored) | -| Math expressions | `tinyexpr` (vendored) | +Noctalia is in early development. Expect breaking configuration and behavior changes while the project is still taking shape. ## Dependencies @@ -43,12 +13,11 @@ A lightweight Wayland shell and bar with no Qt or GTK dependency. sudo dnf install meson gcc-c++ just \ wayland-devel wayland-protocols-devel \ libEGL-devel mesa-libGLES-devel \ - freetype-devel harfbuzz-devel fontconfig-devel \ + freetype-devel fontconfig-devel \ cairo-devel pango-devel \ libxkbcommon-devel \ sdbus-cpp-devel pipewire-devel \ - pam-devel libcurl-devel libwebp-devel \ - libasan libubsan + pam-devel libcurl-devel libwebp-devel ``` ### Arch @@ -56,12 +25,11 @@ sudo dnf install meson gcc-c++ just \ ```sh sudo pacman -S meson gcc just \ wayland wayland-protocols \ - libglvnd freetype2 harfbuzz fontconfig \ + libglvnd freetype2 fontconfig \ cairo pango \ libxkbcommon \ sdbus-cpp libpipewire \ - pam curl libwebp \ - gcc-libs + pam curl libwebp ``` ### Debian / Ubuntu @@ -70,60 +38,59 @@ sudo pacman -S meson gcc just \ sudo apt install meson g++ just \ libwayland-dev wayland-protocols \ libegl-dev libgles-dev \ - libfreetype-dev libharfbuzz-dev libfontconfig-dev \ + libfreetype-dev libfontconfig-dev \ libcairo2-dev libpango1.0-dev \ libxkbcommon-dev \ libsdbus-c++-dev libpipewire-0.3-dev \ - libpam0g-dev libcurl4-openssl-dev libwebp-dev \ - libasan8 libubsan1 + libpam0g-dev libcurl4-openssl-dev libwebp-dev ``` -Vendored (no system package needed): `Wuffs`, `nanosvg`, `tomlplusplus`, `tinyexpr`, `nlohmann/json`. +Vendored dependencies, with no system package needed: `Wuffs`, `nanosvg`, `tomlplusplus`, `tinyexpr`, +`nlohmann/json`, `Luau`, `dr_wav`, `stb_image_resize2`, and Material Color Utilities. -System packages required beyond the Wayland/GL stack: `libwebp` (VP8 lossy WebP; wuffs handles all other formats). +System packages required beyond the Wayland/GL stack: `libwebp` handles WebP decoding and thumbnail encoding. Wuffs +handles the other supported raster image formats. + +Sanitizer runtime packages are only needed for ASan/UBSan builds configured with `just configure asan`. ## Build Requires [just](https://github.com/casey/just) and [meson](https://mesonbuild.com/). ```sh -# Debug (default) — builds in build-debug/ +# Debug build in build-debug/ just configure just build just run -# Optimized release (-march=native, LTO, gc-sections) — builds in build-release/ +# Optimized release build in build-release/ just configure release just build release just run release # Clean rebuild -just rebuild # debug -just rebuild release # release +just rebuild +just rebuild release ``` -
-Manual Meson +## Installation + +After building, install with `just`: ```sh -meson setup build-debug # or: --buildtype=release -Db_lto=true -meson compile -C build-debug -./build-debug/noctalia +sudo just install release ``` -
-## Installation / Packaging +Use `sudo just install` instead if you configured the default debug build. -`meson install` now installs the binary and shipped assets separately using the normal prefix layout: +Meson installs the binary and shipped assets using the normal prefix layout: ```text /usr/local/bin/noctalia /usr/local/share/noctalia/assets/... ``` -With a different Meson `prefix`/`datadir`, the same structure is preserved under that prefix. - -For packagers, the important point is that Noctalia needs the `assets/` tree at runtime. Copying only the bare `noctalia` binary is not enough. +Noctalia needs the shipped `assets/` tree at runtime. Copying only the `noctalia` binary is not enough. Portable bundle layouts are also supported: @@ -139,103 +106,7 @@ bundle/ share/noctalia/assets/ ``` -Runtime asset lookup order: - -1. `NOCTALIA_ASSETS_DIR` -2. `assets/` next to the executable -3. `assets/` one level above the executable -4. install-style `../share/noctalia/assets` relative to the executable -5. the compiled install path from Meson (`//noctalia/assets`) -6. the source-tree `assets/` directory as a development fallback - -An asset root is only accepted if it contains the expected shipped files such as `emoji.json`, `fonts/tabler.ttf`, `templates/builtin.toml`, and `translations/en.json`. - -## Code Style - -This project uses [clang-format](https://clang.llvm.org/docs/ClangFormat.html) for formatting. Run `just format` before committing. - -### Naming Conventions - -| | Convention | Example | -|---|---|---| -| Files | snake_case | `widget_factory.cpp` | -| Directories | snake_case | `shell/widgets/` | -| Types / Classes | PascalCase | `WidgetFactory` | -| Functions / Methods | camelCase | `createWidget()` | -| Variables / Parameters | camelCase | `busName` | -| Private members | m_camelCase | `m_changeCallback` | -| Macros / Enum values | SCREAMING_SNAKE_CASE | `MAX_SIZE` | - -## Project Layout - -``` -src/ - main.cpp Entry point - app/ Application bootstrap, main loop - auth/ PAM authentication (lockscreen) - config/ Configuration and state persistence (TOML) - core/ Logger, timer manager, shared utilities - dbus/ DBus service implementations - debug/ Debug service (runtime log toggling) - idle/ Idle manager and inhibitor - ipc/ IPC client/service (dev.noctalia.* commands) - launcher/ Launcher providers (apps, emoji, math, usage) - net/ HTTP client (libcurl) - notification/ Notification manager - pipewire/ PipeWire audio service and spectrum analyzer - render/ - animation/ Animation manager and easing - core/ EGL/GLES renderer, image decoders - programs/ Shader programs per NodeType - scene/ Scene graph nodes (Rect, Text, Image, Icon, InputArea, ...) - text/ Cairo/Pango text rendering - shell/ - bar/ Bar surface and instance - clipboard/ Clipboard history panel - control_center/ Control center panel and tabs - launcher/ Application launcher panel - lockscreen/ Session lockscreen surface - notification/ Notification popup - osd/ On-screen display (volume, brightness, ...) - overview/ Workspace overview - panel/ Panel base and manager - session/ Session menu (logout, reboot, ...) - tray/ System tray (StatusNotifierItem) - wallpaper/ Wallpaper surface and instance - widget/ Widget base and factory - widgets/ Widget implementations - system/ System monitor (CPU, RAM, temperature) - time/ Time service and polling - ui/ - controls/ Low-level UI building blocks (Button, Input, Label, Flex, ...) - util/ Generic helpers (fuzzy matching, ...) - wayland/ Wayland connection, seat, toplevels, clipboard, ... - compositors/ Compositor-specific workspace backends (ext-workspace, sway, mango, dwl, ...) -third_party/ - tomlplusplus/ TOML parser (vendored) - wuffs/ Raster image decoding (vendored) - nanosvg/ SVG rasterization (vendored) - tinyexpr/ Math expression evaluator (vendored) - nlohmann/ JSON parser (vendored, header-only) -``` - -## Debugging - -All debug commands use the `dev.noctalia.Debug` D-Bus service, available at runtime. - -```sh -# Enable verbose debug logs -gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.SetVerboseLogs true - -# Disable verbose debug logs -gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.SetVerboseLogs false - -# Check current verbose log state -gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.GetVerboseLogs - -# Emit an internal notification (app_name, summary, body, timeout_ms, urgency 0-2) -gdbus call --session --dest dev.noctalia.Debug --object-path /dev/noctalia/Debug --method dev.noctalia.Debug.EmitInternalNotification "Noctalia" "Test" "Hello from debug" 5000 1 -``` +See [CONTRIBUTING.md](CONTRIBUTING.md#runtime-assets) for the full runtime asset lookup order. ## Configuration @@ -260,4 +131,10 @@ changes when the config directory is read-only, such as on NixOS. Both layers are watched for changes and hot-reloaded. If neither declarative config nor state overrides exist, Noctalia falls back to built-in defaults in code. -See [CONFIG.md](CONFIG.md) for the full configuration reference, including shell IPC command examples. +A ready-to-use starting config with all defaults is at [example.toml](example.toml). See [CONFIG.md](CONFIG.md) for the +full configuration reference. + +## Contributing + +Developer notes, architecture overview, code style, project layout, and debugging commands live in +[CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/justfile b/justfile index fa18d48a9..f61fb48ec 100644 --- a/justfile +++ b/justfile @@ -24,6 +24,9 @@ build m=mode: run m=mode: ./build-{{m}}/noctalia +install m=mode: + meson install -C build-{{m}} + format: find src \( -name '*.cpp' -o -name '*.h' \) -print0 | xargs -0 clang-format -i find src \( -name '*.cpp' -o -name '*.h' \) -print0 | xargs -0 grep -ZlP '\s+$' | xargs -0 -r sed -i 's/[[:space:]]*$//' diff --git a/meson.build b/meson.build index b055e8030..78a94dd27 100644 --- a/meson.build +++ b/meson.build @@ -133,7 +133,7 @@ stb_dep = declare_dependency( include_directories: include_directories('third_party/stb', is_system: true), ) -# ── System: libwebp (VP8 lossy WebP; wuffs only handles VP8L lossless) ──────── +# ── System: libwebp (WebP decode and thumbnail encode) ─────────────────────── libwebp_dep = dependency('libwebp', required: true) # ── Vendored: Luau (Roblox's Lua fork) ────────────────────────────────────────