A modern, feature-rich desktop shell for Wayland compositors.
demo.mp4
Built on top of outfoxxed's Quickshell framework, this configuration turns it into a complete desktop shell: a top bar, dock, settings dashboard, on-screen display, notification centre, blue-light filter, Material You theming, and more β all drag-and-drop customisable and compositor-agnostic.
- Features
- Supported Compositors
- MangoWC 0.16+
- Dependencies
- Installation
- Configuration
- Activity Monitor
- Night Light
- Power Profiles
- Audio Equaliser
- Architecture
- Troubleshooting
- Links
- License
- Workspaces β Per-monitor role ranges, occupied/global modes, app grouping, scrolling and Roman / Chinese / decimal labels
- System Info β CPU, RAM, temperature, disk usage, groupable
- Activity Monitor β On-demand CPU, memory, GPU, network, storage and process details; tested on Hyprland and MangoWC
- Audio β Volume control, mute, 10-band parametric equaliser
- Weather & World Clocks β Current conditions plus a configurable multi-city desktop clock; search any city/country, reorder up to eight locations, and get DST-aware local time with live weather
- Markets β Official TCMB USD/TRY buying/selling rates plus live Bitcoin and Ethereum prices with 24-hour change and offline cache
- Draggable desktop widgets β Move World Clocks and Markets freely with the mouse; positions persist independently for each monitor role
- Quick currency converter β Place the converter on the bar or dock and open the complete currency selector with one click
- Clock & Calendar β With agenda and event countdown
- Notification Centre β Grouped history, DND, per-app filters, customisable popup position
- System Tray β Standard StatusNotifierItem protocol
- Clipboard Manager β History with copy-on-click
- Power Profiles β Performance, Balanced and Power Saver with automatic Arch/Fedora backend detection
- Animated zoom effect on hover
- Drag-and-drop pinning and reordering
- Live running indicators (dot or line, configurable)
- Per-monitor visibility
- Auto-hide with intelligent window-overlap detection
- Left/right module slots (Weather, Volume, Tray, Power, Media, Notepad, β¦)
- Drag-and-drop bar module arrangement
- Bar position toggle (top / bottom / left / right)
- Per-screen module assignment (OSD on one monitor, notifications on another)
- Workspace ranges by monitor role (primary 1β5, secondary 6β10, β¦), independent of HDMI/DP port names
- Seven built-in layout presets (macOS, Windows 11, GNOME, KDE, Unity, ZorinOS, Custom)
- Material You theme editor with live wallpaper colour extraction
- System-wide font picker for general and monospace families (writes to
kdeglobalsandqt6ct.conf) - Live preview tiles with the current selection rendered in situ
- Searchable catalogue of every installed family, sourced via
fc-list(includes user fonts in~/.local/share/fonts) - Applies without a shell restart: the Theme singleton re-reads the system font and every bar / dock / popup / settings module updates on the fly
- Nerd Font glyphs stay pinned to
JetBrainsMono Nerd Fontso icons keep rendering after the switch
- Resolution, refresh rate, and independent scale per output
- HDR, VRR, 10-bit colour, wide-gamut colour management (sRGB / DCI-P3 / Adobe RGB / Rec.2020)
- Drag-to-arrange multi-monitor layout canvas with edge snapping
- 10-second Keep / Revert safety prompt after display changes
- SDR brightness, saturation, and reference luminance for HDR outputs
- Applied with a single
hyprctl --batchcall on Hyprland (no flicker)
- Blue-light filter with 1000β6500 K slider and five presets
- Fixed-time schedule with midnight-wrap support (e.g. 19:00 β 07:00)
- Cross-compositor backend:
hyprsunseton Hyprland,gammastepon wlroots - Persists through shell restart; auto-applies on startup
- OSD for volume and brightness
- App Drawer launcher with fuzzy search
- Wallpaper Picker with Material You palette extraction (matugen)
- Lock Screen β wallpaper, dim/lock/suspend timeouts, media inhibit
- Mouse & Keyboard β sensitivity, scroll factor, cursor theme
- Network & Bluetooth connection managers
- VPN connection manager (NetworkManager + WireGuard)
- API Keys β configure SmartComplete AI providers (OpenAI, Claude, Groq, Ollama, β¦)
- Notepad and Event Countdown
Click any of these on the bar to reveal an inline popover.
Equalizer β 10-band parametric EQ with sound theming
|
Notepad β quick scratchpad, autosaved
|
Calendar β month view with today highlighted
|
More Settings pages (click to expand)
| Compositor | Status | Notes |
|---|---|---|
| Niri | Full | Event-driven IPC, auto-reconnect |
| Hyprland | Full | Socket2 event stream; Night Light requires hyprsunset |
| MangoWC | Full | Mango 0.16+ JSON IPC; live tags, clients and per-output display controls |
MangoWC is supported through its native mmsg JSON IPC. Quickshell verifies a
live Mango socket instead of assuming that Mango is active merely because the
mmsg executable is installed. The integration does not call Niri IPC while a
Mango session is running.
- Workspaces / tags β live
all-tagsevents with independent local tag targets on each monitor. In role mode, the primary display can show 1β5 and the secondary display 6β10 while Mango still receives the correct local tag. - Dock β live
all-clientstracking, running indicators, focus and close actions, with polling used only if the Mango event stream is unavailable. - Monitor discovery β reads connected outputs directly from
mmsg get all-monitors;wlr-randris not required for detection. - Per-output controls β scale, position, HDR and VRR are written as separate
monitorruleentries. Changing one display never copies its scale to the other display. A neighbouring output is updated only when its position must move to prevent an overlap. - Safe display changes β configuration is validated before replacement, written atomically, previewed for 10 seconds and reverted automatically unless Keep is selected.
- Mouse settings β sensitivity, scroll factor, acceleration profile, cursor
theme and cursor size are stored in a Quickshell-managed block in
~/.config/mango/config.confand applied withreload_config. - Session actions β workspace switching, window focus/close and logout use Mango dispatch commands.
Current-mode note: Mango 0.16's monitor IPC reports the active mode and logical geometry, but not the complete list of modes advertised by the display. The monitor page therefore shows the current resolution and refresh rate on Mango while still allowing independent scale, placement, HDR and VRR control.
The Mango configuration writer owns only these marked sections and preserves the rest of the user's configuration:
# BEGIN QUICKSHELL MANAGED MONITORS
# monitorrule=...
# END QUICKSHELL MANAGED MONITORS
# BEGIN QUICKSHELL MANAGED MOUSE
# mouse / trackpad / cursor settings
# END QUICKSHELL MANAGED MOUSERequired versions:
- MangoWC 0.16 or newer
- Quickshell 0.3.1 or newer
jqfor JSON-based helper actions
| Package | Purpose |
|---|---|
quickshell |
Shell framework (outfoxxed/quickshell) |
niri, hyprland, or mango |
A Wayland compositor |
networkmanager |
Network management (nmcli) |
bluez + bluez-utils |
Bluetooth |
pipewire + pipewire-pulse + wireplumber + libpulse |
Audio control and EQ filter-chain |
jq |
JSON processing in helper scripts |
python 3.10+ |
Port-independent monitor role manager and helper scripts |
socat or ncat |
Hyprland event stream, monitor hot-plug and live dock updates |
| Font | Package (Arch) |
|---|---|
| JetBrainsMono Nerd Font | ttf-jetbrains-mono-nerd |
| Inter | ttf-inter |
| Font Awesome 6 Free | ttf-font-awesome |
- matugen β Material You palette from wallpapers
- Arch:
sudo pacman -S matugen(or AUR:paru -S matugen-bin) - Fedora:
sudo dnf install matugen - Any supported distribution via Cargo:
cargo install matugen
- Arch:
| Package | Feature |
|---|---|
hypridle + hyprlock |
Lock, dim, monitor-off and suspend timers on Hyprland and Niri |
hyprsunset |
Night Light on Hyprland (required) |
gammastep |
Night Light on Niri / MangoWC (required) |
kconfig |
Fonts picker (kreadconfig6 / kwriteconfig6 write to kdeglobals) |
qt6ct-kde (AUR) |
Fonts picker also writes to qt6ct.conf when QT_QPA_PLATFORMTHEME=qt6ct |
fontconfig |
Fonts picker catalogue via fc-list (pre-installed on most distros) |
inotify-tools |
Event-driven config file watching (otherwise falls back to polling) |
grim + slurp |
Screenshot helpers |
imagemagick |
Wallpaper Spectrum image sampling and the module colour eyedropper (magick) |
wl-clipboard |
Copy captured screenshots to the clipboard |
power-profiles-daemon (Arch) or tuned-ppd + python3-gobject (Fedora) |
Power Profile module; supported profiles are detected from the active service |
hyprmoncfg + xdg-terminal-exec |
Optional Hyprland display-profile management in Display Studio; not required by the built-in monitor settings |
sudo pacman -S quickshell networkmanager bluez bluez-utils pipewire \
pipewire-pulse wireplumber libpulse jq python socat inotify-tools \
kconfig fontconfig power-profiles-daemon \
ttf-jetbrains-mono-nerd ttf-inter ttf-font-awesome
# qt6ct (AUR fork with KDE integration)
yay -S qt6ct-kde-
Clone the repository
git clone https://github.com/ekremx25/quickshell ~/.config/quickshell -
Install dependencies (see the section above).
-
Spawn quickshell at compositor startup
Niri β
~/.config/niri/config.kdlspawn-at-startup "quickshell"
Hyprland β
~/.config/hypr/hyprland.confexec-once = quickshellMangoWC β
~/.config/mango/autostart.shpgrep -x quickshell >/dev/null || quickshell &
Or launch manually:
quickshell. -
Enable the lock and idle timer service (Hyprland and Niri)
systemctl --user enable --now hypridle.serviceStart
hypridlethrough this user service only. Running it a second time from the compositor startup file would leave two independent timeout sets active.
All settings live in ~/.config/quickshell/ and are edited through the in-app Settings dashboard (launcher logo on the bar β settings icon).
| File | Contents |
|---|---|
bar_config.json |
Bar modules, layout, position |
dock_config.json |
Pinned apps, scale, alignment |
monitor_config.json |
Resolution, scale, HDR, VRR, colour mode per output |
monitor_identities.json |
Local EDID identity β stable monitor role mapping (generated locally) |
monitor_role_profiles.json |
Port-independent settings for Main / Secondary / Third (generated locally) |
monitor_runtime.json |
Current role β connector mapping (generated locally) |
theme_config.json |
Material You settings, wallpaper path |
lock_config.json |
Lock screen wallpaper and timeouts |
notification_config.json |
DND, popup position, animation speed, filters |
mouse_config.json |
Sensitivity, scroll factor, cursor theme |
screen_config.json |
Per-component monitor filtering |
nightlight_config.json |
Blue-light filter state + schedule |
weather_config.json |
Main weather location and configurable world-clock cities (generated locally) |
desktop_widgets.json |
Per-monitor-role desktop widget positions (generated locally) |
All writes are atomic (temp file + rename). A shell crash mid-save never leaves a corrupt config.
The bar's Power Profile module is portable and contains no user-specific paths. It resolves the helper relative to each user's XDG configuration directory and automatically chooses the power service available on the host:
- Arch Linux: uses
powerprofilesctlfrompower-profiles-daemon. - Fedora: uses the standard Power Profiles D-Bus API exposed by
tuned-ppd.
Install and start the matching backend once:
# Arch Linux
sudo pacman -S power-profiles-daemon
sudo systemctl enable --now power-profiles-daemon.service
# Fedora
sudo dnf install tuned-ppd python3-gobject
sudo systemctl enable --now tuned.serviceThe popup only displays profiles reported by the active backend, so systems
without hardware support for Performance mode will not show an unusable
option. Do not run power-profiles-daemon and tuned-ppd at the same time;
both provide the same D-Bus service.
On Hyprland, displays are remembered by their physical EDID identity
(manufacturer, model and serial), not by connector names such as DP-1 or
HDMI-A-1. The first launch assigns Main, Secondary and Third roles,
stores them locally, and updates the live role map after every monitor hot-plug.
Moving a display to another HDMI/DisplayPort connector therefore keeps its
role, workspace range and per-screen component selections.
Open Settings β Hardware β Screen Prefs to choose where each component is shown:
- Main / Secondary / Third follows the selected physical display even when its port changes.
- All creates one component instance on every connected display.
- Disable prevents that component from being created.
- Toast controls transient notification cards that appear on screen.
- Notifications controls the notification-centre/bar module; it is separate from Toast.
For notification cards on two monitors, set Toast β All. To show cards on only one physical monitor, select its role instead.
monitor_config.json, monitor_identities.json, monitor_role_profiles.json,
monitor_runtime.json, screen_config.json and desktop_widgets.json are
runtime files excluded by .gitignore. A clone never inherits the repository
owner's monitor ports, serial numbers, layout or screen preferences; every user
gets a local mapping generated from their own hardware.
Displays without a usable EDID serial fall back to capability matching. Two identical displays that both report the same or no serial cannot be physically distinguished by any Wayland shell; in that rare case reconnect both displays, choose the desired roles once, and keep the generated identity file local.
Open Settings β Appearance β Material You, enable Material You and select Wallpaper Spectrum. With ImageMagick installed, this Quickshell-specific scheme samples colours from the image and derives distinct, contrast-adjusted module accents and tinted surfaces. Without ImageMagick, it falls back to matugen's generated palette.
The responsive editor includes a live bar preview, wallpaper thumbnail,
descriptive scheme cards, and light/dark controls. Follow desktop tracks
the current wallpaper through awww, swww, swaybg, or Waypaper's saved
selection. A selected image can also be used independently of the desktop.
Use the module colour editor to search modules, show only custom colours,
choose presets, enter a six-digit hex colour, or sample a screen pixel
(grim, slurp, and magick required). Individual colours can be returned
to automatic mode, and the editor provides undo and reset actions. Custom
module accents are saved in theme_config.json; they are local preferences,
not a requirement for other users.
- Live Update watches both the wallpaper backend and the selected image. Changing paths or overwriting the same image file regenerates the palette.
- Module foregrounds use WCAG relative-luminance contrast and automatically choose a light or dark glyph colour.
- Rapid wallpaper or scheme changes are coalesced; the last requested palette is applied after any running matugen process completes.
- Catppuccin, Kanagawa and Tokyo Night are authored static palettes and do not react to wallpaper changes.
Workspace shape and transparency are independent settings, including a true outline style. Reset uses the same defaults as a fresh bar configuration. Application icons keep their desktop-file colours, with a fallback while icon metadata loads. The appearance layer is shared by Niri, MangoWC and Hyprland; workspace discovery still uses each compositor's own adapter.
Display Studio is available in Bar Settings and opens a movable, resizable
monitor-settings panel. Its separate hyprmoncfg profile and automatic
switching controls require Hyprland and an installed hyprmoncfg tool. They
are not a replacement for the Niri/MangoWC monitor backend. When
hyprmoncfgd.service is active, the monitor-apply helper defers to that daemon
to avoid competing layout writers.
bash scripts/screenshot_capture.sh full captures the desktop; use region
for an interactive selection. Images are saved under Pictures/screen by
default, with optional clipboard copying and a desktop notification. Set
SCREENSHOT_DIR to override the destination. Bind the helper in your own
compositor configuration; installing this repository does not add a keybind.
Run from the repository root:
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p 'test_*.py' -v
for test_file in tests/test_*.js; do node "$test_file" || break; doneQML tests use isolated temporary configuration and an offscreen renderer; they require Quickshell. JavaScript checks require Node.js. These checks cover palette updates, module colour persistence, workspace appearance, compositor adapters, and monitor-role logic; they do not replace live testing of every compositor and display setup.
Open Settings β Features β World Clocks. Select any of the bundled 249 ISO countries/territories, search for a city inside that country, then choose Add clock. Up to eight DST-aware clocks can be reordered or removed. Weather is fetched in one batched Open-Meteo request and the last successful response is cached for offline display. Use Screen Prefs β World Clocks to choose the target monitor(s).
Open Settings β Features β Markets for the official TCMB USD/TRY buying and selling rates plus CoinGecko Bitcoin and Ethereum spot prices in USD/TRY. Crypto cards include the 24-hour percentage change. The built-in converter supports the current currencies published by Frankfurter, including USD, TRY, EUR and Philippine Peso (PHP), with reversible pairs and offline rate caching. Data refreshes every five minutes and the last successful response remains available offline.
The World Clocks and Markets desktop panels can be dragged from anywhere on their surface. Their positions are saved per monitor role in desktop_widgets.json, so the layout survives restarts and connector changes.
Add Activity Monitor from Settings β Appearance β Bar Settings and click its bar chip to open the live panel. The compact view shows CPU, memory, network and disk activity; the expanded view adds GPU, storage and a searchable process table. Sampling starts only while the panel is open, so the module stays idle in the background.
The reader uses Linux /proc and /sys interfaces rather than compositor IPC,
so the same module works on Hyprland, MangoWC and Niri. A prebuilt x86-64 reader
is included. Other architectures can rebuild it locally:
make -C Modules/bar/ActivityMonitor clean allBuilding requires a C++17 compiler. The bundled source and reader are adapted
from stappmus/omarchy-activity-monitor
2.1.1 and retain its MIT licence in
Modules/bar/ActivityMonitor/LICENSE.
Warm-tint the display in the evening to reduce eye strain. Manual control, fixed-time scheduling, cross-compositor.
Install the backend for your compositor:
# Hyprland
sudo pacman -S hyprsunset
# Niri / MangoWC
sudo pacman -S gammastepWhy two backends? Modern Hyprland removed the
wlr-gamma-controlprotocol that gammastep relies on, so it now ships its own daemon (hyprsunset). Quickshell detects the active compositor and uses the appropriate backend automatically.
Settings β Appearance β Night Light:
- Toggle the filter on or off
- Adjust temperature with the 1000β6500 K slider
- Pick a preset (Candle, Warm, Reading, Neutral, Daylight)
- Enable the Schedule card and set on/off times β e.g.
19:00 β 07:00(midnight-wrap supported) - Enable Apply on startup to restore the saved temperature at shell boot
Native 10-band parametric EQ built on a PipeWire filter-chain. The UI writes eq/parametric-eq.txt and a helper script creates:
effect_input.eqβ virtual EQ sink (applications play into this)effect_output.eqβ processed stream, manually linked to the selected physical sink
# Apply a flat curve to the current default sink
~/.config/quickshell/scripts/eq_filter_chain.sh apply 0 0 0 0 0 0 0 0 0 0 auto
# Check status
~/.config/quickshell/scripts/eq_filter_chain.sh status
# Disable
~/.config/quickshell/scripts/eq_filter_chain.sh disableExpected healthy output: conf_exists=yes, plus effect_input.eq and filter-chain visible in wpctl status.
When you change output devices in pavucontrol or another mixer, the Equalizer module refreshes sink state in the background and auto-reapplies the active EQ curve β the same preset follows you from speakers β USB headphones β Bluetooth without rebuilding the curve.
The last known physical sink is stored in ~/.local/state/quickshell/eq_filter_chain.state as BASE_SINK.
A short tour for contributors. Full source is under Services/, Modules/, and Widgets/.
Staged loading β shell.qml
The shell boots in three phases to speed up the first visible frame:
| Phase | Delay | Loads |
|---|---|---|
| 1 | 0 ms | ShellBootstrap + Bar |
| 2 | 300 ms | EqBootstrap, MouseBootstrap |
| 3 | 600 ms | Dock, WeatherDesktop, WorldClockDesktop, MarketsDesktop, ToastHost, VolumeOSD |
Core persistence β Services/core/
| File | Role |
|---|---|
JsonDataStore.qml |
Schema versioning with migrate() and validate() hooks, default fallback |
TextDataStore.qml |
Atomic write (temp + rename) + write queue (no data loss on rapid saves) |
FileChangeWatcher.qml |
inotifywait with automatic polling fallback when inotify-tools is missing |
atomic_write.sh |
Argv-based write helper β zero shell interpretation, no injection risk |
Bar and dock modules are declared once in ModuleRegistry.js, while ModuleCatalog.qml owns their visual factories. The registry provides stable IDs, placement capabilities, alias migrations, automatic layout normalization and a runtime catalog health check. See the module registry contributor guide for the schema and extension workflow.
WorkspaceService.qml owns one compositor event stream and one normalized workspace model for every bar and dock consumer. Active workspaces are tracked per monitor, role-based numbering remains stable when HDMI/DP ports change, and old occupied workspaces stay visible during layout migration. Display mode, range size, empty/special visibility, scrolling and icon limits are persisted in bar_config.json.
Compositor abstraction β Services/CompositorService.qml
A singleton that detects the active compositor from environment variables and exposes a uniform API (monitors, focusWindow, powerOnMonitors, β¦) so modules never need to special-case Hyprland vs. Niri vs. Mango.
Mango's all-monitors, all-tags and all-clients payloads are normalised by
MangoIpc.js. This keeps Mango-specific field names
out of workspace, dock and monitor UI components and makes the parser logic
directly testable without a running compositor.
Every long-running integration (notification server, volume subscription, Niri event stream, Hyprland socket, Mango tag events, PipeWire EQ) ships with retry logic and auto-reconnect after compositor restarts or IPC drops.
Icons are missing or show as empty squares
Install JetBrainsMono Nerd Font and refresh the font cache:
sudo pacman -S ttf-jetbrains-mono-nerd
fc-cache -fvNetwork or Bluetooth toggles do nothing
Make sure the services are running:
systemctl enable --now NetworkManager
systemctl enable --now bluetoothNight Light does not tint the screen
- Hyprland: confirm
hyprsunsetis installed (which hyprsunset). Modern Hyprland no longer exposeswlr-gamma-control, sogammastepwill report "Zero outputs support gamma adjustment" and silently do nothing. - Niri / MangoWC: test
gammastep -O 4000directly β it should tint the screen. If it doesn't, the wlroots gamma-control protocol may not be advertised by your compositor build. - Look for an error banner at the top of Settings β Night Light for diagnostic info.
The equaliser has no effect
Apply a flat curve and inspect PipeWire:
~/.config/quickshell/scripts/eq_filter_chain.sh apply 0 0 0 0 0 0 0 0 0 0 auto
~/.config/quickshell/scripts/eq_filter_chain.sh status
wpctl status | grep -E "effect_input.eq|filter-chain"You should see conf_exists=yes, plus both effect_input.eq and filter-chain in wpctl status. If they're missing, confirm the PipeWire / WirePlumber / libpulse packages from the Core dependency list are installed.
Dock shows no running indicators on Hyprland
The dock uses Hyprland's socket2 stream via socat or ncat. Install one of them:
sudo pacman -S socat
# or
sudo pacman -S openbsd-netcatWithout either, the dock falls back to 2.5 s polling β indicators still work but update slower.
MangoWC shows no monitors, tags or running applications
Confirm that Mango 0.16+ and its IPC client are active in the same session:
mmsg get version
mmsg get all-monitors
mmsg get all-tags
mmsg get all-clientsEach command should return JSON. If they cannot connect, verify that Quickshell
was launched from Mango's session environment and that
MANGO_INSTANCE_SIGNATURE is available. Restart Quickshell after correcting
the session startup command.
A component appears on the wrong monitor after reconnecting cables
First check Settings β Hardware β Screen Prefs. Remember that Toast controls popup notification cards while Notifications controls the notification-centre module.
Inspect the current role map:
cat ~/.config/quickshell/monitor_runtime.jsonTo rebuild only the local physical-display mapping, keep a recoverable backup and restart Quickshell:
mv ~/.config/quickshell/monitor_identities.json \
~/.config/quickshell/monitor_identities.json.bak
quickshell kill
quickshell --daemonizeThe role manager recreates the file from the displays currently connected.
- Demos & tutorials: YouTube: @linuxlifex
- Built on: outfoxxed/quickshell
- Theming: InioX/matugen
- Companion project: ekremx25/smartcomplete



















