The hover-check Glib::signal_timeout re-arms every 50ms and is not owned by
the Workspace. Since Workspaces are destroyed at runtime, a workspace removed
while its check is armed would let the timeout fire on freed memory (use-after-
free, also touching the destroyed m_button). Add a destructor that calls
stopHoverCheck() to disconnect the source.
Currently, modules polling hardware nodes continuously wake up kernel drivers even when the monitor is asleep (e.g., DPMS off), flooding dmesg.
- Adds 'disable-on-sleep' config flag
- Hooks GTK window map/unmap signals to track DPMS state
- Propagates suspend/resume calls to AModule worker threads
Fix an issue in the MPD module where text failed to render
when raw tags containing markup characters were truncated
mid-sequence after sanitization,
resulting in fragmented XML entities (such as `&` cut into `&am`).
Resolve this by shifting the order of operations to
truncate the raw strings *before* running `sanitize_string`.
To keep `setLabel` decoupled and clean,
we introduce helper methods (`getArtistStr`, `getAlbumArtistStr`,
`getAlbumStr`, `getTitleStr`) inside the `MPD` class,
matching the architectural style of MPRIS.
Additionally:
- Introduce support for the customizable `ellipsis` config option
(defaulting to `…`).
- Switch the truncation logic of the MPD module to be
visual-width-aware using the newly extracted
`waybar::util::utf8_truncate`.
- Decouple the tooltip text from the main label's truncated text.
The tooltip now displays un-truncated, complete metadata
(properly escaped), providing a significantly better user
experience.
Move the UTF-8 visual-width measurement and truncation helper functions
from the mpris module to a common utility
(include/util/utf8_string.hpp and src/util/utf8_string.cpp).
This decouples string truncation and width measurement
from the mpris module, allowing other modules (like mpd) to reuse.
The helper function `utf8_truncate` (formerly `truncate` in mpris)
and `utf8_width` is exported under the `waybar::util` namespace,
while the low-level `measure_and_truncate` (formerly `utf8_truncate`)
is encapsulated in an anonymous namespace in src/util/utf8_string.cpp
to avoid unnecessary API exposure.
No functional changes were made to the mpris module's behavior.
Tray::update() already had logic to hide the module when all child items were passive, but it was only re-run on item add/remove — never on a status change. When the last visible item transitioned to Passive, the item hid itself but the now-empty module remained visible.
Connect Tray to each item's Gtk::EventBox signal_show/signal_hide so update() runs on every visibility transition, and simplify update() to check child->get_visible() directly instead of inspecting the `passive` CSS class. The Tray-level `show-passive-items` read becomes redundant since Item already honours it when deciding its own visibility; remove it along with the now-unused Tray::show_passive_ member.
Fixes: #3721
Move buildLuaDispatch and isLuaProtocol from private to
protected/public so IPCTestHelper can access them.
Add 7 tests covering all buildLuaDispatch branches, dispatch
error path, and isLuaProtocol cache behavior.
Hyprland 0.54 replaced the text-based dispatch socket protocol with a
Lua-based one. Commands like "dispatch workspace 1" are now interpreted
as invalid Lua (return hl.dispatch(workspace 1)), breaking workspace
clicks and scroll navigation.
Add IPC::dispatch() that probes the running Hyprland on first call and
routes commands through the new hl.dsp Lua API when the Lua protocol is
detected, falling back to the old text format otherwise.
When netlink events (link/addr/route changes) fire between timer
intervals, dp.emit() triggers update() which consumes the byte delta
and resets bandwidth_down_total_. A subsequent timer update sees
near-zero delta, displaying very small bandwidth.
Cache the last computed bandwidth values and skip recalculation
when update() is called within half the interval. Event-driven
updates reuse the cached values instead.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This allows users to use #RRGGBBAA format in their style.css.
The client now detects 8-bit hex codes, transforms them into
GTK-compatible rgba() syntax, and loads the modified data
into the CSS provider.
- Added utility to detect 8-bit hex patterns.
- Added transformation logic to convert hex alpha to decimal.
- Intercepted CSS loading in Client::setupCss to handle the conversion.
These Nerdfonts codepoints were removed in [3.0.0](https://www.nerdfonts.com/releases#v3.0.0):
> **Breaking 2: Material Design Icons Codepoints**
>
> The old Material Design Icon codepoints are finally dropped. Due to an historic mistake we placed them in between some asiatic glyphs, breaking that script. Since v2.3.0 the (updated and expanded) Material Design Icons have new codepoints in the 5 digit region.
>
> - Dropped codepoints `F500`… and class names `nf-mdi-*`
> - New codepoints `F0001`… and class names `nf-md-*`
> - The whole discussions are here: https://github.com/ryanoasis/nerd-fonts/issues/365
> - A translation table is available here: https://github.com/ryanoasis/nerd-fonts/issues/1059#issuecomment-1404891287
> - There are tools out there that probably can update your configuration.
For the majority of the removed symbols, it was as easy as finding the
replacement with the exact same name. For example, `f76b` (`nf-mdi-format_header_2`)
became `f026c` (`nf-md-format_header_2`).
There was one symbol that was completely removed (it was removed from
Material Design): `f5fc` (`nf-mdi-camcorder_box`). I have substituted it
with `f03d` (`nf-fa-video_camera`) which is not Material Design, but the
closest icon I could find.
Here's some example output from [nerdfix](https://github.com/loichyan/nerdfix)
```
╭─(ignormies)(~/g/fork-waybar) removed-nerdfonts-codepoints
╰──▪ nix-shell -p nerdfix --run "nerdfix check resources/config.jsonc"
INFO Check input from 'resources/config.jsonc'
☞ Found obsolete icon U+F76B
╭─[resources/config.jsonc:131:27]
130 │ "format": "{temperatureC}°C {icon}",
131 │ "format-icons": ["", "", ""]
· ┬
· ╰── Icon 'mdi-format_header_2' is marked as obsolete
132 │ },
╰────
help: You could replace it with:
1. U+F026C md-format_header_2
2. U+F026B md-format_header_1
3. U+F026D md-format_header_3
4. U+F026E md-format_header_4
☞ Found obsolete icon U+F769
╭─[resources/config.jsonc:131:41]
130 │ "format": "{temperatureC}°C {icon}",
131 │ "format-icons": ["", "", ""]
· ┬
· ╰── Icon 'mdi-format_float_right' is marked as obsolete
132 │ },
╰────
help: You could replace it with:
1. U+F026A md-format_float_right
2. U+F0268 md-format_float_left
3. U+F0269 md-format_float_none
4. U+F0263 md-format_align_right
☞ Found obsolete icon U+F5E7
╭─[resources/config.jsonc:146:41]
145 │ "format-full": "{capacity}% {icon}",
146 │ "format-charging": "{capacity}% ",
· ┬
· ╰── Icon 'mdi-cached' is marked as obsolete
147 │ "format-plugged": "{capacity}% ",
╰────
help: You could replace it with:
1. U+F00E8 md-cached
☞ Found obsolete icon U+F796
╭─[resources/config.jsonc:170:45]
169 │ "format-wifi": "{essid} ({signalStrength}%) ",
170 │ "format-ethernet": "{ipaddr}/{cidr} ",
· ┬
· ╰── Icon 'mdi-gamepad_variant' is marked as obsolete
171 │ "tooltip-format": "{ifname} via {gwaddr} ",
╰────
help: You could replace it with:
1. U+F0297 md-gamepad_variant
2. U+F0EB7 md-gamepad_variant_outline
3. U+F0462 md-road_variant
4. U+F025C md-food_variant
☞ Found obsolete icon U+F796
╭─[resources/config.jsonc:171:50]
170 │ "format-ethernet": "{ipaddr}/{cidr} ",
171 │ "tooltip-format": "{ifname} via {gwaddr} ",
· ┬
· ╰── Icon 'mdi-gamepad_variant' is marked as obsolete
172 │ "format-linked": "{ifname} (No IP) ",
╰────
help: You could replace it with:
1. U+F0297 md-gamepad_variant
2. U+F0EB7 md-gamepad_variant_outline
3. U+F0462 md-road_variant
4. U+F025C md-food_variant
☞ Found obsolete icon U+F796
╭─[resources/config.jsonc:172:44]
171 │ "tooltip-format": "{ifname} via {gwaddr} ",
172 │ "format-linked": "{ifname} (No IP) ",
· ┬
· ╰── Icon 'mdi-gamepad_variant' is marked as obsolete
173 │ "format-disconnected": "Disconnected ⚠",
╰────
help: You could replace it with:
1. U+F0297 md-gamepad_variant
2. U+F0EB7 md-gamepad_variant_outline
3. U+F0462 md-road_variant
4. U+F025C md-food_variant
☞ Found obsolete icon U+F6A9
╭─[resources/config.jsonc:180:36]
179 │ "format-bluetooth": "{volume}% {icon} {format_source}",
180 │ "format-bluetooth-muted": " {icon} {format_source}",
· ┬
· ╰── Icon 'mdi-cup' is marked as obsolete
181 │ "format-muted": " {format_source}",
╰────
help: You could replace it with:
1. U+F01AA md-cup
☞ Found obsolete icon U+F6A9
╭─[resources/config.jsonc:181:26]
180 │ "format-bluetooth-muted": " {icon} {format_source}",
181 │ "format-muted": " {format_source}",
· ┬
· ╰── Icon 'mdi-cup' is marked as obsolete
182 │ "format-source": "{volume}% ",
╰────
help: You could replace it with:
1. U+F01AA md-cup
☞ Found obsolete icon U+F590
╭─[resources/config.jsonc:186:28]
185 │ "headphone": "",
186 │ "hands-free": "",
· ┬
· ╰── Icon 'mdi-battery_unknown' is marked as obsolete
187 │ "headset": "",
╰────
help: You could replace it with:
1. U+F0091 md-battery_unknown
2. U+F094A md-battery_unknown_bluetooth
3. U+F17DE md-battery_arrow_down
4. U+F0750 md-microsoft_xbox_controller_battery_unknown
☞ Found obsolete icon U+F590
╭─[resources/config.jsonc:187:25]
186 │ "hands-free": "",
187 │ "headset": "",
· ┬
· ╰── Icon 'mdi-battery_unknown' is marked as obsolete
188 │ "phone": "",
╰────
help: You could replace it with:
1. U+F0091 md-battery_unknown
2. U+F094A md-battery_unknown_bluetooth
3. U+F17DE md-battery_arrow_down
4. U+F0750 md-microsoft_xbox_controller_battery_unknown
```
Load attention and overlay pixmaps from item properties, watch the
corresponding update signals, and prefer attention artwork while an item is in
NeedsAttention state.
When an item only exports an attention movie asset, fall back to loading that
asset as a static pixbuf so the tray still shows the alert state.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
Only add tray widgets after the SNI proxy has finished initializing and the
item has a valid id/category pair.
This also removes invalid items through the host teardown path, refreshes the
tray when item status changes, and avoids calling DBus methods through a null
proxy during early clicks or scroll events.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
Hyprland workspace reloads could stack duplicate scroll-event connections,
causing a single wheel gesture to switch multiple workspaces after repeated
config reloads. The persistent-workspaces monitor-array form also created the
monitor name instead of the configured workspace name.
Disconnect and replace the scroll handler on reinit, fix the persistent
workspace name selection, normalize urgent-window address matching, and reject
malformed workspace payloads before they corrupt the local state machine.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
The window module re-entered the same shared_mutex while refreshing IPC state:
update() took the lock and then called queryActiveWorkspace(), which tried to
lock it again. That is undefined behavior for std::shared_mutex and could
manifest as a deadlock.
Remove the recursive lock path and reset the derived window state before each
IPC refresh. That keeps solo/floating/swallowing/fullscreen classes from
sticking around when the client lookup fails or a workspace becomes empty.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>