-
Notifications
You must be signed in to change notification settings - Fork 1
Configuration
UnixNotis loads config.toml from the XDG config directory and hot-reloads it on change.
The default file is a working starting point, not a fixed product shape. Most panel widgets
are meant to be edited in config: swap commands, point entries at scripts, change icons,
hide sections, or add new toggles/stats/cards for local workflows.
Locations:
$XDG_CONFIG_HOME/unixnotis/config.toml- fallback:
$HOME/.config/unixnotis/config.toml
If the file is missing, built-in defaults are used. Unknown keys are ignored and logged.
Runtime sanitization clamps out-of-range values to safe limits.
Some layout values are also clamped at runtime. For example, the panel keeps a minimum
usable width even if config.toml asks for something smaller.
- The daemon, panel, and popup UIs watch for config changes.
- Updates are applied without restarting the service.
- Reload failures keep the previous valid configuration.
[general]
log_level = "info"
dnd_default = false
[inhibit]
mode = "no_popups"
[panel]
anchor = "right"
width = 420
# Vertical size as a percent of usable monitor height after margins
# and reserved work area
height = 84
# Exact pixel height override for advanced users
# height_override = 1487
empty_text = "NO NOTIFICATIONS"
empty_offset_top = 120
[popups]
anchor = "top-right"
width = 360
[theme]
base_css = "base.css"
popup_css = "popup.css"
panel_css = "panel.css"
widgets_css = "widgets.css"
media_css = "media.css"The default panel includes:
- Sliders: Volume, Brightness
- Toggles: Wi-Fi, Bluetooth, Airplane, Night
- Night uses shipped config-local helper scripts so backend fallback logic stays editable
- Stats: CPU, RAM, Battery
- Cards: Calendar, Weather (static unless configured)
Use this as a template. For custom controls, add or edit [[widgets.toggles]],
[[widgets.stats]], and [[widgets.cards]] blocks. See Widgets for schemas,
command fields, helper-script examples, and default command backends.
-
log_level: tracing filter syntax (RUST_LOGcompatible). -
dnd_default: default DND state when no persisted state exists.
-
mode:no_popups(store notifications, suppress popups) ordrop_all.
-
anchor:top-right,top-left,bottom-right,bottom-left,top,bottom,left,right. -
width: requested width in logical pixels. On smaller displays, runtime caps this to a monitor-aware maximum so the panel remains usable. This is not a hard ceiling. GTK may keep the live panel wider when child widgets need more horizontal space than the requested width. -
height: vertical size as a percent of usable monitor height. The usable area starts from monitor height and subtracts panel margins and Hyprland reserved work area whenrespect_work_area = true. This is a target height, not a forced clip height. Visible header, media, and widget sections still keep their natural minimum size, so very small percentages can look identical until the requested height grows past that content floor. -
height_override: optional exact pixel height for advanced layouts. When this is set,heightis ignored. This still does not force the panel smaller than the visible content minimum. -
keyboard_interactivity:none,on-demand,exclusive. -
output: optional Wayland output name. -
close_on_blur: hide when the panel loses focus. -
close_on_click_outside: hide on outside click (Hyprland only). -
respect_work_area: respects compositor reserved area (Hyprland only). -
empty_text: empty-state label text (supports\nfor multi-line). -
empty_offset_top: top offset when widgets are visible. When no widgets are visible, the empty state is centered in the list area. -
title: main panel header text. -
subtitle: optional secondary header text. Empty hides it. -
search_placeholder: placeholder shown in the panel search entry. -
search_visible: show the search entry by default instead of only after using the search action. -
action_row_visible: show or hide the compact utility action row below the header. -
notification_section_visible: wrap the notification list in a titled card-like section. -
notification_list_expand: let the notification list consume remaining vertical panel space. -
clear_button_placement:action-row,notification-header, orhidden. -
quick_actions_label: heading above toggle buttons. Empty hides the heading. -
system_status_label: heading above stat cards. Empty hides the heading. -
recent_notifications_label: notification-list heading. Empty hides the heading. -
clear_label: label for the clear-all action. -
footer_label: optional passive footer text. Empty hides the footer. It is not clickable; use a custom toggle withtoggle_cmdfor user-defined actions. -
widget_order: top-to-bottom section order usingsliders,media,toggles,stats,cards. -
[panel.margin]: margins in logical pixels.
Width behavior notes:
- A smaller
panel.widthrequest does not force the panel narrower than its current natural width if widget content still needs more room - Widget grid columns are a common cause: defaults are toggles in 4 columns and stats/cards in
2 columns, but
[widgets].toggle_columns,[widgets].stat_columns, and[widgets].card_columnscan tune that without CSS hacks - The media row clamps itself to the panel body width, so it usually becomes a width driver only when media CSS adds aggressive sizing
- Theme CSS can also widen the live panel when controls use large
min-width, padding, margins, or other horizontal sizing -
noticenterctl css-checkwarns when toggle/stat/card/media sizing looks likely to exceed the requested panel width - If a width change appears ignored, inspect widget CSS before assuming config reload is broken
Defaults:
empty_text = "NO NOTIFICATIONS"empty_offset_top = 120height = 84title = "Notifications"subtitle = ""search_placeholder = "Search app, title, or message"search_visible = falseaction_row_visible = truenotification_section_visible = falsenotification_list_expand = trueclear_button_placement = "action-row"quick_actions_label = ""system_status_label = ""recent_notifications_label = "Notifications"clear_label = "Clear"footer_label = ""widget_order = ["sliders", "media", "toggles", "stats", "cards"]
Section titles:
-
quick_actions_labeltitles the toggle section. -
system_status_labeltitles the stat section. -
recent_notifications_labeltitles the notification list. - Empty labels are hidden. This keeps compact layouts clean while still allowing descriptive headings in denser themes.
Height behavior notes:
- The header row always reserves space for the title and action buttons
- Visible widgets and media also reserve their own natural height and any configured
min_height - Because of that, low
heightvalues such as1through20can appear almost the same on a widget-heavy panel - Hiding widgets lowers that floor, which is why the same
heightcan look much smaller when the widget stack is collapsed - If the panel still looks taller than expected, check widget
min_heightvalues and theme CSS padding before assuming the percentage math is wrong
-
anchor,width,spacing,max_visible. -
width: requested width in logical pixels. On smaller displays, runtime caps this to a monitor-aware maximum so popup cards do not dominate the screen. -
default_timeout_ms,critical_timeout_ms. -
allow_click_through: disable input handling when true. -
output: optional Wayland output name. -
[popups.margin]: margins in logical pixels.
-
max_entries: history capacity. -
max_active: active list capacity. Runtime clamps this to12so the panel and popup stack stay bounded under bursts. -
transient_to_history: includes transient notifications in history.
Defaults:
max_entries = 200max_active = 12transient_to_history = false
-
enabled,include_browsers. -
layout: structural media card preset.-
carousel: nav buttons outside the card -
inline: nav buttons folded into the card -
stacked: vertical card with a lower control strip -
showcase: wide card with a dedicated action rail -
player: centered player shell with top art, a lower transport dock, and nav hidden by default
-
-
browser_tokens: case-insensitive browser-family tokens used to classify browser players. Matching is segment-based, not raw substring matching, so short tokens such asedgematch names likemicrosoft-edgewithout also matching unrelated names likeknowledge. -
title_char_limit: marquee starts after this length. -
show_source: show the source badge row above the title. -
show_source_when_single_player: keep the source badge visible when only one player exists. -
show_position: show the player counter. -
show_position_when_single_player: keep the counter visible even when only one player exists. -
show_title,show_artist,show_art,show_controls,show_navigation: hide or show each major media shell region without switching layouts. -
title_fallback: fallback used when the active player has no title.-
identity: show the player identity -
artist: show the artist name -
empty: leave the title lane blank
-
-
position_format: how the player counter is rendered.-
fraction:current/total -
current: just the current slot number
-
-
source_aliases: optional lowercase token map that rewrites noisy player names into friendlier labels. -
allowlist/denylist: case-insensitive substrings for player identities. -
art_position: artwork placement override layered on top of the preset.-
auto,start,top,hidden
-
-
controls_position: transport placement override layered on top of the preset.-
auto,inline,bottom,side,hidden
-
-
navigation_position: player-switch placement override layered on top of the preset.-
auto,external,with_controls,hidden
-
-
art_size_px: preferred artwork edge length. -
text_width_floor_px: minimum width reserved for the title lane. -
card_height_px: optional exact media card height override. -
content_spacing_px: spacing between major shell regions such as art, text, and rails. -
control_spacing_px: spacing between prev, play, and next buttons. -
navigation_spacing_px: spacing between player nav buttons and between nav and transport when they share one rail. -
remote_art_policy: controls which players may fetch remote album art.-
disabled: never fetch remote art -
native_only: allow remotehttpsart only for non-browser players -
browsers_too: also allow browser media sessions to fetch remotehttpsart
-
Defaults:
-
browser_tokensincludes common desktop browsers (Firefox, Chromium, Chrome, Brave, Vivaldi, Edge, Opera, Epiphany, Midori, Zen, Librewolf, Waterfox, Floorp). -
layout = "carousel". -
title_char_limit = 32. -
show_source = true. -
show_position = true. -
show_source_when_single_player = true. -
show_position_when_single_player = false. -
show_title = true. -
show_artist = true. -
show_art = true. -
show_controls = true. -
show_navigation = true. -
title_fallback = "identity". -
position_format = "fraction". -
art_position = "auto". -
controls_position = "auto". -
navigation_position = "auto". -
art_size_px = 50. -
text_width_floor_px = 140. -
card_height_px = none. -
content_spacing_px = 10. -
control_spacing_px = 6. -
navigation_spacing_px = 6. -
remote_art_policy = "native_only". -
playerpreset defaults:art_position = "top"controls_position = "bottom"navigation_position = "hidden"-
card_height_px = 208when no manual override is set
Notes:
- Layout presets change the real GTK shell, not just the CSS classes.
- The preset acts as a default shell, and the position toggles can override it. For example,
layout = "showcase"can still usecontrols_position = "bottom"andart_position = "top". - The centered player presentation is an explicit preset, not a side effect of
art_position = "top". Other top-art shells keep their own alignment rules unless the preset or manual overrides say otherwise. -
show_art = false,show_controls = false, orshow_navigation = falseremove those regions from the shell entirely and lower width pressure. - Local file artwork from native players such as
mpvandsmplayeris still allowed. - Remote art is limited to validated
httpsURLs and bounded fetch sizes. - Browser remote art stays off by default because webpage-controlled metadata can choose the art URL.
- Browser players with the same PID or same track metadata are collapsed into one entry.
- The source label and player counter still respect the single-player flags, so those labels can be hidden on single-player setups without changing multi-player behavior.
Example:
[media]
layout = "player"
show_source = false
show_position = false
title_fallback = "artist"
art_size_px = 56
text_width_floor_px = 220
card_height_px = 176
content_spacing_px = 4
control_spacing_px = 8
[media.source_aliases]
spotify = "Spotify"
firefox = "Firefox"Enable browser remote art only when that tradeoff is acceptable:
[media]
remote_art_policy = "browsers_too"-
enabled. -
default_name: freedesktop sound theme name. -
default_file: sound file path (relative to config dir when not absolute). -
default_dir: directory containing sound files.
Theme CSS file names resolve relative to the config directory. Alpha values are clamped to
0.0..=1.0 and dimensions are clamped to safe ranges.
-
base_css,panel_css,popup_css,widgets_css: theme file paths loaded by the live UI -
media_css: media-widget-only theme layer loaded abovewidgets.cssRelative paths resolve from the config directory. Absolute paths are also allowed - Active theme files do not have to end in
.css, but using the standard names keeps output and troubleshooting easier to follow -
border_width: card/control border thickness. -
card_radius: card corner radius. -
surface_alpha,surface_strong_alpha,card_alpha. -
shadow_soft_alpha,shadow_strong_alpha.
Theme behavior notes:
- existing themes still work through the legacy GTK color path
- GTK runtimes with custom property support can use additive
--unixnotis-*custom properties - those runtime values stay aligned with the
[theme]config knobs instead of forcing theme authors to duplicate the same numbers by hand - shared hook classes are available on panel cards, popup cards, and media cards for more targeted styling
Theme path notes:
-
noticenterctl css-checkfollows the active theme paths fromconfig.tomlinstead of blindly scanning every.cssfile under the config tree - The active path list includes
[theme].media_css - It warns when a configured theme target is missing
- It warns when multiple theme slots resolve to the same file
- It prints the active resolved theme file list before validation so it is clear which files were actually checked
- It accepts valid modern GTK CSS such as supported
var(...)andcalc(...)usage instead of treating them like blanket bad input
-
toggle_tooltips: enables GTK hover tooltips for toggle buttons. Default:false. -
toggle_layout:horizontalorvertical. Controls icon/label placement inside toggle cards. -
toggle_columns: fixed toggle grid column count. Default:4. -
stat_columns: fixed stat grid column count. Default:2. -
card_columns: fixed info-card grid column count. Default:2. -
refresh_interval_ms: base refresh interval for widget polling. -
refresh_interval_slow_ms: slower interval used during stable periods. -
[[widgets.stats]].plugin: optional external plugin for stat values. -
[[widgets.cards]].plugin: optional external plugin for card content.
Plugin block fields:
-
api_version: plugin contract version (currently1). -
command: simple executable command (no shell metacharacters). -
timeout_ms: plugin runtime timeout in milliseconds. -
max_output_bytes: maximum accepted plugin stdout payload size.
See Widgets for the widget schema and command examples.
Rules match notification fields and apply overrides. See Rules for details and examples.