Commit Graph
5265 Commits
Author SHA1 Message Date
Arnaud Venturi e07ee87ab3 Replace lone tab character in style.css with spaces for consistency 2026-07-30 18:16:29 +02:00
Alexis Rouillard d44a27af10 Merge pull request #5219 from 10ne1/fix/sway-ipc-subscribe-race
fix(sway/ipc): don't mistake events for the subscribe reply
2026-07-30 10:11:18 +02:00
Alexis Rouillard d3fb8a621e Merge pull request #5216 from LukashonakV/enum-refactor
util/enum: make header-only and drop mandatory Hyprland dependency
2026-07-30 09:41:01 +02:00
Alexis Rouillard d7e0554b3c Merge pull request #5225 from JuustKiwi/fix-mpris-newlines
fix(mpris): sanitize metadata to prevent multiline UI expansion
2026-07-30 09:34:41 +02:00
Ibrahim Issa f9e2b1dea7 fix(mpris): sanitize metadata to prevent multiline UI expansion 2026-07-28 13:48:40 +02:00
Adrian RatiuandClaude Fable 5 6e0b50567e fix(sway/ipc): don't mistake events for the subscribe reply
Ipc::subscribe() assumes the next message on the event socket is the
reply to the IPC_SUBSCRIBE it just sent.

When a module subscribes more than once (sway/workspaces subscribes to
"workspace" and then to "window"), an event from the first subscription
can arrive before the reply to the second one. The payload check fails
and the thrown exception permanently disables the module for that bar.

This is easy to hit when bars are (re)created on output hotplug, since
sway emits a burst of workspace events at exactly that moment while
moving workspaces to the new output:

[warning] module sway/workspaces: Disabling module "sway/workspaces",
Unable to subscribe ipc event

Fix it by skipping over event messages (type high bit set) until the
subscribe reply is found, re-emitting them on signal_event so none are
lost.

Fixes: #5218
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
2026-07-24 19:22:32 +03:00
Viktar Lukashonak 2d87bd5ba9 Drop mandatory hyprland dependency 2026-07-23 11:58:35 +03:00
Alexis Rouillard 30610d3b68 Merge pull request #5212 from bjnobre/fix/dynamic-tooltip-updates
fix(tooltips): keep dynamic tooltips from resetting hover delay
2026-07-21 21:13:14 +02:00
Alexis Rouillard 7fae3d7d43 Merge pull request #5213 from LukashonakV/cavaBump
cava bump
2026-07-21 15:08:37 +02:00
Viktar Lukashonak 5bd3cd4805 cavaBump 2026-07-21 15:17:55 +03:00
Bene-Jázem B. Nobre d32e7fa86f fix(tooltips): keep dynamic tooltips from resetting hover delay
Cache ALabel tooltip markup and provide it through query-tooltip instead of repeatedly setting GtkWidget's tooltip-markup property. This prevents frequently updating modules from restarting GTK's display-wide tooltip timer.

Keep the active tooltip updated directly so dynamic tooltip contents continue refreshing while the pointer remains stationary.
2026-07-20 11:20:39 -04:00
Alexis Rouillard 456f78ecb1 Merge pull request #5208 from Mrpaoo/ref/rm-dpemit
refactor: rm direct dp.emit() call in constructor.
2026-07-19 19:15:51 +02:00
yubo 5b8c98729f refactor: rm direct dp.emit() call in constructor. 2026-07-18 21:14:08 +08:00
Alexis Rouillard 7f732f0553 Merge pull request #5201 from grishatop1/master
use nmcli implementation for calculating WiFi signal strength
2026-07-16 22:24:23 +02:00
grisha e60ffa4a9c clang format 2026-07-15 22:52:46 +02:00
grisha 73fdafb5d3 use nmcli implementation for calculating signal strength 2026-07-15 16:15:09 +02:00
Alexis Rouillard d4a4417210 Merge pull request #5199 from LukashonakV/cavaImpr_2
refactor(cava): fix thread-safety, resource leaks, and style violations
2026-07-15 15:23:43 +02:00
Viktar Lukashonak 50f636236a man(waybar-cava): refresh and polish documentation
Synchronize the cava module man page with the current implementation:

- Fix scdoc table syntax (correct header/body cell prefixes)
- Add missing Waybar-side options: format-icons, vertex_shader, fragment_shader
- Remove options not consumed by the module (data_format, raw_target)
- Clarify option scope: raw-only, GLSL-only, and cava-config-only settings
- Update descriptions to match backend behavior:
  - ascii_range is derived from format-icons length
  - bar_height is ignored by Waybar
  - bar_delimiter is used for raw output
