Commit Graph
100 Commits
Author SHA1 Message Date
Alex 9b093c53e9 fix(wireplumber): read gboolean into a gboolean, not a 1-byte bool (OOB write)
g_variant_lookup with the "b" format writes a gboolean (gint, 4 bytes),
but muted_ and source_muted_ are C++ bool members (1 byte). Passing their
addresses caused a 3-byte out-of-bounds write past the member (undefined
behavior). Read into a gboolean temporary and assign back to the bool,
preserving the prior value when "mute" is absent.
2026-07-05 10:19:51 +02:00
Alex acc7060be6 fix(wireplumber): guard async callbacks by connection generation; wire scroll once
Addresses review on #5168:

- Generational aliasing (blocking): setupConnection()/onReconnectTimeout()
  rebuild wp_core_/om_/pending_plugins_ in place on the same self, but the
  async load/activate callbacks carried no generation, and isModuleAlive()
  only proves self still exists. If PipeWire dropped again while a previous
  connection's async chain was still in flight, a stale completion would run
  against the rebuilt connection (a stray --pending_plugins_, an out-of-order
  install_object_manager), re-creating #2882's stale/blank state. Each async
  call now carries an AsyncCall{self, generation}; connection_generation_ is
  bumped in setupConnection(), and every callback drops out when its
  generation no longer matches (checked after isModuleAlive short-circuits).

- Duplicate scroll handlers: onMixerApiLoaded re-runs on every reconnect and
  connected a new scroll handler each time (dead but accumulating). Moved the
  one-time wiring to the constructor; handleScroll no-ops while mixer_api_ is
  null, so wiring it before the first connect is safe.
2026-07-05 09:53:11 +02:00
Alex 0b88b4ef0c fix(wireplumber): reconnect when PipeWire/WirePlumber restarts
Previously the wireplumber module connected to PipeWire once in its
constructor and had no handling for the connection being lost. When
PipeWire or the wireplumber service restarted (or crashed), the module
went stale/blank and never recovered until Waybar itself was restarted.

Connect to the WpCore "disconnected" signal and, on disconnect, schedule
a bounded main-loop retry (Glib::signal_timeout) that tears down the now
invalid core/object-manager/mixer-api references and rebuilds the whole
connection from scratch, re-running the async API and object-manager
setup. Connection setup/teardown is factored into setupConnection() and
teardownConnection() so startup and reconnect share one code path.

The reconnect timer is cancelled in the destructor and the existing
isModuleAlive() registry guard still protects in-flight async callbacks,
so teardown during a pending reconnect stays safe.

