driftwm-noctalia

May 6, 2026 · View on GitHub

Noctalia Shell — native driftwm infinite canvas integration

Noctalia Logo

driftwm-noctalia

Last commit driftwm compatible


What is this?

A fork of Noctalia Shell adapted to work natively with driftwm — a trackpad-first infinite canvas Wayland compositor. Think Figma or Google Maps for your desktop.

driftwm-native adaptations

AreaBehavior
WorkspacesSingle synthetic "Canvas" workspace (driftwm has no workspaces)
WallpaperAuto-disabled — driftwm renders its own background via GLSL shaders
BlurAuto-disabled — ext-background-effect-v1 not supported. Toggle hidden in settings
OverviewAuto-disabled — no Niri-style overview (use Mod+W / Mod+A instead)
BarWlrLayer.Overlay + keyboardFocus: OnDemand for clickability above MainScreen mask
Canvas statePolls $XDG_RUNTIME_DIR/driftwm/state (500ms) for viewport, zoom, layout, windows, per-output cameras
DetectionXDG_CURRENT_DESKTOP=driftwm (display manager) with state file fallback (TTY mode)
Window trackingforeign-toplevel-management protocol — clicking a taskbar window pans the viewport to center it
Display scalesQueried via wlr-randr --json at startup
Keyboard layoutReads active layout from state file — displayed in bar widget
Canvas zoom widgetBar widget showing real-time zoom level (driftwm-only)
IPCAll qs ipc commands work (launcher, control center, notifications, session menu, bar toggle)

Installation