- Polish grammar, tighten structure, and fix example filenames
- Refresh STYLE and FRONTENDS sections to match the actual source
2026-07-15 15:46:37 +03:00
Viktar Lukashonak 52a5f74cd2 docs: merge coding conventions into CONTRIBUTING.md
Consolidate the standalone `CONVENTION.md` into `CONTRIBUTING.md` so that
all contributor guidelines live in a single, discoverable file.

Added sections:
- Language, build system, and formatting rules (Google style, clang-format)
- Naming conventions (PascalCase types, snake_case_ members, lowerCamelCase methods)
- Include ordering and header self-sufficiency requirements
- Class/module design patterns (AModule hierarchy, SafeSignal threading)
- JSON configuration and string handling guidelines
- GTK/Glib and OpenGL patterns
- Platform portability and RAII conventions
- Thread-safety rules (GTK single-threaded, background thread marshalling)
- Unsafe patterns to avoid (C-style casts, unbounded buffer copies)
- Singleton lifetime guidance (store config by value, no dangling refs)docs: merge coding conventions into CONTRIBUTING.md
2026-07-14 09:29:06 +03:00
Viktar Lukashonak 5c979152de refactor(cava): fix thread-safety, resource leaks, and style violations
Comprehensive refactor of the cava module backend and frontends.

Style & naming
- Rename Cava -> CavaRaw; snake_case methods -> lowerCamelCase
- Replace NULL with nullptr; replace C-style casts with static_cast
- Add explicit standard-library includes (<memory>, <string>, <chrono>)
- Fix missing trailing underscores on member variables

Architecture
- Remove Gtk::GLArea multiple inheritance in CavaGLSL (composition)
- Return std::unique_ptr from factory; add doAction() to GLSL variant
- Encapsulate thread timing arithmetic in AdaptiveDelay struct

Thread safety & correctness
- Replace raw sigc::signal with SafeSignal for cross-thread marshalling
- Fix data race between loadConfig() and out_thread_ (recursive_mutex)
- Fix audio_raw shallow-copy use-after-free via deep-copy AudioRaw payload
- Make loadConfig() exception-safe with CavaConfigGuard RAII
- Fix blocking read_thread_ race on shutdown (condition_variable + timeout join)
- Fix isSilent() data race (acquire pthread mutex)
- Eliminate doUpdate() recursion (iteration instead)
- Guard audio_raw_clean() against uninitialized state
- Fix format-icons underflow and cava_config buffer overflow
- Store config by value to prevent dangling references on reload
- Cache frontend config and refresh on runtime changes
- Fix signed-char icon lookup bug on x86
- Prevent Json::Value mutation bloat via const-ref lookups
- Broaden exception catches in worker threads (std::exception)

Resource management & GL robustness
- Fix OpenGL resource leaks (persist VBO/IBO/VAO; explicit destructor cleanup)
- Fix shader error handling crashes (valid infoLog allocation)
- Cache uniform locations instead of querying per frame
- Fix gradient color uninitialized stack memory (zero-init + clamped count)
- Fix shader time uniform integer division bug (float arithmetic)
- Add explicit VAO bind in onRender()
- Handle runtime surface config changes independently of shader changes
- Clamp negative gradient_count before GL upload

Follow-up
- Singleton API split (inst() + configure()) intentionally deferred to a
  dedicated PR because it changes the public constructor contract.
2026-07-13 19:50:09 +03:00
Alexis Rouillard cf19c836d3 Merge pull request #5197 from VlkrS/openbsd
fix(idle_inhibitor.cpp): Fix build for systems without SIGRTMIN/SIGRTMAX
2026-07-12 09:30:12 +02:00
Volker Schlecht 795047ba8b idle_inhibitor.cpp: Fix build for systems without SIGRTMIN/SIGRTMAX
See https://github.com/Alexays/Waybar/pull/4992 for reference
2026-07-11 23:36:59 +02:00
Alexis Rouillard 98b2a563f3 Merge pull request #5187 from pajlada/fix/add-waybar-load-manpage
docs(man): add load
2026-07-06 17:22:02 +02:00
Rasmus Karlsson b5abbdc696 docs(man): add load 2026-07-06 16:56:17 +02:00
Alex 624623215d ci(smoke): keep the compositor alive between hardware cases
hardware.sh called smoke::stop between umockdev cases, but smoke::stop runs
`swaymsg exit` and tears down the shared compositor -- so only the first case
(backlight) had a display and the rest failed with "cannot open display".
Kill only waybar between cases; leave compositor teardown to the EXIT trap.
2026-07-06 02:08:06 +02:00
Alex eee2ab92fe style(bluetooth): clang-format the enumerate args 2026-07-05 23:12:38 +02:00
Alexis Rouillard b3e9545899 Merge pull request #5184 from Alexays/fix/smoke-state-hang
ci(smoke): fix state tier hang from bare wait on a lingering daemon
2026-07-05 23:12:19 +02:00
AlexandClaude Opus 4.8 4222d5a213 ci(smoke): fix state tier hang from bare wait on a lingering daemon
The state tier started actually running mpd in 74f0d33, which exposed a
deadlock in teardown: state.sh launches `mpd --no-daemon &` and never kills
it during the tier, and its cleanup() called smoke::stop *before* killing mpd.
smoke::stop ended in a bare `wait`, which reaps *every* background job of the
shell -- including the still-running mpd -- so it blocked until GitHub's 6h
job timeout. continue-on-error doesn't help: it catches failures, not hangs.