Fixes #2882.
2026-07-04 13:41:29 +02:00
Alexis Rouillard d9f2a437d0 Merge pull request #5165 from Alexays/fix/crash-batch3
fix: mpris resume SIGSEGV (#5124), wireplumber async UAF (#3974), stale reload batch state (#4129)
2026-07-04 13:12:17 +02:00
AlexandClaude Opus 4.8 54db6642ce docs: revamp README and add contributor docs
- README: quick-links bar, compositor-support table, module list grouped by
  theme with links to the wiki, getting-started section, collapsible
  dependency blocks, updated badges (CI, release), and a note that module
  docs live in man/ (auto-synced to the wiki)
- add CONTRIBUTING.md (dev build, code style, docs workflow, PR checklist)
- add issue templates (bug report, feature request) and a PR template

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 13:06:47 +02:00
Alexis Rouillard 6d3656a4a8 Merge pull request #5164 from Alexays/fix/tray-taskbar-mpd
fix: tray accel-group crash (#5142), wlr/taskbar shell-exec of built-in actions (#3284), MPD connect-timeout freeze (#1186)
2026-07-04 13:06:44 +02:00
Alex c19abf373b fix(mpris): defer widget visibility to update() to stop resume SIGSEGV
The name-vanished playerctl callback called event_box_.set_visible(false)
directly. On resume from suspend this runs in a re-entrant / torn-down
state and crashes in Gtk::Widget::set_visible. Only clear the player and
dp.emit() from the callback; update() (on the main thread) computes
visibility from player state and hides the module when there is no player,
matching the other hardened handlers.

Fixes #5124.
2026-07-04 13:04:04 +02:00
Alex 8664d9a963 fix(wireplumber): guard async load callbacks against use-after-free on teardown
The WirePlumber module registers three async callbacks (onDefaultNodesApiLoaded,
onMixerApiLoaded, onPluginActivated) that receive a raw self pointer with a NULL
GCancellable. WirePlumber cannot withdraw an in-flight callback, so if the module
is destroyed before a queued callback fires (e.g. a temporary output/bar is removed
while a component load is still pending, or during an audio route transition), the
callback dereferences the freed self, causing heap corruption / a crash.

Guard each of these callbacks with isModuleAlive(), which checks the existing static
modules registry. The destructor already removes this from the registry before any
teardown, so a missing entry means self is dangling and the callback bails out
without touching it.

A GCancellable cannot fix this cleanly here: every callback dereferences self on its
first line, and wp_core_load_component completes via a WpTransition (not a GTask), so
the cancellable is not recoverable from the GAsyncResult either. The liveness check
must not touch self at all.

Fixes #3974.
2026-07-04 13:04:04 +02:00
Alex 268d859043 fix(reload): reset pending bar-batch state on rebind
On reload the GApplication is recreated but the default main context (and any
queued PRIORITY_HIGH_IDLE createBarsBatch source) survives. pending_outputs_
was left holding dangling waybar_output* into the just-cleared outputs_ list;
createBarsBatch filters by address, which can mis-match once a freed slot is
reused. Clear pending_outputs_ and reset bars_scheduled_ in bindInterfaces so
the next run batches from a clean state. Mitigates the dangling-pointer path of
 #4129 (the cross-process app-id race in #4117 is separate).
2026-07-04 13:04:02 +02:00
AlexandClaude Opus 4.8 5180dec43e ci(wiki): fix STYLE lists rendering as blockquotes
Some pandoc versions (incl. the pinned 3.5) render scdoc bullet lists as a
series of `> ·` blockquotes instead of a Markdown list, which made the STYLE
sections look broken. Post-process the generated Markdown to collapse that
artifact back into real `- item` bullets, independent of the pandoc version.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 12:53:20 +02:00
Alexis Rouillard 0895465430 Merge pull request #5163 from Alexays/fix-2215
fix(keyboard-state): read lock LEDs from all devices, not just the first
2026-07-04 12:53:02 +02:00
Alex cb968c9369 fix(mpd): bound the connect timeout so an unreachable server can't freeze the bar
The MPD state machine drives all connection attempts from Glib::signal_timeout
callbacks, which run on the GTK main loop. tryConnect() called
mpd_connection_new() with the user-facing timeout_ (up to 30s by default), so an
unreachable server blocked the whole bar for the full connect timeout.

Bound the connect attempt to a short fixed timeout (2000 ms) so a dead server
fails fast, then restore the configured timeout_ for subsequent command reads so
slow-but-alive servers are unaffected.

Fixes #1186.
2026-07-04 12:50:30 +02:00
Alex b7a6fa8c91 fix(wlr/taskbar): dispatch built-in click actions via doAction, not the shell
wlr/taskbar reads on-click* config values (close, minimize, maximize,
fullscreen, minimize-raise, activate) directly as internal actions in
Task::handle_clicked, but never adopted the eventActionMap_/doAction
mechanism. As a result AModule::handleUserEvent additionally forkExec-ed
the same value as a shell command, e.g. on-click-middle: "close" ran the
action and then failed with "sh: line 1: close: command not found".

Register the taskbar built-in action names in eventActionMap_ so they are
recognized as module actions, and skip the shell forkExec in
handleUserEvent when the configured value is a recognized module action.
Non-action values are still run as user shell commands.

Fixes #3284.
2026-07-04 12:50:30 +02:00
Alex fae2b311de fix(tray): set an accel group on the dbusmenu client to stop Gtk-CRITICAL crash
When a tray item exports menu accelerators (e.g. Mattermost), libdbusmenu-gtk
calls gtk_widget_set_accel_path() with a NULL accel group because the
DbusmenuGtkClient never had one assigned. This raises a Gtk-CRITICAL that
corrupts menu state, and aborts Waybar when running under
G_DEBUG=fatal-criticals.

Assign a fresh GtkAccelGroup to the client right after the menu is created,
before it is populated or shown.

Fixes #5142.
2026-07-04 12:50:30 +02:00
AlexandClaude Opus 4.8 33223d5534 ci(wiki): render option tables, pin pandoc, add visible auto-gen note
Improve the generated wiki pages:
- normalize definition-style option blocks (*name*: / typeof: / default:)
  into scdoc tables, so every module renders options as a clean table like
  the table-style pages (Bluetooth, Network, ... no longer a wall of text)
- drop pandoc's empty leading table-header row so the real header shows
- pin pandoc to 3.5 in CI (the distro 2.x man reader mangled lists into
  blockquotes); matches local output
- prepend a visible "auto-generated from master, do not edit here" note to
  every page (was an invisible HTML comment)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 12:49:30 +02:00
Alex b2d15d1e3a fix(keyboard-state): read lock LEDs from all devices, not just the first
When no explicit device-path is configured, a multi-node keyboard can
expose several event devices where only one actually toggles the lock
LEDs. Previously update() read state from a single arbitrary device
(libinput_devices_.begin()), which often picked a node whose EV_LED
values never change, leaving the indicator stuck. Iterate all devices
and OR their NUML/CAPSL/SCROLLL values together so a lock is reported
on if any device reports it on. The single-device path is preserved
when device-path is set.

Fixes #2215.
2026-07-04 12:36:32 +02:00
Alexis Rouillard 8541ec8189 Merge pull request #5160 from Alexays/fix/clock-graceful
fix(clock): degrade gracefully on an invalid format specifier
2026-07-04 09:13:28 +02:00
Alexis Rouillard 368430208b Merge pull request #5161 from Alexays/fix-wireplumber
fix(wireplumber): correct linear→cubic volume conversion (0% on Bluetooth) + source-muted state
2026-07-04 09:13:11 +02:00
Alex 2650f062b5 fix(wireplumber): apply source-muted for Audio/Source modules
For a module configured node-type "Audio/Source", node_id_ and
source_node_id_ resolve to the same source node, so its primary mute
state is stored in muted_. update() unconditionally mapped muted_ to the
muted/sink-muted classes and source-muted only to the secondary
source_muted_ flag, so a source module could never receive source-muted
-- only the sink classes.

Gate the mute-class selection on the configured node-type: a source-type
module drives source-muted from its primary mute state, while a sink-type
module keeps muted/sink-muted for its sink and source-muted for the
secondary default source it tracks for {format_source}. The primary node
still feeds {volume} via updateVolume, so source-widget volume rendering
is unaffected.

Fixes #4523.
2026-07-04 08:57:36 +02:00
Alex 69b9a14b96 fix(wireplumber): show correct volume on Bluetooth sinks
The mixer-api is configured with the linear scale (0), so volume_ holds
the raw linear gain. The perceptual "cubic" value shown by wpctl and
exposed as {volume} is cbrt(linear), but update() computed pow(volume_, 3)
instead. Cubing under-reads every volume below max and collapses small
linear gains to 0% -- which is why the default Bluetooth sink (whose
normal levels map to low linear gains, e.g. wpctl 0.55 -> linear 0.166)
displayed 0% while wpctl reported a normal, unmuted volume.

Replace the inverted conversions with the correct cube-root/cube pair in
the display path, the scroll-scale conversions (cubic / cubic_percent),
and the max-volume ceiling mapping so scrolling and the cap stay
consistent with the corrected {volume}.

Fixes #5159.
2026-07-04 08:57:15 +02:00
Alex 23d63d2b84 fix(clock): degrade gracefully on an invalid format specifier
An unsupported specifier (e.g. the %-I / %OI no-leading-zero padding
modifiers, which the date/std::chrono formatter does not implement) threw out
of update() and the whole clock module failed to load. Catch it, warn once,
and fall back to {:%H:%M} so the bar still comes up. Addresses #1469.
2026-07-04 08:46:32 +02:00
Alexis Rouillard ea33ceb055 Merge pull request #5158 from Alexays/fix/crash-freeze
fix: batch of crash/freeze fixes (clock DST, interval:0, thread-safety, reconnects)
2026-07-04 08:36:26 +02:00
Alex 45ab8a1211 fix(core): fall back to default interval for periodic modules on interval:0
Addresses review: a zero interval_ must stay reserved for modules whose
default interval is already 0 (event-driven). Periodic modules (clock,
simpleclock, pollers) would otherwise do % interval_ (modulo by zero) or
sleep_for(0) in a tight loop. interval:0 on a periodic module now falls back
to its default interval.
2026-07-04 08:35:11 +02:00
Alex 5c06233340 style: clang-format the crash-fix changes 2026-07-04 03:17:33 +02:00
Alex 6672e924df fix(niri): reconnect IPC and stop per-event throttling to prevent freeze
The niri IPC worker slept 1ms per event and never reconnected. Under an
event burst the per-event cap back-pressures the socket, niri fills its
send buffer and drops the stream; read_line then returns false, the
detached thread exits and the module freezes permanently.

Remove the per-event sleep so events drain as fast as they arrive, and
wrap the socket setup and read loop in a reconnect loop that backs off
and re-establishes the stream on drop. A running_ flag lets the thread
exit cleanly on teardown.

Fixes #5117.
2026-07-04 03:14:13 +02:00
Alex 3831524ba8 fix(audio_backend): never throw across the PulseAudio callback boundary
connectContext() throws std::runtime_error when pa_context_connect() fails.
It was called directly from contextStateCb (the libpulse mainloop thread,
running pure-C callback frames) on the PA_CONTEXT_FAILED reconnect path, so on
a pipewire/pulse restart the exception unwound across the C callback boundary
and triggered std::terminate/SIGABRT.

Add reconnectContext() noexcept which wraps connectContext() and logs failures
instead of throwing, and use it from the callback. Guard against the
FAILED -> connect -> FAILED recursion/busy loop with a reentrancy flag. The
constructor-time connectContext() still throws as before.

Fixes #5141.
2026-07-04 03:14:13 +02:00
Alex d3bfec13cc fix(keyboard-state): make device removal idempotent to stop libinput abort
On device unplug the inotify IN_DELETE handler removed the libinput
device and unref'd it before erasing the entry from libinput_devices_.
A repeated IN_DELETE event for the same path (observed as the
"has been removed" log line printed twice) could reach an
already-unlinked device and trigger a libinput list_remove assertion
abort.

Erase the map entry first (under devices_mutex_) so a second delete for
the same path is a no-op, then call libinput_path_remove_device() and
libinput_device_unref() exactly once per device pointer.

Fixes #5143, #4443, #4566.
2026-07-04 03:14:13 +02:00
Alex 4229dc8ac2 fix(sway/window): resolve app icon on the main thread to stop icon-theme race
onCmd() runs on the sway IPC worker thread and called updateAppIconName(),
which touches the global Gtk::IconTheme cache. Concurrent access with the
main thread's draw (propagate_draw -> gtk_icon_theme_has_icon ->
g_hash_table_lookup) races and can segfault, notably on multi-monitor and
focus changes.

Move the icon-theme lookup into Window::update(), which runs on the main
thread via dp.emit(), and only store app_id_/app_class_ in onCmd().

Fixes #4108.
2026-07-04 03:14:13 +02:00
Alex c0a26104a5 fix(sway/language): apply CSS classes on the main thread to stop SIGSEGV
set_current_layout() mutated label_'s GTK style context (remove_class/
add_class) while being called from the sway IPC worker thread via
onEvent(). Off-main-thread GTK widget mutation caused a SIGSEGV.

