Mox
About
Welcome to Mox, a modern Wayland desktop environment built from the ground up in memory‑safe Rust. Mox strips away heavyweight GUI libraries and instead drives your hardware directly—so every pixel and frame is fully accelerated.
Key features:
-
Zero GUI libraries
Mox relies directly on Wayland and Vulkan, keeping the entire stack small, auditable, and lightning‑fast. -
Fully hardware-accelerated
Different components use either Vulkan or WGPU, depending on their needs, for optimal performance. -
Memory-safe core
Written entirely in Rust, Mox ensures safety without sacrificing speed. -
Keyboard-first design
The entire environment is operable using only the keyboard, making it fast, efficient, and accessible.
moxidle
moxidle is an idle management daemon for mox desktop environment
Configuration
Moxidle's configuration is written in Lua and is located at $XDG_CONFIG_HOME/moxidle/config.lua
or ~/.config/moxidle/config.lua
. A config file is required; moxidle won’t run without one.
General
variable | description | type | default |
---|---|---|---|
lock_cmd | command to run when receiving a dbus lock event (e.g. loginctl lock-session) | string | empty |
unlock_cmd | command to run when receiving a dbus unlock event (e.g. loginctl unlock-session) | string | empty |
before_sleep_cmd | command to run when receiving a dbus prepare_sleep event | string | empty |
after_sleep_cmd | command to run when receiving a dbus post prepare_sleep event | string | empty |
ignore_dbus_inhibit | whether to ignore dbus-sent idle inhibit events (e.g. from firefox) | bool | false |
ignore_systemd_inhibit | whether to ignore systemd-inhibit --what=idle inhibitors | bool | false |
ignore_audio_inhibit | whether to ignore ihbitition when audio is played (e.g. from firefox) | bool | false |
Timeouts
Moxidle uses timeouts to define actions on idleness.
When conditions are met and the system is idle, the timeout countdown (in seconds) begins. After the timeout duration, on_timeout
is triggered. When user activity resumes, on_resume
is executed.
Example timeout:
{
conditions = { "on_battery" }, -- Conditions that must be fullfilled for timeout to begin
timeout = 300, -- In seconds
on_timeout = "notify-send 'You are idle!'" -- Command to run when timeout has passed.
on_resume = "notify-send 'Welcome back!'", -- Command to run when activity is detected after timeout has fired.
},
You can define as many listeners as you want.
Full example with hyprlock
return {
general = {
lock_cmd = "pidof hyprlock || hyprlock", -- If hyprlock isn't running, start it. Prevents multiple instances.
before_sleep_cmd = "loginctl lock-session", -- Locks the session before the system sleeps.
},
timeouts = {
{
conditions = { "on_battery", { battery_below = 20 } }, -- Applies when on battery and battery is below 20%.
timeout = 300, -- Waits 5 minutes (300 seconds) of inactivity.
on_timeout = "systemctl suspend", -- Suspends the system when timeout hits.
},
{
conditions = { "on_ac" }, -- Applies when plugged into AC power.
timeout = 300, -- Waits 5 minutes.
on_timeout = "pidof hyprlock || hyprlock", -- Locks the screen if not already locked.
},
{
conditions = { "on_ac" }, -- Still on AC power.
timeout = 900, -- Waits 15 minutes.
on_timeout = "systemctl suspend", -- Suspends the system after 15 minutes of inactivity.
},
},
}
Conditions
-
on_battery
:- Triggers when the system is running on battery power (not plugged into AC).
-
on_ac
:- Triggers when the system is plugged into an AC power source.
-
battery_below = <int>
:- Triggers when the battery level is below the specified percentage (e.g.,
battery_below = 20
).
- Triggers when the battery level is below the specified percentage (e.g.,
-
battery_above = <int>
:- Triggers when the battery level is above the specified percentage (e.g.,
battery_above = 80
).
- Triggers when the battery level is above the specified percentage (e.g.,
-
battery_equal = <int>
:- Triggers when the battery level is equal to the specified percentage (e.g.,
battery_equal = 50
).
- Triggers when the battery level is equal to the specified percentage (e.g.,
-
battery_equal = <int>
:- Triggers when the battery level is equal to the specified percentage (e.g.,
battery_equal = 50
).
- Triggers when the battery level is equal to the specified percentage (e.g.,
-
battery_level = <BatteryLevel>
:- Triggers when the battery level is equal to the specified level (e.g.,
battery_level = critical
).
- Triggers when the battery level is equal to the specified level (e.g.,
-
battery_state = <BatteryState>
:- Triggers when the battery state is equal to the specified state (e.g.,
battery_state = charging
).
- Triggers when the battery state is equal to the specified state (e.g.,
Valid BatteryLevel
Values
"unkown"
or0
"none"
or1
"low"
or3
"critical"
or4
"normal"
or6
"high"
or7
"full"
or8
Valid BatteryState
Values
"unkown"
or0
"charging"
or1
"discharging"
or2
"empty"
or3
"fully_charged"
or4
"pending_charge"
or5
"pending_discharge"
or6
moxnotify
moxnotify is a notification server for the mox desktop environment. It handles system notifications with customizable appearance, behavior, and sound options.
Configuration
Moxnotify's configuration is written in Lua and located at:
$XDG_CONFIG_HOME/moxnotify/config.lua
or~/.config/moxnotify/config.lua
General Configuration
Option | Description | Type | Default |
---|---|---|---|
margin | Margin of the daemon surface. Can be a single integer for uniform margin or a map with top , right , bottom , and left values. | int or map of int's | 0 |
scroll_sensitivity | Sensitivity of mouse scroll for notification interaction. | float | 20.0 |
hint_characters | Characters used for keyboard button hints. | string | sadfjklewcmpgh |
max_visible | Maximum amount of notifications visible on screen at once. | int | 5 |
anchor | Position of the notifications on screen. | Anchor | top_right |
layer | Layer on which the notifications are rendered. | Layer | overlay |
queue | Order in which notifications are dismissed. | Queue | unordered |
output | Determines on which display output notifications will be rendered. Empty value means all outputs. | string | "" (empty) |
icon_size | Size of the notification icon in pixels. | int | 64 |
app_icon_size | Size of the application icon in pixels. | int | 24 |
default_sound_file | Path to default sound played on new notifications that don't provide their own sound. Can be specified per urgency level. | path or map of paths by urgency | "" (empty) |
ignore_sound_file | When set to true, ignore sounds provided by notifications. | bool | false |
default_timeout | Default timeout in seconds if one isn't requested by notification. Can be specified per urgency level: urgency_low , urgency_normal , urgency_critical . | int or map of ints by urgency | { urgency_low = 5, urgency_normal = 10, urgency_critical = 0 } |
ignore_timeout | When set to true, ignore timeout requested by notification. | bool | false |
history.size | Maximum number of notifications to store in history. | int | 1000 |
history.path | Path to the history database file. | path | ~/.local/share/moxnotify/db.mox |
Example General Configuration
general = {
margin = 0, -- Alternatively, you can use a table: { top = 0, right = 0, bottom = 0, left = 0 }
history = {
size = 1000,
path = "~/.local/share/moxnotify/db.mox"
},
default_sound_file = "/run/current-system/sw/share/sounds/freedesktop/stereo/message.oga", -- you can also use a table to map urgency levels if needed
ignore_sound_file = false,
hint_characters = "sadfjklewcmpgh",
scroll_sensitivity = 20.0,
max_visible = 5,
icon_size = 64,
app_icon_size = 24,
anchor = "top_right", -- Default anchor position
layer = "overlay", -- Default layer for notifications
queue = "unordered", -- Default queue type
output = nil, -- nil means notifications will display on output chosen by compositor (Usually the one currently focused)
default_timeout = {
urgency_low = 5,
urgency_normal = 10,
urgency_critical = 0
},
ignore_timeout = false
}
Keymaps
Moxnotify allows you to define custom keymaps for interacting with notifications inspired by vim. Each keymap consists of the following properties:
- mode: The mode in which the keymap is active (e.g.,
"n"
for normal mode). - keys: The key or combination of keys that trigger the action.
- action: The command that is executed when the key(s) are pressed.
Keymap Modes
Mode | Description |
---|---|
n | Normal mode – general interaction with notifications. |
h | Hint mode – for pressing buttons with keypresses. |
Keymap Actions
Action | Description |
---|---|
dismiss_notification | Dismisses the current notification. |
next_notification | Focuses next notification |
previous_notification | Focuses previous notification |
first_notification | Focuses first notification. |
last_notification | Focuses last notification. |
unfocus | Unfocuses surface |
noop | No operation; placeholder that performs no action. |
hint_mode | Activates hint mode for keyboard-based notification selection. |
normal_mode | Activates normal mode |
mute | Mutes all sounds coming from the daemon |
unmute | Unmutes all sounds coming from the daemon |
toggle_mute | Toggles mute state of the daemon |
inhibit | Inhibits notifications |
uninhibit | Uninhibits notifications |
toggle_inhibit | Toggles inhibit state of notifications |
show_history | Views history of notifications |
hide_history | Hides history of notifications |
toggle_history | Toggles history state |
Example Keymaps Configuration
keymaps = {
{
mode = "n";
keys = "d";
action = "dismiss_notification";
},
{
mode = "n";
keys = "<C-g>";
action = "last_notification";
},
{
mode = "n";
keys = "gw";
action = "hint_mode";
},
{
mode = "n";
keys = "f";
action = "noop";
}
}
Styling System
Each style rule customizes notifications based on a selector (which notifications it applies to) and an optional state (interaction state).
Style Rule Properties
Property | Description | Type | Default |
---|---|---|---|
selector | Target(s) for this style rule. Can be a string (e.g. "notification") or an array of strings (e.g. {"dismiss", "hints"}). | Selector or Selector[] | empty |
state | Interaction state when this rule applies (e.g. "hover", "container_hover"). | State | "default" |
style | The style overrides (fonts, colors, backgrounds, borders, etc.) | Style | {} |
default_timeout | Override global timeout (in seconds) for matching notifications | number | nil |
ignore_timeout | Whether to ignore timeouts for matching notifications | boolean | nil |
default_sound_file | Override default sound file for matching notifications | string (SoundFile) | nil |
ignore_sound_file | Whether to silence sounds for matching notifications | boolean | nil |
Style Properties
Property | Description | Type |
---|---|---|
background | Color of background | hex or map of hex by urgency |
min_width | Minimum width of the element | int or auto |
width | Width of the element | int or auto |
max_width | Maximum width of the element | int or auto |
min_height | Minimum height of the element | int or auto |
height | Height of the element | int or auto |
max_height | Maximum width of the element | int or auto |
font.size | Size of the font | int |
font.family | Family of the font | string |
font.color | Color of the font | string |
border.size | Size of the border | int |
border.color | Color of the border | hex or map of hex by urgency |
border.radius | Radius of the border | int |
margin.left | Margin left of the element | int |
margin.right | Margin right of the element | int |
margin.top | Margin top of the element | int |
margin.bottom | Margin bottom of the element | int |
padding.left | Padding left of the element | int |
padding.right | Padding right of the element | int |
padding.top | Padding top of the element | int |
padding.bottom | Padding bottom of the element | int |
Example Styles Configuration
styles = {
{
selector = "*",
style = {
border = {
color = {
urgency_critical = "#f38ba8",
urgency_low = "#a6e3a1",
urgency_normal = "#cba6f7"
}
},
font = {
color = "#cdd6f4",
family = "DejaVu Sans",
size = 10
}
}
},
{
selector = {
"next_counter",
"prev_counter",
"notification",
"hints"
},
style = {
background = {
urgency_critical = "#181825FF",
urgency_low = "#1e1e2eFF",
urgency_normal = "#181825FF"
}
}
},
{
selector = "notification",
state = "hover",
style = {
background = {
urgency_critical = "#313244FF",
urgency_low = "#313244FF",
urgency_normal = "#313244FF"
}
}
},
{
selector = "action",
state = "hover",
style = {
background = {
urgency_critical = "#f38ba8",
urgency_low = "#f2cdcd",
urgency_normal = "#f2cdcd"
}
}
},
{
selector = "progress",
style = {
background = {
urgency_critical = "#f38ba8",
urgency_low = "#f2cdcd",
urgency_normal = "#f2cdcd"
}
}
},
{
selector = "dismiss",
style = {
font = {
color = "#00000000"
}
}
},
{
selector = "dismiss",
state = "container_hover",
style = {
font = {
color = "#000000"
}
}
}
}
Special Types
Queue
unordered
: Every notification expires independently without orderfifo
: Notifications expire one by one in the order they arrived (First In, First Out)
Anchor
top_right
: Notifications appear in the top-right cornertop_center
: Notifications appear at the toptop_left
: Notifications appear in the top-left cornerbottom_left
: Notifications appear in the bottom-left cornerbottom_center
: Notifications appear at the bottombottom_right
: Notifications appear in the bottom-right cornercenter-right
: Notifications appear at the right of the screencenter
: Notifications appear in the center of the screencenter-left
: Notifications appear at the left of the screen
Layer
background
: Notifications appear behind regular windowsbottom
: Notifications appear above background but below regular windowstop
: Notifications appear above regular windowsoverlay
: Notifications appear above all other windows
Selector
all
: Every elementprev_counter
: The "previous" badgenext_counter
: The "next" badgeall_notifications
: The whole notification listnotification = <string>
: A specific notification instanceaction_button
: Any action buttondismiss_button
: The dismiss ("×") buttonprogress
: Progress baricon
: The notification's iconhints
: Keyboard hint overlays
States
The State enum controls when a style fires:
default
: Normal, resting statehover
: When the mouse is over the targetcontainer_hover
: When the mouse is anywhere over the notification containercontainer_hover = <string>
: Hover state for a container with a specific name