- lib.sh: smoke::stop now waits only on the PIDs it owns (waybar, compositor),
  so an unrelated daemon left running by a tier can't deadlock teardown.
- state.sh: cleanup() tears down mpd/pulseaudio before smoke::stop.
- smoke.yml: add timeout-minutes: 20 so a future hang fails fast instead of
  burning the default 6h runner budget.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 23:10:07 +02:00
Alex 6294ed2520 fix(hyprland/language): apply the CSS class on the main thread
onEvent() runs on the Hyprland IPC listener thread and mutated the label's
style context (add/remove class) directly, racing the GTK main thread's
drawing and corrupting the heap (double free / corrupted double-linked list).
Follow the Submap pattern: onEvent only stores the layout under the mutex and
emits the dispatcher; update() swaps the CSS class on the main thread, tracking
the previously applied class.

Fixes #4665
2026-07-05 23:06:37 +02:00
Alex 6c1a0fa185 fix(bluetooth): accept module-level placeholders in enumerate formats
tooltip-format-enumerate-connected[-battery] only received the device_* args,
so {status}, {num_connections} and {controller_*} threw fmt "argument not
found". Pass those args to the enumerate fmt::format as well.

Fixes #4384
2026-07-05 23:06:37 +02:00
Alex 6d5d5f0768 fix(cava): throw instead of exit() on a bad config
loadConfig() called exit(EXIT_FAILURE) when the cava config failed to load or
no input source was available, killing the whole bar. Throw std::runtime_error
instead: the factory/bar catch it at construction and disable only the cava
module. The read_thread_ also calls loadConfig() at runtime, so contain the
throw there too, logging instead of terminating.

Fixes #4456
2026-07-05 23:06:37 +02:00
Alex 699589b66a fix(river/tags): parse hide-vacant once, not in the wl callbacks
config_["hide-vacant"].asBool() was called from the river status listeners.
When the option is given as a string ("true") jsoncpp's asBool() throws
"Value is not convertible to bool", and that exception unwinding through
libwayland's C dispatch aborts the process. Parse it once in the constructor
into a bool member (accepting the string form) and read the cached value.

Fixes #4078
2026-07-05 23:06:37 +02:00
AlexandClaude Opus 4.8 a7b3a2c0db ci(smoke): fix state tier hang from bare wait on a lingering daemon
The state tier started actually running mpd in 74f0d33, which exposed a
deadlock in teardown: state.sh launches `mpd --no-daemon &` and never kills
it during the tier, and its cleanup() called smoke::stop *before* killing mpd.
smoke::stop ended in a bare `wait`, which reaps *every* background job of the
shell -- including the still-running mpd -- so it blocked until GitHub's 6h
job timeout. continue-on-error doesn't help: it catches failures, not hangs.

- lib.sh: smoke::stop now waits only on the PIDs it owns (waybar, compositor),
  so an unrelated daemon left running by a tier can't deadlock teardown.
- state.sh: cleanup() tears down mpd/pulseaudio before smoke::stop.
- smoke.yml: add timeout-minutes: 20 so a future hang fails fast instead of
  burning the default 6h runner budget.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 23:00:33 +02:00
Alex 74f0d3393a ci(smoke): fix the mpd / hardware / leak tiers so they actually run
The first run went green but the best-effort tiers silently didn't exercise
anything:

