Wayland Desktops on Debian Trixie

Published on
Last updated on
Technical
Linux Wayland

Wayland Desktops

I’ve been using Linux for nearly two decades — Ubuntu, openSUSE, Fedora, Debian. Early on there weren’t many desktop choices, so GNOME was the default. I never warmed to KDE; its UI philosophy never clicked with me. Over time I gravitated toward minimal desktops — XFCE, LXDE, then LXQt. Wayland was the next milestone, but none of these ran well under it. Last year I finally got LXQt working with labwc on Wayland, and it held up until this year when I came across DMS and then Noctalia.

Last week I sat down with my Debian Trixie workstation (NVIDIA GTX 1070 Ti, AOC 27” 4K, 1.2× scale) and built three parallel Wayland desktop stacks that I switch between from SDDM:

  • Niri + DMS — scrollable-tiling compositor + Material You shell (systemd-managed)
  • Sway + Noctalia — battle-tested i3-style tiling + native C++/OpenGL shell (compositor-spawned)
  • labwc + DMS — stacking compositor (Win/macOS-style) + DMS (systemd-managed via man labwc recipe)

Both shells are lightweight and visually striking. DMS’s Material You theming gives the bar a polished, modern feel; Noctalia’s capsule_group system produces compact, connected widget pills that DMS can’t replicate.


Background

Why two shells?

The two shells launch differently:

DMSNoctalia
Launcherdms.service (systemd user unit)noctalia --daemon (foreground process)
Started byWantedBy=graphical-session.targetcompositor’s exec / spawn-at-startup
Lifecyclesystemdthe compositor
Restart on crashRestart=on-failuremanual pkill -x; noctalia --daemon
ConfigJSON via GUITOML modules + GUI
Bar groupingoutline-island workaroundnative capsule_group

DMS only works under systemd-aware compositors (niri, hyprland with a hand-written session target, labwc via man labwc’s recipe). Noctalia is the inverse — no systemd unit, designed to be spawned by the compositor.

Why three compositors?

CompositorStylesystemd integrationBest paired with
niriScrollable tiling (Mac-spaces-like)First-class — ships niri-session + niri.service (BindsTo=graphical-session.target)DMS
swayClassic i3 tilingNone — only env-import in /etc/sway/config.d/50-systemd-user.confNoctalia
labwcStacking (windows overlap)labwc-session.target ships, man labwc documents the systemd recipe with dms.service as the exampleDMS

I pair niri/labwc with DMS because both compositors give me a working systemd chain, and DMS plugs into that for free. I pair sway with Noctalia because sway has no systemd hook and Noctalia doesn’t want one — it’s the simpler match.

