Commit Graph
5161 Commits
Author SHA1 Message Date
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
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
Piotr Wegrzyn 810a8c0f94 feat(net): add {linkSpeed} format replacement
Adds an ethernet link speed ({linkSpeed}) read from
/sys/class/net/<iface>/speed, plus a skip-decimal option on pow_format
to drop a trailing .0. Rebased onto master's store-based network
formatting; existing compact bandwidth args updated for the new
pow_format signature.
2026-07-04 01:54:30 +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
sewaustav 9cd09c2569 feat(niri): add workspace-taskbar support
Adds a per-workspace app-icon taskbar (Workspace class) to the
niri/workspaces module. Rebased onto master: integrated with the
existing window-rewrite feature so the {windows} and {total} format
replacements continue to work alongside the new taskbar.
2026-07-04 01:50:16 +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
Emiliano Deustua 5f7629a36e format: Fix clang formatting 2026-07-04 01:42:54 +02:00
Emiliano Deustua 95664c7662 fix: Remove load persistent workspaces from workspace rules 2026-07-04 01:42:54 +02:00
Emiliano Deustua 7c86f1ccb4 fix: Use workspace ID to handle workspace updates 2026-07-04 01:42:54 +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
Erik Reider eeb7bc702e Added GeoClue2 privacy item
Rebased onto current master and fixed the privacy module build:
- privacy_item.hpp no longer includes privacy.hpp (it does not use the
  Privacy class); this broke the circular include that left PrivacyItem
  undeclared when privacy.hpp was reached first from privacy_item.cpp.
- privacy_item.cpp now includes gtkmm/label.h explicitly, since Gtk::Label
  was previously only pulled in transitively via privacy.hpp.
2026-07-04 01:42:35 +02:00