Replace the getSocket1JsonReply("reload") call in onSpecialWorkspaceActivated
with the module's normal local refresh path: the state update to
m_activeSpecialWorkspaceName is picked up by the update() render (triggered by
the dp.emit() already issued at the end of onEvent), which re-evaluates active
state, icons and CSS classes. This avoids reloading the entire Hyprland config
on every special workspace activation while keeping the special-active icon and
CSS improvements.
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.
The active-layout event payload is `KEYBOARDNAME,LAYOUT`, and kbName was
taken as everything before the first comma. Keyboard names reported by
Hyprland can themselves contain commas (e.g. some MSI keyboards), so a
`keyboard-name` configured with a comma never matched the truncated value
and the module stopped updating.
Match the configured keyboard-name as a full prefix (followed by the ','
separator) instead. Layout parsing already handles commas via the
last-comma-before-parenthesis heuristic, so only the keyboard-name filter
needed fixing.
Addresses the keyboard-name case originally reported by @tirsek in #3406.
The handleScroll method unconditionally dispatched workspace cycling commands
and never checked for custom on-scroll-up/on-scroll-down config values.
Register the scroll handler when custom scroll commands are configured (even
without enable-bar-scroll), and delegate to AModule::handleScroll so user
commands are executed, matching the pattern used by other modules.
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.
Enable per-workspace styling by adding the workspace name as a
CSS class to each workspace button. The name is sanitized to a
valid CSS identifier: lowercased, non-alphanumeric characters
collapsed to hyphens, digit-leading names prefixed with "ws-".
Examples: "IDE" → .ide, "special:telegram" → .telegram, "1" → .ws-1
Allows users to style individual workspaces:
#workspaces button.telegram { color: #54a0e0; }
The window module registers itself with the Hyprland IPC singleton at
the start of its constructor, before calling update(). If update()
throws an exception (e.g. from an invalid format string), the object is
destroyed without the destructor running, leaving a dangling pointer in
the IPC callback list. When the IPC thread receives an event, it
attempts to call onEvent() on this invalid memory, causing a crash.
Moving the update() call before IPC registration ensures that any
initialization errors occur before the pointer is shared. If the
configuration is invalid, the module fails to construct and is
gracefully disabled by the factory without leaving a "landmine" in the
background IPC thread.
Fixes: #4923
Signed-off-by: Emir Baha Yıldırım <jayshozie@gmail.com>
The language and submap modules assumed their Hyprland payload delimiters were
always present. When that assumption is violated, the old code could perform
invalid iterator math or throw while slicing the event string.
Validate the expected separators up front and bail out with a warning when the
event is malformed so the modules degrade safely instead of crashing the update
path.
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>
The Hyprland IPC helper cached the socket folder with the first instance
signature already appended, so later calls ignored their instanceSig argument
and always reused the first path. That made the helper violate its own API even
though most real Waybar sessions only talk to a single Hyprland instance.
Cache only the base socket directory and append the requested signature per
lookup. This fixes correctness for tests, nested or debug multi-instance
setups, and future code that needs to resolve a different signature, without
claiming support for one Waybar process managing multiple Hyprland sessions.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit addresses memory churn caused by implicit deep copies during traversal and allocation of complex structures:
- Replaced pass-by-value 'Json::Value' in std::ranges and range-based for loops with 'const auto&' or 'const Json::Value&' in Hyprland modules, preventing large JSON tree duplications on every update.
- Fixed implicit string and pair copies in UPower and CPU Frequency loops by converting 'auto' to 'const auto&' where possible.
- Added 'std::vector::reserve' calls before 'push_back' loops in MPRIS, Niri, and CFFI modules to prevent exponential vector reallocation during initialization.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
- Replaced pass-by-value std::string parameters with const std::string&
or std::string_view to prevent SSO overallocations.
- Refactored static mapping functions in UPower to return
std::string_view instead of constructing std::string literals, enabling
perfect cache locality.
- Optimized string concatenation in hot loops (network IPs, inhibitor
lists, sway window marks) by using std::string::append() and
pre-reserving capacity instead of overloaded operator+ which produces
temporary heap instances.
These optimizations reduce high-frequency memory churn and overall heap
fragmentation within the main rendering loops.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
Hyprland IPC had fd lifecycle risks on failure/shutdown paths and used a
spin-sleep listener model.
I initialized fd state defensively, tightened connect/close/shutdown handling,
moved to blocking read with newline framing, and added RAII-style fd cleanup in
socket1 reply paths.
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>