Skip to content

Desktop widgets

Desktop widgets are configured through the normal Noctalia config stack. Declare layouts in ~/.config/noctalia/*.toml; the interactive editor writes its layout overrides to settings.toml.

  • Declarative config: [desktop_widgets] in ~/.config/noctalia/*.toml
  • GUI/editor overrides: $NOCTALIA_STATE_HOME/noctalia/settings.toml, $XDG_STATE_HOME/noctalia/settings.toml, or ~/.local/state/noctalia/settings.toml
[desktop_widgets]
enabled = true
[desktop_widgets.widget.clock_main]
type = "clock"
output = "DP-1"
cx = 960.0
cy = 540.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.clock_main.settings]
format = "{:%H:%M}"

When enabled, Noctalia renders each desktop widget as its own tightly-sized layer-shell surface on the Bottom layer. The current implementation ships button, clock, label, audio_visualizer, fancy_audio_visualizer, sticker, weather, media_player, and sysmon widget types plus an interactive edit mode.


Terminal window
noctalia msg desktop-widgets-edit
noctalia msg desktop-widgets-exit
noctalia msg desktop-widgets-toggle-edit

You can also turn edit mode on from Settings → Desktop → Toggle Editor. Noctalia shows a short internal notification and you should switch to an empty workspace (no windows covering the desktop) so the editor overlay is visible.

ActionEffect
Drag widget bodyMove
Drag outer selection ringRotate
Drag bottom-right handleResize uniformly
Drag toolbar handleReposition the editor toolbar on that output
GToggle snap grid
Shift + dragTemporarily disable snapping
Delete / BackspaceRemove selected widget
Settings inspector → Reset to DefaultsRestore all settings for the selected widget to built-in defaults
Escape / click DoneExit edit mode

When the snap grid is active, moving a widget snaps the nearest outer edge or center line to the grid, screen edges, and nearby widgets. Resizing keeps the opposite edge anchored and snaps the dragged edge to the same guides, with a horizontal bias for corner drags so matching widget widths is easier.

Primary-colored center guides are always shown in edit mode. Dragging a widget snaps its center to the monitor center when nearby, even if the snap grid is hidden or temporarily disabled with Shift.


Widget definitions are named tables under [desktop_widgets.widget.<id>]. This makes them friendly to split config files and deep-merge overrides. Edit mode writes the same schema into settings.toml; use Settings -> Export Config… -> Merged User Config to promote GUI-edited layouts back into declarative config. When widget_order is present, it is the authoritative widget list and order; unlisted widget tables are ignored.

[desktop_widgets]
enabled = true
schema_version = 2
widget_order = ["clock_main"]
[desktop_widgets.grid]
visible = true
cell_size = 16
major_interval = 4
[desktop_widgets.widget.clock_main]
type = "clock"
output = "DP-1"
cx = 960.0
cy = 540.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.clock_main.settings]
format = "{:%H:%M}"
FieldTypeDefaultDescription
Table keystring(required)Unique widget identifier (clock_main in [desktop_widgets.widget.clock_main])
typestring(required)Widget type (clock, weather, media_player, etc.)
outputstringMonitor name (e.g. "DP-1")
cx, cyfloatCenter position in logical pixels
box_widthfloat0.0Widget box width in logical pixels; 0.0 auto-fits the content
box_heightfloat0.0Widget box height in logical pixels; 0.0 auto-fits the content
rotationfloat0.0Rotation in radians
enabledbooltrueSet to false to temporarily hide a widget without removing it
[desktop_widgets.widget.clock_main]
type = "clock"
enabled = false # hidden, but preserved

All desktop widget types support an optional rounded background rectangle:

SettingTypeDefaultDescription
backgroundboolfalseShow a filled rounded rectangle behind the widget
background_colorstring"surface" (80% opacity)Background fill color role; fixed hex colors are also supported
background_radiusfloat12.0Corner radius in logical pixels
background_paddingfloat10.0Padding between content and background edge

Prefer color role names so desktop widgets follow the active palette. Fixed hex colors (#RGB, #RGBA, #RRGGBB, #RRGGBBAA) are supported when a non-palette color is intentional. Invalid role names or malformed hex colors are treated as config errors.

[desktop_widgets.widget.clock_main.settings]
background = true
background_color = "surface"

The clock, weather, media_player, and sysmon widget types additionally support text styling:

SettingTypeDefaultDescription
colorstring"on_surface"Text/glyph color role (e.g. "primary", "tertiary"); fixed hex colors are also supported
shadowbooltrueDraw a drop shadow behind text and glyphs for readability on wallpapers
[desktop_widgets.widget.clock_main.settings]
color = "primary"
shadow = true

[desktop_widgets.widget.clock_main]
type = "clock"
output = "DP-1"
cx = 960.0
cy = 540.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.clock_main.settings]
clock_style = "digital"
format = "{:%H:%M}"
color = "on_surface"
shadow = true
center_text = false
circle = true
SettingTypeDefaultDescription
clock_stylestring"digital""digital" renders a formatted text clock; "analog" renders a circular clock with hour, minute, and second hands.
formatstring"{:%H:%M}"Digital clock format string. Ignored when clock_style = "analog". Supports the same syntax and tokens as the bar clock format; see Date format tokens.
center_textboolfalseDigital only. Center-aligns the formatted time inside the clock box. When false, the clock keeps the leading edge stable as digits change width.
circlebooltrueAnalog only. Shows the outer ring and minute tick marks around the dial. When disabled, only the hands are drawn.

Desktop audio visualizers fill their widget box: the spectrum spans the full box width and the bars use the full box height. box_width and box_height set the box size — resize the box to change the visualizer’s shape; leave both 0.0 to start from the default footprint. They also accept optional mirrored, centered, show_when_idle, color_1, and color_2 settings; both colors default to primary.

[desktop_widgets.widget.audio_main]
type = "audio_visualizer"
output = "DP-1"
cx = 1040.0
cy = 620.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.audio_main.settings]
bands = 32
mirrored = true
centered = true
show_when_idle = false
color_1 = "primary"
color_2 = "secondary"
SettingTypeDefaultDescription
bandsint32Number of frequency bands
mirroredbooltrueMirror the spectrum horizontally
centeredbooltrueCenter bars vertically instead of aligning them to the bottom edge
show_when_idleboolfalseKeep the widget visible even when no media is playing
color_1string"primary"First gradient color role; fixed hex colors are also supported
color_2string"primary"Second gradient color role; fixed hex colors are also supported

Fancy audio visualizers render circular bars, waves, and rings. box_width and box_height control the fitted widget box size; leave both 0.0 to auto-fit the content. fade_when_idle is enabled by default so the widget fades out completely when no audio is active and fades back in when sound returns.

[desktop_widgets.widget.fancy_audio_main]
type = "fancy_audio_visualizer"
output = "DP-1"
cx = 960.0
cy = 540.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.fancy_audio_main.settings]
visualization_mode = "bars_rings"
sensitivity = 1.5
rotation_speed = 0.5
bar_width = 0.6
ring_opacity = 0.8
inner_diameter = 0.7
bloom_intensity = 0.5
fade_when_idle = true
primary_color = "primary"
secondary_color = "secondary"
SettingTypeDefaultDescription
visualization_modestring"bars_rings"One of "bars", "wave", "rings", "bars_rings", "wave_rings", or "all"
sensitivityfloat1.5Multiplier for bar and wave response
rotation_speedfloat0.5Rotation speed for animated elements
bar_widthfloat0.6Width of radial bars
wave_thicknessfloat1.0Thickness of the wave fill and edge
ring_opacityfloat0.8Opacity multiplier for ring elements
inner_diameterfloat0.7Diameter of the inner circular area
bloom_intensityfloat0.5Glow intensity around active bars, waves, and rings
fade_when_idlebooltrueFade the widget out when no audio is active
primary_colorstring"primary"Primary color role; fixed hex colors are also supported
secondary_colorstring"secondary"Secondary color role; fixed hex colors are also supported

Draws the current weather glyph alongside the temperature and short condition, driven by the shared WeatherService. Requires [weather] enabled = true in config.toml (see Services — Weather) — the widget will render a placeholder otherwise.

[desktop_widgets.widget.weather_main]
type = "weather"
output = "DP-1"
cx = 320.0
cy = 200.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.weather_main.settings]
color = "on_surface"
shadow = true
show_forecast = false
forecast_days = 3
SettingTypeDefaultDescription
show_forecastboolfalseShow upcoming daily forecast rows below the current conditions
forecast_daysint3Number of forecast days to show (1–6; only applies when show_forecast is enabled)

MPRIS media player showing album art, track title, artist, and playback controls (prev, play/pause, next). Requires an active MPRIS player.

[desktop_widgets.widget.media_main]
type = "media_player"
output = "DP-1"
cx = 500.0
cy = 700.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.media_main.settings]
layout = "horizontal"
color = "on_surface"
shadow = true
hide_when_no_media = true
SettingTypeDefaultDescription
layoutstring"horizontal""horizontal" (cover on left) or "vertical" (cover on top)
hide_when_no_mediaboolfalseHide the widget when no MPRIS player is active

Clickable button with an optional glyph and label. Runs a shell command on left click. Size auto-fits the content when box_width and box_height are 0.0; when a box is set, the button stretches to fill it and scales its text and glyph to match.

[desktop_widgets.widget.launcher_main]
type = "button"
output = "DP-1"
cx = 960.0
cy = 540.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.launcher_main.settings]
glyph = "terminal"
label = "Terminal"
command = "alacritty"
variant = "default"
hover_background = "hover"
background = true
SettingTypeDefaultDescription
glyphstring""Tabler glyph name shown before the label; omit for text-only
labelstring""Button text; omit for glyph-only
commandstring""Shell command run on left click
backgroundbooltrueShow the button’s own fill and border; when false, only the label and glyph are drawn
variantstring"default"Button style: default, primary, secondary, outline, ghost, destructive
colorstring(variant default)Label and glyph color role or fixed hex; omit to use the variant’s default foreground
hover_backgroundstring"hover"Background color role on hover; fixed hex colors are also supported

Displays an image file on the desktop. PNG, JPEG, WebP, SVG, and GIF are supported; animated GIFs play at their encoded per-frame durations and loop forever.

[desktop_widgets.widget.sticker_main]
type = "sticker"
output = "DP-1"
cx = 800.0
cy = 400.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.sticker_main.settings]
image_path = "/path/to/image.png"
opacity = 1.0
SettingTypeDefaultDescription
image_pathstringAbsolute path to the image file (PNG, JPEG, WebP, SVG, or GIF)
opacityfloat1.0Sticker image opacity from 0.0 to 1.0

Static title and description text block. The title uses a larger bold line; the description wraps below it and is hidden when empty.

[desktop_widgets.widget.note_main]
type = "label"
output = "DP-1"
cx = 400.0
cy = 300.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.note_main.settings]
title = "Welcome"
description = "Edit this in the widget inspector or settings.toml."
color = "on_surface"
opacity = 1.0
shadow = true
background = true
SettingTypeDefaultDescription
titlestring"Title"Primary heading text
descriptionstring""Body text under the title (omitted from layout when empty)
colorstring"on_surface"Text color role for both lines; fixed hex colors are also supported
opacityfloat1.0Text opacity from 0.0 to 1.0
shadowbooltrueDrop shadow on the text

System monitor widget with graph or pill-gauge display modes. Uses the shared SystemMonitorService. Poll intervals are configured globally under [system.monitor], not in the widget settings below.

[desktop_widgets.widget.sysmon_main]
type = "sysmon"
output = "DP-1"
cx = 200.0
cy = 800.0
box_width = 0.0
box_height = 0.0
rotation = 0.0
[desktop_widgets.widget.sysmon_main.settings]
display = "graph"
stat = "cpu_usage"
stat2 = "cpu_temp"
interface = ""
color = "primary"
color2 = "secondary"
show_label = true
shadow = true
background = true
# Gauge mode example:
# display = "gauge"
# gauge_layout = "horizontal" # icon | vertical pill | value (row)
# highlight_color = "error"
# label_min_width = 0
SettingTypeDefaultDescription
displaystring"graph""graph" shows a scrolling history chart; "gauge" shows a compact pill gauge like the bar sysmon widget
statstring"cpu_usage"Primary stat: "cpu_usage", "cpu_temp", "gpu_temp", "gpu_vram", "ram_pct", "swap_pct", "net_rx", "net_tx"
stat2stringGraph mode only. Optional secondary stat (same values as stat). Omit for single curve.
gauge_layoutstring"horizontal"Gauge mode only. "horizontal" lays out icon, vertical pill gauge, and value in a row; "vertical" stacks icon, horizontal pill gauge, and value
interfacestring""Network interface to monitor for net_rx/net_tx; empty uses the total across all non-loopback interfaces
colorstring"primary"Primary color role (graph line or gauge fill); fixed hex colors are also supported
color2string"secondary"Graph mode only. Secondary line color role when stat2 is set
highlight_colorstring"error"Gauge mode only. Color role used when the stat crosses activity/critical thresholds from [system.monitor]
show_labelbooltrueShow the current value as text
label_min_widthint0Gauge mode only. Minimum width for the value label in logical pixels (0 = auto)

For net_rx and net_tx, set interface to an exact kernel interface name from /proc/net/dev (for example wlan0 or enp5s0) to show only that interface. Leave it empty to show the total across all non-loopback interfaces.

GPU temperature is read from Linux hwmon when available, with an NVML fallback for NVIDIA proprietary drivers. GPU VRAM is read from AMDGPU DRM sysfs when available, with an NVML fallback for NVIDIA proprietary drivers.