Skip to content

Architecture

P3DROVFX edited this page Oct 12, 2026 · 2 revisions

Architecture

A guided tour of how ii-p3drovfx is put together — for contributors, widget authors, and the curious. The short version: QML all the way down, one singleton per concern, and lazy loading everywhere it counts.


The stack

  • Hyprland — the Wayland compositor, configured natively in Lua (~/.config/hypr/hyprland.lua + modules; requires Hyprland 0.56.1+)
  • Quickshell — the Qt Quick shell framework that hosts every panel, popup and window
  • Matugen 4.1+ — Material You palette generation from wallpapers (with a compatibility fallback for Matugen 3)
  • Helper layers: shell/Python scripts (scripts/), two native Rust utilities (workspace profiles & compactor), and a large services/ layer bridging system CLIs and D-Bus

Repository layout

ii-p3drovfx/
├── setup-ii-p3drovfx.sh     # installer entry point
├── setup + sdata/           # installer internals: deps, per-distro (Arch, Fedora, Gentoo, Nix)
├── update-fork.sh           # updater
├── diagnose                 # troubleshooting helper
└── dots/
    ├── .config/hypr/        # Hyprland Lua config, hyprlock, hypridle
    └── .config/quickshell/ii/   # the shell itself

Inside dots/.config/quickshell/ii/:

Path What it is
shell.qml Entry point: boots eager services, loads the active panel family, hosts Settings/Welcome loaders and global IPC
panelFamilies/ IllogicalImpulseFamily.qml (the default II experience), WaffleFamily.qml, and the shared PanelLoader
modules/common/ Shared foundations: Config, Persistent, GlobalStates, Appearance, Directories, registries, reusable widgets
modules/ii/ The II family's surfaces: bar, dynamicIsland, sidebarDashboard, sidebarPolicies, overview, background, regionSelector, videoEditor, lock, dock, cheatsheet, settings-adjacent windows… one directory per surface
modules/waffle/ The Waffle family — a work-in-progress Windows-style experience: start menu, taskbar, task view, action center, notification center
modules/settings/ The Settings app (pages in configs/, registered via SettingsPageRegistry)
modules/welcome/ The first-run onboarding
services/ ~80 singletons — the entire system-integration layer
scripts/ Shell/Python helpers grouped by domain (colors, videos, hyprland, kdeconnect, ticktick, …)
translations/ i18n JSON files (German, Spanish, French, Japanese, Portuguese and more)
defaults/, assets/ Bundled themes, AI prompts, icons

Panel families

The shell can wear two completely different faces, switched at runtime (Ctrl + Super + P, or Config.options.panelFamily):

  • II — the Material 3 Expressive experience this wiki mostly documents
  • Waffle — a Windows-11-style recreation (start menu, taskbar, action center), still WIP

shell.qml wraps each family in a LazyLoader, so only the active one exists in memory. Family-independent pieces (reload popup, Settings, Welcome, global IPC) live above the families.

The singleton pattern

Almost everything follows one rule: state lives in a singleton, UI binds to it.

  • Config.qml — persistent preferences (see Configuration Reference for the mechanics: JsonAdapter, debounced writes, schema migrations, health repair)
  • Persistent.qml — remembered UI state (states.json)
  • GlobalStates.qml — runtime state: which surfaces are open, plus IpcHandlers and GlobalShortcuts that let Hyprland keybinds drive the shell (quickshell:overviewWorkspacesToggle and friends)
  • services/*.qml — one per domain: Audio, Network, BluetoothStatus, Battery, Brightness, HyprlandData, Notifications, MprisController, KdeConnectService, TilingAssistant… Services talk to PipeWire, D-Bus, Hyprland IPC or CLIs and expose reactive properties; every surface that shows the same fact binds to the same object, which is why the Bar, Dashboard, island and widgets never disagree

shell.qml's Component.onCompleted "touches" the services that must run regardless of visible UI (usage sampler, water reminder, tiling watcher, wallpaper state…), while everything else initializes on first use.

Lazy loading as a discipline

The codebase is aggressive about not paying for what you don't use: panel families, the Dynamic Island, the Overview's visual window, Settings (kept warm briefly after closing, then dropped to reclaim memory), Welcome (destroyed immediately on close), widget previews, and config-gated features all sit behind Loader/LazyLoader with careful activation conditions.

Connect Mode

The II family has two window architectures, chosen by Config.options.sidebar.sidebarStyle:

  • Default — each panel (bar, sidebars, frame) is its own Wayland PanelWindow
  • Connect — bar, frame, Dashboard and Policies consolidate into one transparent fullscreen surface (modules/ii/topLayer/TopLayerPanel.qml) with input-region masking deciding where clicks pass through. Sidebars overlay windows instead of resizing them (no Hyprland layout recalculation = no lag), and blur/transparency render continuously across the whole surface. The interactive Region mask is the critical piece — it's what keeps the rest of the screen clickable

The full design document ships in the repo as CONNECT.md.

Hyprland integration

  • Lua config — Hyprland's native Lua system; the shell reads and writes Hyprland options (gaps, borders, rounding, blur) through HyprlandConfig/HyprlandSettings, and user overrides live in ~/.config/hypr/custom/*.lua (Keybinds has the details)
  • State — HyprlandData.qml centralizes monitors/workspaces/windows/addresses; Quickshell's ToplevelManager links shell previews to real Wayland windows
  • Keybind bridge — Hyprland global dispatchers fire Quickshell GlobalShortcuts; most shell binds have non-shell fallbacks so the desktop stays usable if Quickshell is down

Native helpers

Two Rust binaries handle work QML shouldn't: workspace_profile_manager (capture/restore full working environments) and workspace_compactor (renumber occupied workspaces) — both built locally with Cargo from scripts/hyprland/*_src/, with Settings showing the build command when the binary is missing.

Installer & updater

setup-ii-p3drovfx.sh drives a modular installer (sdata/) with per-distro dependency handling for Arch, Fedora (COPR-aware), Gentoo and Nix, automatic backups of replaced files, and a post-install Hyprland reload into the Welcome onboarding. The About & Updates Settings page can switch sources and update the fork in place — one of this fork's signature additions.


Related pages

← Back to Home

Clone this wiki locally