Record only the target layout in set_current_layout() and apply the
matching CSS class in update(), which the dispatcher runs on the GTK
main thread. A new applied_class_ member tracks the currently applied
class so update() can swap it. The shared layout_/applied_class_ state
is guarded by the existing mutex_.

Fixes #3702.
2026-07-04 03:14:13 +02:00
Alex c29ed5f972 fix(client): don't exit when the desktop portal fails to start
The Portal constructor synchronously auto-starts org.freedesktop.portal.Desktop
via a Gio::DBus::Proxy. If that service fails or crashes on start it throws a
Glib::Error, which was previously uncaught and terminated Waybar. Wrap the
construction in a try/catch, log a warning and leave portal as nullptr on
failure, and null-guard every dereference so a missing portal simply disables
light/dark appearance detection instead of crashing.

Fixes #3140, #3601.
2026-07-04 03:14:13 +02:00
Alex d130ce6a66 fix(clock): disambiguate DST transitions to stop tooltip crash
Building a zoned_time/zoned_seconds from a local_time throws
ambiguous_local_time during the DST fall-back hour and nonexistent_local_time
across the spring-forward gap. update() runs this every minute with the
tooltip enabled by default and has no try/catch, so Waybar aborts every
minute during a DST transition. Pass choose::earliest at each construction to
resolve deterministically instead of throwing.