The shells are compositor-agnostic at the configuration level. ~/.config/DankMaterialShell/settings.json and ~/.config/noctalia/*.toml work under any supported compositor. Only the compositor-config-side launch line changes when you swap.

What lives where

~/.config/DankMaterialShell/ DMS settings (JSON) + plugins
~/.config/noctalia/ Noctalia settings (TOML modules)
~/.config/niri/ niri compositor config
~/.config/sway/ sway compositor config
~/.config/labwc/ labwc compositor config + autostart/shutdown
~/.config/termusic/ shared music daemon config (server + tui)
~/.config/fcitx5/ shared input method config

Installing the components

Debian Trixie is conservative — most things either come from a third-party repo or get built from source. Run these once before configuring any stack.

1. Install compositors

Terminal window
# niri (Trixie backports has it)
sudo apt install -t trixie-backports niri
# sway (Trixie main)
sudo apt install sway
# labwc — Trixie main has 0.8.3, I built 0.20.0 from upstream master
# (steps in ~/development/osc/desktop/labwc-build/)

All three ship a /usr/share/wayland-sessions/*.desktop so SDDM picks them up.

2. Install DankMaterialShell + quickshell

DMS author AvengeMedia maintains an OBS apt repo:

Terminal window
# Add danklinux + dms repos (saves keyrings to /etc/apt/keyrings/)
curl -fsSL https://install.danklinux.com | sh
sudo apt install dms quickshell dgop

3. Build Noctalia from source

No Debian package; clone the v5 repo and just-build:

Terminal window
sudo apt install -y libqt6{quick,qml,quickcontrols2,svg,wayland}-dev \
qt6-base-dev qt6-tools-dev meson ninja-build pkg-config
git clone https://github.com/Noctalia-dev/noctalia-shell.git
cd noctalia-shell
just configure release "/usr"
just build
sudo just install # → /usr/bin/noctalia

After upgrading the source you must just build && sudo just install and restart noctalia, otherwise new widget IDs added to your *.toml won’t render — noctalia config validate only checks TOML syntax, not whether the running binary knows the widget.

4. Build termusic with mpv backend

The Debian package ships only the rusty backend, which mis-resamples 44.1k WAV → static noise. Build from source with --features all-backends and choose mpv:

Terminal window
sudo apt install -y libmpv-dev libsoundtouch-dev \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
git clone https://github.com/tramhao/termusic.git
cd termusic
make all-backends
install -m755 target/release/termusic ~/.local/bin/termusic
install -m755 target/release/termusic-server ~/.local/bin/termusic-server

5. Install Maple Mono NF CN font

One font that bundles Nerd Font icons (NF variants) AND CJK glyph coverage (CN variant). Used by both shells, fcitx5, ghostty, vim — everything terminal-ish.

Terminal window
VERSION="v7.4"
TMP=$(mktemp -d)
curl -L -o "$TMP/MapleMono-NF-CN.zip" \
"https://github.com/subframe7536/maple-font/releases/download/${VERSION}/MapleMono-NF-CN.zip"
sudo mkdir -p /usr/share/fonts/maple
cd "$TMP" && unzip MapleMono-NF-CN.zip
sudo install -m644 *.ttf /usr/share/fonts/maple/
sudo fc-cache -fv | grep -i maple
fc-match 'Maple Mono Normal NF CN'
# → MapleMonoNormal-NF-CN-Regular.ttf: "Maple Mono Normal NF CN" "Regular"

6. Install shared bits

Terminal window
sudo apt install \
fcitx5 fcitx5-chinese-addons fcitx5-frontend-gtk4 fcitx5-frontend-qt6 \
flameshot playerctl ddcutil cosmic-files

7. Sanity check

Terminal window
$ which niri sway labwc dms quickshell noctalia termusic-server
/usr/bin/niri
/usr/bin/sway
/usr/bin/labwc
/usr/bin/dms
/usr/bin/quickshell
/usr/bin/noctalia
/home/jenningsl/.local/bin/termusic-server
$ ls /usr/share/wayland-sessions/
labwc.desktop niri.desktop sway.desktop

Stack A: Niri + DMS

Niri+DMS bar

DMS in outline island mode — fully transparent bar background, every widget is its own 50%-opacity capsule with a 2px outline.

Step 1 — Confirm the systemd chain

When you select Niri at SDDM, niri-session activates graphical-session.target and dms.service auto-starts. Verify with:

Terminal window
$ systemctl --user is-active graphical-session.target
active
$ systemctl --user list-dependencies graphical-session.target --reverse
graphical-session.target
├─dms.service
└─niri.service

No additional setup needed — DMS auto-starts.

Step 2 — Configure niri startup spawns

niri’s spawn-at-startup runs once at login (no reload re-trigger). Put user spawns in ~/.config/niri/user-binds.kdl:

// fcitx5 — niri doesn't auto-spawn
spawn-at-startup "sh" "-c" "pkill -x fcitx5 2>/dev/null; sleep 1; fcitx5 -d --replace"
// termusic-server — MPRIS music daemon (used by both shells)
// Use `setsid -f` to survive parent shell exit (otherwise SIGHUP)
spawn-at-startup "sh" "-c" "pkill -x termusic-server 2>/dev/null; sleep 1; setsid -f termusic-server"
binds {
Mod+Shift+S { screenshot; }
Ctrl+Shift+X { spawn "flameshot" "gui"; }
Mod+E { spawn "cosmic-files"; }
}

KDL gotcha — each shell argument is its own quoted string. "sh" "-c" "command" is three args, not "sh -c 'command'".

Step 3 — Set the DMS bar layout (outline island)

~/.config/DankMaterialShell/settings.json:

{
"barConfigs": [{
"id": "default",
"transparency": 0,
"widgetTransparency": 0.5,
"widgetOutlineEnabled": true,
"widgetOutlineColor": "surfaceText",
"widgetOutlineThickness": 2,
"widgetPadding": 12,
"leftWidgets": ["launcherButton", "workspaceSwitcher",
{"id": "spacer", "size": 30}, "focusedWindow"],
"centerWidgets": ["music", "musicLyrics",
{"id": "spacer", "size": 60},
"clock", "lunarCalendar", "worldClock", "weather"],
"rightWidgets": ["systemTray", "screenRecorder", "clipboard", "cpuUsage",
{"id": "spacer", "size": 60},
"notificationButton", "controlCenterButton", "powerMenuButton"]
}]
}

The four lines that produce the outline-island look:

"transparency": 0, // bar background fully transparent
"widgetTransparency": 0.5, // each capsule 50% opaque
"widgetOutlineEnabled": true, // 2px outline traces every capsule
"widgetOutlineColor": "surfaceText" // white-ish, high contrast

{"id": "spacer", "size": 60} between clusters breaks them into floating islands. The default spacer is 20px — invisible at 4K. You must pass an explicit size.

Step 4 — Enable the dock

{
"showDock": true,
"dockPosition": 1, // 0=top 1=right 2=left 3=bottom
"dockIconSize": 40,
"dockGroupByApp": false,
"dockOpenOnOverview": true,
"dockIndicatorStyle": "circle",
"dockLauncherEnabled": true
}

Step 5 — Install plugins

Terminal window
# Drop each plugin directory into:
~/.config/DankMaterialShell/plugins/<id>/
# Then enable via IPC:
dms ipc call plugins enable <id>

The plugins I run on DMS:

PluginWhat it does
lunarCalendarChinese 农历 in the bar (calls Debian’s lunar command)
worldClockMulti-timezone bar widget with cycling
musicLyricsSynced lyrics from lrclib / Navidrome / Musixmatch
screenRecordergpu-screen-recorder wrapper, start/stop from the bar
alarmClockAlarms + stopwatch with WAV alarm sound

After installation, set controlCenterWidgets and the relevant barConfigs.centerWidgets / rightWidgets arrays to include the plugin IDs.


Stack B: Sway + Noctalia

Sway+Noctalia bar

Sway is what I’ve used for years; Noctalia is a wlroots-native C++ shell with the killer capsule_group feature — multiple widgets sharing one visible pill.

Step 1 — Wire up sway startup

~/.config/sway/config:

Terminal window
# Sway has no systemd-session hook; we just import env so user units can find Wayland.
# Debian's /etc/sway/config.d/50-systemd-user.conf already does dbus-update-activation-environment.
exec dbus-update-activation-environment --systemd XDG_CURRENT_DESKTOP=sway
# Noctalia v5 — desktop shell. exec_always lets Mod+Shift+R reload restart it in place.
exec_always sh -c 'pkill -x noctalia; noctalia --daemon'
# polkit graphical agent (sudo dialogs)
exec /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 2>/dev/null || \
/usr/bin/lxqt-policykit-agent
# fcitx5 Chinese input
exec_always sh -c 'pkill -x fcitx5; fcitx5 -d --replace'
# termusic-server (the trailing play→pause is the Noctalia MPRIS workaround — see below)
exec_always sh -c 'pkill -x termusic-server 2>/dev/null; sleep 1; setsid -f termusic-server; sleep 4; playerctl --player=termusic play 2>/dev/null; sleep 1; playerctl --player=termusic pause 2>/dev/null'

Two sway pitfalls:

  • ; is an IPC separator, not a shell separator. exec_always pkill -x noctalia; noctalia --daemon parses as two IPC commands (the second is invalid). Always wrap in sh -c '...'.
  • exec vs exec_alwaysexec runs once at login; exec_always re-runs on every config reload. The pkill -x foo; foo pattern with exec_always lets Mod+Shift+R cleanly restart any daemon.

Step 2 — Configure Noctalia (modular TOML)

Noctalia v5 reads ~/.config/noctalia/*.toml in alphabetic order. Split into 6 files:

00-shell.toml # font, polkit, panel transparency_mode
10-theme.toml # source, wallpaper-derived palette
20-bar.toml # capsule_groups (multi-widget shared pills)
30-widgets.toml # per-widget settings (clock format, lunar, media)
40-services.toml # weather location, brightness ddcutil, wallpaper
90-overrides.toml # one-off final overrides (sandbox)

The bar file uses Noctalia’s killer feature, capsule_group:

~/.config/noctalia/20-bar.toml
[bar.default]
position = "top"
background_opacity = 0.0 # whole bar invisible
end = ["media", "tray", "clipboard", "notifications",
"network", "brightness", "volume",
"nvidia-gpu-monitoring-plugin", "screen-recorder",
"sticky-notes", "noctalia-calculator",
"weather", "lunar", "clock", "world-clock", "session"]
# Multiple widgets share ONE pill
[[bar.default.capsule_group]]
id = "systray"
members = ["media", "tray", "clipboard", "notifications",
"network", "brightness", "volume",
"nvidia-gpu-monitoring-plugin"]
opacity = 0.92
radius = 14.0
[[bar.default.capsule_group]]
id = "tools"
members = ["screen-recorder", "sticky-notes", "noctalia-calculator"]
opacity = 0.92
radius = 14.0
[[bar.default.capsule_group]]
id = "time-weather"
members = ["weather", "lunar", "clock", "world-clock"]
opacity = 0.92
radius = 14.0

Result: 4 connected pills floating across the top, not 16 individual capsules.

Step 3 — Install Noctalia plugins

Drop plugin directories into ~/.local/share/Noctalia/plugins/<id>/ (the directory name should match manifest.json:id), then enable each one in Control Center → Plugins.

Plugins on my Noctalia setup:

PluginWhat it does
nvidia-gpu-monitoring-pluginReal-time GPU temp / utilization / VRAM (polls nvidia-smi)
screen-recorder (official)gpu-screen-recorder wrapper with replay buffer
sticky-notesMarkdown notes with optional GitHub Gist sync
noctalia-calculatorTheme-aware calculator with bar widget
world-clockMulti-timezone with auto-rotate
lyrics-fetchSynced lyrics from lrclib.net

Once enabled in the GUI, add the matching ID to your 20-bar.toml start / center / end array (and to a capsule_group.members if you want it inside an existing pill).

Step 4 — Configure the dock (optional)

~/.config/noctalia/90-overrides.toml
[dock]
enabled = true
position = "bottom"
icon_size = 48
magnification = true
magnification_scale = 1.45
launcher_position = "start"
show_running = true
auto_hide = false
# Pin apps by their .desktop basename or reverse-DNS id
pinned = ["ghostty", "google-chrome", "zed", "com.system76.CosmicFiles"]

Find the right id with ls /usr/share/applications/ ~/.local/share/applications/ | grep <name>.

Caveat about overrides: if you set the dock via the GUI first, ~/.local/state/noctalia/settings.toml gets all 30 fields populated. A partial [dock] block in 90-overrides.toml will overwrite GUI-set fields you don’t repeat. Either keep all fields in your override, or skip overrides and stick to the GUI.


Stack C: labwc + DMS

After Stack A and B I added labwc as a third option — a stacking compositor (windows overlap like Win/macOS) with the same DMS shell as Stack A.

Step 1 — Read man labwc

The man labwc page documents the systemd integration recipe and even uses dms.service as the example service to enable:

A systemd user unit named labwc-session.target is also shipped… It binds to the standard graphical-session.target. Labwc does not activate the target itself; users opt in by adding lines like the following to their autostart and shutdown files:

systemctl --user --no-block start labwc-session.target
systemctl --user stop graphical-session.target

So labwc is closer to “user opts in to systemd in 4 commands” than to “no integration”.

Step 2 — One-time enable of dms.service

Terminal window
systemctl --user enable dms.service
# Creates /etc/systemd/user/graphical-session.target.wants/dms.service

This is the link that makes dms.service auto-start whenever any compositor activates graphical-session.target.

Step 3 — Wire up autostart

~/.config/labwc/autostart (chmod +x):

#!/bin/sh
# 4K HiDPI scaling
wlr-randr --output DP-1 --scale 1.2
# Activate the systemd chain — dms.service auto-starts via WantedBy
{
systemctl --user add-wants labwc-session.target dms.service 2>/dev/null
systemctl --user --no-block start labwc-session.target
} &
# Session daemons (same as sway/niri share)
swaybg -i /usr/share/lxqt/wallpapers/Valendas.png >/dev/null 2>&1 &
fcitx5 -d --replace 2>/dev/null &
pkill -x termusic-server 2>/dev/null
sleep 1
setsid -f termusic-server &
/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 2>/dev/null &
swayidle -w timeout 300 "wlopm --off \*" resume "wlopm --on \*" >/dev/null 2>&1 &

Step 4 — Wire up shutdown

~/.config/labwc/shutdown (chmod +x — labwc runs this on exit):

#!/bin/sh
# Clean stop so dms.service and other graphical-session WantedBy units shut down properly
systemctl --user stop graphical-session.target

Step 5 — Configure the root menu

~/.config/labwc/menu.xml — right-click on empty desktop:

<openbox_menu>
<menu id="root-menu">
<item label="Terminal (ghostty)"><action name="Execute" command="ghostty" /></item>
<item label="File Manager"><action name="Execute" command="cosmic-files" /></item>
<separator />
<item label="DMS Launcher"><action name="Execute" command="dms ipc call spotlight toggle" /></item>
<item label="DMS Control Center"><action name="Execute" command="dms ipc call control-center toggle" /></item>
<item label="DMS Power Menu"><action name="Execute" command="dms ipc call powermenu toggle" /></item>
<separator />
<item label="Screenshot"><action name="Execute" command="flameshot gui" /></item>
<item label="Lock Screen"><action name="Execute" command="dms ipc call lock lock" /></item>
<item label="Reconfigure"><action name="Reconfigure" /></item>
</menu>
</openbox_menu>

Step 6 — Set default file manager

Terminal window
xdg-mime default com.system76.CosmicFiles.desktop inode/directory

This makes “open folder” actions everywhere launch cosmic-files.


Shared services

fcitx5 with Maple Mono NF CN

~/.config/fcitx5/conf/classicui.conf:

Vertical Candidate List=False
WheelForPaging=True
Font="Maple Mono Normal NF CN Medium Medium 18"
MenuFont="Maple Mono Normal NF CN Medium Medium 18"
TrayFont="Maple Mono Normal NF CN 15"
Theme=macos12-light
DarkTheme=macos12-dark
UseDarkTheme=True
PerScreenDPI=True
EnableFractionalScale=True

The "Maple Mono Normal NF CN Medium Medium 18" syntax is family + style + weight + size; the double “Medium” is correct — fcitx5 takes both the named weight and the typographic weight. Apply with fcitx5 -d --replace.

termusic music daemon

~/.config/termusic/server.toml:

version = "2"
[player]
music_dirs = ["/home/jenningsl/Musics/班得瑞合集"]
loop_mode = "playlist"
volume = 80
gapless = true
use_mediacontrols = true # ★ MPRIS — required for noctalia/DMS to see termusic
backend = "mpv" # ★ mpv backend, see "Lessons" below
startup_state = "stopped"
[player.remember_position]
music = "no"
podcast = "yes"
[backends.mpv]
audio_device = "auto" # mpv picks pipewire automatically

~/.config/termusic/tui.toml:

version = "2"
com = "same"
[behavior]
quit_server_on_exit = false # ★ closing TUI does NOT kill server — daemon semantics
[coverart]
hidden = true # avoids ueberzug/sixel terminal control noise

First-run scan — the server doesn’t scan music_dirs at startup. The TUI does the scan, and the TUI uses crossterm which panics in non-tty environments. So after first install, open a real terminal and run termusic once to populate library.db.

Podcast import (OPML)

Terminal window
pkill -x termusic-server # server must be off — sqlite write conflict
termusic-server import ~/podcasts.opml # bulk import RSS URLs

Why no conky?

Earlier drafts had a Wayland-native conky on the right edge of the screen with CPU / GPU / RAM stats. Removed in 2026-06 — every value it showed (CPU, RAM, GPU temp, GPU utilization) is already in the bar widgets:

  • DMScpuUsage widget in the bar; nvidia-smi values not built-in but available via the nvidia-gpu-monitoring-plugin if you want them
  • Noctalianvidia-gpu-monitoring-plugin in the systray pill

Two sources of the same numbers is just visual noise.


The Noctalia MPRIS quirk

After hooking termusic-server up I noticed an asymmetry:

  • DMS bar’s media widget worked immediately — it could play, pause, skip from the bar
  • Noctalia bar’s media widget showed “Nothing playing”

Both shells listen to the same MPRIS bus. The difference is in the discovery filter.

Noctalia (src/dbus/mpris/mpris_service.cpp:1721):

const MprisPlayerInfo info = readPlayerInfoFromProperties(...);
if (!playerFailed && !hasStrongNowPlayingMetadata(info)) {
removePlayerCacheEntry(busName); // rejected!
return;
}
bool hasStrongNowPlayingMetadata(const MprisPlayerInfo& info) {
return !info.title.empty() || !info.artists.empty() || !info.album.empty();
}

DMS (Services/MprisController.qml):

readonly property list<MprisPlayer> availablePlayers: Mpris.players.values
// No filter. Every MPRIS player on the bus is available.

Termusic in Stopped state exposes only mpris:trackid="/" — no title, artist, or album. Noctalia rejects it. Worse: Noctalia only re-introspects on NameOwnerChanged (i.e., termusic restart), so even after termusic later starts playing with full metadata, Noctalia never re-queries.

Workaround — make termusic briefly play then pause at startup so Noctalia’s first introspect catches strong metadata. This is the trailing play; pause in Stack B’s sway config:

Terminal window
exec_always sh -c '
pkill -x termusic-server 2>/dev/null
sleep 1
setsid -f termusic-server
sleep 4 # wait for MPRIS registration
playerctl --player=termusic play 2>/dev/null # populate metadata
sleep 1
playerctl --player=termusic pause 2>/dev/null # back to Paused
'

About 6 seconds of silence at login, no audible interruption, and Noctalia caches termusic permanently.

This workaround is only needed for sway+Noctalia. niri+DMS and labwc+DMS do NOT need it. Don’t mirror it across stacks symmetrically.


Lessons learned

  1. Pair compositor with the shell that matches its lifecycle model. systemd-aware compositors (niri, labwc with the man-page recipe) → DMS. Bare-binary compositors (sway) → Noctalia. Forcing the wrong pair adds ceremony for nothing.

  2. Don’t mirror workarounds across stacks. I added the Noctalia MPRIS play; pause workaround to all three compositors initially. Only sway+Noctalia needs it. Symmetric configs are tempting but wrong when the underlying problem is asymmetric.

  3. DMS plugin QML uses different property names than regular QMLDankIcon is size: not font.pixelSize:, Proc.runCommand callback is (stdout, exitCode) not a single object. Read existing plugins before writing your own.

  4. Wayland MPRIS controllers vary wildly in strictness. Quickshell’s Mpris service is liberal; Noctalia’s hand-rolled C++ filter is strict. Always test with playerctl --list-all first to confirm the bus name is registered, then test in each shell separately.

  5. NVIDIA + sway — set SWAY_UNSUPPORTED_GPU=true in ~/.config/environment.d/95-sway.conf to suppress the boot banner. Sway works fine on the proprietary driver in 2026.

  6. rusty audio backend has a 44.1k → 48k resample bug — every WAV file picks up static. Use the mpv backend instead. The fix requires make all-backends from termusic source; the Debian package is rusty-only.

  7. Termusic library scan needs a real tty. Crossterm panics otherwise — script the first scan interactively, not in a startup hook.

  8. Don’t let plugins crash the shell. A musicLyrics Musixmatch parser tried to read result.message.body.track.track_id without a null check — when YouTube videos returned an empty body, Quickshell’s QML binding system segfaulted. Always defensive-chain async API responses: result.message && result.message.body && result.message.body.track.

  9. Two stacks cost less than expected. DMS and Noctalia configs are independent files in different directories. Termusic, fcitx5, fonts, and wallpapers are all shared. Switching is just choosing a different SDDM session.

  10. man <compositor> is an underused source. man labwc documents the exact systemd recipe and names dms.service as the example. The DMS install doc still lists labwc as “Coming Soon” — but the labwc man page beat them to it.


Files referenced

~/.config/sway/config # sway compositor + spawns
~/.config/niri/config.kdl # niri main config
~/.config/niri/user-binds.kdl # niri spawns + binds (user-controlled)
~/.config/niri/dms/*.kdl # niri pieces auto-generated by DMS
~/.config/labwc/{rc.xml,autostart,shutdown,menu.xml} # labwc compositor
~/.config/noctalia/00..90-*.toml # Noctalia v5 modular config
~/.config/DankMaterialShell/settings.json # DMS config
~/.config/DankMaterialShell/plugins/<id>/ # DMS plugins
~/.local/share/Noctalia/plugins/<id>/ # Noctalia plugins
~/.config/termusic/server.toml # termusic backend + music_dirs
~/.config/termusic/tui.toml # quit_server_on_exit = false
~/.config/termusic/playlist.log # current playlist (line 0 = index)
~/.config/environment.d/95-sway.conf # SWAY_UNSUPPORTED_GPU=true
~/.config/environment.d/90-dms.conf # ELECTRON_OZONE_PLATFORM_HINT=auto

The scrollable tiling of niri is starting to grow on me, but sway+Noctalia’s connected-pill bar is hard to give up, and labwc + DMS makes the third path my “macOS-feeling” option for stacking work. All three coexist on the same machine — switch at SDDM depending on the day’s mood.

Back to Blog