- state.sh: the mpd `audio_output { ... }` block was on one line, which mpd
  rejects ("Unknown tokens after '{'"), so mpd never started and the mpd
  sub-tier (the #5183 empty-queue repro) skipped. Split the block across lines.
  Also move teardown into a cleanup() with `|| true` so a dead-pid kill under
  `set -e` no longer makes the step exit 1.
- hardware.sh: umockdev-run's LD_PRELOAD lands ahead of the linked-in ASan
  runtime, so ASan aborted before main() ("ASan runtime does not come first")
  and waybar never started -- the backlight/slider (#5179) path wasn't tested.
  Set verify_asan_link_order=0 so the instrumented binary runs under the preload.
- leakcheck.sh: abort_on_error=1 turned LSan's exit report into a core dump;
  force abort_on_error=0 for this report-only tier.
- lib.sh: assert_clean now also flags "ASan runtime does not come first" so a
  future preload/link-order regression fails loudly instead of passing.
2026-07-05 22:39:35 +02:00
Alex 9a10949938 ci(smoke): cover teardown, state transitions and fake hardware
The smoke test only exercised steady-state rendering and killed waybar with
SIGTERM, so whole crash classes were invisible: exit-time use-after-free
(#5182), module state transitions (#5183) and hardware-backed modules (#5179).
Add tiers that hit those paths under ASan (+ _GLIBCXX_ASSERTIONS):

- lib.sh: assert_clean_exit (SIGINT teardown -> checks segfault/abort + ASan
  report emitted during destruction), output hotplug helpers, signal/reload,
  WAYBAR_WRAP hook, opt-in leak detection.
- lifecycle.sh (gating): clean exit, runtime output hotplug (Bar/module
  destroy), toggle/reload churn, fast-interval teardown race (#5182 class).
- fuzz.sh (gating): pathological custom-backend output (empty, nonzero exit,
  invalid JSON, huge, non-UTF8, empty format).
- coverage.sh (gating): every Factory module must be classified for smoke
  coverage; a new unlisted module fails the job (#5179 slipped through).
- modules.sh: also render the whole matrix inside a group; SIGINT teardown per
  module instead of SIGTERM.
- state.sh (best-effort): real mpd driven through an empty queue (#5183) +
  stop/clear; pulseaudio + slider on a null sink.
- hardware.sh (best-effort): backlight, backlight/slider (#5179) and battery
  via umockdev.
- leakcheck.sh (report-only): clean-exit run under LSan.
2026-07-05 22:21:46 +02:00
Alex 445e2aec1f fix(bar): avoid use-after-free segfault on exit
Members are destroyed in reverse declaration order, so modules_all_ (and
the modules it owns) are gone before the GtkWindow. Tearing down a mapped
window emits `unmap`, whose handler runs toggleSuspend() over the already
freed modules. Disconnect the map/unmap handlers in ~Bar first.

Fixes #5182
2026-07-05 22:03:28 +02:00
Alex 9d8a8356b5 fix(mpd): don't dereference a null song when the queue is cleared
mpd_run_current_song() returns NULL when there is no current song (e.g.
after `mpc clear`), leaving song_ null. setLabel() always evaluates the
fmt::format() tag arguments -- even for format-stopped -- so getTag() and
getFilename() would call mpd_song_get_tag()/mpd_song_get_uri() on a null
song and segfault. Guard both against a null song_.

Fixes #5183
2026-07-05 22:03:28 +02:00
Alexis Rouillard 6888243c50 Merge pull request #5180 from khaneliman/fix/taskbar-all-outputs
fix(wlr/taskbar): respect all-outputs
2026-07-05 18:32:05 +02:00
Austin Horstman ebbc7ea4dc fix(wlr/taskbar): re-show task when it no longer matches ignore-list
The un-ignore branch in hide_if_ignored() computed is_was_ignored
after the enclosing condition already required ignored_ to be false,
so it never ran, and a task whose app_id/title changed away from an
ignore-list entry stayed hidden forever.

Reset ignored_ and show the button again, subject to the same
all-outputs/output-membership check used everywhere else.
2026-07-05 10:23:58 -05:00
Austin Horstman cbad42bc9b fix(wlr/taskbar): stop forcing tasks onto every output's bar
hide_if_duplicate() unconditionally re-ran handle_output_enter() with
the bar's own wl_output for every non-squashed task, so any app_id or
title event made the task visible on all bars and "all-outputs": false
was effectively ignored. The un-squash path in handle_closed() showed
the replacement task unconditionally, with the same effect.

Track whether the toplevel is actually on the bar's output from the
protocol's output_enter/output_leave events, split the button
show/hide logic out of the protocol handlers, and gate every synthetic
re-show on all-outputs or the tracked output membership.

Fixes #5178
2026-07-05 10:23:06 -05:00
Alexis Rouillard bf59a21815 Merge pull request #5177 from Alexays/fix/recent-issue-bugs
fix: backlight I/O flooding (#5020) + network IP recovery after link flap (#5122)
2026-07-05 11:28:24 +02:00
Alex d518110e6f fix(network): recover IP address after a link flap / router reboot
The network module only populates the interface address from netlink
events (RTM_NEWADDR) or an explicit address dump. The interval timer
re-queries WiFi and bandwidth but never re-fetches the address, so the
module relies entirely on receiving the RTM_NEWADDR event.

Netlink multicast delivery is reliable unless the socket receive buffer
overflows, in which case the kernel drops notifications and reports
ENOBUFS. During a burst of link/address/route changes -- e.g. a router
reboot or a PPPoE redial -- this can drop the RTM_NEWADDR carrying the
interface's new IP (after the old one was removed by RTM_DELADDR). With
no overrun handling and no periodic resync, the address field stays
blank until Waybar is restarted (which re-dumps addresses).

Handle the overrun: when nl_recvmsgs_default reports ENOBUFS/NLE_NOMEM,
request a fresh link/address (and route, when auto-detecting) dump to
resynchronise, instead of silently continuing with lost state. Also
enlarge the event socket receive buffer to make overruns less likely in
the first place. The fix stays within the event thread, so it adds no
new locking or cross-thread socket access.

Fixes #5122.
2026-07-05 11:09:46 +02:00
Alex 5711b1f4ef fix(backlight): stop per-tick filesystem re-enumeration / I/O flooding
The backlight udev worker thread called enumerate_devices() on every
epoll_wait timeout, i.e. once per polling interval. enumerate_devices()
runs udev_enumerate_scan_devices(), which walks the entire
/sys/class/backlight and /sys/class/leds trees and opens/closes the
sysfs root and every device path. With no `interval` configured the
module polls on its default cadence, so this full re-scan ran
continuously even when brightness never changed, flooding the
filesystem (observed via fatrace as constant open/close of `/`).
Raising `interval` only lowered the cadence, which is why the reporter's
`interval: 10` workaround reduced the flood.

The full re-enumeration is redundant: the udev monitor already delivers
change/add/remove events for the backlight and leds subsystems. On the
timeout path, re-read only the sysfs attributes of the devices already
tracked (via udev_device_new_from_subsystem_sysname) instead of
re-scanning the whole tree. This keeps periodic refresh working for
firmware backlights such as acpi_video that may not emit udev change
events, while eliminating the tree-wide scan. Device discovery of
new/removed devices continues through the udev monitor.

Fixes #5020.
2026-07-05 11:09:46 +02:00
Alex 969855f99e ci(freebsd): provide a bzip2.pc stub for freetype2
Installing the bzip2 package does not ship a pkg-config file, so freetype2.pc
(a transitive requirement of gtkmm-3.0) still failed with 'Package bzip2 ...
not found'. bzip2 lives in the FreeBSD base system; write a minimal bzip2.pc
before meson setup so pkg-config can resolve it.
2026-07-05 10:46:58 +02:00
Alex d2493906df ci(freebsd): install bzip2 so freetype2's pkg-config resolves
The FreeBSD build broke on 'Package bzip2, required by freetype2, not found':
freetype2.pc lists bzip2 as a (private) requirement, but no bzip2.pc was
installed, so pkg-config could not generate cflags for gtkmm-3.0. Add bzip2
to the package list.
2026-07-05 10:43:57 +02:00
Alexis Rouillard 3868e06dee Merge pull request #5173 from Alexays/ci/smoke-plus
ci(smoke): sanitizer build + module/interaction/a11y/layout coverage
2026-07-05 10:39:29 +02:00
Alexis Rouillard 6fc23046f6 Merge pull request #5168 from Alexays/fix-2882
fix(wireplumber): reconnect when PipeWire/WirePlumber restarts (#2882)
2026-07-05 10:38:39 +02:00
Alexis Rouillard d8425b8fbb Merge pull request #5174 from Alexays/fix-5051
fix(image): don't crash at startup when the widget isn't realized yet (#5051)
2026-07-05 10:38:00 +02:00
Alexis Rouillard 61187b31c7 Merge pull request #5176 from Alexays/fix/review-lowsev
fix: resource-leak / correctness cleanups from the 0.15.0..master review (low severity)
2026-07-05 10:37:59 +02:00
Alexis Rouillard e92fe4b62a Merge pull request #5175 from Alexays/fix/post-0150-review
fix: batch of bugs found reviewing the 0.15.0..master diff
2026-07-05 10:35:13 +02:00