Fixes #2615; resolves the recurring DST-crash duplicates #5006, #5018, #5063,
#5096, #3024.
2026-07-04 03:10:55 +02:00
Alex bfe38bd1e2 fix(custom): validate JSON output UTF-8 and stop restart-interval:0 busy loop
- parseOutputJson() passed script text/alt/tooltip straight to Pango/GTK; an
  invalid-UTF-8 byte aborted the bar in g_utf8_collate. Validate/make_valid
  like parseOutputRaw already does. Fixes #2829.
- restart-interval:0 was floored to 1ms, respawning the script ~1000x/s and
  starving the main loop; a non-positive restart-interval now stops instead.
  Part of #4842.
2026-07-04 03:09:20 +02:00
Alex b5842d4f53 fix(core): don't floor an explicit interval:0 to 1ms
std::max(1L, interval*1000) turned a user's explicit "interval": 0 into a
1ms periodic refresh, i.e. a ~1000x/s busy loop that starves the GTK main
loop and leaks memory (mpris RSS growth, missing tooltips, frozen updates).
An explicit 0 now stays the 'no periodic refresh' sentinel. Fixes #4987,
#4842; helps #4864, #4917, #4998, #5145.
2026-07-04 03:09:20 +02:00
Alex 4eb2513cc0 fix(hyprland/language): pass named args in format-<lang> branches
The format-<short_description>[-<variant>] override branches only passed a
positional arg, so a format using {short}/{long}/{variant} threw 'argument
not found', which disabled the whole module. Now supply the same named args
as the fallback/tooltip branches. Fixes #5120.
2026-07-04 03:09:20 +02:00
Alex 1d86e8dfa9 fix(custom/graph): guard signal config with isInt() to avoid SIGABRT
refresh() called config_["signal"].asInt() unconditionally on every RT
signal; a non-integer "signal" value throws Json::LogicError and aborts
Waybar. Matches the guard already present in custom/image/idle_inhibitor.
Fixes #3514.
2026-07-04 03:09:20 +02:00
AlexandClaude Opus 4.8 4e76d7339f ci(wiki): auto-insert new module pages into the sidebar
generate.py now keeps _Sidebar.md in sync: any Module:-* page from the
mapping that is not yet linked is inserted alphabetically into the
Modules list. Existing entries (custom labels, nested sub-entries,
hand-written non-module links) are left untouched, so adding a module no
longer requires editing the sidebar by hand.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 03:07:53 +02:00
AlexandClaude Opus 4.8 c76bfc018b ci: auto-sync GitHub wiki module pages from man pages
Add tooling that makes the scdoc man pages the single source of truth and
regenerates the wiki module pages from them:

- .github/wiki/mapping.json: man-page -> wiki-page mapping (aggregation-aware)
- .github/wiki/generate.py: scdoc -> pandoc -> gfm, strips man-only sections,
  concatenates aggregated pages, appends optional extras/<Page>.md
- .github/wiki/extras/: hand-kept appendices (screenshots) with no man equivalent
- .github/workflows/wiki.yml: on push to man/** (or the tooling), regenerate
  and push the wiki; other wiki pages are left untouched

Covers all 65 man pages -> 45 wiki pages (5 new: GPS, Inhibitor, Mango, Menu,
WWAN). Non-module and hand-written wiki pages are never modified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 03:02:10 +02:00
AlexandClaude Opus 4.8 a3b39cfcf6 docs(man): backfill man pages with wiki-only info (source-of-truth pass)
Port information that previously lived only in the GitHub wiki into the
authoritative scdoc man pages, so the man pages become the single source
of truth for module documentation.

33 man pages enriched (options, format replacements, actions, style
selectors, troubleshooting and implementation notes). Additions were
verified against the source; stale/incorrect wiki entries were
deliberately not ported. All pages still compile with scdoc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 02:55:57 +02:00
AlexandClaude Opus 4.8 72fdf77c19 docs: align man pages with code + fill documentation gaps (0.16.0 audit)
A full man<->code consistency audit surfaced options, format placeholders
and CSS classes that were implemented but undocumented, documented but not
implemented (some causing fmt crashes when copied from examples), and
defaults that disagreed with the code. This aligns the docs with the code
and fixes a few genuine code gaps.

Docs:
- Add the missing waybar-user(5) man page (and register it in meson.build)
- Document previously-undocumented options/placeholders/CSS across many
  modules (custom image-path/image-name/icon-size, graph_type/width/
  datapoints; battery smooth-power; wireplumber format-source/only-physical;
  mpris {position}/prefer-album-artist; network {signalStrengthApp}/compact
  bandwidth; pulseaudio {source_volume}/{source_desc}; upower {temperature}/
  {model}/{native-path}; wwan {power_state}/{imei}; tray ignore-list; and
  many CSS state classes: .sink-muted, .source-muted, .workspace-hover, etc.)
- Correct documented defaults to match the code (hyprland format {name},
  gamemode {count}, cpu-graph interval 5, cava input_delay 4, niri taskbar
  icon-size 16, disk/gps/wayfire formats, menu-actions object type, ...)
- Remove placeholders/options that do not apply (custom-graph {icon}/format/
  format-icons/rotate) and fix crashing examples (wwan {mode}, gps
  format-no-fix); note cava background/foreground/continuous_rendering are
  cava-config-file options

Code:
- bluetooth: accept the documented `controller` key as a synonym of
  `controller-alias` (the option was silently ignored)
- mango/workspaces: supply the documented `{name}` fmt arg (was missing ->
  fmt::format threw)
- privacy: read `tooltip` as a bool (was guarded on isString(), so the
  documented `tooltip: false` was silently ignored)

All man pages validated with scdoc 1.11.4. Not compiled locally (no gtkmm);
C++ build relies on CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 02:39:38 +02:00
AlexandClaude Opus 4.8 14cb78b835 ci: install systemd-dev for systemd.pc in build-full job
On Debian sid, `dependency('systemd')` needs systemd.pc, which is shipped by
the `systemd-dev` package, not `libsystemd-dev`. Add it so the forced
-Dsystemd=enabled configure step succeeds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 02:34:31 +02:00
AlexandClaude Opus 4.8 45276f217e ci: add feature-complete build job to guarantee all modules compile
The linux matrix ran every distro with features in `auto` mode, so any
module whose dependency was missing from the image was silently skipped
and never compiled. Three modules (privacy/pipewire, gps, wwan) were built
by no CI job at all, and several others only on one or two distros.

Add a dedicated `build-full` job (Debian image) that installs the missing
dependencies inline and force-enables every optional feature, turning a
broken include or a missing dep into a hard build error instead of a silent
skip. Drop `debian` from the auto matrix since `build-full` uses the same
image and builds a strict superset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 02:32:33 +02:00
Alexis Rouillard ae968044a7 Merge pull request #5157 from Alexays/fix/0.16.0-review-and-ci
fix: backward-compat + bug fixes and man-page build fix for 0.16.0
2026-07-04 02:18:36 +02:00
AlexandClaude Opus 4.8 f72f84e011 fix: backward-compat + bug fixes and man-page build fix for 0.16.0
Post-0.15.0 review of the 0.15.0..HEAD range surfaced regressions and
bugs. This restores backward compatibility for existing configs/CSS,
fixes confirmed defects, and repairs the scdoc man-page build break on
master. Pango-markup tooltips are intentional and were kept.

Backward-compat restorations:
- AModule: honor legacy numeric Gdk::CursorType cursor values (int overload)
- memory: correct GiB divisor (was ~2.3% low); round bare {} placeholders
- wireplumber: scale max-volume into the linear domain so the cap works again
- idle_inhibitor: gate right/middle-click deactivate & scroll on dynamic-timeouts;
  accept both dynamic-timeout(s); widen timeout to double (no fractional truncation)
- custom: keep #custom-<name>.<class> CSS selectors working (classes on box_)
- image: don't wordexp-split a single path; fall back to the literal path
- niri/window: restore hide-when-empty (new show-empty opt-in); escape tooltip
- wlr/taskbar: plain-text tooltip when markup is disabled

Bug fixes:
- tray: fix use-after-free in onAdd; guard the watcher retry timeout
- hyprland: clamp max-windows iterator (OOB); drop duplicate language tooltip block
- niri/window: supply {col}/{max_col} args in the empty branch (fmt::format_error)
- mpris: escape {dynamic}/{player} tooltip; fix dangling player; albumArtist source
- mango: fix use-after-free race (dispatch under callback_mutex_)
- mpd: contain throwing checkErrors in noexcept idle paths (no std::terminate/UAF)
- keyboard_state: always render every lock label, with guarded defaults
- bluetooth: bound GATT ReadValue timeout, opt-in + services-resolved gating,
  preserve authoritative Battery1 percentage
- wireplumber: fix WpDevice reference leak / NULL handling
- battery, clock, dwl, wayfire, graph, custom_graph, transform, river: assorted
  crash/logic fixes

Man page / build:
- niri-workspaces: fix scdoc "indented by an amount greater than 1"
  (workspace-taskbar sub-options were mis-indented; breaks man-page build)
- document new show-empty (niri/window); correct network {txBitrate}/{rxBitrate}

Not compiled locally (no gtkmm on this host); C++ build relies on CI.
Man pages validated with scdoc 1.11.4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 02:14:13 +02:00
Alexis Rouillard 482cfab64e Merge pull request #2891 from awariac/link-speed
net: add ethernet link speed
2026-07-04 01:54:42 +02:00
Alexis Rouillard 237d6c7c7b Merge pull request #4997 from sewaustav/feat/niri-workspaces-taskbar
feat(niri): add workspace-taskbar support
2026-07-04 01:50:29 +02:00
Alexis Rouillard 7887cdacda Merge pull request #4504 from ErikReider/geoclue-privacy
Add GeoClue2 location privacy item
2026-07-04 01:50:22 +02:00
Alexis Rouillard 16c79c8dc1 Merge pull request #4557 from adryzz/wwan-module
WWAN module (ModemManager)
2026-07-04 01:48:42 +02:00
Alexis Rouillard bff291889d Merge pull request #4536 from Esensats/master
feat: sway/workspaces: add custom workspace sorting functionality
2026-07-04 01:44:23 +02:00
Alexis Rouillard 8eb7ee46cb Merge pull request #4850 from yangyingchao/master
(sni) be able to control oder of tray items, and clean up sni module based on clang-tidy
2026-07-04 01:43:31 +02:00
Alexis Rouillard d6b6e72896 Merge pull request #4305 from edeustua/fix_hyprland_window_count
fix: Use workspace ID to handle hyprland/workspace updates
2026-07-04 01:43:07 +02:00
Alexis Rouillard 0bb207d56f Merge pull request #5115 from jaschiu/jaschiu-patch-1
fix(tray): segfault due to use-after-free from iterating children
2026-07-04 01:42:36 +02:00
Alexis Rouillard ddce791b43 Merge pull request #4396 from kabhijeet/master
feat (niri/workspaces): add dynamic window icons to workspaces matching hyprland/workspaces
2026-07-04 01:42:35 +02:00
Alexis Rouillard 7ffee464b3 Merge pull request #1358 from RyanGibb/output-dimensions
added output-dimensions option
2026-07-04 01:37:55 +02:00
Alex 5ecda40166 meson: fix libmm-glib dependency to use correct pkg-config name 'mm-glib'
The ModemManager libmm-glib library installs its pkg-config file as
mm-glib.pc (not libmm-glib.pc), so dependency('libmm-glib') never
resolved and the nix-flake-check build failed with the wwan module
enabled.
2026-07-04 01:37:11 +02:00
Alex 8fa58b1000 nix: add libmm-glib for the wwan module 2026-07-04 01:36:46 +02:00
Alex 247e18fb0b Fix clang-format 2026-07-04 01:36:46 +02:00
Alex 41d86d92a8 fix(wwan): null-initialize pointer members to avoid UB in destructor 2026-07-04 01:36:46 +02:00
Alex 2aa74a523c wwan: fix hide-disconnected default, plug dup() leaks, meson/man cleanup
- update(): only hide the module when hide-disconnected is set AND the
  modem is not in the CONNECTED state, instead of hiding it unconditionally
  (the module was invisible by default).
- free the gchar* returned by mm_modem_dup_physdev/
  mm_modem_dup_equipment_identifier/mm_sim_dup_operator_name.
- meson.build: drop duplicate libgps dependency, install the wwan man page.
- man: document hide-disconnected (replacing the unimplemented
  hide-failed/hide-disabled/hide-not-registered options).
- remove stray empty subprojects/.wraplock.
2026-07-04 01:36:46 +02:00
Alexis Rouillard 46e96dfbaa Merge pull request #4545 from mbroemme/2025-wlr-taskbar-truncate-to-ellipsize-long-button
feat(wlr/taskbar): add `truncate` option to ellipsize long button text
2026-07-04 01:24:40 +02:00
Alexis Rouillard e36824e7be Merge pull request #2157 from savely-krasovsky/mediaplayer-py-enhancement
feat: added dbus handler to update current player
2026-07-04 01:14:56 +02:00
Alex efe31dfecf build: install wayfire man pages (register in meson man_files)
The wayfire window/workspaces man pages existed but were never added to
man_files, so they were never installed. Fixes #4264.
2026-07-04 01:13:28 +02:00
Alexis Rouillard 1214776ca2 Merge pull request #3818 from Sduniii/patch-1
feat: Added source_desc argument to format_source in pulseaudio.cpp
2026-07-04 01:13:07 +02:00
Alexis Rouillard d6523df849 Merge pull request #3817 from JarKz/master
feat: add way to use environment value for 'output' option
2026-07-04 01:12:14 +02:00
Alexis Rouillard 37dbd59dac Merge pull request #3017 from 0x000C0A71/master
[hyprland/workspaces] Add tooltips to hyprland/workspaces
2026-07-04 01:12:10 +02:00
Alexis Rouillard 78b9a38532 Merge pull request #4320 from LoricAndre/master
feat(hyprland/workspaces): add uniqueIcons option
2026-07-04 01:12:05 +02:00
Alexis Rouillard 285e68c098 Merge pull request #3151 from VPavliashvili/module-images
feat: add new module 'images' to render multiple images under one gtk container
2026-07-04 01:10:43 +02:00
Alexis Rouillard 48c3f9712f Merge pull request #3311 from AtomToast/master
add format-icons to river/layout
2026-07-04 01:09:58 +02:00
Alexis Rouillard a560e6a6d3 Merge pull request #4265 from g-goessel/master
feat: Add wifi network link bitrate value
2026-07-04 01:09:20 +02:00
Alexis Rouillard a4380bb600 Merge pull request #3573 from rossmeier/master
add click coordinates to script
2026-07-04 01:08:26 +02:00
Alexis Rouillard d42e0503e2 Merge pull request #3740 from NoakPalander/feature/squash-list
Added a taskbar squash option
2026-07-04 01:07:25 +02:00
Alexis Rouillard 39fdf7b9fb Merge pull request #3370 from torgiren/idle_inhibitor
allow dynamic timeout setting for idle inhibitor
2026-07-04 01:02:30 +02:00
Alexis Rouillard 84e1577489 Merge pull request #4001 from hansp27/niri-workspaces-display-preference
feat: add display-condition configuration option
2026-07-04 01:02:19 +02:00
Alexis Rouillard 7484cb8db3 Merge pull request #4014 from piwonskp/4008/dynamic-drawer
feat(Group/Drawer): add dynamic drawer hiding modules based on module's class
2026-07-04 01:02:14 +02:00
Alex ca9bfe5bfa Merge remote-tracking branch 'origin/master' into pr-2157
# Conflicts:
#	resources/custom_modules/mediaplayer.py
2026-07-04 00:59:00 +02:00
Alexis Rouillard 01d1b5a47e Merge pull request #4940 from beyertom/clock/configurable-week-numbering
clock: add weeks-numbering option for configurable CW calculation
2026-07-04 00:56:29 +02:00
Alex 8276f6a629 Merge remote-tracking branch 'origin/master' into pr-3017
# Conflicts:
#	include/modules/hyprland/workspaces.hpp
#	man/waybar-hyprland-workspaces.5.scd
#	src/modules/hyprland/workspaces.cpp
2026-07-04 00:55:38 +02:00
Alexis Rouillard 24dba2bb24 Merge pull request #4694 from whymusticode/max-icons
feat(hyprland/workspaces): add deduplication and max-icons option to workspace-taskbar
2026-07-04 00:55:34 +02:00
Alexis Rouillard 2e9e0ba706 Merge pull request #4714 from PickNicko13/master
Implemented "only-physical" parameter in the wireplumber module.
2026-07-04 00:55:27 +02:00
Alex 35dd0af208 Merge remote-tracking branch 'origin/master' into pr-4001
# Conflicts:
#	man/waybar-niri-workspaces.5.scd
#	src/modules/niri/workspaces.cpp
2026-07-04 00:54:50 +02:00
Alex f7ff8eab58 Merge remote-tracking branch 'origin/master' into pr-3370
# Conflicts:
#	include/modules/idle_inhibitor.hpp
#	man/waybar-idle-inhibitor.5.scd
#	src/modules/idle_inhibitor.cpp
2026-07-04 00:54:41 +02:00
Alex 328b6dc017 Merge remote-tracking branch 'origin/master' into pr-4014
# Conflicts:
#	include/group.hpp
#	src/group.cpp
2026-07-04 00:54:02 +02:00
Alexis Rouillard 10add89802 Merge pull request #4624 from andresilva/tray-hide-icons
Support hiding tray icons
2026-07-04 00:53:31 +02:00
Alexis Rouillard 4e13253230 Merge pull request #4685 from AckslD/no-switch-output
feat: allow not switching output when clicking sway/workspace
2026-07-04 00:53:26 +02:00
Alex a45328359d Merge remote-tracking branch 'origin/master' into pr-4265
# Conflicts:
#	src/modules/network.cpp
2026-07-04 00:52:34 +02:00
Alexis Rouillard 40042f42ac Merge pull request #4537 from thomascrha/niri-workspace-ignore-workspaces
feat(niri/worspaces): add ignore-workspaces configuration option
2026-07-04 00:52:19 +02:00
Alex 90883da500 Merge remote-tracking branch 'origin/master' into pr-3151
# Conflicts:
#	include/modules/image.hpp
#	src/modules/image.cpp
2026-07-04 00:51:52 +02:00
Alexis Rouillard 49f6edf67b Merge pull request #4543 from mbroemme/2025-wlr-taskbar-evenly-distribute-buttons
feat(wlr/taskbar): add `homogeneous` option to evenly distribute button widths
2026-07-04 00:51:24 +02:00
Alex 05f32172df Merge remote-tracking branch 'origin/master' into pr-4320
# Conflicts:
#	include/modules/hyprland/workspaces.hpp
#	man/waybar-hyprland-workspaces.5.scd
#	src/modules/hyprland/workspace.cpp
#	src/modules/hyprland/workspaces.cpp
2026-07-04 00:51:21 +02:00
Alex 23762842c6 Merge remote-tracking branch 'origin/master' into pr-3573
# Conflicts:
#	src/AModule.cpp
2026-07-04 00:51:06 +02:00
Alex 3df1a13b7d Merge remote-tracking branch 'origin/master' into pr-3740
# Conflicts:
#	include/modules/wlr/taskbar.hpp
#	src/modules/wlr/taskbar.cpp
2026-07-04 00:50:23 +02:00
Alexis Rouillard 2709d293ee Merge pull request #4941 from sjudin/groups-add-empty-css-class
feat(group): Add .empty class to empty groups
2026-07-04 00:50:01 +02:00
Alex 29c014e3e5 Merge remote-tracking branch 'origin/master' into pr-3817
# Conflicts:
#	src/config.cpp
2026-07-04 00:49:37 +02:00
Alex 5c0f954db7 Merge remote-tracking branch 'origin/master' into pr-3311
# Conflicts:
#	src/modules/river/layout.cpp
2026-07-04 00:49:01 +02:00
Alex 2600e1e641 Merge remote-tracking branch 'origin/master' into pr-3818
# Conflicts:
#	src/modules/pulseaudio.cpp
2026-07-04 00:48:49 +02:00
Alexis Rouillard e9494bd271 Merge pull request #5153 from Grinchuelo/feat-customizable-icon-thresholds
feat(ALabel): allow custom percentage thresholds in format-icons
2026-07-04 00:44:34 +02:00
Alexis Rouillard 0e8d875079 Merge pull request #5033 from Habbie/css-import-semicolon
waybar-styles.5: add semicolon to css import statement
2026-07-04 00:42:56 +02:00
Alexis Rouillard 3cd93d849f Merge pull request #5032 from yyyumeniku/master
hyprland/workspaces: add debounce timer to prevent workspace button f…
2026-07-04 00:42:04 +02:00
Alex 08e457e3cd Merge remote-tracking branch 'origin/master' into pr-4694
# Conflicts:
#	src/modules/hyprland/workspace.cpp
2026-07-04 00:41:50 +02:00
Alexis Rouillard 15fd0b6c5d Merge pull request #4772 from szbmrk/feat-hyprland-submap-icon-handling
feat(hyprland/submap): add config option to specify different icons for submaps
2026-07-04 00:41:11 +02:00
Alex 9f3e5c09a3 Merge remote-tracking branch 'origin/master' into pr-4537
# Conflicts:
#	include/modules/niri/workspaces.hpp
#	src/modules/niri/workspaces.cpp
2026-07-04 00:40:14 +02:00