Prerequisites

  • driftwm installed and running (curl -fsSL https://raw.githubusercontent.com/malbiruk/driftwm/main/install.sh | sudo sh)
  • Build tools: cmake, ninja, gcc/clang
  • Qt6 development: qt6-qtbase-devel, qt6-qtdeclarative-devel, qt6-qtwayland-devel
  • Runtime deps: pipewire, wireplumber (for audio), upower (for battery)

Fedora

# Install build dependencies
sudo dnf install cmake ninja-build gcc-c++ \
  qt6-qtbase-devel qt6-qtdeclarative-devel qt6-qtwayland-devel \
  qt6-qtbase-private-devel wayland-devel wayland-protocols-devel \
  pipewire-devel libxkbcommon-devel

# Install runtime dependencies
sudo dnf install wlr-randr wl-clipboard brightnessctl

Arch Linux

sudo pacman -S cmake ninja gcc qt6-base qt6-declarative qt6-wayland \
  wayland wayland-protocols pipewire libxkbcommon wlr-randr wl-clipboard

Ubuntu/Debian

sudo apt install cmake ninja-build g++ qt6-base-dev qt6-declarative-dev \
  qt6-wayland-dev libwayland-dev wayland-protocols libpipewire-0.3-dev \
  libxkbcommon-dev wlr-randr wl-clipboard

Step 1: Install noctalia-qs

Build the Quickshell fork from source (required — standard quickshell lacks noctalia's QML APIs):

git clone --depth 1 https://github.com/noctalia-dev/noctalia-qs.git ~/builds/noctalia-qs
cd ~/builds/noctalia-qs
cmake -GNinja -B build \
  -DCMAKE_BUILD_TYPE=RelWithDebInfo \
  -DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build
sudo cmake --install build

Verify:

qs --version
# Expected: noctalia-qs 0.0.12 (or newer)

Step 2: Install driftwm-noctalia

mkdir -p ~/.config/quickshell
git clone https://github.com/youssefvdel/driftwm-noctalia.git \
  ~/.config/quickshell/noctalia-shell

Step 3: Configure driftwm

Add to ~/.config/driftwm/config.toml:

# Launch the shell on startup
autostart = ["qs -c noctalia-shell -d"]

# Keybindings for noctalia panels
[keybindings]
"mod+d"   = "spawn qs ipc -c noctalia-shell call launcher toggle"
"mod+n"   = "spawn qs ipc -c noctalia-shell call notifications toggleHistory"
"mod+v"   = "spawn qs ipc -c noctalia-shell call launcher clipboard"
"mod+tab" = "spawn qs ipc -c noctalia-shell call sessionMenu toggle"

Important: Use -d (daemonize) in the autostart — without it, the shell may not launch properly inside driftwm's autostart.

Apply config:

touch ~/.config/driftwm/config.toml   # driftwm auto-reloads on config change

Or restart driftwm.

Step 4: Verify

After restarting driftwm, you should see the noctalia bar at the top of each monitor.

# Check the shell is running
ps aux | grep quickshell

# Test launcher via keybinding (Mod+d) or command line
qs ipc -c noctalia-shell call launcher toggle

# Test control center
qs ipc -c noctalia-shell call controlCenter toggle

# Check for errors
ls -t /run/user/1000/quickshell/by-id/ | head -1 | xargs -I{} \
  strings /run/user/1000/quickshell/by-id/{}/log.qslog | grep ERROR

Feature Compatibility

FeatureStatusNotes
Bar / taskbarFullWindow list, tray, clock, widgets, auto-hide, canvas zoom indicator
LauncherFullApp search, clipboard history, session search, settings search
Control CenterFullAudio, brightness, network, bluetooth, power profiles
SettingsFullAll panels functional. Blur/workspace options hidden on driftwm
NotificationsFullD-Bus notifications, history, do-not-disturb
OSDFullVolume, brightness on-screen display
Session MenuFullLogout, suspend, reboot, lock
Lock ScreenFullClock, keyboard layout, session controls
System TrayFullXDG StatusNotifierItem support
Desktop WidgetsFullClock, stickers, system stats on canvas
DockFullmacOS-style dock with window previews
Display ScalesFullQueried from wlr-randr --json on startup
Keyboard LayoutDisplayShows active layout from driftwm state file
PluginsFullPlugin system inherited from upstream
Themes / Color SchemesFullMaterial Design 3 theming, custom schemes
Canvas Zoom WidgetFullBar widget: real-time zoom level (driftwm-only)
WallpaperOffAuto-disabled — driftwm renders GLSL shader background
Blur EffectsOffProtocol not supported by driftwm
Overview ModeOffUse driftwm Mod+W (zoom-to-fit) / Mod+A (home)
Keyboard Layout CyclingNo-opWidget shows layout, click does nothing — compositor has no layout-switch IPC

IPC Commands

All commands use qs ipc -c noctalia-shell call <target> <action>:

qs ipc -c noctalia-shell call launcher toggle
qs ipc -c noctalia-shell call notifications toggleHistory
qs ipc -c noctalia-shell call controlCenter toggle
qs ipc -c noctalia-shell call sessionMenu toggle
qs ipc -c noctalia-shell call bar toggle
qs ipc -c noctalia-shell call launcher clipboard
qs ipc -c noctalia-shell show

Troubleshooting

Shell not launching from autostart

Make sure -d (daemonize) is in the autostart command:

autostart = ["qs -c noctalia-shell -d"]

Bar not visible / not clickable

The bar uses WlrLayer.Overlay on driftwm. If you changed the bar position or monitor config, the bar might be off-screen or hidden. Check:

cat /run/user/1000/driftwm/state | grep layers

You should see entries like noctalia-bar-content-<output-name>.

IPC commands fail with "No running instances"

This means the shell process isn't registered properly. Kill any stale instances and restart:

pkill -f "qs -c noctalia-shell"
qs -c noctalia-shell -d

High CPU usage

During first startup, the shell loads icons, plugins, and fonts (~1 minute at high CPU). After settling, expect ~10-15% CPU. If it stays above 30%, check for plugin issues:

# Check which plugins are loaded
cat ~/.config/noctalia/plugins.json

Settings not persisting

Settings are stored in ~/.config/noctalia/settings.json. If driftwm-specific settings (wallpaper=enabled, blur=enabled) keep reverting, the DriftwmService.initialize() auto-applies them at every startup. This is expected behavior.


Known Limitations

LimitationWorkaround
Keyboard layout can't be cycled via widget clickUse driftwm's built-in grp:win_space_toggle in [input] config
No overview/zoom-to-fit via shellUse driftwm Mod+W (zoom-to-fit) or Mod+A (home toggle)
Canvas zoom widget not auto-added to barAdd it manually: Settings → Bar → Widgets → CanvasPosition
Wallpaper management not availableConfigure background in ~/.config/driftwm/config.toml [background] section

What We Can Improve

✅ Done

  • Display scale detection (wlr-randr)
  • Keyboard layout display (state file)
  • Canvas zoom widget
  • State poll optimization (500ms)

Next up

  1. Window rules management — Settings panel for driftwm [[window_rules]]
  2. Home/Zoom-to-fit keybindings — Expose Mod+A/Mod+W as Noctalia actions
  3. Background shader picker — Preview and switch GLSL shaders from settings
  4. Multi-monitor canvas indicators — Show other viewport positions on the canvas
  5. State file inotify — Replace polling with file-watch for zero-overhead updates

Supported Compositors

CompositorStatusBackend
driftwmNativeDriftwmService (state file polling + foreign-toplevel)
HyprlandInheritedHyprlandService (hyprctl IPC)
NiriInheritedNiriService (native C++ bindings)
Sway / ScrollInheritedSwayService (swaymsg IPC)
LabwcInheritedLabwcService (labwc-ipc)
MangoWCInheritedMangoService (native IPC)
GenericInheritedExtWorkspaceService (ext-workspace-v1 protocol)

Architecture

shell.qml (entry point)
├── Services/Compositor/CompositorService.qml  (detection router)
│   └── DriftwmService.qml  ★ this fork's backend
├── Modules/
│   ├── Bar/            (taskbar + widgets including CanvasPosition)
│   ├── Panels/         (launcher, control center, settings, etc.)
│   ├── MainScreen/     (per-output panel host + bar)
│   ├── Dock/           (macOS-style dock)
│   ├── Background/     (wallpaper — disabled on driftwm)
│   ├── Notification/   (notification popups)
│   ├── OSD/            (on-screen display)
│   └── LockScreen/     (session lock)
├── Services/           (backend logic)
└── Commons/            (shared utilities, settings, i18n)

Upstream

This is a fork of Noctalia Shell by noctalia-dev. All credit for the original shell goes to the Noctalia team.

PR #2630 open to merge driftwm support upstream.

License

MIT License — see LICENSE for details.