Merge branch 'master' of https://github.com/Alexays/Waybar
This commit is contained in:
+187
@@ -0,0 +1,187 @@
|
|||||||
|
# Contributing to Waybar
|
||||||
|
|
||||||
|
Thanks for helping improve Waybar! This guide covers the essentials.
|
||||||
|
|
||||||
|
## Building for development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
meson setup build
|
||||||
|
ninja -C build
|
||||||
|
./build/waybar # run your build directly
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable all optional modules while developing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
meson setup build -Dexperimental=true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
|
||||||
|
Waybar follows [Google's C++ style guide](https://google.github.io/styleguide/cppguide.html).
|
||||||
|
Format your changes before committing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clang-format -i <files>
|
||||||
|
```
|
||||||
|
|
||||||
|
CI runs `clang-format` and a full build on Linux and FreeBSD — please make sure
|
||||||
|
both pass.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Module documentation lives in [`man/`](man) as scdoc man pages, **not** in the
|
||||||
|
wiki. Editing a man page and merging to `master` regenerates the matching wiki
|
||||||
|
page automatically (see [`.github/wiki`](.github/wiki)). When you add a module,
|
||||||
|
add its man page and a line in [`.github/wiki/mapping.json`](.github/wiki/mapping.json).
|
||||||
|
|
||||||
|
## Pull requests
|
||||||
|
|
||||||
|
- Branch from `master` and keep each PR focused on one change.
|
||||||
|
- Describe what changed and why; link any related issues.
|
||||||
|
- Add or update the man page for every user-facing option you introduce.
|
||||||
|
- Build and test against the module(s) you touched.
|
||||||
|
|
||||||
|
Have fun :)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Coding Conventions
|
||||||
|
|
||||||
|
## 1. Language & Build
|
||||||
|
- **Standard**: C++20.
|
||||||
|
- **Build system**: Meson (`meson.build`). Project version is defined there.
|
||||||
|
- **Compiler flags**: Added via `add_project_arguments()` in Meson. Feature flags use `HAVE_*` / `WANT_*` prefixes (e.g. `-DHAVE_NIRI`, `-DHAVE_HYPRLAND`, `-DHAVE_LIBUDEV`).
|
||||||
|
|
||||||
|
## 2. Formatting
|
||||||
|
- **Tool**: `.clang-format` is checked in. **Never bypass it.**
|
||||||
|
- **Style**: Google base style.
|
||||||
|
- **Indent**: 2 spaces. No tabs.
|
||||||
|
- **Column limit**: 100.
|
||||||
|
- **Braces**: K&R (opening brace on the same line).
|
||||||
|
- **Declaration alignment**: Disabled (`AlignConsecutiveDeclarations: false`).
|
||||||
|
- **Pointer/reference alignment**: Left (`const Json::Value& config`, `int* ptr`, not `int *ptr`).
|
||||||
|
|
||||||
|
## 3. Naming
|
||||||
|
|
||||||
|
### Files
|
||||||
|
- Match the primary exported class exactly: `AAppIconLabel.hpp`, `workspaces.cpp`, `backlight_backend.hpp`.
|
||||||
|
- Corresponding header and source should live in predictable paths:
|
||||||
|
- `include/<module/path>.hpp`
|
||||||
|
- `src/<module/path>.cpp`
|
||||||
|
|
||||||
|
### Types
|
||||||
|
- **Classes / Structs**: `PascalCase`.
|
||||||
|
- Abstract base classes are prefixed with `A` (e.g., `AModule`, `ALabel`, `AIconLabel`, `AAppIconLabel`).
|
||||||
|
- **Enums / Enum classes**: `PascalCase` name.
|
||||||
|
- Enumerators: `UPPER_SNAKE_CASE` (e.g., `SCROLL_DIR::NONE`, `KillSignalAction::RELOAD`, `ChangeType::Increase`).
|
||||||
|
- **Concepts / Type aliases**: `PascalCase`.
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
- **Member variables**: `snake_case_` with a **trailing underscore**.
|
||||||
|
- Examples: `config_`, `bar_`, `label_`, `app_icon_size_`, `distance_scrolled_y_`, `on_updated_cb_`.
|
||||||
|
- **Function parameters & locals**: `snake_case` (no trailing underscore).
|
||||||
|
- Examples: `workspace_data`, `should_refresh`, `app_identifier`, `preferred_device`.
|
||||||
|
- **Static / constexpr constants**: `UPPER_SNAKE_CASE` or descriptive `kPascalCase`.
|
||||||
|
- Examples: `MODULE_CLASS`, `EPOLL_MAX_EVENTS`, `kExecFailureExitCode`.
|
||||||
|
|
||||||
|
### Functions & Methods
|
||||||
|
- **Free functions**: `snake_case`.
|
||||||
|
- Examples: `sanitize_string()`, `rewrite_string()`, `get_total_memory()`, `best_device()`.
|
||||||
|
- **Class methods**: `lowerCamelCase`.
|
||||||
|
- Examples: `update()`, `tooltipEnabled()`, `handleScroll()`, `getScrollDir()`, `resolveFormat()`, `setBrightness()`.
|
||||||
|
- **Virtual overrides**: Mark with `override` (and `final` where applicable). Header signatures often use a trailing return type:
|
||||||
|
```cpp
|
||||||
|
auto update() -> void override;
|
||||||
|
auto refresh(int should_refresh) -> void;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Namespaces
|
||||||
|
- All lowercase, nested by module path:
|
||||||
|
```cpp
|
||||||
|
namespace waybar { }
|
||||||
|
namespace waybar::modules::niri { }
|
||||||
|
namespace waybar::util { }
|
||||||
|
```
|
||||||
|
- Close every namespace with a comment:
|
||||||
|
```cpp
|
||||||
|
} // namespace waybar::modules::niri
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Includes & Headers
|
||||||
|
- Use `#pragma once` in all project headers.
|
||||||
|
- Include order in `.cpp` files:
|
||||||
|
1. Corresponding header first.
|
||||||
|
2. Blank line.
|
||||||
|
3. External library headers (`<fmt/...>`, `<spdlog/...>`, `<gtkmm/...>`, `<json/json.h>`).
|
||||||
|
4. Standard library headers (`<algorithm>`, `<vector>`, `<memory>`).
|
||||||
|
5. Blank line.
|
||||||
|
6. Other project headers (`"util/..."`, `"modules/..."`).
|
||||||
|
- Do not use `using namespace` in headers. In `.cpp` files it is acceptable for narrow scopes (e.g., `using namespace std::literals::chrono_literals;`).
|
||||||
|
- Headers that expose standard-library types in their public interface (e.g. `std::chrono::milliseconds` as a return type or `std::vector<T>` as a member) must `#include` the corresponding standard header directly. Do not rely on transitive includes from other headers.
|
||||||
|
|
||||||
|
## 5. Class & Module Design
|
||||||
|
|
||||||
|
### Base Class Patterns
|
||||||
|
- All UI modules ultimately derive from `AModule` (and often `ALabel` or `AIconLabel`).
|
||||||
|
- Accept configuration in constructors:
|
||||||
|
```cpp
|
||||||
|
MyModule(const Json::Value& config, const std::string& name, const std::string& id, ...);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Signals & Threading
|
||||||
|
- Use `Glib::Dispatcher` (via `waybar::SafeSignal`) to marshal work to the GTK main thread.
|
||||||
|
- Use `sigc::signal` for normal GTK++ signals.
|
||||||
|
- If a scope must not be interrupted by `pthread_cancel`, guard it with `waybar::util::CancellationGuard`.
|
||||||
|
|
||||||
|
### State / IPC
|
||||||
|
- Modules that talk to a compositor often implement a small `EventHandler` interface (`onEvent(...)`) and delegate to a singleton backend (e.g., `gIPC`).
|
||||||
|
|
||||||
|
### RAII
|
||||||
|
- Prefer `std::unique_ptr` with custom deleters over raw `new/delete` for C-API resources (see `ScopedFd`, `UdevDeleter`, `UdevDeviceDeleter`, `ScopeGuard`).
|
||||||
|
|
||||||
|
## 6. JSON Configuration
|
||||||
|
- Every module receives `const Json::Value& config` (usually as the first constructor argument).
|
||||||
|
- Always validate node type before reading:
|
||||||
|
```cpp
|
||||||
|
if (config_["sort-by-id"].isBool()) { ... }
|
||||||
|
if (config.isMember("window-rewrite-default") && config["window-rewrite-default"].isString()) { ... }
|
||||||
|
```
|
||||||
|
- Use `waybar::util::JsonParser` if you need to pre-process JSON with non-standard escape sequences.
|
||||||
|
|
||||||
|
## 7. String & UI Formatting
|
||||||
|
- Use `fmt::format` / `fmt::join` for all string composition.
|
||||||
|
- Use `fmt::dynamic_format_arg_store<fmt::format_context>` when building arguments dynamically.
|
||||||
|
- Custom `fmt::formatter` specializations are allowed for domain types (e.g., `Glib::ustring`, project enums).
|
||||||
|
- Sanitize arbitrary text before inserting into Pango markup with `waybar::util::sanitize_string`.
|
||||||
|
- Use `waybar::util::rewriteString` for user-configurable regex rewrites.
|
||||||
|
- Truncate UTF-8 safely with `waybar::util::utf8_truncate` / `utf8_width`.
|
||||||
|
|
||||||
|
## 8. Error Handling & Logging
|
||||||
|
- Use `spdlog` for all logging:
|
||||||
|
- `spdlog::error("Context: {}", e.what());`
|
||||||
|
- `spdlog::warn("Deprecated key '{}', prefer '{}'", old, replacement);`
|
||||||
|
- `spdlog::debug("State changed to {}", value);`
|
||||||
|
- Throw `std::runtime_error` (or similar) for fatal initialization failures that should bubble up to `main()`.
|
||||||
|
|
||||||
|
## 9. GTK / Glib Patterns
|
||||||
|
- Prefer gtkmm-3.0 types (`Gtk::Button`, `Gtk::Label`, `Gdk::Pixbuf`, `Glib::RefPtr`, `Glib::ustring`) over raw C GTK APIs.
|
||||||
|
- Access the default icon theme through thread-safe wrappers if off the main thread (`DefaultGtkIconThemeWrapper`).
|
||||||
|
- Tooltips and labels should respect the module `tooltip` toggle (see `tooltipEnabled()` in `AModule`).
|
||||||
|
|
||||||
|
## 10. Platform Portability
|
||||||
|
- Isolate platform-specific code in dedicated files (e.g., `linux.cpp`, `bsd.cpp`).
|
||||||
|
- Use preprocessor guards for platform differences (`#if defined(__FreeBSD__)`, `#if defined(HAVE_LIBNL)`).
|
||||||
|
- Keep the common interface in a shared header or base class.
|
||||||
|
|
||||||
|
## 11. Thread Safety & Cross-Thread Communication
|
||||||
|
- GTK is strictly single-threaded. Never emit raw `sigc::signal` from background threads.
|
||||||
|
- Use `waybar::SafeSignal<T...>` to marshal events from worker threads to the GTK main loop.
|
||||||
|
- When a module manages background threads, use `std::mutex`, `std::recursive_mutex`, or atomic variables to protect shared state, and ensure the destructor joins or synchronizes with those threads before destroying resources.
|
||||||
|
|
||||||
|
## 12. Unsafe Patterns to Avoid
|
||||||
|
- Do not use `strcpy`, `strcat`, or `sprintf` into fixed-size buffers (e.g. `char buf[PATH_MAX]`). Prefer `std::string`, `std::vector<char>`, or `std::array` with bounds-safe operations.
|
||||||
|
- When passing a `std::vector<char>` buffer to a C API that expects a mutable `char*` string, always ensure the buffer is null-terminated and clamp the written length to `size() - 1`. Never use `std::copy` from an unbounded source into a fixed-size buffer.
|
||||||
|
|
||||||
|
## 13. Singleton Lifetime
|
||||||
|
- Singletons or objects with process-wide lifetime must not store references (`&`) or pointers to objects with shorter lifetime (e.g., configuration trees, GTK widgets, or bar instances) unless they are explicitly notified of destruction. Prefer storing configuration by value (`Json::Value`, `std::string`, etc.) if the singleton outlives the config loader.
|
||||||
@@ -3,5 +3,5 @@
|
|||||||
FROM archlinux:base-devel
|
FROM archlinux:base-devel
|
||||||
|
|
||||||
RUN pacman -Syu --noconfirm && \
|
RUN pacman -Syu --noconfirm && \
|
||||||
pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols glib2-devel pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl iniparser fftw && \
|
pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols glib2-devel pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl iniparser fftw clang && \
|
||||||
sed -Ei 's/#(en_(US|GB)\.UTF)/\1/' /etc/locale.gen && locale-gen
|
sed -Ei 's/#(en_(US|GB)\.UTF)/\1/' /etc/locale.gen && locale-gen
|
||||||
|
|||||||
@@ -27,5 +27,10 @@ test-detailed:
|
|||||||
meson test -C build --verbose --print-errorlogs --test-args='--reporter console -s'
|
meson test -C build --verbose --print-errorlogs --test-args='--reporter console -s'
|
||||||
.PHONY: test-detailed
|
.PHONY: test-detailed
|
||||||
|
|
||||||
|
format:
|
||||||
|
git diff --name-only --diff-filter=ACMR | \
|
||||||
|
grep -E '\.(c|h|cpp|hpp)$$' | \
|
||||||
|
xargs -r clang-format -i
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf build
|
rm -rf build
|
||||||
|
|||||||
@@ -4,78 +4,87 @@ This is my fork of [Waybar](https://github.com/Alexays/Waybar). It has a few
|
|||||||
changes with the biggest being that it works with my fork or river (the Wayland
|
changes with the biggest being that it works with my fork or river (the Wayland
|
||||||
compositor). In fact, it will probably **not** work with vanilla river.
|
compositor). In fact, it will probably **not** work with vanilla river.
|
||||||
|
|
||||||
# Waybar [](LICENSE) [](https://paypal.me/ARouillard)<br>
|
# Waybar
|
||||||
|
|
||||||
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
|
[](LICENSE)
|
||||||
> Available in [all major distributions](https://github.com/Alexays/Waybar/wiki/Installation)<br>
|
[](https://paypal.me/ARouillard)
|
||||||
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
|
[](https://github.com/Alexays/Waybar/actions/workflows/linux.yml)
|
||||||
|
[](https://github.com/Alexays/Waybar/releases)
|
||||||
|
|
||||||
#### Current features
|

|
||||||
- Sway (Workspaces, Binding mode, Focused window name)
|
|
||||||
- River (Mapping mode, Tags, Focused window name)
|
|
||||||
- Hyprland (Window Icons, Workspaces, Focused window name)
|
|
||||||
- Niri (Workspaces, Focused window name, Language)
|
|
||||||
- DWL (Tags, Focused window name) [requires dwl ipc patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc)
|
|
||||||
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
|
||||||
- Local time
|
|
||||||
- Battery
|
|
||||||
- UPower
|
|
||||||
- Power profiles daemon
|
|
||||||
- Network
|
|
||||||
- Bluetooth
|
|
||||||
- Pulseaudio
|
|
||||||
- Privacy Info
|
|
||||||
- Wireplumber
|
|
||||||
- Disk
|
|
||||||
- Memory
|
|
||||||
- Cpu load average
|
|
||||||
- Temperature
|
|
||||||
- MPD
|
|
||||||
- Custom scripts
|
|
||||||
- Custom image
|
|
||||||
- Multiple output configuration
|
|
||||||
- And many more customizations
|
|
||||||
|
|
||||||
#### Configuration and Styling
|
> Highly customizable Wayland bar for Sway and wlroots-based compositors.<br>
|
||||||
|
> Available in [all major distributions](https://github.com/Alexays/Waybar/wiki/Installation).
|
||||||
|
|
||||||
[See the wiki for more details](https://github.com/Alexays/Waybar/wiki).
|
**[Installation](#installation) · [Wiki](https://github.com/Alexays/Waybar/wiki) · [Configuration](https://github.com/Alexays/Waybar/wiki/Configuration) · [Styling](https://github.com/Alexays/Waybar/wiki/Styling) · [Examples](https://github.com/Alexays/Waybar/wiki/Examples) · [FAQ](https://github.com/Alexays/Waybar/wiki/FAQ)**
|
||||||
|
|
||||||
### Installation
|
## Features
|
||||||
|
|
||||||
Waybar is available from a number of Linux distributions:
|
### Compositor integration
|
||||||
|
|
||||||
|
| Compositor | Workspaces / Tags | Window | Layout | Language | Mode |
|
||||||
|
| --- | :---: | :---: | :---: | :---: | :---: |
|
||||||
|
| [Sway](https://github.com/Alexays/Waybar/wiki/Module:-Sway) | ✅ | ✅ | | ✅ | ✅ |
|
||||||
|
| [River](https://github.com/Alexays/Waybar/wiki/Module:-River) | ✅ | ✅ | ✅ | | ✅ |
|
||||||
|
| [Hyprland](https://github.com/Alexays/Waybar/wiki/Module:-Hyprland) | ✅ | ✅ | | ✅ | ✅ |
|
||||||
|
| [Niri](https://github.com/Alexays/Waybar/wiki/Module:-Niri) | ✅ | ✅ | | ✅ | |
|
||||||
|
| [Mango](https://github.com/Alexays/Waybar/wiki/Module:-Mango) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| [DWL](https://github.com/Alexays/Waybar/wiki/Module:-Dwl) | ✅ | ✅ | | | |
|
||||||
|
| [Wayfire](https://github.com/Alexays/Waybar/wiki/Module:-Wayfire) | ✅ | ✅ | | | |
|
||||||
|
|
||||||
|
> DWL requires the [dwl IPC patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc).
|
||||||
|
|
||||||
|
### Modules
|
||||||
|
|
||||||
|
- **Power & hardware** — [Battery](https://github.com/Alexays/Waybar/wiki/Module:-Battery), [UPower](https://github.com/Alexays/Waybar/wiki/Module:-UPower), [Power profiles daemon](https://github.com/Alexays/Waybar/wiki/Module:-PowerProfilesDaemon), [Backlight](https://github.com/Alexays/Waybar/wiki/Module:-Backlight), [CPU](https://github.com/Alexays/Waybar/wiki/Module:-CPU), [Memory](https://github.com/Alexays/Waybar/wiki/Module:-Memory), [Disk](https://github.com/Alexays/Waybar/wiki/Module:-Disk), [Temperature](https://github.com/Alexays/Waybar/wiki/Module:-Temperature)
|
||||||
|
- **Connectivity** — [Network](https://github.com/Alexays/Waybar/wiki/Module:-Network), [Bluetooth](https://github.com/Alexays/Waybar/wiki/Module:-Bluetooth), [GPS](https://github.com/Alexays/Waybar/wiki/Module:-GPS), [WWAN](https://github.com/Alexays/Waybar/wiki/Module:-WWAN)
|
||||||
|
- **Audio & media** — [PulseAudio](https://github.com/Alexays/Waybar/wiki/Module:-PulseAudio), [WirePlumber](https://github.com/Alexays/Waybar/wiki/Module:-WirePlumber), [JACK](https://github.com/Alexays/Waybar/wiki/Module:-JACK), [sndio](https://github.com/Alexays/Waybar/wiki/Module:-Sndio), [Cava](https://github.com/Alexays/Waybar/wiki/Module:-Cava), [MPD](https://github.com/Alexays/Waybar/wiki/Module:-MPD), [MPRIS](https://github.com/Alexays/Waybar/wiki/Module:-MPRIS)
|
||||||
|
- **Desktop** — [Clock & calendar](https://github.com/Alexays/Waybar/wiki/Module:-Clock), [System tray](https://github.com/Alexays/Waybar/wiki/Module:-Tray), [Idle inhibitor](https://github.com/Alexays/Waybar/wiki/Module:-Idle-Inhibitor), [Keyboard state](https://github.com/Alexays/Waybar/wiki/Module:-Keyboard-State), [Privacy](https://github.com/Alexays/Waybar/wiki/Module:-Privacy), [Gamemode](https://github.com/Alexays/Waybar/wiki/Module:-Gamemode), [Systemd failed units](https://github.com/Alexays/Waybar/wiki/Module:-Systemd-failed-units), [Image](https://github.com/Alexays/Waybar/wiki/Module:-Image), [Custom scripts](https://github.com/Alexays/Waybar/wiki/Module:-Custom)
|
||||||
|
|
||||||
|
…and more. Every module is documented on the [wiki](https://github.com/Alexays/Waybar/wiki) (see the *Modules* sidebar).
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/Alexays/Waybar
|
||||||
|
cd Waybar
|
||||||
|
meson setup build
|
||||||
|
ninja -C build
|
||||||
|
./build/waybar # run without installing
|
||||||
|
```
|
||||||
|
|
||||||
|
Waybar launches with a sensible [default config](resources/config.jsonc). To make
|
||||||
|
it yours, copy the default config and stylesheet into `~/.config/waybar/` and edit
|
||||||
|
them. The [Configuration](https://github.com/Alexays/Waybar/wiki/Configuration)
|
||||||
|
and [Styling](https://github.com/Alexays/Waybar/wiki/Styling) guides cover every
|
||||||
|
option, and [Examples](https://github.com/Alexays/Waybar/wiki/Examples) has
|
||||||
|
ready-to-use community setups.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Waybar is packaged by most distributions:
|
||||||
|
|
||||||
[](https://repology.org/project/waybar/versions)
|
[](https://repology.org/project/waybar/versions)
|
||||||
|
|
||||||
An Ubuntu PPA with more recent versions is available
|
An Ubuntu PPA with more recent versions is available [here](https://launchpad.net/~nschloe/+archive/ubuntu/waybar).
|
||||||
[here](https://launchpad.net/~nschloe/+archive/ubuntu/waybar).
|
|
||||||
|
|
||||||
|
### Building from source
|
||||||
#### Building from source
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git clone https://github.com/Alexays/Waybar
|
git clone https://github.com/Alexays/Waybar
|
||||||
$ cd Waybar
|
cd Waybar
|
||||||
$ meson setup build
|
meson setup build
|
||||||
$ ninja -C build
|
ninja -C build
|
||||||
$ ./build/waybar
|
ninja -C build install # optional
|
||||||
# If you want to install it
|
|
||||||
$ ninja -C build install
|
|
||||||
$ waybar
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Dependencies**
|
<details>
|
||||||
|
<summary><b>Runtime dependencies</b></summary>
|
||||||
|
|
||||||
```
|
```
|
||||||
gtkmm3
|
gtkmm3 jsoncpp libsigc++ fmt wayland
|
||||||
jsoncpp
|
chrono-date spdlog xkbregistry libgtk-3-dev upower
|
||||||
libsigc++
|
|
||||||
fmt
|
|
||||||
wayland
|
|
||||||
chrono-date
|
|
||||||
spdlog
|
|
||||||
libgtk-3-dev [gtk-layer-shell]
|
|
||||||
gobject-introspection [gtk-layer-shell]
|
|
||||||
libgirepository1.0-dev [gtk-layer-shell]
|
|
||||||
libpulse [Pulseaudio module]
|
libpulse [Pulseaudio module]
|
||||||
libnl [Network module]
|
libnl [Network module]
|
||||||
libappindicator-gtk3 [Tray module]
|
libappindicator-gtk3 [Tray module]
|
||||||
@@ -83,84 +92,55 @@ libdbusmenu-gtk3 [Tray module]
|
|||||||
libmpdclient [MPD module]
|
libmpdclient [MPD module]
|
||||||
libsndio [sndio module]
|
libsndio [sndio module]
|
||||||
libevdev [KeyboardState module]
|
libevdev [KeyboardState module]
|
||||||
xkbregistry
|
|
||||||
upower [UPower battery module]
|
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
**Build dependencies**
|
<details>
|
||||||
|
<summary><b>Build dependencies</b></summary>
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake
|
cmake meson scdoc wayland-protocols
|
||||||
meson
|
|
||||||
scdoc
|
|
||||||
wayland-protocols
|
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
On Ubuntu, you can install all the relevant dependencies using this command (tested with 19.10 and 20.04):
|
<details>
|
||||||
|
<summary><b>Install dependencies — Ubuntu</b></summary>
|
||||||
|
|
||||||
```
|
```bash
|
||||||
sudo apt install \
|
sudo apt install \
|
||||||
clang-tidy \
|
clang-tidy gobject-introspection libdbusmenu-gtk3-dev libevdev-dev \
|
||||||
gobject-introspection \
|
libfmt-dev libgirepository1.0-dev libgtk-3-dev libgtkmm-3.0-dev \
|
||||||
libdbusmenu-gtk3-dev \
|
libinput-dev libjsoncpp-dev libmpdclient-dev libnl-3-dev libnl-genl-3-dev \
|
||||||
libevdev-dev \
|
libpulse-dev libsigc++-2.0-dev libspdlog-dev libwayland-dev scdoc upower \
|
||||||
libfmt-dev \
|
|
||||||
libgirepository1.0-dev \
|
|
||||||
libgtk-3-dev \
|
|
||||||
libgtkmm-3.0-dev \
|
|
||||||
libinput-dev \
|
|
||||||
libjsoncpp-dev \
|
|
||||||
libmpdclient-dev \
|
|
||||||
libnl-3-dev \
|
|
||||||
libnl-genl-3-dev \
|
|
||||||
libpulse-dev \
|
|
||||||
libsigc++-2.0-dev \
|
|
||||||
libspdlog-dev \
|
|
||||||
libwayland-dev \
|
|
||||||
scdoc \
|
|
||||||
upower \
|
|
||||||
libxkbregistry-dev
|
libxkbregistry-dev
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
On Arch, you can use this command:
|
<details>
|
||||||
|
<summary><b>Install dependencies — Arch</b></summary>
|
||||||
|
|
||||||
```
|
```bash
|
||||||
pacman -S --asdeps \
|
pacman -S --asdeps \
|
||||||
gtkmm3 \
|
gtkmm3 jsoncpp libsigc++ fmt wayland chrono-date spdlog gtk3 \
|
||||||
jsoncpp \
|
gobject-introspection libgirepository libpulse libnl libappindicator-gtk3 \
|
||||||
libsigc++ \
|
libdbusmenu-gtk3 libmpdclient sndio libevdev libxkbcommon upower meson \
|
||||||
fmt \
|
cmake scdoc wayland-protocols glib2-devel
|
||||||
wayland \
|
|
||||||
chrono-date \
|
|
||||||
spdlog \
|
|
||||||
gtk3 \
|
|
||||||
gobject-introspection \
|
|
||||||
libgirepository \
|
|
||||||
libpulse \
|
|
||||||
libnl \
|
|
||||||
libappindicator-gtk3 \
|
|
||||||
libdbusmenu-gtk3 \
|
|
||||||
libmpdclient \
|
|
||||||
sndio \
|
|
||||||
libevdev \
|
|
||||||
libxkbcommon \
|
|
||||||
upower \
|
|
||||||
meson \
|
|
||||||
cmake \
|
|
||||||
scdoc \
|
|
||||||
wayland-protocols \
|
|
||||||
glib2-devel
|
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
Contributions welcome!<br>
|
Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). The style
|
||||||
Have fun :)<br>
|
guidelines are [Google's C++ style](https://google.github.io/styleguide/cppguide.html).
|
||||||
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
|
|
||||||
|
> **Docs live in the man pages.** Module documentation is written in
|
||||||
|
> [`man/`](man) (scdoc) and auto-synced to the wiki. Edit the man page, not the
|
||||||
|
> wiki — see [`.github/wiki`](.github/wiki).
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> Distributions of Waybar are only released on the [official GitHub page](https://github.com/Alexays/Waybar).<br/>
|
> Distributions of Waybar are only released on the [official GitHub page](https://github.com/Alexays/Waybar).<br>
|
||||||
> Waybar does **not** have an official website. Do not trust any sites that claim to be official.
|
> Waybar does **not** have an official website. Do not trust any site claiming to be official.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Waybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/Alexays/Waybar/blob/master/LICENSE).
|
Waybar is licensed under the MIT license. [See LICENSE for details](https://github.com/Alexays/Waybar/blob/master/LICENSE).
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glibmm/markup.h>
|
||||||
|
#include <gtkmm/label.h>
|
||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "AModule.hpp"
|
||||||
|
|
||||||
|
namespace waybar {
|
||||||
|
|
||||||
|
enum class GraphType { LINE, BAR, GAUGE };
|
||||||
|
|
||||||
|
class AGraph : public AModule {
|
||||||
|
public:
|
||||||
|
AGraph(const Json::Value&, const std::string&, const std::string&, uint16_t interval = 0,
|
||||||
|
bool enable_click = false, bool enable_scroll = false);
|
||||||
|
virtual ~AGraph() = default;
|
||||||
|
auto update() -> void override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Gtk::DrawingArea graph_;
|
||||||
|
std::deque<int> values_;
|
||||||
|
uint16_t datapoints_ = 20;
|
||||||
|
GraphType graph_type_ = GraphType::LINE;
|
||||||
|
|
||||||
|
void addValue(const int n);
|
||||||
|
|
||||||
|
const std::chrono::milliseconds interval_;
|
||||||
|
|
||||||
|
bool onDraw(const Cairo::RefPtr<Cairo::Context>& cr);
|
||||||
|
|
||||||
|
std::map<std::string, GtkMenuItem*> submenus_;
|
||||||
|
std::map<std::string, std::string> menuActionsMap_;
|
||||||
|
static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawFilledArea(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||||
|
const std::vector<std::pair<double, double>>& points, double height,
|
||||||
|
const Gdk::RGBA& bg_color);
|
||||||
|
|
||||||
|
void drawLine(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||||
|
const std::vector<std::pair<double, double>>& points, const Gdk::RGBA& fg_color);
|
||||||
|
|
||||||
|
void drawPath(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||||
|
const std::vector<std::pair<double, double>>& points);
|
||||||
|
|
||||||
|
void drawBars(const Cairo::RefPtr<Cairo::Context>& cr, double width, double height,
|
||||||
|
int current_value, const Gdk::RGBA& fg_color);
|
||||||
|
|
||||||
|
void drawGauge(const Cairo::RefPtr<Cairo::Context>& cr, double width, double height,
|
||||||
|
int current_value, const Gdk::RGBA& fg_color);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar
|
||||||
@@ -14,10 +14,14 @@ class AIconLabel : public ALabel {
|
|||||||
bool enable_click = false, bool enable_scroll = false);
|
bool enable_click = false, bool enable_scroll = false);
|
||||||
virtual ~AIconLabel() = default;
|
virtual ~AIconLabel() = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
static std::tuple<std::string, std::string> extractIcon(const std::string& input);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Gtk::Image image_;
|
Gtk::Image image_;
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
|
unsigned app_icon_size_{24};
|
||||||
|
|
||||||
|
bool label_contains_icon{false};
|
||||||
|
|
||||||
bool iconEnabled() const;
|
bool iconEnabled() const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/args.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <glibmm/markup.h>
|
#include <glibmm/markup.h>
|
||||||
#include <gtkmm/label.h>
|
#include <gtkmm/label.h>
|
||||||
|
#include <gtkmm/tooltip.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
@@ -25,12 +32,68 @@ class ALabel : public AModule {
|
|||||||
bool alt_ = false;
|
bool alt_ = false;
|
||||||
std::string default_format_;
|
std::string default_format_;
|
||||||
|
|
||||||
|
bool setLabelMarkup(const Glib::ustring& markup);
|
||||||
|
bool setTooltipMarkup(const Glib::ustring& markup);
|
||||||
|
|
||||||
|
// resolveTooltipFormat() / resolveFormat() are inherited from AModule.
|
||||||
|
|
||||||
|
// Combined label + tooltip helper. Builds a single fmt argument store from
|
||||||
|
// `args`, renders `labelFormat` into the label and the resolved tooltip format
|
||||||
|
// into the tooltip, both through the dedup-aware setters. Honors the `tooltip`
|
||||||
|
// toggle. This replaces the label/tooltip formatting boilerplate that modules
|
||||||
|
// used to duplicate. `state` selects `tooltip-format-<state>` when non-empty.
|
||||||
|
template <typename... Args>
|
||||||
|
void updateLabelAndTooltipForState(const std::string& state, const std::string& labelFormat,
|
||||||
|
const std::string& tooltipDefault, Args&&... args) {
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
|
(store.push_back(std::forward<Args>(args)), ...);
|
||||||
|
setLabelMarkup(fmt::vformat(labelFormat, store));
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
setTooltipMarkup(fmt::vformat(resolveTooltipFormat(tooltipDefault, state), store));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void updateLabelAndTooltip(const std::string& labelFormat, const std::string& tooltipDefault,
|
||||||
|
Args&&... args) {
|
||||||
|
updateLabelAndTooltipForState("", labelFormat, tooltipDefault, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overloads accepting a pre-built argument store, for modules that must
|
||||||
|
// assemble a dynamic set of format arguments (e.g. per-core CPU stats) that
|
||||||
|
// cannot be expressed through a fixed variadic call.
|
||||||
|
// A non-const reference is used so this overload is preferred over the
|
||||||
|
// variadic template above (which would otherwise bind the store as a single
|
||||||
|
// forwarded argument).
|
||||||
|
void updateLabelAndTooltipForState(const std::string& state, const std::string& labelFormat,
|
||||||
|
const std::string& tooltipDefault,
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context>& store) {
|
||||||
|
setLabelMarkup(fmt::vformat(labelFormat, store));
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
setTooltipMarkup(fmt::vformat(resolveTooltipFormat(tooltipDefault, state), store));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateLabelAndTooltip(const std::string& labelFormat, const std::string& tooltipDefault,
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context>& store) {
|
||||||
|
updateLabelAndTooltipForState("", labelFormat, tooltipDefault, store);
|
||||||
|
}
|
||||||
|
|
||||||
bool handleToggle(GdkEventButton* const& e) override;
|
bool handleToggle(GdkEventButton* const& e) override;
|
||||||
|
void copyToClipboard(const std::string&);
|
||||||
virtual std::string getState(uint8_t value, bool lesser = false);
|
virtual std::string getState(uint8_t value, bool lesser = false);
|
||||||
|
|
||||||
std::map<std::string, GtkMenuItem*> submenus_;
|
std::map<std::string, GtkMenuItem*> submenus_;
|
||||||
std::map<std::string, std::string> menuActionsMap_;
|
std::map<std::string, std::string> menuActionsMap_;
|
||||||
static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
|
static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Raw UTF-8 bytes, not Glib::ustring: ustring::operator== collates with
|
||||||
|
// g_utf8_collate(), which gives private-use codepoints (nerd-font icons)
|
||||||
|
// no collation weight, so two different icons compare equal.
|
||||||
|
std::optional<std::string> last_label_markup_;
|
||||||
|
std::optional<std::string> last_tooltip_markup_;
|
||||||
|
Glib::RefPtr<Gtk::Tooltip> active_tooltip_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
+58
-2
@@ -1,11 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/args.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
#include <glibmm/dispatcher.h>
|
#include <glibmm/dispatcher.h>
|
||||||
#include <glibmm/markup.h>
|
#include <glibmm/markup.h>
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
#include <gtkmm/eventbox.h>
|
#include <gtkmm/eventbox.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
@@ -15,6 +20,7 @@ class AModule : public IModule {
|
|||||||
static constexpr const char* MODULE_CLASS = "module";
|
static constexpr const char* MODULE_CLASS = "module";
|
||||||
|
|
||||||
~AModule() override;
|
~AModule() override;
|
||||||
|
sigc::signal<void, AModule*> signal_updated;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
virtual auto refresh(int shouldRefresh) -> void {};
|
virtual auto refresh(int shouldRefresh) -> void {};
|
||||||
operator Gtk::Widget&() override;
|
operator Gtk::Widget&() override;
|
||||||
@@ -25,6 +31,10 @@ class AModule : public IModule {
|
|||||||
|
|
||||||
bool expandEnabled() const;
|
bool expandEnabled() const;
|
||||||
|
|
||||||
|
virtual void suspend() {};
|
||||||
|
virtual void resume() {};
|
||||||
|
bool shouldSuspend() const { return disable_on_sleep_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Don't need to make an object directly
|
// Don't need to make an object directly
|
||||||
// Derived classes are able to use it
|
// Derived classes are able to use it
|
||||||
@@ -36,11 +46,47 @@ class AModule : public IModule {
|
|||||||
SCROLL_DIR getScrollDir(GdkEventScroll* e);
|
SCROLL_DIR getScrollDir(GdkEventScroll* e);
|
||||||
bool tooltipEnabled() const;
|
bool tooltipEnabled() const;
|
||||||
|
|
||||||
|
// --- Generic format/tooltip resolution (config-only, usable by any module,
|
||||||
|
// ALabel-derived or not). Prefers `<key>-<state>`, then `<key>`, then default.
|
||||||
|
std::string resolveFormat(const std::string& defaultFormat, const std::string& state = "") const {
|
||||||
|
if (!state.empty() && config_["format-" + state].isString()) {
|
||||||
|
return config_["format-" + state].asString();
|
||||||
|
}
|
||||||
|
if (config_["format"].isString()) {
|
||||||
|
return config_["format"].asString();
|
||||||
|
}
|
||||||
|
return defaultFormat;
|
||||||
|
}
|
||||||
|
std::string resolveTooltipFormat(const std::string& defaultFormat,
|
||||||
|
const std::string& state = "") const {
|
||||||
|
if (!state.empty() && config_["tooltip-format-" + state].isString()) {
|
||||||
|
return config_["tooltip-format-" + state].asString();
|
||||||
|
}
|
||||||
|
if (config_["tooltip-format"].isString()) {
|
||||||
|
return config_["tooltip-format"].asString();
|
||||||
|
}
|
||||||
|
return defaultFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic tooltip for any widget: honors the `tooltip` toggle and
|
||||||
|
// `tooltip-format`, formats with the given args and applies it. Lets modules
|
||||||
|
// that are not ALabel-derived (e.g. gamemode) reuse the shared logic.
|
||||||
|
template <typename... Args>
|
||||||
|
void updateTooltip(Gtk::Widget& widget, const std::string& defaultFormat, Args&&... args) {
|
||||||
|
if (!tooltipEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
widget.set_tooltip_markup(
|
||||||
|
fmt::format(fmt::runtime(resolveTooltipFormat(defaultFormat)), std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> pid_children_;
|
std::vector<int> pid_children_;
|
||||||
const std::string name_;
|
const std::string name_;
|
||||||
const Json::Value& config_;
|
const Json::Value& config_;
|
||||||
Gtk::EventBox event_box_;
|
Gtk::EventBox event_box_;
|
||||||
|
|
||||||
|
virtual void setCursor(std::string const& c);
|
||||||
|
// Backward-compat overload for legacy numeric Gdk::CursorType configs (pre-0.16)
|
||||||
virtual void setCursor(Gdk::CursorType const& c);
|
virtual void setCursor(Gdk::CursorType const& c);
|
||||||
|
|
||||||
virtual bool handleToggle(GdkEventButton* const& ev);
|
virtual bool handleToggle(GdkEventButton* const& ev);
|
||||||
@@ -48,8 +94,17 @@ class AModule : public IModule {
|
|||||||
virtual bool handleMouseLeave(GdkEventCrossing* const& ev);
|
virtual bool handleMouseLeave(GdkEventCrossing* const& ev);
|
||||||
virtual bool handleScroll(GdkEventScroll*);
|
virtual bool handleScroll(GdkEventScroll*);
|
||||||
virtual bool handleRelease(GdkEventButton* const& ev);
|
virtual bool handleRelease(GdkEventButton* const& ev);
|
||||||
|
|
||||||
|
bool disable_on_sleep_{false};
|
||||||
GObject* menu_ = nullptr;
|
GObject* menu_ = nullptr;
|
||||||
|
|
||||||
|
// Maps a configured event name (e.g. "on-click-middle") to a built-in module
|
||||||
|
// action name. Populated from the `actions` config section, and by modules
|
||||||
|
// that interpret on-click* config values as internal actions (e.g.
|
||||||
|
// wlr/taskbar). Entries here are dispatched through doAction() instead of
|
||||||
|
// being run as shell commands.
|
||||||
|
std::map<std::string, std::string> eventActionMap_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool handleUserEvent(GdkEventButton* const& ev);
|
bool handleUserEvent(GdkEventButton* const& ev);
|
||||||
const bool isTooltip;
|
const bool isTooltip;
|
||||||
@@ -57,7 +112,7 @@ class AModule : public IModule {
|
|||||||
bool hasUserEvents_;
|
bool hasUserEvents_;
|
||||||
gdouble distance_scrolled_y_;
|
gdouble distance_scrolled_y_;
|
||||||
gdouble distance_scrolled_x_;
|
gdouble distance_scrolled_x_;
|
||||||
std::map<std::string, std::string> eventActionMap_;
|
sigc::connection cursor_timeout_conn_;
|
||||||
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
|
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
|
||||||
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
|
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
|
||||||
{std::make_pair(1, GdkEventType::GDK_BUTTON_RELEASE), "on-click-release"},
|
{std::make_pair(1, GdkEventType::GDK_BUTTON_RELEASE), "on-click-release"},
|
||||||
@@ -78,7 +133,8 @@ class AModule : public IModule {
|
|||||||
{std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"},
|
{std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"},
|
||||||
{std::make_pair(9, GdkEventType::GDK_BUTTON_RELEASE), "on-click-forward-release"},
|
{std::make_pair(9, GdkEventType::GDK_BUTTON_RELEASE), "on-click-forward-release"},
|
||||||
{std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"},
|
{std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"},
|
||||||
{std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"}};
|
{std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"},
|
||||||
|
{std::make_pair(10, GdkEventType::GDK_BUTTON_PRESS), "on-click-copy"}};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ struct waybar_output {
|
|||||||
Glib::RefPtr<Gdk::Monitor> monitor;
|
Glib::RefPtr<Gdk::Monitor> monitor;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string identifier;
|
std::string identifier;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
|
||||||
std::unique_ptr<struct zxdg_output_v1, decltype(&zxdg_output_v1_destroy)> xdg_output = {
|
std::unique_ptr<struct zxdg_output_v1, decltype(&zxdg_output_v1_destroy)> xdg_output = {
|
||||||
nullptr, &zxdg_output_v1_destroy};
|
nullptr, &zxdg_output_v1_destroy};
|
||||||
@@ -75,6 +77,8 @@ class Bar : public sigc::trackable {
|
|||||||
util::KillSignalAction getOnSigusr1Action();
|
util::KillSignalAction getOnSigusr1Action();
|
||||||
util::KillSignalAction getOnSigusr2Action();
|
util::KillSignalAction getOnSigusr2Action();
|
||||||
|
|
||||||
|
void toggleSuspend(bool suspend);
|
||||||
|
|
||||||
struct waybar_output* output;
|
struct waybar_output* output;
|
||||||
Json::Value config;
|
Json::Value config;
|
||||||
struct wl_surface* surface;
|
struct wl_surface* surface;
|
||||||
@@ -99,6 +103,7 @@ class Bar : public sigc::trackable {
|
|||||||
void setMode(const bar_mode&);
|
void setMode(const bar_mode&);
|
||||||
void setPassThrough(bool passthrough);
|
void setPassThrough(bool passthrough);
|
||||||
void setPosition(Gtk::PositionType position);
|
void setPosition(Gtk::PositionType position);
|
||||||
|
void forceLayerCommit();
|
||||||
void onConfigure(GdkEventConfigure* ev);
|
void onConfigure(GdkEventConfigure* ev);
|
||||||
void configureGlobalOffset(int width, int height);
|
void configureGlobalOffset(int width, int height);
|
||||||
void onOutputGeometryChanged();
|
void onOutputGeometryChanged();
|
||||||
@@ -126,6 +131,10 @@ class Bar : public sigc::trackable {
|
|||||||
|
|
||||||
waybar::util::KillSignalAction onSigusr1 = util::SIGNALACTION_DEFAULT_SIGUSR1;
|
waybar::util::KillSignalAction onSigusr1 = util::SIGNALACTION_DEFAULT_SIGUSR1;
|
||||||
waybar::util::KillSignalAction onSigusr2 = util::SIGNALACTION_DEFAULT_SIGUSR2;
|
waybar::util::KillSignalAction onSigusr2 = util::SIGNALACTION_DEFAULT_SIGUSR2;
|
||||||
|
|
||||||
|
/* Disconnected in ~Bar before the modules are destroyed (#5182). */
|
||||||
|
sigc::connection map_conn_;
|
||||||
|
sigc::connection unmap_conn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
struct zwp_idle_inhibitor_v1;
|
struct zwp_idle_inhibitor_v1;
|
||||||
struct zwp_idle_inhibit_manager_v1;
|
struct zwp_idle_inhibit_manager_v1;
|
||||||
|
struct ext_idle_notifier_v1;
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ class Client {
|
|||||||
struct wl_registry* registry = nullptr;
|
struct wl_registry* registry = nullptr;
|
||||||
struct zxdg_output_manager_v1* xdg_output_manager = nullptr;
|
struct zxdg_output_manager_v1* xdg_output_manager = nullptr;
|
||||||
struct zwp_idle_inhibit_manager_v1* idle_inhibit_manager = nullptr;
|
struct zwp_idle_inhibit_manager_v1* idle_inhibit_manager = nullptr;
|
||||||
|
struct ext_idle_notifier_v1* idle_notifier = nullptr;
|
||||||
std::vector<std::unique_ptr<Bar>> bars;
|
std::vector<std::unique_ptr<Bar>> bars;
|
||||||
Config config;
|
Config config;
|
||||||
std::string bar_id;
|
std::string bar_id;
|
||||||
@@ -48,7 +50,9 @@ class Client {
|
|||||||
static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name,
|
static void handleGlobal(void* data, struct wl_registry* registry, uint32_t name,
|
||||||
const char* interface, uint32_t version);
|
const char* interface, uint32_t version);
|
||||||
static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
|
static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
|
||||||
|
static void handleOutputLogicalSize(void*, struct zxdg_output_v1*, int32_t, int32_t);
|
||||||
static void handleOutputDone(void*, struct zxdg_output_v1*);
|
static void handleOutputDone(void*, struct zxdg_output_v1*);
|
||||||
|
void createBarsBatch();
|
||||||
static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
|
static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
|
||||||
static void handleOutputDescription(void*, struct zxdg_output_v1*, const char*);
|
static void handleOutputDescription(void*, struct zxdg_output_v1*, const char*);
|
||||||
void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor);
|
void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor);
|
||||||
@@ -65,6 +69,8 @@ class Client {
|
|||||||
std::map<int, bool> signal_toggle_state;
|
std::map<int, bool> signal_toggle_state;
|
||||||
sigc::connection monitor_added_connection_;
|
sigc::connection monitor_added_connection_;
|
||||||
sigc::connection monitor_removed_connection_;
|
sigc::connection monitor_removed_connection_;
|
||||||
|
std::list<waybar_output*> pending_outputs_;
|
||||||
|
bool bars_scheduled_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
+2
-1
@@ -29,7 +29,8 @@ class Config {
|
|||||||
|
|
||||||
Json::Value& getConfig() { return config_; }
|
Json::Value& getConfig() { return config_; }
|
||||||
|
|
||||||
std::vector<Json::Value> getOutputConfigs(const std::string& name, const std::string& identifier);
|
std::vector<Json::Value> getOutputConfigs(const std::string& name, const std::string& identifier,
|
||||||
|
int32_t width, int32_t height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupConfig(Json::Value& dst, const std::string& config_file, int depth);
|
void setupConfig(Json::Value& dst, const std::string& config_file, int depth);
|
||||||
|
|||||||
+11
-2
@@ -12,15 +12,17 @@
|
|||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
class Group : public AModule {
|
class Group : public AModule {
|
||||||
|
sigc::connection reveal_timeout_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Group(const std::string&, const std::string&, const Json::Value&, bool);
|
Group(const std::string&, const std::string&, const Json::Value&, bool);
|
||||||
~Group() override = default;
|
~Group() override;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
operator Gtk::Widget&() override;
|
operator Gtk::Widget&() override;
|
||||||
auto refresh(int sig) -> void override;
|
auto refresh(int sig) -> void override;
|
||||||
|
|
||||||
virtual Gtk::Box& getBox();
|
virtual Gtk::Box& getBox();
|
||||||
void addWidget(Gtk::Widget& widget);
|
void addWidget(AModule* module);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Gtk::Box box;
|
Gtk::Box box;
|
||||||
@@ -30,6 +32,9 @@ class Group : public AModule {
|
|||||||
bool is_drawer = false;
|
bool is_drawer = false;
|
||||||
bool click_to_reveal = false;
|
bool click_to_reveal = false;
|
||||||
std::optional<int> toggle_signal;
|
std::optional<int> toggle_signal;
|
||||||
|
std::string always_visible_class;
|
||||||
|
bool empty_if_drawer_empty = false;
|
||||||
|
int reveal_delay = 0;
|
||||||
std::string add_class_to_drawer_children;
|
std::string add_class_to_drawer_children;
|
||||||
bool handleMouseEnter(GdkEventCrossing* const& ev) override;
|
bool handleMouseEnter(GdkEventCrossing* const& ev) override;
|
||||||
bool handleMouseLeave(GdkEventCrossing* const& ev) override;
|
bool handleMouseLeave(GdkEventCrossing* const& ev) override;
|
||||||
@@ -45,6 +50,10 @@ class Group : public AModule {
|
|||||||
hide_group();
|
hide_group();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void manage_visibility(AModule* module);
|
||||||
|
void show_widget(Gtk::Widget& widget);
|
||||||
|
void hide_widget(Gtk::Widget& widget);
|
||||||
|
void hide_current_widget_if_inactive();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -51,6 +52,11 @@ class Battery : public ALabel {
|
|||||||
bool warnFirstTime_{true};
|
bool warnFirstTime_{true};
|
||||||
bool weightedAverage_{true};
|
bool weightedAverage_{true};
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
|
bool smoothPowerEnable_{false};
|
||||||
|
double time_constant_s_{260.0};
|
||||||
|
double smooth_power_{0.0}; // µW
|
||||||
|
std::chrono::steady_clock::time_point last_t_{std::chrono::steady_clock::now()};
|
||||||
|
std::string old_status_raw_{""};
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
util::SleeperThread thread_battery_update_;
|
util::SleeperThread thread_battery_update_;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class Bluetooth : public ALabel {
|
|||||||
bool services_resolved;
|
bool services_resolved;
|
||||||
// NOTE: experimental feature in bluez
|
// NOTE: experimental feature in bluez
|
||||||
std::optional<unsigned char> battery_percentage;
|
std::optional<unsigned char> battery_percentage;
|
||||||
|
std::optional<unsigned char> battery_percentage_peripheral;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -59,6 +60,12 @@ class Bluetooth : public ALabel {
|
|||||||
gpointer) -> void;
|
gpointer) -> void;
|
||||||
|
|
||||||
auto getDeviceBatteryPercentage(GDBusObject*) -> std::optional<unsigned char>;
|
auto getDeviceBatteryPercentage(GDBusObject*) -> std::optional<unsigned char>;
|
||||||
|
auto getDeviceGattBatteryLevels(GDBusObject*, std::optional<unsigned char>&,
|
||||||
|
std::optional<unsigned char>&) -> void;
|
||||||
|
static auto processBatteryServiceCharacteristics(GList*, const std::string&, const std::string&,
|
||||||
|
const std::string&,
|
||||||
|
std::optional<unsigned char>&,
|
||||||
|
std::optional<unsigned char>&) -> void;
|
||||||
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
|
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
|
||||||
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
|
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1,64 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <epoxy/gl.h>
|
#include <epoxy/gl.h>
|
||||||
|
#include <gtkmm/glarea.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <sigc++/connection.h>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
#include "cava_backend.hpp"
|
#include "cava_backend.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::cava {
|
namespace waybar::modules::cava {
|
||||||
|
|
||||||
class CavaGLSL final : public AModule, public Gtk::GLArea {
|
class CavaGLSL final : public AModule {
|
||||||
public:
|
public:
|
||||||
CavaGLSL(const std::string&, const Json::Value&);
|
CavaGLSL(const std::string&, const Json::Value&);
|
||||||
~CavaGLSL() = default;
|
~CavaGLSL();
|
||||||
|
auto doAction(const std::string& name) -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Action = void (CavaGLSL::*)();
|
||||||
|
|
||||||
|
Gtk::GLArea gl_area_;
|
||||||
std::shared_ptr<CavaBackend> backend_;
|
std::shared_ptr<CavaBackend> backend_;
|
||||||
struct ::cava::config_params prm_;
|
// Cached config params (deep-copied strings to avoid dangling char* on backend reload)
|
||||||
int frame_counter{0};
|
int sdl_width_{0};
|
||||||
|
int sdl_height_{0};
|
||||||
|
int bar_width_{0};
|
||||||
|
int bar_spacing_{0};
|
||||||
|
int gradient_count_{0};
|
||||||
|
std::string vertex_shader_;
|
||||||
|
std::string fragment_shader_;
|
||||||
|
std::string bcolor_;
|
||||||
|
std::string color_;
|
||||||
|
std::array<std::string, 8> gradient_colors_;
|
||||||
|
int frame_counter_{0};
|
||||||
bool silence_{false};
|
bool silence_{false};
|
||||||
bool hide_on_silence_{false};
|
bool hide_on_silence_{false};
|
||||||
|
bool mapped_{false};
|
||||||
// Cava method
|
// Cava method
|
||||||
auto onUpdate(const ::cava::audio_raw& input) -> void;
|
void pauseResume();
|
||||||
|
auto onUpdate(const CavaBackend::AudioRaw& input) -> void;
|
||||||
auto onSilence() -> void;
|
auto onSilence() -> void;
|
||||||
// Member variable to store the shared pointer
|
auto onBackendConfigChanged() -> void;
|
||||||
std::shared_ptr<::cava::audio_raw> m_data_;
|
void cacheConfigParams(const ::cava::config_params& src);
|
||||||
GLuint shaderProgram_;
|
// Member variable to store audio data
|
||||||
|
CavaBackend::AudioRaw m_data_;
|
||||||
|
GLuint shaderProgram_{0};
|
||||||
// OpenGL variables
|
// OpenGL variables
|
||||||
GLuint fbo_;
|
GLuint fbo_{0};
|
||||||
GLuint texture_;
|
GLuint texture_{0};
|
||||||
|
GLuint vbo_{0};
|
||||||
|
GLuint ibo_{0};
|
||||||
|
GLuint vao_{0};
|
||||||
GLint uniform_bars_;
|
GLint uniform_bars_;
|
||||||
GLint uniform_previous_bars_;
|
GLint uniform_previous_bars_;
|
||||||
GLint uniform_bars_count_;
|
GLint uniform_bars_count_;
|
||||||
GLint uniform_time_;
|
GLint uniform_time_;
|
||||||
|
GLint uniform_input_texture_;
|
||||||
// Methods
|
// Methods
|
||||||
void onRealize();
|
void onRealize();
|
||||||
bool onRender(const Glib::RefPtr<Gdk::GLContext>& context);
|
bool onRender(const Glib::RefPtr<Gdk::GLContext>& context);
|
||||||
@@ -39,5 +67,13 @@ class CavaGLSL final : public AModule, public Gtk::GLArea {
|
|||||||
void initSurface();
|
void initSurface();
|
||||||
void initGLSL();
|
void initGLSL();
|
||||||
GLuint loadShader(const std::string& fileName, GLenum type);
|
GLuint loadShader(const std::string& fileName, GLenum type);
|
||||||
|
void cleanupGL();
|
||||||
|
|
||||||
|
// ModuleActionMap
|
||||||
|
static const std::map<std::string, Action> actionMap_;
|
||||||
|
|
||||||
|
sigc::connection audio_raw_update_conn_;
|
||||||
|
sigc::connection silence_conn_;
|
||||||
|
sigc::connection config_changed_conn_;
|
||||||
};
|
};
|
||||||
} // namespace waybar::modules::cava
|
} // namespace waybar::modules::cava
|
||||||
|
|||||||
@@ -1,30 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <sigc++/connection.h>
|
||||||
|
|
||||||
#include "ALabel.hpp"
|
#include "ALabel.hpp"
|
||||||
#include "cava_backend.hpp"
|
#include "cava_backend.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::cava {
|
namespace waybar::modules::cava {
|
||||||
|
|
||||||
class Cava final : public ALabel, public sigc::trackable {
|
class CavaRaw final : public ALabel {
|
||||||
public:
|
public:
|
||||||
Cava(const std::string&, const Json::Value&);
|
CavaRaw(const std::string&, const Json::Value&);
|
||||||
~Cava() = default;
|
~CavaRaw();
|
||||||
auto doAction(const std::string& name) -> void override;
|
auto doAction(const std::string& name) -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Action = void (CavaRaw::*)();
|
||||||
|
|
||||||
std::shared_ptr<CavaBackend> backend_;
|
std::shared_ptr<CavaBackend> backend_;
|
||||||
// Text to display
|
// Text to display
|
||||||
Glib::ustring label_text_{""};
|
Glib::ustring label_text_;
|
||||||
bool silence_{false};
|
bool silence_{false};
|
||||||
bool hide_on_silence_{false};
|
bool hide_on_silence_{false};
|
||||||
std::string format_silent_{""};
|
std::string format_silent_;
|
||||||
int ascii_range_{0};
|
|
||||||
// Cava method
|
// Cava method
|
||||||
void pause_resume();
|
void pauseResume();
|
||||||
auto onUpdate(const std::string& input) -> void;
|
auto onUpdate(const std::string& input) -> void;
|
||||||
auto onSilence() -> void;
|
auto onSilence() -> void;
|
||||||
// ModuleActionMap
|
// ModuleActionMap
|
||||||
static inline std::map<const std::string, void (waybar::modules::cava::Cava::* const)()>
|
static const std::map<std::string, Action> actionMap_;
|
||||||
actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}};
|
|
||||||
|
sigc::connection update_conn_;
|
||||||
|
sigc::connection silence_conn_;
|
||||||
};
|
};
|
||||||
} // namespace waybar::modules::cava
|
} // namespace waybar::modules::cava
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <sigc++/sigc++.h>
|
#include <sigc++/sigc++.h>
|
||||||
|
|
||||||
|
#include "util/SafeSignal.hpp"
|
||||||
#include "util/sleeper_thread.hpp"
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
namespace cava {
|
namespace cava {
|
||||||
@@ -21,7 +30,6 @@ extern "C" {
|
|||||||
} // namespace cava
|
} // namespace cava
|
||||||
|
|
||||||
namespace waybar::modules::cava {
|
namespace waybar::modules::cava {
|
||||||
using namespace std::literals::chrono_literals;
|
|
||||||
|
|
||||||
class CavaBackend final {
|
class CavaBackend final {
|
||||||
public:
|
public:
|
||||||
@@ -29,19 +37,38 @@ class CavaBackend final {
|
|||||||
|
|
||||||
virtual ~CavaBackend();
|
virtual ~CavaBackend();
|
||||||
// Methods
|
// Methods
|
||||||
int getAsciiRange();
|
int getAsciiRange() const;
|
||||||
void doPauseResume();
|
void doPauseResume();
|
||||||
void Update();
|
void update();
|
||||||
const struct ::cava::config_params* getPrm();
|
const ::cava::config_params& getPrm() const;
|
||||||
std::chrono::milliseconds getFrameTimeMilsec();
|
std::chrono::milliseconds getFrameTimeMilsec() const;
|
||||||
|
|
||||||
|
struct AudioRaw {
|
||||||
|
std::vector<float> bars_raw;
|
||||||
|
std::vector<float> previous_bars_raw;
|
||||||
|
int number_of_bars = 0;
|
||||||
|
|
||||||
|
AudioRaw() = default;
|
||||||
|
explicit AudioRaw(const ::cava::audio_raw& raw) {
|
||||||
|
number_of_bars = raw.number_of_bars;
|
||||||
|
if (raw.bars_raw != nullptr && number_of_bars > 0) {
|
||||||
|
bars_raw.assign(raw.bars_raw, raw.bars_raw + number_of_bars);
|
||||||
|
}
|
||||||
|
if (raw.previous_bars_raw != nullptr && number_of_bars > 0) {
|
||||||
|
previous_bars_raw.assign(raw.previous_bars_raw, raw.previous_bars_raw + number_of_bars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Signal accessor
|
// Signal accessor
|
||||||
using type_signal_update = sigc::signal<void(const std::string&)>;
|
using SignalUpdate = SafeSignal<const std::string&>;
|
||||||
type_signal_update signal_update();
|
SignalUpdate& signalUpdate();
|
||||||
using type_signal_audio_raw_update = sigc::signal<void(const ::cava::audio_raw&)>;
|
using SignalAudioRawUpdate = SafeSignal<AudioRaw>;
|
||||||
type_signal_audio_raw_update signal_audio_raw_update();
|
SignalAudioRawUpdate& signalAudioRawUpdate();
|
||||||
using type_signal_silence = sigc::signal<void()>;
|
using SignalSilence = SafeSignal<>;
|
||||||
type_signal_silence signal_silence();
|
SignalSilence& signalSilence();
|
||||||
|
using SignalConfigChanged = SafeSignal<>;
|
||||||
|
SignalConfigChanged& signalConfigChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CavaBackend(const Json::Value& config);
|
CavaBackend(const Json::Value& config);
|
||||||
@@ -49,36 +76,78 @@ class CavaBackend final {
|
|||||||
util::SleeperThread out_thread_;
|
util::SleeperThread out_thread_;
|
||||||
|
|
||||||
// Cava API to read audio source
|
// Cava API to read audio source
|
||||||
::cava::ptr input_source_{NULL};
|
::cava::ptr input_source_{nullptr};
|
||||||
|
|
||||||
struct ::cava::error_s error_{}; // cava errors
|
struct ::cava::error_s error_{}; // cava errors
|
||||||
struct ::cava::config_params prm_{}; // cava parameters
|
struct ::cava::config_params prm_{}; // cava parameters
|
||||||
struct ::cava::audio_raw audio_raw_{}; // cava handled raw audio data(is based on audio_data)
|
struct ::cava::audio_raw audio_raw_{}; // cava handled raw audio data(is based on audio_data)
|
||||||
struct ::cava::audio_data audio_data_{}; // cava audio data
|
struct ::cava::audio_data audio_data_{}; // cava audio data
|
||||||
struct ::cava::cava_plan* plan_{NULL}; //{new cava_plan{}};
|
struct ::cava::cava_plan* plan_{nullptr}; //{new cava_plan{}};
|
||||||
|
|
||||||
std::chrono::seconds fetch_input_delay_{4};
|
std::chrono::seconds fetch_input_delay_{4};
|
||||||
// Delay to handle audio source
|
|
||||||
std::chrono::milliseconds frame_time_milsec_{1s};
|
|
||||||
|
|
||||||
const Json::Value& config_;
|
struct AdaptiveDelay {
|
||||||
|
std::chrono::milliseconds delay;
|
||||||
|
std::chrono::seconds delta{0};
|
||||||
|
|
||||||
|
explicit AdaptiveDelay(std::chrono::milliseconds initial = std::chrono::seconds(1))
|
||||||
|
: delay(initial) {}
|
||||||
|
|
||||||
|
bool increase() {
|
||||||
|
if (delta == std::chrono::seconds{0}) {
|
||||||
|
delta += std::chrono::seconds{1};
|
||||||
|
delay += delta;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decrease() {
|
||||||
|
if (delta > std::chrono::seconds{0}) {
|
||||||
|
delay -= delta;
|
||||||
|
delta -= std::chrono::seconds{1};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::milliseconds current() const { return delay; }
|
||||||
|
|
||||||
|
void reset(std::chrono::milliseconds new_delay) {
|
||||||
|
delay = new_delay;
|
||||||
|
delta = std::chrono::seconds{0};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AdaptiveDelay adaptive_delay_;
|
||||||
|
|
||||||
|
Json::Value config_;
|
||||||
int re_paint_{0};
|
int re_paint_{0};
|
||||||
bool silence_{false};
|
bool silence_{false};
|
||||||
bool silence_prev_{false};
|
bool silence_prev_{false};
|
||||||
std::chrono::seconds suspend_silence_delay_{0};
|
|
||||||
int sleep_counter_{0};
|
int sleep_counter_{0};
|
||||||
std::string output_{};
|
std::string output_{};
|
||||||
// Methods
|
// Methods
|
||||||
void invoke();
|
void invoke();
|
||||||
void execute();
|
void execute();
|
||||||
bool isSilence();
|
bool isSilent();
|
||||||
void doUpdate(bool force = false);
|
void doUpdate(bool force = false);
|
||||||
void loadConfig();
|
void loadConfig();
|
||||||
void freeBackend();
|
void freeBackend();
|
||||||
|
|
||||||
// Signal
|
// Signal
|
||||||
type_signal_update m_signal_update_;
|
SignalUpdate m_signal_update_;
|
||||||
type_signal_audio_raw_update m_signal_audio_raw_;
|
SignalAudioRawUpdate m_signal_audio_raw_;
|
||||||
type_signal_silence m_signal_silence_;
|
SignalSilence m_signal_silence_;
|
||||||
|
SignalConfigChanged m_signal_config_changed_;
|
||||||
|
|
||||||
|
std::atomic<bool> shutdown_{false};
|
||||||
|
bool audio_raw_initialized_{false};
|
||||||
|
mutable std::recursive_mutex state_mutex_;
|
||||||
|
|
||||||
|
// Synchronization for joining read_thread_ during destruction
|
||||||
|
bool read_thread_exited_{false};
|
||||||
|
mutable std::mutex read_thread_exit_mutex_;
|
||||||
|
std::condition_variable read_thread_exit_cv_;
|
||||||
};
|
};
|
||||||
} // namespace waybar::modules::cava
|
} // namespace waybar::modules::cava
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#ifdef HAVE_LIBCAVA
|
#ifdef HAVE_LIBCAVA
|
||||||
#include "cavaRaw.hpp"
|
#include "cavaRaw.hpp"
|
||||||
#include "cava_backend.hpp"
|
#include "cava_backend.hpp"
|
||||||
@@ -9,16 +11,16 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace waybar::modules::cava {
|
namespace waybar::modules::cava {
|
||||||
AModule* getModule(const std::string& id, const Json::Value& config) {
|
inline std::unique_ptr<AModule> getModule(const std::string& id, const Json::Value& config) {
|
||||||
#ifdef HAVE_LIBCAVA
|
#ifdef HAVE_LIBCAVA
|
||||||
const std::shared_ptr<CavaBackend> backend_{waybar::modules::cava::CavaBackend::inst(config)};
|
const std::shared_ptr<CavaBackend> backend_{waybar::modules::cava::CavaBackend::inst(config)};
|
||||||
switch (backend_->getPrm()->output) {
|
switch (backend_->getPrm().output) {
|
||||||
#ifdef HAVE_LIBCAVAGLSL
|
#ifdef HAVE_LIBCAVAGLSL
|
||||||
case ::cava::output_method::OUTPUT_SDL_GLSL:
|
case ::cava::output_method::OUTPUT_SDL_GLSL:
|
||||||
return new waybar::modules::cava::CavaGLSL(id, config);
|
return std::make_unique<waybar::modules::cava::CavaGLSL>(id, config);
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return new waybar::modules::cava::Cava(id, config);
|
return std::make_unique<waybar::modules::cava::CavaRaw>(id, config);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
throw std::runtime_error("Unknown module");
|
throw std::runtime_error("Unknown module");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const std::string kOrdPlaceholder{"ordinal_date"};
|
|||||||
|
|
||||||
enum class CldMode { MONTH, YEAR };
|
enum class CldMode { MONTH, YEAR };
|
||||||
enum class WS { LEFT, RIGHT, HIDDEN };
|
enum class WS { LEFT, RIGHT, HIDDEN };
|
||||||
|
enum class WeekNumbering { LOCALE, ISO, MONDAY, SUNDAY };
|
||||||
|
|
||||||
class Clock final : public ALabel {
|
class Clock final : public ALabel {
|
||||||
public:
|
public:
|
||||||
@@ -51,6 +52,7 @@ class Clock final : public ALabel {
|
|||||||
date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
|
date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
|
||||||
std::string cldText_{""}; // calendar text to print
|
std::string cldText_{""}; // calendar text to print
|
||||||
bool iso8601Calendar_{false}; // whether the calendar is in ISO8601
|
bool iso8601Calendar_{false}; // whether the calendar is in ISO8601
|
||||||
|
WeekNumbering weekNumbering_{WeekNumbering::LOCALE}; // week number calculation method
|
||||||
CldMode cldMode_{CldMode::MONTH};
|
CldMode cldMode_{CldMode::MONTH};
|
||||||
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
|
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
|
||||||
const date::time_zone* tz) -> const std::string;
|
const date::time_zone* tz) -> const std::string;
|
||||||
@@ -80,6 +82,7 @@ class Clock final : public ALabel {
|
|||||||
void cldShift_reset();
|
void cldShift_reset();
|
||||||
void tz_up();
|
void tz_up();
|
||||||
void tz_down();
|
void tz_down();
|
||||||
|
void action_exec(const std::string& action);
|
||||||
// Module Action Map
|
// Module Action Map
|
||||||
static inline std::map<const std::string, void (waybar::modules::Clock::* const)()> actionMap_{
|
static inline std::map<const std::string, void (waybar::modules::Clock::* const)()> actionMap_{
|
||||||
{"mode", &waybar::modules::Clock::cldModeSwitch},
|
{"mode", &waybar::modules::Clock::cldModeSwitch},
|
||||||
@@ -88,6 +91,9 @@ class Clock final : public ALabel {
|
|||||||
{"shift_reset", &waybar::modules::Clock::cldShift_reset},
|
{"shift_reset", &waybar::modules::Clock::cldShift_reset},
|
||||||
{"tz_up", &waybar::modules::Clock::tz_up},
|
{"tz_up", &waybar::modules::Clock::tz_up},
|
||||||
{"tz_down", &waybar::modules::Clock::tz_down}};
|
{"tz_down", &waybar::modules::Clock::tz_down}};
|
||||||
|
static inline std::map<const std::string,
|
||||||
|
void (waybar::modules::Clock::* const)(const std::string& action)>
|
||||||
|
actionWithArgsMap_{{"exec", &waybar::modules::Clock::action_exec}};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <fstream>
|
||||||
|
#include <numeric>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "AGraph.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
class CpuGraph : public AGraph {
|
||||||
|
public:
|
||||||
|
CpuGraph(const std::string&, const Json::Value&);
|
||||||
|
virtual ~CpuGraph() = default;
|
||||||
|
auto update() -> void override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr const char* MODERATE_CLASS = "cpu-moderate";
|
||||||
|
static constexpr const char* HIGH_CLASS = "cpu-high";
|
||||||
|
static constexpr const char* INTENSIVE_CLASS = "cpu-intensive";
|
||||||
|
|
||||||
|
std::vector<std::tuple<size_t, size_t>> prev_times_;
|
||||||
|
util::SleeperThread thread_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules
|
||||||
@@ -3,16 +3,18 @@
|
|||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "ALabel.hpp"
|
#include "AIconLabel.hpp"
|
||||||
#include "util/command.hpp"
|
#include "util/command.hpp"
|
||||||
|
#include "util/command_line_stream.hpp"
|
||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
#include "util/sleeper_thread.hpp"
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
class Custom : public ALabel {
|
class Custom : public AIconLabel {
|
||||||
public:
|
public:
|
||||||
Custom(const std::string&, const std::string&, const Json::Value&, const std::string&);
|
Custom(const std::string&, const std::string&, const Json::Value&, const std::string&);
|
||||||
virtual ~Custom();
|
virtual ~Custom();
|
||||||
@@ -22,6 +24,9 @@ class Custom : public ALabel {
|
|||||||
private:
|
private:
|
||||||
void delayWorker();
|
void delayWorker();
|
||||||
void continuousWorker();
|
void continuousWorker();
|
||||||
|
void startContinuousProcess(bool throw_on_failure);
|
||||||
|
void handleContinuousProcessExit(int exit_code);
|
||||||
|
void scheduleContinuousRestart();
|
||||||
void waitingWorker();
|
void waitingWorker();
|
||||||
void parseOutputRaw();
|
void parseOutputRaw();
|
||||||
void parseOutputJson();
|
void parseOutputJson();
|
||||||
@@ -36,13 +41,16 @@ class Custom : public ALabel {
|
|||||||
std::string alt_;
|
std::string alt_;
|
||||||
std::string tooltip_;
|
std::string tooltip_;
|
||||||
std::string last_tooltip_markup_;
|
std::string last_tooltip_markup_;
|
||||||
|
std::string image_path_;
|
||||||
|
std::string image_name_;
|
||||||
|
unsigned app_icon_size_{24};
|
||||||
const bool tooltip_format_enabled_;
|
const bool tooltip_format_enabled_;
|
||||||
std::vector<std::string> class_;
|
std::vector<std::string> class_;
|
||||||
int percentage_;
|
int percentage_;
|
||||||
FILE* fp_;
|
|
||||||
int pid_;
|
|
||||||
util::command::res output_;
|
util::command::res output_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
|
std::unique_ptr<util::command::LineStream> continuous_stream_;
|
||||||
|
sigc::connection restart_connection_;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "AGraph.hpp"
|
||||||
|
#include "util/command.hpp"
|
||||||
|
#include "util/json.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
class CustomGraph : public AGraph {
|
||||||
|
public:
|
||||||
|
CustomGraph(const std::string&, const std::string&, const Json::Value&, const std::string&);
|
||||||
|
virtual ~CustomGraph();
|
||||||
|
auto update() -> void override;
|
||||||
|
void refresh(int /*signal*/) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void delayWorker();
|
||||||
|
void continuousWorker();
|
||||||
|
void waitingWorker();
|
||||||
|
void parseOutputRaw();
|
||||||
|
void parseOutputJson();
|
||||||
|
void handleEvent();
|
||||||
|
bool handleScroll(GdkEventScroll* e) override;
|
||||||
|
bool handleToggle(GdkEventButton* const& e) override;
|
||||||
|
|
||||||
|
const std::string name_;
|
||||||
|
const std::string output_name_;
|
||||||
|
std::string text_;
|
||||||
|
std::string id_;
|
||||||
|
std::string alt_;
|
||||||
|
std::string tooltip_;
|
||||||
|
const bool tooltip_format_enabled_;
|
||||||
|
std::vector<std::string> class_;
|
||||||
|
int percentage_;
|
||||||
|
FILE* fp_;
|
||||||
|
int pid_;
|
||||||
|
util::command::res output_;
|
||||||
|
util::JsonParser parser_;
|
||||||
|
|
||||||
|
util::SleeperThread thread_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "ALabel.hpp"
|
#include "ALabel.hpp"
|
||||||
#include "util/format.hpp"
|
#include "util/format.hpp"
|
||||||
@@ -19,7 +20,9 @@ class Disk : public ALabel {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
std::string path_;
|
std::string header_;
|
||||||
|
std::vector<std::string> paths_;
|
||||||
|
std::string separator_;
|
||||||
std::string unit_;
|
std::string unit_;
|
||||||
|
|
||||||
float calc_specific_divisor(const std::string& divisor);
|
float calc_specific_divisor(const std::string& divisor);
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ class Tags : public waybar::AModule {
|
|||||||
void handle_primary_clicked(uint32_t tag);
|
void handle_primary_clicked(uint32_t tag);
|
||||||
bool handle_button_press(GdkEventButton* event_button, uint32_t tag);
|
bool handle_button_press(GdkEventButton* event_button, uint32_t tag);
|
||||||
|
|
||||||
|
void handle_active_output(zdwl_ipc_output_v2* zdwl_output_v2, uint32_t active);
|
||||||
|
|
||||||
struct zdwl_ipc_manager_v2* status_manager_;
|
struct zdwl_ipc_manager_v2* status_manager_;
|
||||||
struct wl_seat* seat_;
|
struct wl_seat* seat_;
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@ class Tags : public waybar::AModule {
|
|||||||
const waybar::Bar& bar_;
|
const waybar::Bar& bar_;
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
std::vector<Gtk::Button> buttons_;
|
std::vector<Gtk::Button> buttons_;
|
||||||
|
bool hide_vacant_;
|
||||||
struct zdwl_ipc_output_v2* output_status_;
|
struct zdwl_ipc_output_v2* output_status_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class Window : public AAppIconLabel, public sigc::trackable {
|
|||||||
void handle_layout(const uint32_t layout);
|
void handle_layout(const uint32_t layout);
|
||||||
void handle_title(const char* title);
|
void handle_title(const char* title);
|
||||||
void handle_appid(const char* ppid);
|
void handle_appid(const char* ppid);
|
||||||
|
void handle_active(const uint32_t active);
|
||||||
void handle_layout_symbol(const char* layout_symbol);
|
void handle_layout_symbol(const char* layout_symbol);
|
||||||
void handle_frame();
|
void handle_frame();
|
||||||
|
|
||||||
@@ -30,6 +31,9 @@ class Window : public AAppIconLabel, public sigc::trackable {
|
|||||||
std::string title_;
|
std::string title_;
|
||||||
std::string appid_;
|
std::string appid_;
|
||||||
std::string layout_symbol_;
|
std::string layout_symbol_;
|
||||||
|
bool active_;
|
||||||
|
bool hide_inactive_;
|
||||||
|
bool hide_empty_;
|
||||||
uint32_t layout_;
|
uint32_t layout_;
|
||||||
|
|
||||||
struct zdwl_ipc_output_v2* output_status_;
|
struct zdwl_ipc_output_v2* output_status_;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class Language : public waybar::ALabel, public EventHandler {
|
|||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
|
|
||||||
Layout layout_;
|
Layout layout_;
|
||||||
|
std::string prev_short_name_; // applied CSS class; touched only in update() (#4665)
|
||||||
|
|
||||||
IPC& m_ipc;
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ class Submap : public waybar::ALabel, public EventHandler {
|
|||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::string submap_;
|
std::string submap_;
|
||||||
|
std::string icon_;
|
||||||
std::string prev_submap_;
|
std::string prev_submap_;
|
||||||
bool always_on_ = false;
|
bool always_on_ = false;
|
||||||
std::string default_submap_ = "Default";
|
std::string default_submap_ = "Default";
|
||||||
|
std::unordered_map<std::string, std::string> icons_;
|
||||||
|
|
||||||
IPC& m_ipc;
|
IPC& m_ipc;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ class Workspace {
|
|||||||
public:
|
public:
|
||||||
explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
|
explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
|
||||||
const Json::Value& clients_data = Json::Value::nullRef);
|
const Json::Value& clients_data = Json::Value::nullRef);
|
||||||
std::string& selectIcon(std::map<std::string, std::string>& icons_map);
|
~Workspace();
|
||||||
|
std::string& selectString(std::map<std::string, std::string>& string_map);
|
||||||
Gtk::Button& button() { return m_button; };
|
Gtk::Button& button() { return m_button; };
|
||||||
|
|
||||||
int id() const { return m_id; };
|
int id() const { return m_id; };
|
||||||
@@ -45,12 +46,22 @@ class Workspace {
|
|||||||
bool isUrgent() const { return m_isUrgent; };
|
bool isUrgent() const { return m_isUrgent; };
|
||||||
|
|
||||||
bool handleClicked(GdkEventButton* bt) const;
|
bool handleClicked(GdkEventButton* bt) const;
|
||||||
|
|
||||||
|
bool handleEnter(GdkEventCrossing* event);
|
||||||
|
bool handleLeave(GdkEventCrossing* event);
|
||||||
|
|
||||||
|
void startHoverCheck();
|
||||||
|
void stopHoverCheck();
|
||||||
|
bool syncHoverClass();
|
||||||
|
bool pointerInsideButton();
|
||||||
|
|
||||||
void setActive(bool value = true) { m_isActive = value; };
|
void setActive(bool value = true) { m_isActive = value; };
|
||||||
void setPersistentRule(bool value = true) { m_isPersistentRule = value; };
|
void setPersistentRule(bool value = true) { m_isPersistentRule = value; };
|
||||||
void setPersistentConfig(bool value = true) { m_isPersistentConfig = value; };
|
void setPersistentConfig(bool value = true) { m_isPersistentConfig = value; };
|
||||||
void setUrgent(bool value = true) { m_isUrgent = value; };
|
void setUrgent(bool value = true) { m_isUrgent = value; };
|
||||||
void setVisible(bool value = true) { m_isVisible = value; };
|
void setVisible(bool value = true) { m_isVisible = value; };
|
||||||
void setWindows(uint value) { m_windows = value; };
|
void setWindows(uint value) { m_windows = value; };
|
||||||
|
void setId(int value) { m_id = value; };
|
||||||
void setName(std::string const& value) { m_name = value; };
|
void setName(std::string const& value) { m_name = value; };
|
||||||
void setOutput(std::string const& value) { m_output = value; };
|
void setOutput(std::string const& value) { m_output = value; };
|
||||||
bool containsWindow(WindowAddress const& addr) const {
|
bool containsWindow(WindowAddress const& addr) const {
|
||||||
@@ -64,13 +75,14 @@ class Workspace {
|
|||||||
bool onWindowOpened(WindowCreationPayload const& create_window_payload);
|
bool onWindowOpened(WindowCreationPayload const& create_window_payload);
|
||||||
std::optional<WindowRepr> closeWindow(WindowAddress const& addr);
|
std::optional<WindowRepr> closeWindow(WindowAddress const& addr);
|
||||||
|
|
||||||
void update(const std::string& workspace_icon);
|
void update(const std::string& workspace_icon, const std::string& workspace_tooltip);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Workspaces& m_workspaceManager;
|
Workspaces& m_workspaceManager;
|
||||||
|
|
||||||
int m_id;
|
int m_id;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
std::string m_prevNameClass;
|
||||||
std::string m_output;
|
std::string m_output;
|
||||||
uint m_windows;
|
uint m_windows;
|
||||||
bool m_isActive = false;
|
bool m_isActive = false;
|
||||||
@@ -80,6 +92,8 @@ class Workspace {
|
|||||||
bool m_isUrgent = false;
|
bool m_isUrgent = false;
|
||||||
bool m_isVisible = false;
|
bool m_isVisible = false;
|
||||||
|
|
||||||
|
sigc::connection m_hoverCheckConnection;
|
||||||
|
|
||||||
std::vector<WindowRepr> m_windowMap;
|
std::vector<WindowRepr> m_windowMap;
|
||||||
|
|
||||||
Gtk::Button m_button;
|
Gtk::Button m_button;
|
||||||
|
|||||||
@@ -39,9 +39,11 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
auto allOutputs() const -> bool { return m_allOutputs; }
|
auto allOutputs() const -> bool { return m_allOutputs; }
|
||||||
auto showSpecial() const -> bool { return m_showSpecial; }
|
auto showSpecial() const -> bool { return m_showSpecial; }
|
||||||
auto activeOnly() const -> bool { return m_activeOnly; }
|
auto activeOnly() const -> bool { return m_activeOnly; }
|
||||||
|
auto hideActive() const -> bool { return m_hideActive; }
|
||||||
auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; }
|
auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; }
|
||||||
auto persistentOnly() const -> bool { return m_persistentOnly; }
|
auto persistentOnly() const -> bool { return m_persistentOnly; }
|
||||||
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
|
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
|
||||||
|
auto uniqueIcons() const -> bool { return m_uniqueIcons; }
|
||||||
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
|
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
|
||||||
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
|
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
|
||||||
auto barScroll() const -> bool { return m_barScroll; }
|
auto barScroll() const -> bool { return m_barScroll; }
|
||||||
@@ -52,16 +54,20 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
auto taskbarFormatBefore() const -> std::string { return m_taskbarFormatBefore; }
|
auto taskbarFormatBefore() const -> std::string { return m_taskbarFormatBefore; }
|
||||||
auto taskbarFormatAfter() const -> std::string { return m_taskbarFormatAfter; }
|
auto taskbarFormatAfter() const -> std::string { return m_taskbarFormatAfter; }
|
||||||
auto taskbarIconSize() const -> int { return m_taskbarIconSize; }
|
auto taskbarIconSize() const -> int { return m_taskbarIconSize; }
|
||||||
|
auto taskbarMaxIcons() const -> int { return m_taskbarMaxIcons; }
|
||||||
auto taskbarOrientation() const -> Gtk::Orientation { return m_taskbarOrientation; }
|
auto taskbarOrientation() const -> Gtk::Orientation { return m_taskbarOrientation; }
|
||||||
auto taskbarReverseDirection() const -> bool { return m_taskbarReverseDirection; }
|
auto taskbarReverseDirection() const -> bool { return m_taskbarReverseDirection; }
|
||||||
auto onClickWindow() const -> std::string { return m_onClickWindow; }
|
auto onClickWindow() const -> std::string { return m_onClickWindow; }
|
||||||
auto getIgnoredWindows() const -> std::vector<std::regex> { return m_ignoreWindows; }
|
auto getIgnoredWindows() const -> std::vector<std::regex> { return m_ignoreWindows; }
|
||||||
|
auto maxWindows() const -> int { return m_maxWindows; }
|
||||||
|
|
||||||
enum class ActiveWindowPosition { NONE, FIRST, LAST };
|
enum class ActiveWindowPosition { NONE, FIRST, LAST };
|
||||||
auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; }
|
auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; }
|
||||||
|
|
||||||
std::string getRewrite(const std::string& window_class, const std::string& window_title);
|
std::string getRewrite(const std::string& window_class, const std::string& window_title);
|
||||||
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
|
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
|
||||||
|
auto windowRewriteGroupThreshold() const -> int { return m_windowRewriteGroupThreshold; }
|
||||||
|
auto const& getWindowRewriteGroupFormat() const { return m_windowRewriteGroupFormat; }
|
||||||
bool isWorkspaceIgnored(std::string const& workspace_name);
|
bool isWorkspaceIgnored(std::string const& workspace_name);
|
||||||
|
|
||||||
bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; }
|
bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; }
|
||||||
@@ -89,6 +95,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
|
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
|
||||||
auto populateFormatWindowSeparatorConfig(const Json::Value& config) -> void;
|
auto populateFormatWindowSeparatorConfig(const Json::Value& config) -> void;
|
||||||
auto populateWindowRewriteConfig(const Json::Value& config) -> void;
|
auto populateWindowRewriteConfig(const Json::Value& config) -> void;
|
||||||
|
auto populateMaxWindowsConfig(const Json::Value& config) -> void;
|
||||||
auto populateWorkspaceTaskbarConfig(const Json::Value& config) -> void;
|
auto populateWorkspaceTaskbarConfig(const Json::Value& config) -> void;
|
||||||
|
|
||||||
void registerIpc();
|
void registerIpc();
|
||||||
@@ -101,6 +108,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
Json::Value const& clientsData = Json::Value::nullRef);
|
Json::Value const& clientsData = Json::Value::nullRef);
|
||||||
void onWorkspaceMoved(std::string const& payload);
|
void onWorkspaceMoved(std::string const& payload);
|
||||||
void onWorkspaceRenamed(std::string const& payload);
|
void onWorkspaceRenamed(std::string const& payload);
|
||||||
|
void onWorkspaceIdChanged(std::string const& payload);
|
||||||
static std::optional<int> parseWorkspaceId(std::string const& workspaceIdStr);
|
static std::optional<int> parseWorkspaceId(std::string const& workspaceIdStr);
|
||||||
|
|
||||||
// monitor events
|
// monitor events
|
||||||
@@ -146,9 +154,11 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
bool m_allOutputs = false;
|
bool m_allOutputs = false;
|
||||||
bool m_showSpecial = false;
|
bool m_showSpecial = false;
|
||||||
bool m_activeOnly = false;
|
bool m_activeOnly = false;
|
||||||
|
bool m_hideActive = false;
|
||||||
bool m_specialVisibleOnly = false;
|
bool m_specialVisibleOnly = false;
|
||||||
bool m_persistentOnly = false;
|
bool m_persistentOnly = false;
|
||||||
bool m_moveToMonitor = false;
|
bool m_moveToMonitor = false;
|
||||||
|
bool m_uniqueIcons = false;
|
||||||
bool m_barScroll = false;
|
bool m_barScroll = false;
|
||||||
Json::Value m_persistentWorkspaceConfig;
|
Json::Value m_persistentWorkspaceConfig;
|
||||||
|
|
||||||
@@ -158,9 +168,9 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
std::map<WindowAddress, WindowRepr, std::less<>> m_orphanWindowMap;
|
std::map<WindowAddress, WindowRepr, std::less<>> m_orphanWindowMap;
|
||||||
|
|
||||||
enum class SortMethod { ID, NAME, NUMBER, SPECIAL_CENTERED, DEFAULT };
|
enum class SortMethod { ID, NAME, NUMBER, SPECIAL_CENTERED, DEFAULT };
|
||||||
util::EnumParser<SortMethod> m_enumParser;
|
|
||||||
SortMethod m_sortBy = SortMethod::DEFAULT;
|
SortMethod m_sortBy = SortMethod::DEFAULT;
|
||||||
std::map<std::string, SortMethod> m_sortMap = {{"ID", SortMethod::ID},
|
static inline const std::map<std::string, SortMethod> m_sortMap = {
|
||||||
|
{"ID", SortMethod::ID},
|
||||||
{"NAME", SortMethod::NAME},
|
{"NAME", SortMethod::NAME},
|
||||||
{"NUMBER", SortMethod::NUMBER},
|
{"NUMBER", SortMethod::NUMBER},
|
||||||
{"SPECIAL-CENTERED", SortMethod::SPECIAL_CENTERED},
|
{"SPECIAL-CENTERED", SortMethod::SPECIAL_CENTERED},
|
||||||
@@ -170,9 +180,13 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
std::string m_formatAfter;
|
std::string m_formatAfter;
|
||||||
|
|
||||||
std::map<std::string, std::string> m_iconsMap;
|
std::map<std::string, std::string> m_iconsMap;
|
||||||
|
std::map<std::string, std::string> m_tooltipMap;
|
||||||
|
bool m_withTooltip = false;
|
||||||
util::RegexCollection m_windowRewriteRules;
|
util::RegexCollection m_windowRewriteRules;
|
||||||
bool m_anyWindowRewriteRuleUsesTitle = false;
|
bool m_anyWindowRewriteRuleUsesTitle = false;
|
||||||
std::string m_formatWindowSeparator;
|
std::string m_formatWindowSeparator;
|
||||||
|
int m_windowRewriteGroupThreshold = 0;
|
||||||
|
std::string m_windowRewriteGroupFormat = "{icon}×{count}";
|
||||||
|
|
||||||
bool m_withIcon;
|
bool m_withIcon;
|
||||||
uint64_t m_monitorId;
|
uint64_t m_monitorId;
|
||||||
@@ -191,17 +205,18 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
std::string m_taskbarFormatBefore;
|
std::string m_taskbarFormatBefore;
|
||||||
std::string m_taskbarFormatAfter;
|
std::string m_taskbarFormatAfter;
|
||||||
int m_taskbarIconSize = 16;
|
int m_taskbarIconSize = 16;
|
||||||
|
int m_taskbarMaxIcons = 0; // 0 means unlimited
|
||||||
Gtk::Orientation m_taskbarOrientation = Gtk::ORIENTATION_HORIZONTAL;
|
Gtk::Orientation m_taskbarOrientation = Gtk::ORIENTATION_HORIZONTAL;
|
||||||
bool m_taskbarReverseDirection = false;
|
bool m_taskbarReverseDirection = false;
|
||||||
util::EnumParser<ActiveWindowPosition> m_activeWindowEnumParser;
|
|
||||||
ActiveWindowPosition m_activeWindowPosition = ActiveWindowPosition::NONE;
|
ActiveWindowPosition m_activeWindowPosition = ActiveWindowPosition::NONE;
|
||||||
std::map<std::string, ActiveWindowPosition> m_activeWindowPositionMap = {
|
static inline std::map<std::string, ActiveWindowPosition> m_activeWindowPositionMap = {
|
||||||
{"NONE", ActiveWindowPosition::NONE},
|
{"NONE", ActiveWindowPosition::NONE},
|
||||||
{"FIRST", ActiveWindowPosition::FIRST},
|
{"FIRST", ActiveWindowPosition::FIRST},
|
||||||
{"LAST", ActiveWindowPosition::LAST},
|
{"LAST", ActiveWindowPosition::LAST},
|
||||||
};
|
};
|
||||||
std::string m_onClickWindow;
|
std::string m_onClickWindow;
|
||||||
std::string m_currentActiveWindowAddress;
|
std::string m_currentActiveWindowAddress;
|
||||||
|
int m_maxWindows = 0;
|
||||||
|
|
||||||
std::vector<std::regex> m_ignoreWorkspaces;
|
std::vector<std::regex> m_ignoreWorkspaces;
|
||||||
std::vector<std::regex> m_ignoreWindows;
|
std::vector<std::regex> m_ignoreWindows;
|
||||||
@@ -211,6 +226,10 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
Gtk::Box m_box;
|
Gtk::Box m_box;
|
||||||
sigc::connection m_scrollEventConnection_;
|
sigc::connection m_scrollEventConnection_;
|
||||||
IPC& m_ipc;
|
IPC& m_ipc;
|
||||||
|
|
||||||
|
// Coalesces bursts of Hyprland events into a single UI refresh. Armed and
|
||||||
|
// disconnected only on the GTK main thread (see Workspaces::update).
|
||||||
|
sigc::connection m_debounceTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
|||||||
@@ -6,25 +6,42 @@
|
|||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
|
|
||||||
|
struct ext_idle_notification_v1;
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
class IdleInhibitor : public ALabel {
|
class IdleInhibitor : public ALabel {
|
||||||
sigc::connection timeout_;
|
sigc::connection timeout_;
|
||||||
|
ext_idle_notification_v1* idle_notification_;
|
||||||
|
uint32_t idle_timeout_ms_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
|
IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||||
virtual ~IdleInhibitor();
|
virtual ~IdleInhibitor();
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
auto refresh(int) -> void override;
|
||||||
static std::list<waybar::AModule*> modules;
|
static std::list<waybar::AModule*> modules;
|
||||||
static bool status;
|
static bool status;
|
||||||
|
static long deactivationTime;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool handleToggle(GdkEventButton* const& e) override;
|
bool handleToggle(GdkEventButton* const& e) override;
|
||||||
void toggleStatus();
|
bool handleScroll(GdkEventScroll* e) override;
|
||||||
|
|
||||||
|
void toggleStatus(int force_status = -1);
|
||||||
|
void setupIdleNotification();
|
||||||
|
void teardownIdleNotification();
|
||||||
|
static void handleIdled(void* data, ext_idle_notification_v1* notification);
|
||||||
|
static void handleResumed(void* data, ext_idle_notification_v1* notification);
|
||||||
|
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
struct zwp_idle_inhibitor_v1* idle_inhibitor_;
|
struct zwp_idle_inhibitor_v1* idle_inhibitor_;
|
||||||
int pid_;
|
int pid_;
|
||||||
|
|
||||||
|
bool dynamicTimeout = false;
|
||||||
|
double timeout;
|
||||||
|
double timeout_step;
|
||||||
|
bool wait_for_activity_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
|||||||
@@ -14,6 +14,69 @@
|
|||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
namespace image {
|
||||||
|
|
||||||
|
class IStrategy {
|
||||||
|
public:
|
||||||
|
virtual ~IStrategy() = default;
|
||||||
|
// Runs on the worker thread before update(). Use it for blocking work (e.g.
|
||||||
|
// spawning a user script) so the GTK main loop isn't stalled. Default no-op.
|
||||||
|
virtual void fetch() {}
|
||||||
|
virtual void update() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SingleImageStrategy : public IStrategy {
|
||||||
|
public:
|
||||||
|
SingleImageStrategy(const std::string&, const Json::Value&, const std::string&, Gtk::EventBox&,
|
||||||
|
bool);
|
||||||
|
~SingleImageStrategy() override = default;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parseOutputRaw();
|
||||||
|
|
||||||
|
util::command::res output_;
|
||||||
|
Json::Value config_;
|
||||||
|
Gtk::Image image_;
|
||||||
|
std::string path_;
|
||||||
|
std::string tooltip_;
|
||||||
|
int size_;
|
||||||
|
Gtk::Box box_;
|
||||||
|
bool hasTooltip_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MultipleImageStrategy : public IStrategy {
|
||||||
|
public:
|
||||||
|
MultipleImageStrategy(const std::string&, const Json::Value&, const std::string&, Gtk::EventBox&);
|
||||||
|
~MultipleImageStrategy() override = default;
|
||||||
|
void fetch() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ImageData {
|
||||||
|
std::string path;
|
||||||
|
std::string marker;
|
||||||
|
std::string tooltip;
|
||||||
|
std::string on_click;
|
||||||
|
std::shared_ptr<Gtk::Image> img;
|
||||||
|
std::shared_ptr<Gtk::Button> btn;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setImagesData(const Json::Value&);
|
||||||
|
void setupAndDraw();
|
||||||
|
void resetBoxAndMemory();
|
||||||
|
void handleClick(const Glib::ustring& data);
|
||||||
|
|
||||||
|
Json::Value config_;
|
||||||
|
int size_;
|
||||||
|
Gtk::Box box_;
|
||||||
|
std::vector<ImageData> images_data_;
|
||||||
|
// stdout captured by fetch() on the worker thread and consumed by update()
|
||||||
|
std::string exec_output_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace image
|
||||||
|
|
||||||
class Image : public AModule {
|
class Image : public AModule {
|
||||||
public:
|
public:
|
||||||
Image(const std::string&, const Json::Value&);
|
Image(const std::string&, const Json::Value&);
|
||||||
@@ -24,16 +87,11 @@ class Image : public AModule {
|
|||||||
private:
|
private:
|
||||||
void delayWorker();
|
void delayWorker();
|
||||||
void handleEvent();
|
void handleEvent();
|
||||||
void parseOutputRaw();
|
static std::unique_ptr<image::IStrategy> getStrategy(const std::string&, const Json::Value&,
|
||||||
|
const std::string&, Gtk::EventBox&, bool);
|
||||||
|
|
||||||
Gtk::Box box_;
|
|
||||||
Gtk::Image image_;
|
|
||||||
std::string path_;
|
|
||||||
std::string tooltip_;
|
|
||||||
int size_;
|
|
||||||
std::chrono::milliseconds interval_;
|
std::chrono::milliseconds interval_;
|
||||||
util::command::res output_;
|
std::unique_ptr<image::IStrategy> strategy_;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ class KeyboardState : public AModule {
|
|||||||
std::string capslock_format_;
|
std::string capslock_format_;
|
||||||
std::string scrolllock_format_;
|
std::string scrolllock_format_;
|
||||||
const std::chrono::seconds interval_;
|
const std::chrono::seconds interval_;
|
||||||
std::string icon_locked_;
|
std::unordered_map<std::string, std::vector<std::string>> key_icon_states_;
|
||||||
std::string icon_unlocked_;
|
|
||||||
std::string devices_path_;
|
std::string devices_path_;
|
||||||
|
|
||||||
struct libinput* libinput_;
|
struct libinput* libinput_;
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// include/modules/mango/backend.hpp
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <list>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "util/json.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::mango {
|
||||||
|
|
||||||
|
class EventHandler {
|
||||||
|
public:
|
||||||
|
virtual void onEvent(const Json::Value& ev) = 0;
|
||||||
|
virtual ~EventHandler() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPC {
|
||||||
|
public:
|
||||||
|
static IPC& getInstance();
|
||||||
|
IPC(const IPC&) = delete;
|
||||||
|
IPC& operator=(const IPC&) = delete;
|
||||||
|
|
||||||
|
void registerForIPC(const std::string& ev, EventHandler* handler);
|
||||||
|
void unregisterForIPC(EventHandler* handler);
|
||||||
|
|
||||||
|
static Json::Value send(const Json::Value& request);
|
||||||
|
static void sendAsync(const Json::Value& request);
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lockData() { return std::unique_lock<std::mutex>(data_mutex_); }
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Json::Value> getMonitors() const;
|
||||||
|
Json::Value getMonitor(const std::string& name);
|
||||||
|
Json::Value getActiveClientForMonitor(const std::string& name) const;
|
||||||
|
std::string getKeyboardLayout() const;
|
||||||
|
std::string getKeymode() const;
|
||||||
|
std::string getLayoutSymbolForMonitor(const std::string& name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IPC();
|
||||||
|
~IPC();
|
||||||
|
void startIPC();
|
||||||
|
static int connectToSocket();
|
||||||
|
void parseIPC(const std::string& line);
|
||||||
|
|
||||||
|
void handleMonitorUpdate(const Json::Value& mon);
|
||||||
|
void updateFocusingClient(const Json::Value& client);
|
||||||
|
void updateKeyboardLayout(const std::string& layout);
|
||||||
|
|
||||||
|
static Json::Value sendCommand(const std::string& cmd);
|
||||||
|
|
||||||
|
std::atomic<bool> running_ = true;
|
||||||
|
int sockfd_ = -1;
|
||||||
|
std::thread ipc_thread_;
|
||||||
|
mutable std::mutex data_mutex_;
|
||||||
|
std::unordered_map<std::string, Json::Value> monitors_;
|
||||||
|
std::unordered_map<uint64_t, Json::Value> clients_;
|
||||||
|
uint64_t focusing_client_id_ = 0;
|
||||||
|
std::string keyboard_layout_;
|
||||||
|
std::string keymode_;
|
||||||
|
Json::Value active_client_;
|
||||||
|
std::mutex callback_mutex_;
|
||||||
|
std::list<std::pair<std::string, EventHandler*>> callbacks_;
|
||||||
|
};
|
||||||
|
} // namespace waybar::modules::mango
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/mango/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::mango {
|
||||||
|
|
||||||
|
class Keymode : public ALabel, public EventHandler {
|
||||||
|
public:
|
||||||
|
Keymode(const std::string&, const Bar&, const Json::Value&);
|
||||||
|
~Keymode() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onEvent(const Json::Value& ev) override;
|
||||||
|
void doUpdate();
|
||||||
|
|
||||||
|
std::mutex mutex_;
|
||||||
|
const Bar& bar_;
|
||||||
|
std::string last_keymode_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::mango
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xkbcommon/xkbregistry.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/mango/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::mango {
|
||||||
|
|
||||||
|
class Language : public ALabel, public EventHandler {
|
||||||
|
public:
|
||||||
|
Language(const std::string&, const Bar&, const Json::Value&);
|
||||||
|
~Language() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateFromIPC();
|
||||||
|
void onEvent(const Json::Value& ev) override;
|
||||||
|
void doUpdate();
|
||||||
|
|
||||||
|
struct Layout {
|
||||||
|
std::string full_name;
|
||||||
|
std::string short_name;
|
||||||
|
std::string variant;
|
||||||
|
std::string short_description;
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout getLayout(const std::string& fullName);
|
||||||
|
|
||||||
|
std::mutex mutex_;
|
||||||
|
const Bar& bar_;
|
||||||
|
|
||||||
|
std::vector<Layout> layouts_;
|
||||||
|
unsigned current_idx_;
|
||||||
|
std::string last_short_name_;
|
||||||
|
|
||||||
|
struct rxkb_context* rxkb_ctx_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::mango
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/mango/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::mango {
|
||||||
|
|
||||||
|
class Layout : public ALabel, public EventHandler {
|
||||||
|
public:
|
||||||
|
Layout(const std::string&, const Bar&, const Json::Value&);
|
||||||
|
~Layout() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onEvent(const Json::Value& ev) override;
|
||||||
|
void doUpdate();
|
||||||
|
|
||||||
|
std::mutex mutex_;
|
||||||
|
const Bar& bar_;
|
||||||
|
std::string last_symbol_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::mango
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <json/value.h>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "AAppIconLabel.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/mango/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::mango {
|
||||||
|
|
||||||
|
class Window : public AAppIconLabel, public EventHandler {
|
||||||
|
public:
|
||||||
|
Window(const std::string&, const Bar&, const Json::Value&);
|
||||||
|
~Window() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onEvent(const Json::Value& ev) override;
|
||||||
|
void doUpdate();
|
||||||
|
void setClass(const std::string& className, bool enable);
|
||||||
|
|
||||||
|
const Bar& bar_;
|
||||||
|
std::string oldAppId_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::mango
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <json/value.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "AModule.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/mango/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::mango {
|
||||||
|
|
||||||
|
class Workspaces : public AModule, public EventHandler {
|
||||||
|
public:
|
||||||
|
Workspaces(const std::string&, const Bar&, const Json::Value&);
|
||||||
|
~Workspaces() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onEvent(const Json::Value& ev) override;
|
||||||
|
void doUpdate();
|
||||||
|
|
||||||
|
Gtk::Button& addButton(uint64_t idx);
|
||||||
|
void updateButtonState(Gtk::Button& button, const Json::Value& tag, const Json::Value& monitor);
|
||||||
|
std::string getIcon(const std::string& value, const Json::Value& tag);
|
||||||
|
bool handleButtonClick(GdkEventButton* event, uint64_t idx, bool isOverview);
|
||||||
|
|
||||||
|
const Bar& bar_;
|
||||||
|
Gtk::Box box_;
|
||||||
|
|
||||||
|
std::unordered_map<uint64_t, Gtk::Button> buttons_;
|
||||||
|
Gtk::Button* overview_button_ = nullptr;
|
||||||
|
|
||||||
|
std::string on_click_left_;
|
||||||
|
std::string on_click_middle_;
|
||||||
|
std::string on_click_right_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::mango
|
||||||
@@ -19,8 +19,6 @@ class Memory : public ALabel {
|
|||||||
private:
|
private:
|
||||||
void parseMeminfo();
|
void parseMeminfo();
|
||||||
|
|
||||||
static float calc_divisor(const std::string& divisor);
|
|
||||||
|
|
||||||
std::unordered_map<std::string, unsigned long> meminfo_;
|
std::unordered_map<std::string, unsigned long> meminfo_;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
|
|||||||
@@ -28,11 +28,14 @@ class MPD : public ALabel {
|
|||||||
|
|
||||||
unsigned timeout_;
|
unsigned timeout_;
|
||||||
|
|
||||||
|
unsigned playing_interval_;
|
||||||
|
|
||||||
detail::unique_connection connection_;
|
detail::unique_connection connection_;
|
||||||
|
|
||||||
detail::unique_status status_;
|
detail::unique_status status_;
|
||||||
mpd_state state_;
|
mpd_state state_;
|
||||||
detail::unique_song song_;
|
detail::unique_song song_;
|
||||||
|
std::string ellipsis_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MPD(const std::string&, const Json::Value&);
|
MPD(const std::string&, const Json::Value&);
|
||||||
@@ -45,6 +48,10 @@ class MPD : public ALabel {
|
|||||||
void setLabel();
|
void setLabel();
|
||||||
std::string getStateIcon() const;
|
std::string getStateIcon() const;
|
||||||
std::string getOptionIcon(const std::string& optionName, bool activated) const;
|
std::string getOptionIcon(const std::string& optionName, bool activated) const;
|
||||||
|
std::string getArtistStr(bool truncated) const;
|
||||||
|
std::string getAlbumArtistStr(bool truncated) const;
|
||||||
|
std::string getAlbumStr(bool truncated) const;
|
||||||
|
std::string getTitleStr(bool truncated) const;
|
||||||
|
|
||||||
// GUI-side methods
|
// GUI-side methods
|
||||||
bool handlePlayPause(GdkEventButton* const&);
|
bool handlePlayPause(GdkEventButton* const&);
|
||||||
@@ -54,11 +61,11 @@ class MPD : public ALabel {
|
|||||||
void tryConnect();
|
void tryConnect();
|
||||||
void checkErrors(mpd_connection* conn);
|
void checkErrors(mpd_connection* conn);
|
||||||
void fetchState();
|
void fetchState();
|
||||||
void queryMPD();
|
|
||||||
|
|
||||||
inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; }
|
inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; }
|
||||||
inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; }
|
inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; }
|
||||||
inline bool paused() const { return connection_ && state_ == MPD_STATE_PAUSE; }
|
inline bool paused() const { return connection_ && state_ == MPD_STATE_PAUSE; }
|
||||||
|
inline unsigned playing_interval() const { return playing_interval_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(MPD_NOINLINE)
|
#if !defined(MPD_NOINLINE)
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ class Idle : public State {
|
|||||||
class Playing : public State {
|
class Playing : public State {
|
||||||
Context* const ctx_;
|
Context* const ctx_;
|
||||||
sigc::connection timer_connection_;
|
sigc::connection timer_connection_;
|
||||||
|
sigc::connection idle_connection_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Playing(Context* const ctx) : ctx_{ctx} {}
|
Playing(Context* const ctx) : ctx_{ctx} {}
|
||||||
@@ -98,7 +99,10 @@ class Playing : public State {
|
|||||||
Playing(Playing const&) = delete;
|
Playing(Playing const&) = delete;
|
||||||
Playing& operator=(Playing const&) = delete;
|
Playing& operator=(Playing const&) = delete;
|
||||||
|
|
||||||
|
void timer() noexcept;
|
||||||
|
void idle() noexcept;
|
||||||
bool on_timer();
|
bool on_timer();
|
||||||
|
bool on_io(Glib::IOCondition const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Paused : public State {
|
class Paused : public State {
|
||||||
@@ -194,10 +198,10 @@ class Context {
|
|||||||
bool is_paused() const;
|
bool is_paused() const;
|
||||||
bool is_stopped() const;
|
bool is_stopped() const;
|
||||||
constexpr std::size_t interval() const;
|
constexpr std::size_t interval() const;
|
||||||
|
unsigned playing_interval() const;
|
||||||
void tryConnect() const;
|
void tryConnect() const;
|
||||||
void checkErrors(mpd_connection*) const;
|
void checkErrors(mpd_connection*) const;
|
||||||
void do_update();
|
void do_update();
|
||||||
void queryMPD() const;
|
|
||||||
void fetchState() const;
|
void fetchState() const;
|
||||||
constexpr mpd_state state() const;
|
constexpr mpd_state state() const;
|
||||||
void emit() const;
|
void emit() const;
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
inline bool Context::is_connected() const { return mpd_module_->connection_ != nullptr; }
|
inline bool Context::is_connected() const { return mpd_module_->connection_ != nullptr; }
|
||||||
inline bool Context::is_playing() const { return mpd_module_->playing(); }
|
inline bool Context::is_playing() const { return mpd_module_->playing(); }
|
||||||
inline bool Context::is_paused() const { return mpd_module_->paused(); }
|
inline bool Context::is_paused() const { return mpd_module_->paused(); }
|
||||||
inline bool Context::is_stopped() const { return mpd_module_->stopped(); }
|
inline bool Context::is_stopped() const { return mpd_module_->stopped(); }
|
||||||
|
|
||||||
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_.count(); }
|
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_ / 1s; }
|
||||||
|
inline unsigned Context::playing_interval() const { return mpd_module_->playing_interval(); }
|
||||||
inline void Context::tryConnect() const { mpd_module_->tryConnect(); }
|
inline void Context::tryConnect() const { mpd_module_->tryConnect(); }
|
||||||
inline unique_connection& Context::connection() { return mpd_module_->connection_; }
|
inline unique_connection& Context::connection() { return mpd_module_->connection_; }
|
||||||
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
|
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
|
||||||
@@ -15,7 +17,6 @@ constexpr inline mpd_state Context::state() const { return mpd_module_->state_;
|
|||||||
inline void Context::do_update() { mpd_module_->setLabel(); }
|
inline void Context::do_update() { mpd_module_->setLabel(); }
|
||||||
|
|
||||||
inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); }
|
inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); }
|
||||||
inline void Context::queryMPD() const { mpd_module_->queryMPD(); }
|
|
||||||
inline void Context::fetchState() const { mpd_module_->fetchState(); }
|
inline void Context::fetchState() const { mpd_module_->fetchState(); }
|
||||||
inline void Context::emit() const { mpd_module_->emit(); }
|
inline void Context::emit() const { mpd_module_->emit(); }
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class Mpris : public ALabel {
|
|||||||
|
|
||||||
std::optional<std::string> artist;
|
std::optional<std::string> artist;
|
||||||
std::optional<std::string> album;
|
std::optional<std::string> album;
|
||||||
|
std::optional<std::string> album_artist;
|
||||||
std::optional<std::string> title;
|
std::optional<std::string> title;
|
||||||
std::optional<std::string> length; // as HH:MM:SS
|
std::optional<std::string> length; // as HH:MM:SS
|
||||||
std::optional<std::string> position; // same format
|
std::optional<std::string> position; // same format
|
||||||
@@ -76,6 +77,8 @@ class Mpris : public ALabel {
|
|||||||
std::string player_;
|
std::string player_;
|
||||||
std::vector<std::string> ignored_players_;
|
std::vector<std::string> ignored_players_;
|
||||||
|
|
||||||
|
bool prefer_album_artist_;
|
||||||
|
|
||||||
PlayerctlPlayerManager* manager;
|
PlayerctlPlayerManager* manager;
|
||||||
PlayerctlPlayer* player;
|
PlayerctlPlayer* player;
|
||||||
PlayerctlPlayer* last_active_player_ = nullptr;
|
PlayerctlPlayer* last_active_player_ = nullptr;
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
#include "util/rfkill.hpp"
|
#include "util/rfkill.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ETH_ALEN 6
|
||||||
|
|
||||||
enum ip_addr_pref : uint8_t { IPV4, IPV6, IPV4_6 };
|
enum ip_addr_pref : uint8_t { IPV4, IPV6, IPV4_6 };
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
@@ -34,6 +36,7 @@ class Network : public ALabel {
|
|||||||
static int handleEvents(struct nl_msg*, void*);
|
static int handleEvents(struct nl_msg*, void*);
|
||||||
static int handleEventsDone(struct nl_msg*, void*);
|
static int handleEventsDone(struct nl_msg*, void*);
|
||||||
static int handleScan(struct nl_msg*, void*);
|
static int handleScan(struct nl_msg*, void*);
|
||||||
|
static int handleStationGet(struct nl_msg *msg, void *data);
|
||||||
|
|
||||||
void askForStateDump(void);
|
void askForStateDump(void);
|
||||||
|
|
||||||
@@ -48,15 +51,18 @@ class Network : public ALabel {
|
|||||||
bool matchInterface(const std::string& ifname, const std::vector<std::string>& altnames,
|
bool matchInterface(const std::string& ifname, const std::vector<std::string>& altnames,
|
||||||
std::string& matched) const;
|
std::string& matched) const;
|
||||||
auto getInfo() -> void;
|
auto getInfo() -> void;
|
||||||
|
bool isWireless() const;
|
||||||
const std::string getNetworkState() const;
|
const std::string getNetworkState() const;
|
||||||
void clearIface();
|
void clearIface();
|
||||||
std::optional<std::pair<unsigned long long, unsigned long long>> readBandwidthUsage();
|
std::optional<std::pair<unsigned long long, unsigned long long>> readBandwidthUsage();
|
||||||
|
uint32_t readLinkSpeed() const;
|
||||||
|
|
||||||
int ifid_{-1};
|
int ifid_{-1};
|
||||||
ip_addr_pref addr_pref_{ip_addr_pref::IPV4};
|
ip_addr_pref addr_pref_{ip_addr_pref::IPV4};
|
||||||
struct sockaddr_nl nladdr_{0};
|
struct sockaddr_nl nladdr_{0};
|
||||||
struct nl_sock* sock_{nullptr};
|
struct nl_sock* sock_{nullptr};
|
||||||
struct nl_sock* ev_sock_{nullptr};
|
struct nl_sock* ev_sock_{nullptr};
|
||||||
|
struct nl_sock* station_sock_{nullptr};
|
||||||
int efd_{-1};
|
int efd_{-1};
|
||||||
int ev_fd_{-1};
|
int ev_fd_{-1};
|
||||||
int nl80211_id_{-1};
|
int nl80211_id_{-1};
|
||||||
@@ -90,6 +96,7 @@ class Network : public ALabel {
|
|||||||
uint8_t signal_strength_;
|
uint8_t signal_strength_;
|
||||||
std::string signal_strength_app_;
|
std::string signal_strength_app_;
|
||||||
uint32_t route_priority;
|
uint32_t route_priority;
|
||||||
|
uint32_t link_speed_{0};
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
util::SleeperThread thread_timer_;
|
util::SleeperThread thread_timer_;
|
||||||
@@ -97,6 +104,8 @@ class Network : public ALabel {
|
|||||||
util::Rfkill rfkill_{RFKILL_TYPE_WLAN};
|
util::Rfkill rfkill_{RFKILL_TYPE_WLAN};
|
||||||
#endif
|
#endif
|
||||||
float frequency_{0};
|
float frequency_{0};
|
||||||
|
uint32_t tx_bitrate_{0};
|
||||||
|
uint32_t rx_bitrate_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -18,6 +19,7 @@ class EventHandler {
|
|||||||
class IPC {
|
class IPC {
|
||||||
public:
|
public:
|
||||||
IPC();
|
IPC();
|
||||||
|
~IPC();
|
||||||
|
|
||||||
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
|
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
|
||||||
void unregisterForIPC(EventHandler* handler);
|
void unregisterForIPC(EventHandler* handler);
|
||||||
@@ -32,7 +34,7 @@ class IPC {
|
|||||||
unsigned keyboardLayoutCurrent() const { return keyboardLayoutCurrent_; }
|
unsigned keyboardLayoutCurrent() const { return keyboardLayoutCurrent_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startIPC();
|
void startIPC(int initial_socketfd);
|
||||||
static int connectToSocket();
|
static int connectToSocket();
|
||||||
void parseIPC(const std::string&);
|
void parseIPC(const std::string&);
|
||||||
|
|
||||||
@@ -45,6 +47,8 @@ class IPC {
|
|||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::mutex callbackMutex_;
|
std::mutex callbackMutex_;
|
||||||
std::list<std::pair<std::string, EventHandler*>> callbacks_;
|
std::list<std::pair<std::string, EventHandler*>> callbacks_;
|
||||||
|
|
||||||
|
std::atomic<bool> running_{true};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<IPC> gIPC;
|
inline std::unique_ptr<IPC> gIPC;
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm/box.h>
|
||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <gtkmm/image.h>
|
||||||
|
#include <gtkmm/label.h>
|
||||||
|
#include <json/value.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace waybar::modules::niri {
|
||||||
|
|
||||||
|
class Workspaces;
|
||||||
|
|
||||||
|
class Workspace {
|
||||||
|
public:
|
||||||
|
Workspace(const Json::Value& workspace_data, Workspaces& manager);
|
||||||
|
~Workspace() = default;
|
||||||
|
|
||||||
|
Workspace(const Workspace&) = delete;
|
||||||
|
Workspace& operator=(const Workspace&) = delete;
|
||||||
|
|
||||||
|
Gtk::Button& button() { return button_; }
|
||||||
|
uint64_t id() const { return id_; }
|
||||||
|
|
||||||
|
void update(const Json::Value& workspace_data, const std::vector<Json::Value>& all_windows,
|
||||||
|
const std::string& windows_str, std::size_t total);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void rebuildTaskbar(const std::vector<Json::Value>& my_windows);
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> loadIcon(const std::string& app_id, int size);
|
||||||
|
|
||||||
|
Workspaces& manager_;
|
||||||
|
uint64_t id_;
|
||||||
|
|
||||||
|
// Layout: button_
|
||||||
|
// └─ box_ (horizontal)
|
||||||
|
// ├─ label_ workspace label / icon
|
||||||
|
// └─ taskbar_box_ app icon buttons (shown only when taskbar enabled)
|
||||||
|
Gtk::Button button_;
|
||||||
|
Gtk::Box box_;
|
||||||
|
Gtk::Label label_;
|
||||||
|
Gtk::Box taskbar_box_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::niri
|
||||||
@@ -1,30 +1,62 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gtkmm/button.h>
|
#include <gtkmm/box.h>
|
||||||
#include <json/value.h>
|
#include <json/value.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <regex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "modules/niri/backend.hpp"
|
#include "modules/niri/backend.hpp"
|
||||||
|
#include "modules/niri/workspace.hpp"
|
||||||
|
#include "util/regex_collection.hpp" // Added for rewrite rules
|
||||||
|
|
||||||
namespace waybar::modules::niri {
|
namespace waybar::modules::niri {
|
||||||
|
|
||||||
class Workspaces : public AModule, public EventHandler {
|
class Workspaces : public AModule, public EventHandler {
|
||||||
public:
|
public:
|
||||||
Workspaces(const std::string&, const Bar&, const Json::Value&);
|
Workspaces(const std::string& id, const Bar& bar, const Json::Value& config);
|
||||||
~Workspaces() override;
|
~Workspaces() override;
|
||||||
|
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|
||||||
|
const Json::Value& config() const { return config_; }
|
||||||
|
const Bar& bar() const { return bar_; }
|
||||||
|
|
||||||
|
std::string getIcon(const std::string& value, const Json::Value& ws) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onEvent(const Json::Value& ev) override;
|
void onEvent(const Json::Value& ev) override;
|
||||||
void doUpdate();
|
void doUpdate();
|
||||||
Gtk::Button& addButton(const Json::Value& ws);
|
void createWorkspace(const Json::Value& workspace_data);
|
||||||
std::string getIcon(const std::string& value, const Json::Value& ws);
|
void sortWorkspaces(std::vector<const Json::Value*>& workspaces) const;
|
||||||
|
bool isWorkspaceIgnored(const std::string& name);
|
||||||
|
bool handleScroll(GdkEventScroll* /*unused*/) override;
|
||||||
|
// Added for window rewrite
|
||||||
|
void populateWindowRewriteConfig();
|
||||||
|
void populateFormatWindowSeparatorConfig();
|
||||||
|
std::string getRewrite(const std::string& app_id, const std::string& title);
|
||||||
|
std::string getWindowsRepresentation(const Json::Value& ws);
|
||||||
|
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
// Map from niri workspace id to button.
|
|
||||||
std::unordered_map<uint64_t, Gtk::Button> buttons_;
|
std::vector<std::unique_ptr<Workspace>> workspaces_;
|
||||||
|
|
||||||
|
// Vec of regex rules to ignore workspaces.
|
||||||
|
std::vector<std::regex> ignoreWorkspaces_;
|
||||||
|
|
||||||
|
bool sort_by_id_ = false;
|
||||||
|
bool sort_by_name_ = false;
|
||||||
|
bool sort_by_coordinates_ = false;
|
||||||
|
|
||||||
|
// Added for window rewrite
|
||||||
|
util::RegexCollection m_windowRewriteRules;
|
||||||
|
std::string m_windowRewriteDefault;
|
||||||
|
std::string m_formatWindowSeparator;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::niri
|
} // namespace waybar::modules::niri
|
||||||
|
|||||||
@@ -9,9 +9,18 @@ namespace waybar::modules {
|
|||||||
|
|
||||||
struct Profile {
|
struct Profile {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
// Legacy driver field, kept for backward compatibility with the
|
||||||
|
// `{driver}` format placeholder and with older power-profiles-daemon
|
||||||
|
// versions that only expose a single `Driver` DBus property.
|
||||||
std::string driver;
|
std::string driver;
|
||||||
|
std::string cpuDriver;
|
||||||
|
std::string platformDriver;
|
||||||
|
|
||||||
Profile(std::string n, std::string d) : name(std::move(n)), driver(std::move(d)) {}
|
Profile(std::string n, std::string d, std::string cd, std::string pd)
|
||||||
|
: name(std::move(n)),
|
||||||
|
driver(std::move(d)),
|
||||||
|
cpuDriver(std::move(cd)),
|
||||||
|
platformDriver(std::move(pd)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PowerProfilesDaemon : public ALabel {
|
class PowerProfilesDaemon : public ALabel {
|
||||||
|
|||||||
@@ -1,40 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "gtkmm/box.h"
|
#include "gtkmm/box.h"
|
||||||
#include "modules/privacy/privacy_item.hpp"
|
#include "modules/privacy/privacy_item.hpp"
|
||||||
|
#include "util/geoclue_backend.hpp"
|
||||||
#include "util/pipewire/pipewire_backend.hpp"
|
#include "util/pipewire/pipewire_backend.hpp"
|
||||||
#include "util/pipewire/privacy_node_info.hpp"
|
#include "util/pipewire/privacy_node_info.hpp"
|
||||||
|
|
||||||
using waybar::util::PipewireBackend::PrivacyNodeInfo;
|
using waybar::util::PipewireBackend::PrivacyNodeType;
|
||||||
|
using waybar::util::PipewireBackend::PWPrivacyNodeInfo;
|
||||||
|
|
||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
|
||||||
class Privacy : public AModule {
|
class Privacy : public AModule {
|
||||||
public:
|
public:
|
||||||
Privacy(const std::string&, const Json::Value&, Gtk::Orientation, const std::string& pos);
|
Privacy(const std::string&, const Json::Value&, Gtk::Orientation, const std::string& pos);
|
||||||
|
~Privacy() override;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
void onPrivacyNodesChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<PrivacyNodeInfo*> nodes_screenshare; // Screen is being shared
|
std::list<PWPrivacyNodeInfo*> nodes_screenshare; // Screen is being shared
|
||||||
std::list<PrivacyNodeInfo*> nodes_audio_in; // Application is using the microphone
|
std::list<PWPrivacyNodeInfo*> nodes_audio_in; // Application is using the microphone
|
||||||
std::list<PrivacyNodeInfo*> nodes_audio_out; // Application is outputting audio
|
std::list<PWPrivacyNodeInfo*> nodes_audio_out; // Application is outputting audio
|
||||||
|
std::atomic<bool> location_in_use; // GeoClue is being used
|
||||||
|
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
sigc::connection visibility_conn;
|
sigc::connection visibility_conn;
|
||||||
|
sigc::connection geoclue_timeout_conn;
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
|
std::vector<PrivacyItem*> modules_;
|
||||||
uint iconSpacing = 4;
|
uint iconSpacing = 4;
|
||||||
uint iconSize = 20;
|
uint iconSize = 20;
|
||||||
uint transition_duration = 250;
|
uint transition_duration = 250;
|
||||||
std::set<std::pair<PrivacyNodeType, std::string>> ignore;
|
std::set<std::pair<PrivacyNodeType, std::string>> ignore;
|
||||||
bool ignore_monitor = true;
|
bool ignore_monitor = true;
|
||||||
|
|
||||||
std::shared_ptr<util::PipewireBackend::PipewireBackend> backend = nullptr;
|
std::shared_ptr<util::PipewireBackend::PipewireBackend> pw_backend = nullptr;
|
||||||
|
std::shared_ptr<util::GeoClueBackend::GeoClueBackend> geoclue_backend = nullptr;
|
||||||
|
|
||||||
|
void onPWPrivacyNodesChanged();
|
||||||
|
bool locationTimeout(bool in_use);
|
||||||
|
void onGeoCluePrivacyNodesChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::privacy
|
} // namespace waybar::modules::privacy
|
||||||
|
|||||||
@@ -9,35 +9,36 @@
|
|||||||
#include "gtkmm/revealer.h"
|
#include "gtkmm/revealer.h"
|
||||||
#include "util/pipewire/privacy_node_info.hpp"
|
#include "util/pipewire/privacy_node_info.hpp"
|
||||||
|
|
||||||
using waybar::util::PipewireBackend::PrivacyNodeInfo;
|
|
||||||
using waybar::util::PipewireBackend::PrivacyNodeType;
|
using waybar::util::PipewireBackend::PrivacyNodeType;
|
||||||
|
using waybar::util::PipewireBackend::PWPrivacyNodeInfo;
|
||||||
|
|
||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
|
||||||
class PrivacyItem : public Gtk::Revealer {
|
class PrivacyItem : public Gtk::Revealer {
|
||||||
public:
|
protected:
|
||||||
PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
||||||
std::list<PrivacyNodeInfo*>* nodes, Gtk::Orientation orientation,
|
Gtk::Orientation orientation, const std::string& pos, const uint icon_size,
|
||||||
const std::string& pos, const uint icon_size, const uint transition_duration);
|
const uint transition_duration);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void set_tooltip() = 0;
|
||||||
|
|
||||||
enum PrivacyNodeType privacy_type;
|
enum PrivacyNodeType privacy_type;
|
||||||
|
|
||||||
void set_in_use(bool in_use);
|
void set_in_use(bool in_use);
|
||||||
|
|
||||||
private:
|
uint tooltipIconSize = 24;
|
||||||
std::list<PrivacyNodeInfo*>* nodes;
|
|
||||||
|
|
||||||
sigc::connection signal_conn;
|
|
||||||
|
|
||||||
Gtk::Box tooltip_window;
|
Gtk::Box tooltip_window;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sigc::connection signal_conn;
|
||||||
|
|
||||||
bool init = false;
|
bool init = false;
|
||||||
bool in_use = false;
|
bool in_use = false;
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
std::string iconName = "image-missing-symbolic";
|
std::string iconName = "image-missing-symbolic";
|
||||||
bool tooltip = true;
|
bool tooltip = true;
|
||||||
uint tooltipIconSize = 24;
|
|
||||||
|
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
Gtk::Image icon_;
|
Gtk::Image icon_;
|
||||||
@@ -45,4 +46,28 @@ class PrivacyItem : public Gtk::Revealer {
|
|||||||
void update_tooltip();
|
void update_tooltip();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GeoCluePrivacyItem : public PrivacyItem {
|
||||||
|
public:
|
||||||
|
GeoCluePrivacyItem(const Json::Value& config_, Gtk::Orientation orientation,
|
||||||
|
const std::string& pos, const uint icon_size, const uint transition_duration)
|
||||||
|
: PrivacyItem(config_, util::PipewireBackend::PRIVACY_NODE_TYPE_LOCATION, orientation, pos,
|
||||||
|
icon_size, transition_duration) {}
|
||||||
|
|
||||||
|
void set_tooltip() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PWPrivacyItem : public PrivacyItem {
|
||||||
|
public:
|
||||||
|
PWPrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
||||||
|
std::list<PWPrivacyNodeInfo*>* nodes_, Gtk::Orientation orientation,
|
||||||
|
const std::string& pos, const uint icon_size, const uint transition_duration)
|
||||||
|
: PrivacyItem(config_, privacy_type_, orientation, pos, icon_size, transition_duration),
|
||||||
|
nodes(nodes_) {}
|
||||||
|
|
||||||
|
void set_tooltip() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<PWPrivacyNodeInfo*>* nodes;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::privacy
|
} // namespace waybar::modules::privacy
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class Pulseaudio : public ALabel {
|
|||||||
const std::vector<std::string> getPulseIcon() const;
|
const std::vector<std::string> getPulseIcon() const;
|
||||||
|
|
||||||
std::shared_ptr<util::AudioBackend> backend = nullptr;
|
std::shared_ptr<util::AudioBackend> backend = nullptr;
|
||||||
|
util::PulseaudioTarget target = util::PulseaudioTarget::Sink;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
|||||||
@@ -6,11 +6,6 @@
|
|||||||
#include "util/audio_backend.hpp"
|
#include "util/audio_backend.hpp"
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
enum class PulseaudioSliderTarget {
|
|
||||||
Sink,
|
|
||||||
Source,
|
|
||||||
};
|
|
||||||
|
|
||||||
class PulseaudioSlider : public ASlider {
|
class PulseaudioSlider : public ASlider {
|
||||||
public:
|
public:
|
||||||
PulseaudioSlider(const std::string&, const Json::Value&);
|
PulseaudioSlider(const std::string&, const Json::Value&);
|
||||||
@@ -21,7 +16,15 @@ class PulseaudioSlider : public ASlider {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<util::AudioBackend> backend = nullptr;
|
std::shared_ptr<util::AudioBackend> backend = nullptr;
|
||||||
PulseaudioSliderTarget target = PulseaudioSliderTarget::Sink;
|
util::PulseaudioTarget target = util::PulseaudioTarget::Sink;
|
||||||
|
|
||||||
|
bool zero_on_mute = true;
|
||||||
|
bool unmute_on_volume_change = true;
|
||||||
|
// zero_on_mute and unmute_on_volume_change default to true
|
||||||
|
// in order to maintain previous behaviour when using a
|
||||||
|
// config in which these values are undefined
|
||||||
|
|
||||||
|
bool previously_muted = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
@@ -21,6 +21,8 @@ class Tags : public waybar::AModule {
|
|||||||
void handle_view_tags(struct wl_array* tags);
|
void handle_view_tags(struct wl_array* tags);
|
||||||
void handle_urgent_tags(uint32_t tags);
|
void handle_urgent_tags(uint32_t tags);
|
||||||
void handle_focused_view(const char *title, uint32_t tags);
|
void handle_focused_view(const char *title, uint32_t tags);
|
||||||
|
void handle_focused_output(struct wl_output* output);
|
||||||
|
void handle_unfocused_output(struct wl_output* output);
|
||||||
|
|
||||||
void handle_show();
|
void handle_show();
|
||||||
void handle_primary_clicked(uint32_t tag);
|
void handle_primary_clicked(uint32_t tag);
|
||||||
@@ -28,17 +30,17 @@ class Tags : public waybar::AModule {
|
|||||||
|
|
||||||
struct zriver_status_manager_v1* status_manager_;
|
struct zriver_status_manager_v1* status_manager_;
|
||||||
struct zriver_control_v1* control_;
|
struct zriver_control_v1* control_;
|
||||||
struct zriver_seat_status_v1 *seat_status_;
|
|
||||||
struct wl_seat* seat_;
|
struct wl_seat* seat_;
|
||||||
// used to make sure the focused view tags are on the correct output
|
|
||||||
const wl_output* output_;
|
|
||||||
const wl_output* focused_output_;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const waybar::Bar& bar_;
|
const waybar::Bar& bar_;
|
||||||
|
struct wl_output* focused_output_; // stores the focused output
|
||||||
|
struct wl_output* output_; // stores the output this module belongs to
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
std::vector<Gtk::Button> buttons_;
|
std::vector<Gtk::Button> buttons_;
|
||||||
struct zriver_output_status_v1* output_status_;
|
struct zriver_output_status_v1* output_status_;
|
||||||
|
struct zriver_seat_status_v1* seat_status_;
|
||||||
|
bool hide_vacant_ = false; // parsed once; asBool() in a wl callback would throw (#4078)
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace waybar::modules::river */
|
} /* namespace waybar::modules::river */
|
||||||
|
|||||||
@@ -14,16 +14,22 @@ namespace waybar::modules::SNI {
|
|||||||
|
|
||||||
class Host {
|
class Host {
|
||||||
public:
|
public:
|
||||||
Host(const std::size_t id, const Json::Value&, const Bar&,
|
Host(std::size_t id, const Json::Value&, const Bar&, const std::vector<std::string>&,
|
||||||
const std::function<void(std::unique_ptr<Item>&)>&,
|
const std::function<void(std::unique_ptr<Item>&)>&,
|
||||||
const std::function<void(std::unique_ptr<Item>&)>&, const std::function<void()>&);
|
const std::function<void(std::unique_ptr<Item>&)>&, const std::function<void()>&,
|
||||||
|
const std::function<void()>&);
|
||||||
~Host();
|
~Host();
|
||||||
|
|
||||||
|
void checkIgnoreList(const std::vector<std::string>& ignore_list,
|
||||||
|
const std::function<void(std::unique_ptr<Item>&)>& on_remove);
|
||||||
|
|
||||||
|
void reorderItems();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
|
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&);
|
||||||
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring,
|
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&,
|
||||||
const Glib::ustring&);
|
const Glib::ustring&);
|
||||||
void nameVanished(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
|
void nameVanished(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&);
|
||||||
static void proxyReady(GObject*, GAsyncResult*, gpointer);
|
static void proxyReady(GObject*, GAsyncResult*, gpointer);
|
||||||
static void registerHost(GObject*, GAsyncResult*, gpointer);
|
static void registerHost(GObject*, GAsyncResult*, gpointer);
|
||||||
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
|
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
|
||||||
@@ -33,7 +39,7 @@ class Host {
|
|||||||
void removeItem(std::vector<std::unique_ptr<Item>>::iterator);
|
void removeItem(std::vector<std::unique_ptr<Item>>::iterator);
|
||||||
void clearItems();
|
void clearItems();
|
||||||
|
|
||||||
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
|
static std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string&);
|
||||||
void addRegisteredItem(const std::string& service);
|
void addRegisteredItem(const std::string& service);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Item>> items_;
|
std::vector<std::unique_ptr<Item>> items_;
|
||||||
@@ -43,10 +49,19 @@ class Host {
|
|||||||
std::size_t watcher_id_;
|
std::size_t watcher_id_;
|
||||||
GCancellable* cancellable_ = nullptr;
|
GCancellable* cancellable_ = nullptr;
|
||||||
SnWatcher* watcher_ = nullptr;
|
SnWatcher* watcher_ = nullptr;
|
||||||
|
sigc::connection retry_connection_;
|
||||||
|
unsigned retry_count_ = 0;
|
||||||
const Json::Value& config_;
|
const Json::Value& config_;
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
|
const std::vector<std::string> ignore_list_;
|
||||||
const std::function<void(std::unique_ptr<Item>&)> on_add_;
|
const std::function<void(std::unique_ptr<Item>&)> on_add_;
|
||||||
const std::function<void(std::unique_ptr<Item>&)> on_remove_;
|
const std::function<void(std::unique_ptr<Item>&)> on_remove_;
|
||||||
|
// Re-applies the configured ordering to the already-added tray widgets. This
|
||||||
|
// must NOT re-run the add path (which would re-parent widgets and reconnect
|
||||||
|
// signals); it only reorders existing children.
|
||||||
|
const std::function<void()> on_reorder_;
|
||||||
|
|
||||||
|
ItemOrderMap orders_;
|
||||||
const std::function<void()> on_update_;
|
const std::function<void()> on_update_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
class IconManager {
|
class IconManager {
|
||||||
public:
|
public:
|
||||||
@@ -19,7 +20,10 @@ class IconManager {
|
|||||||
std::string app_name = key;
|
std::string app_name = key;
|
||||||
const Json::Value& icon_value = icons_config[key];
|
const Json::Value& icon_value = icons_config[key];
|
||||||
|
|
||||||
if (icon_value.isString()) {
|
if (icon_value.isBool() && !icon_value.asBool()) {
|
||||||
|
// false value means hide this app
|
||||||
|
hidden_apps_.insert(app_name);
|
||||||
|
} else if (icon_value.isString()) {
|
||||||
std::string icon_path = icon_value.asString();
|
std::string icon_path = icon_value.asString();
|
||||||
icons_map_[app_name] = icon_path;
|
icons_map_[app_name] = icon_path;
|
||||||
}
|
}
|
||||||
@@ -37,7 +41,12 @@ class IconManager {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isHidden(const std::string& app_name) const {
|
||||||
|
return hidden_apps_.find(app_name) != hidden_apps_.end();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IconManager() = default;
|
IconManager() = default;
|
||||||
std::unordered_map<std::string, std::string> icons_map_;
|
std::unordered_map<std::string, std::string> icons_map_;
|
||||||
|
std::unordered_set<std::string> hidden_apps_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,11 +24,15 @@ struct ToolTip {
|
|||||||
Glib::ustring text;
|
Glib::ustring text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Host;
|
||||||
|
|
||||||
|
using ItemOrderMap = std::unordered_map<std::string, int>;
|
||||||
|
|
||||||
class Item : public sigc::trackable {
|
class Item : public sigc::trackable {
|
||||||
public:
|
public:
|
||||||
Item(const std::string&, const std::string&, const Json::Value&, const Bar&,
|
Item(const std::string&, const std::string&, const Json::Value&, const Bar&,
|
||||||
const std::function<void(Item&)>&, const std::function<void(Item&)>&,
|
const std::function<void(Item&)>&, const std::function<void(Item&)>&,
|
||||||
const std::function<void()>&);
|
const std::function<void()>&, Host&, const ItemOrderMap&);
|
||||||
~Item();
|
~Item();
|
||||||
|
|
||||||
bool isReady() const;
|
bool isReady() const;
|
||||||
@@ -46,6 +50,7 @@ class Item : public sigc::trackable {
|
|||||||
std::string title;
|
std::string title;
|
||||||
std::string icon_name;
|
std::string icon_name;
|
||||||
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
|
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
|
||||||
|
bool has_custom_icon_ = false;
|
||||||
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
||||||
std::string overlay_icon_name;
|
std::string overlay_icon_name;
|
||||||
Glib::RefPtr<Gdk::Pixbuf> overlay_icon_pixmap;
|
Glib::RefPtr<Gdk::Pixbuf> overlay_icon_pixmap;
|
||||||
@@ -63,6 +68,7 @@ class Item : public sigc::trackable {
|
|||||||
* while compliant SNI implementation would always reset the flag to desired value.
|
* while compliant SNI implementation would always reset the flag to desired value.
|
||||||
*/
|
*/
|
||||||
bool item_is_menu = true;
|
bool item_is_menu = true;
|
||||||
|
int order_ = -1; // -1 means not set
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onConfigure(GdkEventConfigure* ev);
|
void onConfigure(GdkEventConfigure* ev);
|
||||||
@@ -100,6 +106,8 @@ class Item : public sigc::trackable {
|
|||||||
gdouble distance_scrolled_y_ = 0;
|
gdouble distance_scrolled_y_ = 0;
|
||||||
// visibility of items with Status == Passive
|
// visibility of items with Status == Passive
|
||||||
bool show_passive_ = false;
|
bool show_passive_ = false;
|
||||||
|
// hidden via config
|
||||||
|
bool is_hidden_ = false;
|
||||||
bool ready_ = false;
|
bool ready_ = false;
|
||||||
Glib::ustring status_ = "active";
|
Glib::ustring status_ = "active";
|
||||||
|
|
||||||
@@ -111,6 +119,9 @@ class Item : public sigc::trackable {
|
|||||||
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
|
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
|
||||||
Glib::RefPtr<Gio::Cancellable> cancellable_;
|
Glib::RefPtr<Gio::Cancellable> cancellable_;
|
||||||
std::set<std::string_view> update_pending_;
|
std::set<std::string_view> update_pending_;
|
||||||
|
|
||||||
|
Host& host_;
|
||||||
|
const ItemOrderMap& orders_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::SNI
|
} // namespace waybar::modules::SNI
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include <sigc++/connection.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
@@ -13,19 +17,28 @@ namespace waybar::modules::SNI {
|
|||||||
class Tray : public AModule {
|
class Tray : public AModule {
|
||||||
public:
|
public:
|
||||||
Tray(const std::string&, const Bar&, const Json::Value&);
|
Tray(const std::string&, const Bar&, const Json::Value&);
|
||||||
virtual ~Tray() = default;
|
~Tray() override = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onAdd(std::unique_ptr<Item>& item);
|
void onAdd(std::unique_ptr<Item>& item);
|
||||||
void onRemove(std::unique_ptr<Item>& item);
|
void onRemove(std::unique_ptr<Item>& item);
|
||||||
|
// Reorders the already-added tray widgets by their configured order. Does not
|
||||||
|
// add or remove any widget.
|
||||||
|
void reorderBox();
|
||||||
|
void checkIgnoreList(std::unique_ptr<Item>* item);
|
||||||
|
std::vector<std::string> parseIgnoreList(const Json::Value& config);
|
||||||
void queueUpdate();
|
void queueUpdate();
|
||||||
|
|
||||||
static inline std::size_t nb_hosts_ = 0;
|
static inline std::size_t nb_hosts_ = 0;
|
||||||
bool show_passive_ = false;
|
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
SNI::Watcher::singleton watcher_;
|
SNI::Watcher::singleton watcher_;
|
||||||
|
std::vector<std::string> ignore_list_;
|
||||||
SNI::Host host_;
|
SNI::Host host_;
|
||||||
|
std::vector<Item*> items_;
|
||||||
|
// signal_show/signal_hide connections owned per added item, so they can be
|
||||||
|
// disconnected on removal instead of leaking and accumulating.
|
||||||
|
std::unordered_map<Item*, std::pair<sigc::connection, sigc::connection>> item_connections_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::SNI
|
} // namespace waybar::modules::SNI
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sigc++/sigc++.h>
|
#include <sigc++/sigc++.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
#include "util/SafeSignal.hpp"
|
#include "util/SafeSignal.hpp"
|
||||||
@@ -41,11 +39,20 @@ class Ipc {
|
|||||||
static inline const std::string ipc_magic_ = "i3-ipc";
|
static inline const std::string ipc_magic_ = "i3-ipc";
|
||||||
static inline const size_t ipc_header_size_ = ipc_magic_.size() + 8;
|
static inline const size_t ipc_header_size_ = ipc_magic_.size() + 8;
|
||||||
|
|
||||||
const std::string getSocketPath() const;
|
static std::string getSocketPath();
|
||||||
int open(const std::string&) const;
|
static int open(const std::string&);
|
||||||
|
|
||||||
struct ipc_response send(int fd, uint32_t type, const std::string& payload = "");
|
struct ipc_response send(int fd, uint32_t type, const std::string& payload = "");
|
||||||
struct ipc_response recv(int fd);
|
struct ipc_response recv(int fd);
|
||||||
|
|
||||||
|
// Re-establish the event socket and re-subscribe after sway drops us, backing
|
||||||
|
// off between attempts so we don't busy-loop while sway is unavailable.
|
||||||
|
void reconnectEvent();
|
||||||
|
|
||||||
|
std::string socketPath_;
|
||||||
|
std::vector<std::string> subscribed_events_;
|
||||||
|
std::atomic<bool> running_{true};
|
||||||
|
|
||||||
util::ScopedFd fd_;
|
util::ScopedFd fd_;
|
||||||
util::ScopedFd fd_event_;
|
util::ScopedFd fd_event_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ class Language : public ALabel, public sigc::trackable {
|
|||||||
const static std::string XKB_ACTIVE_LAYOUT_NAME_KEY;
|
const static std::string XKB_ACTIVE_LAYOUT_NAME_KEY;
|
||||||
|
|
||||||
Layout layout_;
|
Layout layout_;
|
||||||
|
// CSS class currently applied to label_. Tracked so update() (main thread) can swap classes
|
||||||
|
// instead of set_current_layout() mutating the widget from the IPC worker thread (#3702).
|
||||||
|
std::string applied_class_;
|
||||||
std::string tooltip_format_ = "";
|
std::string tooltip_format_ = "";
|
||||||
std::map<std::string, Layout> layouts_map_;
|
std::map<std::string, Layout> layouts_map_;
|
||||||
bool hide_single_;
|
bool hide_single_;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <gtkmm/button.h>
|
#include <gtkmm/button.h>
|
||||||
#include <gtkmm/label.h>
|
#include <gtkmm/label.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -24,12 +25,15 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::string_view workspace_switch_cmd_ = "workspace {} \"{}\"";
|
static constexpr std::string_view workspace_switch_cmd_ = "workspace {} \"{}\"";
|
||||||
|
static constexpr std::string_view workspace_switch_number_cmd_ = "workspace {} number {}";
|
||||||
static constexpr std::string_view persistent_workspace_switch_cmd_ =
|
static constexpr std::string_view persistent_workspace_switch_cmd_ =
|
||||||
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
|
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
|
||||||
|
|
||||||
static int convertWorkspaceNameToNum(const std::string& name);
|
static int convertWorkspaceNameToNum(const std::string& name);
|
||||||
static int windowRewritePriorityFunction(std::string const& window_rule);
|
static int windowRewritePriorityFunction(std::string const& window_rule);
|
||||||
|
|
||||||
|
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
|
||||||
|
bool isWorkspaceIgnored(std::string const& name);
|
||||||
void onCmd(const struct Ipc::ipc_response&);
|
void onCmd(const struct Ipc::ipc_response&);
|
||||||
void onEvent(const struct Ipc::ipc_response&);
|
void onEvent(const struct Ipc::ipc_response&);
|
||||||
bool filterButtons();
|
bool filterButtons();
|
||||||
@@ -41,6 +45,7 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
|
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
|
||||||
uint16_t getWorkspaceIndex(const std::string& name) const;
|
uint16_t getWorkspaceIndex(const std::string& name) const;
|
||||||
static std::string trimWorkspaceName(const std::string&);
|
static std::string trimWorkspaceName(const std::string&);
|
||||||
|
std::optional<uint16_t> getCustomSortIndex(const std::string& name) const;
|
||||||
bool handleScroll(GdkEventScroll* /*unused*/) override;
|
bool handleScroll(GdkEventScroll* /*unused*/) override;
|
||||||
|
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
@@ -49,9 +54,11 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
std::vector<std::string> workspaces_order_;
|
std::vector<std::string> workspaces_order_;
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
std::string m_formatWindowSeparator;
|
std::string m_formatWindowSeparator;
|
||||||
|
std::vector<std::regex> m_ignoreWorkspaces;
|
||||||
util::RegexCollection m_windowRewriteRules;
|
util::RegexCollection m_windowRewriteRules;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::unordered_map<std::string, Gtk::Button> buttons_;
|
std::unordered_map<std::string, Gtk::Button> buttons_;
|
||||||
|
std::unordered_map<std::string, uint16_t> custom_sort_priorities_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
Ipc ipc_;
|
Ipc ipc_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ class Temperature : public ALabel {
|
|||||||
Temperature(const std::string&, const Json::Value&);
|
Temperature(const std::string&, const Json::Value&);
|
||||||
virtual ~Temperature() = default;
|
virtual ~Temperature() = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
void suspend() override;
|
||||||
|
void resume() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float getTemperature();
|
float getTemperature();
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ class Wireplumber : public ALabel {
|
|||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool setupConnection();
|
||||||
|
void teardownConnection();
|
||||||
|
void scheduleReconnect();
|
||||||
|
bool onReconnectTimeout();
|
||||||
|
static void onCoreDisconnected(waybar::modules::Wireplumber* self);
|
||||||
void asyncLoadRequiredApiModules();
|
void asyncLoadRequiredApiModules();
|
||||||
void prepare(waybar::modules::Wireplumber* self);
|
void prepare(waybar::modules::Wireplumber* self);
|
||||||
void activatePlugins();
|
void activatePlugins();
|
||||||
@@ -24,17 +29,25 @@ class Wireplumber : public ALabel {
|
|||||||
static void updateNodeName(waybar::modules::Wireplumber* self, uint32_t id);
|
static void updateNodeName(waybar::modules::Wireplumber* self, uint32_t id);
|
||||||
static void updateSourceVolume(waybar::modules::Wireplumber* self, uint32_t id);
|
static void updateSourceVolume(waybar::modules::Wireplumber* self, uint32_t id);
|
||||||
static void updateSourceName(waybar::modules::Wireplumber* self, uint32_t id); // NEW
|
static void updateSourceName(waybar::modules::Wireplumber* self, uint32_t id); // NEW
|
||||||
static void onPluginActivated(WpObject* p, GAsyncResult* res, waybar::modules::Wireplumber* self);
|
static void onPluginActivated(WpObject* p, GAsyncResult* res, gpointer data);
|
||||||
static void onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res,
|
static void onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res, gpointer data);
|
||||||
waybar::modules::Wireplumber* self);
|
static void onMixerApiLoaded(WpObject* p, GAsyncResult* res, gpointer data);
|
||||||
static void onMixerApiLoaded(WpObject* p, GAsyncResult* res, waybar::modules::Wireplumber* self);
|
|
||||||
static void onObjectManagerInstalled(waybar::modules::Wireplumber* self);
|
static void onObjectManagerInstalled(waybar::modules::Wireplumber* self);
|
||||||
static void onMixerChanged(waybar::modules::Wireplumber* self, uint32_t id);
|
static void onMixerChanged(waybar::modules::Wireplumber* self, uint32_t id);
|
||||||
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
|
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
|
||||||
|
|
||||||
bool handleScroll(GdkEventScroll* e) override;
|
bool handleScroll(GdkEventScroll* e) override;
|
||||||
|
std::vector<std::string> getWPIcon();
|
||||||
|
|
||||||
static std::list<waybar::modules::Wireplumber*> modules;
|
static std::list<waybar::modules::Wireplumber*> modules;
|
||||||
|
// Returns true while `self` is still a live module. Async load/activation callbacks use this to
|
||||||
|
// avoid dereferencing a `self` that was destroyed before the callback fired (see #3974).
|
||||||
|
static bool isModuleAlive(waybar::modules::Wireplumber* self);
|
||||||
|
|
||||||
|
uint32_t resolvePhysicalSink(uint32_t start_id);
|
||||||
|
uint32_t findPlaybackNodeId(const gchar* description);
|
||||||
|
uint32_t get_linked_sink_id(WpObjectManager* om, uint32_t from_node_id);
|
||||||
|
uint32_t get_linked_node_from_output_ports(WpObjectManager* om, uint32_t from_node_id);
|
||||||
|
|
||||||
WpCore* wp_core_;
|
WpCore* wp_core_;
|
||||||
GPtrArray* apis_;
|
GPtrArray* apis_;
|
||||||
@@ -43,6 +56,10 @@ class Wireplumber : public ALabel {
|
|||||||
WpPlugin* def_nodes_api_;
|
WpPlugin* def_nodes_api_;
|
||||||
gchar* default_node_name_;
|
gchar* default_node_name_;
|
||||||
uint32_t pending_plugins_;
|
uint32_t pending_plugins_;
|
||||||
|
// Bumped on every (re)connection. The async load/activate callbacks capture the generation they
|
||||||
|
// were scheduled under (via their user_data) and no-op if it no longer matches, so a completion
|
||||||
|
// from a connection that was already torn down cannot corrupt the new generation's state (#2882).
|
||||||
|
uint32_t connection_generation_{0};
|
||||||
bool muted_;
|
bool muted_;
|
||||||
double volume_;
|
double volume_;
|
||||||
double min_step_;
|
double min_step_;
|
||||||
@@ -54,6 +71,12 @@ class Wireplumber : public ALabel {
|
|||||||
bool source_muted_;
|
bool source_muted_;
|
||||||
double source_volume_;
|
double source_volume_;
|
||||||
gchar* default_source_name_;
|
gchar* default_source_name_;
|
||||||
|
bool only_physical_;
|
||||||
|
bool resolved_physical_;
|
||||||
|
std::string form_factor_;
|
||||||
|
// Timer used to retry connecting to PipeWire after it goes away; disconnected in the destructor
|
||||||
|
// so a pending attempt can't outlive the module. See #2882.
|
||||||
|
sigc::connection reconnect_timer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <ranges>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
|
#include "ext-workspace-v1-client-protocol.h"
|
||||||
#include "giomm/desktopappinfo.h"
|
#include "giomm/desktopappinfo.h"
|
||||||
#include "util/icon_loader.hpp"
|
#include "util/icon_loader.hpp"
|
||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
@@ -68,6 +70,11 @@ class Task {
|
|||||||
Glib::RefPtr<Gio::DesktopAppInfo> app_info_;
|
Glib::RefPtr<Gio::DesktopAppInfo> app_info_;
|
||||||
bool button_visible_ = false;
|
bool button_visible_ = false;
|
||||||
bool ignored_ = false;
|
bool ignored_ = false;
|
||||||
|
bool squashed_ = false;
|
||||||
|
/* Whether the toplevel is on this bar's output, per the protocol's
|
||||||
|
* output_enter/output_leave events */
|
||||||
|
bool on_bar_output_ = false;
|
||||||
|
bool size_allocate_connected_ = false;
|
||||||
|
|
||||||
bool with_icon_ = false;
|
bool with_icon_ = false;
|
||||||
bool with_name_ = false;
|
bool with_name_ = false;
|
||||||
@@ -80,6 +87,7 @@ class Task {
|
|||||||
std::string title_;
|
std::string title_;
|
||||||
std::string app_id_;
|
std::string app_id_;
|
||||||
uint32_t state_ = 0;
|
uint32_t state_ = 0;
|
||||||
|
struct ext_workspace_handle_v1* workspace_ = nullptr;
|
||||||
|
|
||||||
int32_t drag_start_x;
|
int32_t drag_start_x;
|
||||||
int32_t drag_start_y;
|
int32_t drag_start_y;
|
||||||
@@ -91,6 +99,9 @@ class Task {
|
|||||||
void set_minimize_hint();
|
void set_minimize_hint();
|
||||||
void on_button_size_allocated(Gtk::Allocation& alloc);
|
void on_button_size_allocated(Gtk::Allocation& alloc);
|
||||||
void hide_if_ignored();
|
void hide_if_ignored();
|
||||||
|
void hide_if_duplicate();
|
||||||
|
void show_button();
|
||||||
|
void hide_button();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Getter functions */
|
/* Getter functions */
|
||||||
@@ -102,6 +113,9 @@ class Task {
|
|||||||
bool minimized() const { return state_ & MINIMIZED; }
|
bool minimized() const { return state_ & MINIMIZED; }
|
||||||
bool active() const { return state_ & ACTIVE; }
|
bool active() const { return state_ & ACTIVE; }
|
||||||
bool fullscreen() const { return state_ & FULLSCREEN; }
|
bool fullscreen() const { return state_ & FULLSCREEN; }
|
||||||
|
bool visible() const { return button_visible_; }
|
||||||
|
struct ext_workspace_handle_v1* workspace() const { return workspace_; }
|
||||||
|
void set_workspace(struct ext_workspace_handle_v1* workspace) { workspace_ = workspace; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Callbacks for the wlr protocol */
|
/* Callbacks for the wlr protocol */
|
||||||
@@ -142,6 +156,12 @@ using TaskPtr = std::unique_ptr<Task>;
|
|||||||
|
|
||||||
class Taskbar : public waybar::AModule {
|
class Taskbar : public waybar::AModule {
|
||||||
public:
|
public:
|
||||||
|
struct WorkspaceState {
|
||||||
|
Taskbar* taskbar;
|
||||||
|
struct ext_workspace_handle_v1* handle;
|
||||||
|
uint32_t state = 0;
|
||||||
|
};
|
||||||
|
|
||||||
Taskbar(const std::string&, const waybar::Bar&, const Json::Value&);
|
Taskbar(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||||
~Taskbar();
|
~Taskbar();
|
||||||
void update();
|
void update();
|
||||||
@@ -153,32 +173,56 @@ class Taskbar : public waybar::AModule {
|
|||||||
|
|
||||||
IconLoader icon_loader_;
|
IconLoader icon_loader_;
|
||||||
std::unordered_set<std::string> ignore_list_;
|
std::unordered_set<std::string> ignore_list_;
|
||||||
|
std::unordered_set<std::string> squash_list_;
|
||||||
std::map<std::string, std::string> app_ids_replace_map_;
|
std::map<std::string, std::string> app_ids_replace_map_;
|
||||||
|
|
||||||
struct zwlr_foreign_toplevel_manager_v1* manager_;
|
struct zwlr_foreign_toplevel_manager_v1* manager_;
|
||||||
|
struct ext_workspace_manager_v1* workspace_manager_;
|
||||||
struct wl_seat* seat_;
|
struct wl_seat* seat_;
|
||||||
|
std::vector<struct ext_workspace_group_handle_v1*> workspace_groups_;
|
||||||
|
std::vector<std::unique_ptr<WorkspaceState>> workspaces_;
|
||||||
|
struct ext_workspace_handle_v1* current_workspace_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Callbacks for global registration */
|
/* Callbacks for global registration */
|
||||||
void register_manager(struct wl_registry*, uint32_t name, uint32_t version);
|
void register_manager(struct wl_registry*, uint32_t name, uint32_t version);
|
||||||
|
void register_workspace_manager(struct wl_registry*, uint32_t name, uint32_t version);
|
||||||
void register_seat(struct wl_registry*, uint32_t name, uint32_t version);
|
void register_seat(struct wl_registry*, uint32_t name, uint32_t version);
|
||||||
|
|
||||||
/* Callbacks for the wlr protocol */
|
/* Callbacks for the wlr protocol */
|
||||||
void handle_toplevel_create(struct zwlr_foreign_toplevel_handle_v1*);
|
void handle_toplevel_create(struct zwlr_foreign_toplevel_handle_v1*);
|
||||||
void handle_finished();
|
void handle_finished();
|
||||||
|
void handle_workspace_group_create(struct ext_workspace_group_handle_v1*);
|
||||||
|
void handle_workspace_group_removed(struct ext_workspace_group_handle_v1*);
|
||||||
|
void handle_workspace_create(struct ext_workspace_handle_v1*);
|
||||||
|
void handle_workspace_done();
|
||||||
|
void handle_workspace_finished();
|
||||||
|
void handle_workspace_removed(struct ext_workspace_handle_v1*);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void add_button(Gtk::Button&);
|
void add_button(Gtk::Button&);
|
||||||
void move_button(Gtk::Button&, int);
|
void move_button(Gtk::Button&, int);
|
||||||
void remove_button(Gtk::Button&);
|
void remove_button(Gtk::Button&);
|
||||||
void remove_task(uint32_t);
|
void remove_task(uint32_t);
|
||||||
|
void assign_current_workspace(Task&);
|
||||||
|
void update_bar_css_classes();
|
||||||
|
|
||||||
bool show_output(struct wl_output*) const;
|
bool show_output(struct wl_output*) const;
|
||||||
bool all_outputs() const;
|
bool all_outputs() const;
|
||||||
|
|
||||||
const IconLoader& icon_loader() const;
|
const IconLoader& icon_loader() const;
|
||||||
const std::unordered_set<std::string>& ignore_list() const;
|
const std::unordered_set<std::string>& ignore_list() const;
|
||||||
|
const std::unordered_set<std::string>& squash_list() const;
|
||||||
const std::map<std::string, std::string>& app_ids_replace_map() const;
|
const std::map<std::string, std::string>& app_ids_replace_map() const;
|
||||||
|
std::size_t task_id_count(std::string_view id) const;
|
||||||
|
std::size_t task_title_count(std::string_view title) const;
|
||||||
|
|
||||||
|
auto tasks() {
|
||||||
|
return tasks_ | std::views::transform([](auto& task) -> Task& { return *task; });
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_bar_css_class(const std::string&, bool);
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace waybar::modules::wlr */
|
} /* namespace waybar::modules::wlr */
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <libmm-glib/libmm-glib.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
#include "util/format.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules {
|
||||||
|
|
||||||
|
class Wwan : public ALabel {
|
||||||
|
public:
|
||||||
|
Wwan(const std::string&, const Json::Value&);
|
||||||
|
virtual ~Wwan();
|
||||||
|
auto update() -> void override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateCurrentModem();
|
||||||
|
|
||||||
|
util::SleeperThread thread_;
|
||||||
|
std::string state_;
|
||||||
|
GDBusConnection* connection = nullptr;
|
||||||
|
MMManager* manager = nullptr;
|
||||||
|
MMModem* current_modem = nullptr;
|
||||||
|
|
||||||
|
bool hideDisconnected = true;
|
||||||
|
|
||||||
|
const std::string dbus_name = "org.freedesktop.ModemManager1";
|
||||||
|
const std::string dbus_obj_path = "/org/freedesktop/ModemManager1/";
|
||||||
|
const std::string dbus_modems_path = "/org/freedesktop/ModemManager1/Modems/";
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules
|
||||||
@@ -12,11 +12,6 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
|
||||||
#define SIGRTMIN SIGUSR1 - 1
|
|
||||||
#define SIGRTMAX SIGUSR1 + 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,6 +14,11 @@
|
|||||||
|
|
||||||
namespace waybar::util {
|
namespace waybar::util {
|
||||||
|
|
||||||
|
enum class PulseaudioTarget {
|
||||||
|
Sink,
|
||||||
|
Source,
|
||||||
|
};
|
||||||
|
|
||||||
class AudioBackend {
|
class AudioBackend {
|
||||||
private:
|
private:
|
||||||
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
|
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
|
||||||
@@ -22,12 +27,21 @@ class AudioBackend {
|
|||||||
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
|
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
|
||||||
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
|
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
|
||||||
static void volumeModifyCb(pa_context*, int, void*);
|
static void volumeModifyCb(pa_context*, int, void*);
|
||||||
|
static void sourceVolumeModifyCb(pa_context*, int, void*);
|
||||||
void connectContext();
|
void connectContext();
|
||||||
|
// Non-throwing reconnect used from the PulseAudio callback thread. Throwing
|
||||||
|
// across the libpulse C callback boundary calls std::terminate, so this
|
||||||
|
// swallows any failure and reports it via the return value instead.
|
||||||
|
bool reconnectContext() noexcept;
|
||||||
|
|
||||||
pa_threaded_mainloop* mainloop_;
|
pa_threaded_mainloop* mainloop_;
|
||||||
pa_mainloop_api* mainloop_api_;
|
pa_mainloop_api* mainloop_api_;
|
||||||
pa_context* context_;
|
pa_context* context_;
|
||||||
|
// Guards against the FAILED -> connect -> FAILED recursion / busy loop when a
|
||||||
|
// reconnect attempt fails synchronously inside pa_context_connect().
|
||||||
|
bool reconnecting_{false};
|
||||||
pa_cvolume pa_volume_;
|
pa_cvolume pa_volume_;
|
||||||
|
pa_cvolume pa_source_volume_;
|
||||||
|
|
||||||
// SINK
|
// SINK
|
||||||
uint32_t sink_idx_{0};
|
uint32_t sink_idx_{0};
|
||||||
@@ -50,6 +64,7 @@ class AudioBackend {
|
|||||||
std::string default_source_name_;
|
std::string default_source_name_;
|
||||||
|
|
||||||
std::vector<std::string> ignored_sinks_;
|
std::vector<std::string> ignored_sinks_;
|
||||||
|
std::map<std::string, std::string> sink_mapping_;
|
||||||
|
|
||||||
std::function<void()> on_updated_cb_ = NOOP;
|
std::function<void()> on_updated_cb_ = NOOP;
|
||||||
|
|
||||||
@@ -67,10 +82,13 @@ class AudioBackend {
|
|||||||
AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag);
|
AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag);
|
||||||
~AudioBackend();
|
~AudioBackend();
|
||||||
|
|
||||||
void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100);
|
void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100,
|
||||||
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100);
|
PulseaudioTarget target = PulseaudioTarget::Sink);
|
||||||
|
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100,
|
||||||
|
PulseaudioTarget target = PulseaudioTarget::Sink);
|
||||||
|
|
||||||
void setIgnoredSinks(const Json::Value& config);
|
void setIgnoredSinks(const Json::Value& config);
|
||||||
|
void setSinkMapping(const Json::Value& config);
|
||||||
|
|
||||||
std::string getSinkPortName() const { return port_name_; }
|
std::string getSinkPortName() const { return port_name_; }
|
||||||
std::string getFormFactor() const { return form_factor_; }
|
std::string getFormFactor() const { return form_factor_; }
|
||||||
@@ -92,6 +110,10 @@ class AudioBackend {
|
|||||||
void toggleSourceMute();
|
void toggleSourceMute();
|
||||||
void toggleSourceMute(bool);
|
void toggleSourceMute(bool);
|
||||||
|
|
||||||
|
uint16_t getVolume(PulseaudioTarget) const;
|
||||||
|
bool getMuted(PulseaudioTarget) const;
|
||||||
|
void unmute(PulseaudioTarget);
|
||||||
|
|
||||||
bool isBluetooth();
|
bool isBluetooth();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ namespace waybar::util {
|
|||||||
class BacklightDevice {
|
class BacklightDevice {
|
||||||
public:
|
public:
|
||||||
BacklightDevice() = default;
|
BacklightDevice() = default;
|
||||||
BacklightDevice(std::string name, int actual, int max, bool powered);
|
BacklightDevice(std::string name, int actual, int max, bool powered,
|
||||||
|
std::string subsystem = "backlight");
|
||||||
|
|
||||||
std::string name() const;
|
std::string name() const;
|
||||||
|
std::string subsystem() const;
|
||||||
int get_actual() const;
|
int get_actual() const;
|
||||||
void set_actual(int actual);
|
void set_actual(int actual);
|
||||||
int get_max() const;
|
int get_max() const;
|
||||||
@@ -45,6 +47,7 @@ class BacklightDevice {
|
|||||||
int actual_ = 1;
|
int actual_ = 1;
|
||||||
int max_ = 1;
|
int max_ = 1;
|
||||||
bool powered_ = true;
|
bool powered_ = true;
|
||||||
|
std::string subsystem_ = "backlight";
|
||||||
};
|
};
|
||||||
|
|
||||||
class BacklightBackend {
|
class BacklightBackend {
|
||||||
@@ -70,7 +73,8 @@ class BacklightBackend {
|
|||||||
std::mutex udev_thread_mutex_;
|
std::mutex udev_thread_mutex_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set_brightness_internal(const std::string& device_name, int brightness, int max_brightness);
|
void set_brightness_internal(const std::string& device_name, int brightness, int max_brightness,
|
||||||
|
const std::string& subsystem = "backlight");
|
||||||
|
|
||||||
std::function<void()> on_updated_cb_;
|
std::function<void()> on_updated_cb_;
|
||||||
std::chrono::milliseconds polling_interval_;
|
std::chrono::milliseconds polling_interval_;
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glibmm/main.h>
|
||||||
|
#include <glibmm/spawn.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace waybar::util::command {
|
||||||
|
|
||||||
|
class LineStream {
|
||||||
|
public:
|
||||||
|
using OutputCallback = std::function<void(const std::string&)>;
|
||||||
|
using ExitCallback = std::function<void(int)>;
|
||||||
|
|
||||||
|
LineStream(std::string output_name, OutputCallback on_output, ExitCallback on_exit);
|
||||||
|
~LineStream();
|
||||||
|
|
||||||
|
void start(const std::string& cmd);
|
||||||
|
void stop();
|
||||||
|
bool running() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool handleStdout(Glib::IOCondition condition);
|
||||||
|
void handleExit(Glib::Pid pid, int status);
|
||||||
|
void closeStdout();
|
||||||
|
void drainStdout(bool flush_trailing_line);
|
||||||
|
static int statusToExitCode(int status);
|
||||||
|
|
||||||
|
std::string output_name_;
|
||||||
|
OutputCallback on_output_;
|
||||||
|
ExitCallback on_exit_;
|
||||||
|
std::string buffer_;
|
||||||
|
Glib::Pid pid_;
|
||||||
|
int stdout_fd_;
|
||||||
|
sigc::connection stdout_connection_;
|
||||||
|
sigc::connection child_connection_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::util::command
|
||||||
@@ -14,12 +14,14 @@ struct pollfd;
|
|||||||
namespace waybar {
|
namespace waybar {
|
||||||
class CssReloadHelper {
|
class CssReloadHelper {
|
||||||
public:
|
public:
|
||||||
CssReloadHelper(std::string cssFile, std::function<void()> callback);
|
CssReloadHelper(std::string cssFile, std::function<void(const std::string&)> callback);
|
||||||
|
|
||||||
virtual ~CssReloadHelper() = default;
|
virtual ~CssReloadHelper() = default;
|
||||||
|
|
||||||
virtual void monitorChanges();
|
virtual void monitorChanges();
|
||||||
|
|
||||||
|
virtual void changeCssFile(const std::string& newCssFile);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::string> parseImports(const std::string& cssFile);
|
std::vector<std::string> parseImports(const std::string& cssFile);
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ class CssReloadHelper {
|
|||||||
private:
|
private:
|
||||||
std::string m_cssFile;
|
std::string m_cssFile;
|
||||||
|
|
||||||
std::function<void()> m_callback;
|
std::function<void(const std::string&)> m_callback;
|
||||||
|
|
||||||
std::vector<std::tuple<Glib::RefPtr<Gio::FileMonitor>>> m_fileMonitors;
|
std::vector<std::tuple<Glib::RefPtr<Gio::FileMonitor>>> m_fileMonitors;
|
||||||
};
|
};
|
||||||
|
|||||||
+21
-7
@@ -1,19 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "util/string.hpp"
|
||||||
|
|
||||||
namespace waybar::util {
|
namespace waybar::util {
|
||||||
|
|
||||||
template <typename EnumType>
|
template <typename EnumType>
|
||||||
struct EnumParser {
|
//struct EnumParser {
|
||||||
public:
|
|
||||||
EnumParser();
|
|
||||||
~EnumParser();
|
|
||||||
|
|
||||||
EnumType parseStringToEnum(const std::string& str,
|
EnumType parseStringToEnum(const std::string& str,
|
||||||
const std::map<std::string, EnumType>& enumMap);
|
const std::map<std::string, EnumType>& enumMap) {
|
||||||
};
|
std::string uppercaseStr = capitalize(str);
|
||||||
|
std::map<std::string, EnumType> capitalizedEnumMap;
|
||||||
|
std::transform(
|
||||||
|
enumMap.begin(), enumMap.end(),
|
||||||
|
std::inserter(capitalizedEnumMap, capitalizedEnumMap.end()),
|
||||||
|
[](const auto& pair) {
|
||||||
|
return std::make_pair(capitalize(pair.first), pair.second);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto it = capitalizedEnumMap.find(uppercaseStr);
|
||||||
|
if (it != capitalizedEnumMap.end()) return it->second;
|
||||||
|
|
||||||
|
throw std::invalid_argument("Invalid string representation for enum");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace waybar::util
|
} // namespace waybar::util
|
||||||
|
|||||||
+122
-38
@@ -5,41 +5,69 @@
|
|||||||
|
|
||||||
class pow_format {
|
class pow_format {
|
||||||
public:
|
public:
|
||||||
pow_format(long long val, std::string&& unit, bool binary = false)
|
pow_format(long long val, std::string&& unit, bool binary = false, bool skip_decimal = false,
|
||||||
: val_(val), unit_(unit), binary_(binary) {};
|
int min_pow_for_decimal = 0)
|
||||||
|
: val_(val),
|
||||||
|
unit_(unit),
|
||||||
|
binary_(binary),
|
||||||
|
skip_decimal_(skip_decimal),
|
||||||
|
min_pow_for_decimal_(min_pow_for_decimal) {};
|
||||||
|
|
||||||
long long val_;
|
long long val_;
|
||||||
std::string unit_;
|
std::string unit_;
|
||||||
bool binary_;
|
bool binary_;
|
||||||
|
bool skip_decimal_;
|
||||||
|
int min_pow_for_decimal_;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace fmt {
|
namespace fmt {
|
||||||
template <>
|
template <>
|
||||||
struct formatter<pow_format> {
|
struct formatter<pow_format> {
|
||||||
char spec = 0;
|
char spec = 0; // alignment: '>', '<', '=' (0 = none)
|
||||||
int width = 0;
|
int width = 0; // width digits; enforced only when scale_spec != 0
|
||||||
|
char scale_spec = 0; // forced scale: 0 = auto, else one of '#','k','M','G','T','P'
|
||||||
|
char unit_pref = 0; // unit tri-state: 0 = default, 'u' = hide, 'U' = show
|
||||||
|
char base_pref = 0; // base tri-state: 0 = call-site, 'b' = decimal, 'B' = binary
|
||||||
|
bool force_int = false; // 'i': force integer display
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = ctx.begin(), end = ctx.end();
|
auto it = ctx.begin(), end = ctx.end();
|
||||||
if (it != end && *it == ':') ++it;
|
if (it != end && *it == ':') ++it;
|
||||||
if (it && (*it == '>' || *it == '<' || *it == '=')) {
|
if (it != end && (*it == '>' || *it == '<' || *it == '=')) {
|
||||||
spec = *it;
|
spec = *it;
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
if (it == end || *it == '}') return it;
|
// Consume scale/flag modifiers and the width in any order, until '}' or end.
|
||||||
if ('0' <= *it && *it <= '9') {
|
// The width digits (parsed but only enforced when a scale is forced — see
|
||||||
// We ignore it for now, but keep it for compatibility with
|
// format()) may appear anywhere among the modifiers, so both {:=#3} and the
|
||||||
// existing configs where the format for pow_format'ed numbers was
|
// more natural {:=3#} are accepted. On an unrecognised char we stop and let
|
||||||
// 'string' and specifications such as {:>9} were valid.
|
// fmt raise its usual error.
|
||||||
// The rationale for ignoring it is that the only reason to specify
|
while (it != end && *it != '}') {
|
||||||
// an alignment and a with is to get a fixed width bar, and ">" is
|
char c = *it;
|
||||||
// sufficient in this implementation.
|
if (c == '#' || c == 'k' || c == 'M' || c == 'G' || c == 'T' || c == 'P') {
|
||||||
|
scale_spec = c;
|
||||||
|
++it;
|
||||||
|
} else if (c == 'u' || c == 'U') {
|
||||||
|
unit_pref = c;
|
||||||
|
++it;
|
||||||
|
} else if (c == 'b' || c == 'B') {
|
||||||
|
base_pref = c;
|
||||||
|
++it;
|
||||||
|
} else if (c == 'i') {
|
||||||
|
force_int = true;
|
||||||
|
++it;
|
||||||
|
} else if ('0' <= c && c <= '9') {
|
||||||
|
// Width kept for compatibility with existing configs such as {:>9}; only
|
||||||
|
// enforced (fixed field + '#' overflow) when a scale is forced.
|
||||||
#if FMT_VERSION < 80000
|
#if FMT_VERSION < 80000
|
||||||
width = parse_nonnegative_int(it, end, ctx);
|
width = parse_nonnegative_int(it, end, ctx);
|
||||||
#else
|
#else
|
||||||
width = detail::parse_nonnegative_int(it, end, -1);
|
width = detail::parse_nonnegative_int(it, end, -1);
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
@@ -47,44 +75,100 @@ struct formatter<pow_format> {
|
|||||||
template <class FormatContext>
|
template <class FormatContext>
|
||||||
auto format(const pow_format& s, FormatContext& ctx) const -> decltype(ctx.out()) {
|
auto format(const pow_format& s, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
const char* units[] = {"", "k", "M", "G", "T", "P", nullptr};
|
const char* units[] = {"", "k", "M", "G", "T", "P", nullptr};
|
||||||
|
const int max_pow = 5; // last valid index in units[]
|
||||||
|
|
||||||
auto base = s.binary_ ? 1024ull : 1000ll;
|
// Effective base: 'b'/'B' override the call-site binary_.
|
||||||
|
bool binary = base_pref == 'B' ? true : base_pref == 'b' ? false : s.binary_;
|
||||||
|
auto base = binary ? 1024ull : 1000ll;
|
||||||
|
auto div = 1ll;
|
||||||
auto fraction = (double)s.val_;
|
auto fraction = (double)s.val_;
|
||||||
|
|
||||||
int pow;
|
int pow;
|
||||||
|
if (scale_spec != 0) {
|
||||||
|
// Forced scale: map the char to a fixed index into units[].
|
||||||
|
switch (scale_spec) {
|
||||||
|
case 'k':
|
||||||
|
pow = 1;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
pow = 2;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
pow = 3;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
pow = 4;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
pow = 5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pow = 0;
|
||||||
|
break; // '#' -> base scale
|
||||||
|
}
|
||||||
|
if (pow > max_pow) pow = max_pow;
|
||||||
|
for (int i = 0; i < pow; ++i) div *= base;
|
||||||
|
fraction /= div;
|
||||||
|
} else {
|
||||||
for (pow = 0; units[pow + 1] != nullptr && fraction / base >= 1; ++pow) {
|
for (pow = 0; units[pow + 1] != nullptr && fraction / base >= 1; ++pow) {
|
||||||
fraction /= base;
|
fraction /= base;
|
||||||
|
div *= base;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto number_width = 5 // coeff in {:.1f} format
|
// Precision: 'i' forces 0; otherwise 1 (or 0 when skip_decimal_ divides
|
||||||
+ s.binary_; // potential 4th digit before the decimal point
|
// evenly). min_pow_for_decimal_ keeps its default-branch-only effect.
|
||||||
auto max_width = number_width + 1 // prefix from units array
|
int precision = force_int ? 0 : (s.skip_decimal_ && ((s.val_ % div) == 0)) ? 0 : 1;
|
||||||
+ s.binary_ // for the 'i' in GiB.
|
if (!force_int && scale_spec == 0 && pow < s.min_pow_for_decimal_) precision = 0;
|
||||||
+ s.unit_.length();
|
|
||||||
|
// Unit visibility: default on for auto scale, off for a forced scale; 'u'/'U'
|
||||||
|
// override. The binary 'i' is part of the scale prefix, so the unit is just
|
||||||
|
// unit_.
|
||||||
|
bool hide_unit = unit_pref == 'u' || (unit_pref == 0 && scale_spec != 0);
|
||||||
|
|
||||||
|
// Scale prefix (letter + binary 'i'), suppressed entirely when a scale is
|
||||||
|
// forced.
|
||||||
|
std::string prefix =
|
||||||
|
scale_spec != 0 ? "" : std::string(units[pow]) + ((binary && pow) ? "i" : "");
|
||||||
|
std::string unit = hide_unit ? "" : s.unit_;
|
||||||
|
|
||||||
|
auto number_width = 3 + precision // coeff in {:.{precision}f} format
|
||||||
|
+ (precision != 0) // float dot
|
||||||
|
+ binary; // potential digit before the decimal point
|
||||||
|
// In auto mode the prefix column is always reserved (letter + optional 'i'),
|
||||||
|
// matching the historical fixed max_width even at base scale (the '=' padding
|
||||||
|
// fills the gap). A forced scale drops the prefix column entirely.
|
||||||
|
auto prefix_col = scale_spec != 0 ? 0 : 1 + binary;
|
||||||
|
auto max_width = number_width + prefix_col + unit.length();
|
||||||
|
|
||||||
|
// The numeric coefficient string. When a scale is forced with a width and the
|
||||||
|
// number does not fit, it overflows to '#' (spreadsheet-style).
|
||||||
|
bool fixed_num = scale_spec != 0 && width > 0;
|
||||||
|
std::string number = fmt::format("{:.{}f}", fraction, precision);
|
||||||
|
if (fixed_num && (int)number.length() > width) number = std::string(width, '#');
|
||||||
|
|
||||||
|
// Base-scale compensation for the '=' column-align: only in auto mode, where
|
||||||
|
// the absent prefix (and binary 'i') would otherwise shift the unit column.
|
||||||
|
const char* padding = (scale_spec == 0 && pow == 0) ? (binary ? " " : " ") : "";
|
||||||
|
|
||||||
const char* format;
|
|
||||||
std::string string;
|
|
||||||
switch (spec) {
|
switch (spec) {
|
||||||
case '>':
|
|
||||||
return fmt::format_to(ctx.out(), "{:>{}}", fmt::format("{}", s), max_width);
|
|
||||||
case '<':
|
|
||||||
return fmt::format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width);
|
|
||||||
case '=':
|
case '=':
|
||||||
format = "{coefficient:<{number_width}.1f}{padding}{prefix}{unit}";
|
// Column-align: left-justify the coefficient within its column, then pad
|
||||||
break;
|
// so the prefix/unit line up across values of different magnitude.
|
||||||
|
return fmt::format_to(ctx.out(), "{:<{}}{}{}{}", number, fixed_num ? width : number_width,
|
||||||
|
padding, prefix, unit);
|
||||||
|
case '>':
|
||||||
|
case '<':
|
||||||
case 0:
|
case 0:
|
||||||
default:
|
default: {
|
||||||
format = "{coefficient:.1f}{prefix}{unit}";
|
// Right-justify the numeric field to the fixed width when forced.
|
||||||
break;
|
std::string body =
|
||||||
|
(fixed_num ? fmt::format("{:>{}}", number, width) : number) + prefix + unit;
|
||||||
|
if (spec == '>') return fmt::format_to(ctx.out(), "{:>{}}", body, max_width);
|
||||||
|
if (spec == '<') return fmt::format_to(ctx.out(), "{:<{}}", body, max_width);
|
||||||
|
return fmt::format_to(ctx.out(), "{}", body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return fmt::format_to(
|
|
||||||
ctx.out(), fmt::runtime(format), fmt::arg("coefficient", fraction),
|
|
||||||
fmt::arg("number_width", number_width),
|
|
||||||
fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")),
|
|
||||||
fmt::arg("unit", s.unit_),
|
|
||||||
fmt::arg("padding", pow ? ""
|
|
||||||
: s.binary_ ? " "
|
|
||||||
: " "));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <giomm/dbusconnection.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "giomm/dbusproxy.h"
|
||||||
|
|
||||||
|
namespace waybar::util::GeoClueBackend {
|
||||||
|
|
||||||
|
class GeoClueBackend {
|
||||||
|
private:
|
||||||
|
guint watcherID_;
|
||||||
|
sigc::connection signal_conn;
|
||||||
|
Glib::RefPtr<Gio::DBus::Proxy> proxy;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
/* Hack to keep constructor inaccessible but still public.
|
||||||
|
* This is required to be able to use std::make_shared.
|
||||||
|
* It is important to keep this class only accessible via a reference-counted
|
||||||
|
* pointer because the destructor will manually free memory, and this could be
|
||||||
|
* a problem with C++20's copy and move semantics.
|
||||||
|
*/
|
||||||
|
struct PrivateConstructorTag {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
sigc::signal<void> in_use_changed_signal_event;
|
||||||
|
|
||||||
|
std::atomic<bool> location_in_use; // GeoClue is being used
|
||||||
|
|
||||||
|
static std::shared_ptr<GeoClueBackend> getInstance();
|
||||||
|
|
||||||
|
// DBus callbacks
|
||||||
|
void onAppear(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&,
|
||||||
|
const Glib::ustring&);
|
||||||
|
void onVanished(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&);
|
||||||
|
void propertyChanged(const Gio::DBus::Proxy::MapChangedProperties& changedProperties,
|
||||||
|
const std::vector<Glib::ustring>& invalidatedProperties);
|
||||||
|
|
||||||
|
GeoClueBackend(PrivateConstructorTag tag);
|
||||||
|
~GeoClueBackend();
|
||||||
|
};
|
||||||
|
} // namespace waybar::util::GeoClueBackend
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <json/value.h>
|
||||||
|
|
||||||
|
namespace waybar::util {
|
||||||
|
bool valid_host(const Json::Value& config);
|
||||||
|
} // namespace waybar::util
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
#include <memory>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#if (FMT_VERSION >= 90000)
|
#if (FMT_VERSION >= 90000)
|
||||||
@@ -26,14 +27,19 @@ class JsonParser {
|
|||||||
Json::Value root;
|
Json::Value root;
|
||||||
|
|
||||||
// replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences
|
// replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences
|
||||||
std::string modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
|
std::string modifiedJsonStr;
|
||||||
|
const std::string* json = &jsonStr;
|
||||||
|
if (jsonStr.find("\\x") != std::string::npos) {
|
||||||
|
modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
|
||||||
|
json = &modifiedJsonStr;
|
||||||
|
}
|
||||||
|
|
||||||
std::istringstream jsonStream(modifiedJsonStr);
|
|
||||||
std::string errs;
|
std::string errs;
|
||||||
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
||||||
// parser can be called concurrently from multiple module threads
|
// parser can be called concurrently from multiple module threads
|
||||||
Json::CharReaderBuilder readerBuilder;
|
Json::CharReaderBuilder readerBuilder;
|
||||||
if (!Json::parseFromStream(readerBuilder, jsonStream, &root, &errs)) {
|
auto reader = std::unique_ptr<Json::CharReader>(readerBuilder.newCharReader());
|
||||||
|
if (!reader->parse(json->data(), json->data() + json->size(), &root, &errs)) {
|
||||||
throw std::runtime_error("Error parsing JSON: " + errs);
|
throw std::runtime_error("Error parsing JSON: " + errs);
|
||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ enum class KillSignalAction : std::uint8_t {
|
|||||||
HIDE,
|
HIDE,
|
||||||
NOOP,
|
NOOP,
|
||||||
};
|
};
|
||||||
const std::map<std::string, KillSignalAction> userKillSignalActions = {
|
inline const std::map<std::string, KillSignalAction> userKillSignalActions = {
|
||||||
{"TOGGLE", KillSignalAction::TOGGLE},
|
{"TOGGLE", KillSignalAction::TOGGLE},
|
||||||
{"RELOAD", KillSignalAction::RELOAD},
|
{"RELOAD", KillSignalAction::RELOAD},
|
||||||
{"SHOW", KillSignalAction::SHOW},
|
{"SHOW", KillSignalAction::SHOW},
|
||||||
{"HIDE", KillSignalAction::HIDE},
|
{"HIDE", KillSignalAction::HIDE},
|
||||||
{"NOOP", KillSignalAction::NOOP}};
|
{"NOOP", KillSignalAction::NOOP}};
|
||||||
|
|
||||||
const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR1 = KillSignalAction::TOGGLE;
|
inline const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR1 = KillSignalAction::TOGGLE;
|
||||||
const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR2 = KillSignalAction::RELOAD;
|
inline const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR2 = KillSignalAction::RELOAD;
|
||||||
|
|
||||||
}; // namespace waybar::util
|
}; // namespace waybar::util
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class PipewireBackend {
|
|||||||
public:
|
public:
|
||||||
sigc::signal<void> privacy_nodes_changed_signal_event;
|
sigc::signal<void> privacy_nodes_changed_signal_event;
|
||||||
|
|
||||||
std::unordered_map<uint32_t, PrivacyNodeInfo*> privacy_nodes;
|
std::unordered_map<uint32_t, PWPrivacyNodeInfo*> privacy_nodes;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
|
||||||
static std::shared_ptr<PipewireBackend> getInstance();
|
static std::shared_ptr<PipewireBackend> getInstance();
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ enum PrivacyNodeType {
|
|||||||
PRIVACY_NODE_TYPE_NONE,
|
PRIVACY_NODE_TYPE_NONE,
|
||||||
PRIVACY_NODE_TYPE_VIDEO_INPUT,
|
PRIVACY_NODE_TYPE_VIDEO_INPUT,
|
||||||
PRIVACY_NODE_TYPE_AUDIO_INPUT,
|
PRIVACY_NODE_TYPE_AUDIO_INPUT,
|
||||||
PRIVACY_NODE_TYPE_AUDIO_OUTPUT
|
PRIVACY_NODE_TYPE_AUDIO_OUTPUT,
|
||||||
|
PRIVACY_NODE_TYPE_LOCATION
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrivacyNodeInfo {
|
class PWPrivacyNodeInfo {
|
||||||
public:
|
public:
|
||||||
PrivacyNodeType type = PRIVACY_NODE_TYPE_NONE;
|
PrivacyNodeType type = PRIVACY_NODE_TYPE_NONE;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|||||||
@@ -79,6 +79,12 @@ class SleeperThread {
|
|||||||
auto sleep_for(std::chrono::system_clock::duration dur) {
|
auto sleep_for(std::chrono::system_clock::duration dur) {
|
||||||
std::unique_lock lk(mutex_);
|
std::unique_lock lk(mutex_);
|
||||||
CancellationGuard cancel_lock;
|
CancellationGuard cancel_lock;
|
||||||
|
|
||||||
|
condvar_.wait(lk, [this] {
|
||||||
|
return !is_paused_ || signal_.load(std::memory_order_relaxed) ||
|
||||||
|
!do_run_.load(std::memory_order_relaxed);
|
||||||
|
});
|
||||||
|
|
||||||
constexpr auto max_time_point = std::chrono::steady_clock::time_point::max();
|
constexpr auto max_time_point = std::chrono::steady_clock::time_point::max();
|
||||||
auto wait_end = max_time_point;
|
auto wait_end = max_time_point;
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
@@ -95,6 +101,12 @@ class SleeperThread {
|
|||||||
time_point) {
|
time_point) {
|
||||||
std::unique_lock lk(mutex_);
|
std::unique_lock lk(mutex_);
|
||||||
CancellationGuard cancel_lock;
|
CancellationGuard cancel_lock;
|
||||||
|
|
||||||
|
condvar_.wait(lk, [this] {
|
||||||
|
return !is_paused_ || signal_.load(std::memory_order_relaxed) ||
|
||||||
|
!do_run_.load(std::memory_order_relaxed);
|
||||||
|
});
|
||||||
|
|
||||||
return condvar_.wait_until(lk, time_point, [this] {
|
return condvar_.wait_until(lk, time_point, [this] {
|
||||||
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
|
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
|
||||||
});
|
});
|
||||||
@@ -122,6 +134,17 @@ class SleeperThread {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pause() {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
is_paused_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resume() {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
is_paused_ = false;
|
||||||
|
condvar_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
~SleeperThread() {
|
~SleeperThread() {
|
||||||
connection_.disconnect();
|
connection_.disconnect();
|
||||||
stop();
|
stop();
|
||||||
@@ -137,6 +160,7 @@ class SleeperThread {
|
|||||||
std::atomic<bool> do_run_ = true;
|
std::atomic<bool> do_run_ = true;
|
||||||
std::atomic<bool> signal_ = false;
|
std::atomic<bool> signal_ = false;
|
||||||
sigc::connection connection_;
|
sigc::connection connection_;
|
||||||
|
bool is_paused_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::util
|
} // namespace waybar::util
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace waybar::util {
|
||||||
|
size_t utf8_width(const std::string& str);
|
||||||
|
void utf8_truncate(std::string& s, const std::string& ellipsis, size_t max_len);
|
||||||
|
} // namespace waybar::util
|
||||||
@@ -29,13 +29,30 @@ The brightness can be controlled by dragging the slider across the bar or clicki
|
|||||||
|
|
||||||
*device*: ++
|
*device*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
The name of the preferred device to control. If left empty, a device will be chosen automatically.
|
The name of the preferred device to control. If left empty, a device will be chosen automatically. ++
|
||||||
|
Both screen backlights (the udev *backlight* subsystem) and keyboard backlights (LEDs in the udev *leds* subsystem, e.g. *white:kbd_backlight*) are supported; name such an LED here to control it. When left empty, a screen backlight is always preferred for automatic selection.
|
||||||
|
|
||||||
|
*interval*: ++
|
||||||
|
typeof: uint ++
|
||||||
|
default: 1000 ++
|
||||||
|
The interval in milliseconds at which the brightness is polled and the slider is updated.
|
||||||
|
|
||||||
*expand*: ++
|
*expand*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
Enables this module to consume all left over space dynamically.
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
*Note*: As well as the JSON configuration, the slider modules are special in
|
||||||
|
that they *require* styling to work. You *need* to set *min-width* and/or
|
||||||
|
*min-height* (depending on whether your slider is vertical or not) for it to
|
||||||
|
display correctly. That is a GTK detail, not an issue with Waybar. See the
|
||||||
|
*STYLE* section below.
|
||||||
|
|
||||||
|
*Warning*: If *min* is set to *0* (default), the slider can set brightness to
|
||||||
|
*0*, which may completely disable the backlight on some devices, making the
|
||||||
|
screen fully black. Consider setting a small minimum value (e.g. *10*) or
|
||||||
|
configuring brightness keybinds as a fallback.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ The *backlight* module displays the current backlight level.
|
|||||||
default: 2 ++
|
default: 2 ++
|
||||||
The interval in which information gets polled.
|
The interval in which information gets polled.
|
||||||
|
|
||||||
|
*device*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The name of the preferred backlight device to display. If left empty, a device will be chosen automatically. ++
|
||||||
|
Both screen backlights (the udev *backlight* subsystem) and keyboard backlights (LEDs in the udev *leds* subsystem, e.g. *white:kbd_backlight*) are supported; name such an LED here to control it. When left empty, a screen backlight is always preferred for automatic selection.
|
||||||
|
|
||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: {percent}% ++
|
default: {percent}% ++
|
||||||
@@ -74,7 +79,13 @@ The *backlight* module displays the current backlight level.
|
|||||||
|
|
||||||
*reverse-scrolling*: ++
|
*reverse-scrolling*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
Option to reverse the scroll direction.
|
default: false ++
|
||||||
|
Option to reverse the scroll direction for devices other than a mouse (touchpad, trackpad, etc).
|
||||||
|
|
||||||
|
*reverse-mouse-scrolling*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Option to reverse the scroll direction for mice.
|
||||||
|
|
||||||
*scroll-step*: ++
|
*scroll-step*: ++
|
||||||
typeof: float ++
|
typeof: float ++
|
||||||
@@ -86,6 +97,15 @@ The *backlight* module displays the current backlight level.
|
|||||||
default: 0.0 ++
|
default: 0.0 ++
|
||||||
The minimum brightness of the backlight.
|
The minimum brightness of the backlight.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Text to be displayed in the tooltip.
|
||||||
|
|
||||||
*menu*: ++
|
*menu*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
Action that popups the menu.
|
Action that popups the menu.
|
||||||
@@ -104,6 +124,16 @@ The *backlight* module displays the current backlight level.
|
|||||||
default: false ++
|
default: false ++
|
||||||
Enables this module to consume all left over space dynamically.
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
*{percent}*: The current brightness in percent.
|
||||||
|
|
||||||
|
*{percent_exp}*: The current brightness in percent, adjusted with a power curve to better match perceived brightness.
|
||||||
|
|
||||||
|
*{icon}*: The icon from *format-icons* chosen according to *{percent}*.
|
||||||
|
|
||||||
|
*{icon_exp}*: The icon from *format-icons* chosen according to *{percent_exp}*.
|
||||||
|
|
||||||
# EXAMPLE:
|
# EXAMPLE:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -27,11 +27,26 @@ The *battery* module displays the current capacity and state (eg. charging) of y
|
|||||||
default: false ++
|
default: false ++
|
||||||
Option to use the battery design capacity instead of its current maximal capacity.
|
Option to use the battery design capacity instead of its current maximal capacity.
|
||||||
|
|
||||||
|
*full-at-plugged*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
When enabled, a battery that is *Full* while the adapter is online is reported with the *Plugged* status instead of *Full* (so you can style/format it separately). Disabled by default to preserve the existing *Full* behaviour.
|
||||||
|
|
||||||
*interval*: ++
|
*interval*: ++
|
||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
default: 60 ++
|
default: 60 ++
|
||||||
The interval in which the information gets polled.
|
The interval in which the information gets polled.
|
||||||
|
|
||||||
|
*smooth-power*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Enable exponential smoothing of the battery power reading used to estimate the *{time}* remaining, so the estimate fluctuates less between refreshes.
|
||||||
|
|
||||||
|
*smooth-power-time-constant*: ++
|
||||||
|
typeof: double ++
|
||||||
|
default: 260.0 ++
|
||||||
|
The time constant (in seconds) of the *smooth-power* exponential filter. Only used when *smooth-power* is enabled. Values below 1.0 are clamped to 1.0.
|
||||||
|
|
||||||
*states*: ++
|
*states*: ++
|
||||||
typeof: object ++
|
typeof: object ++
|
||||||
A number of battery states which get activated on certain capacity levels. See *waybar-states(5)*.
|
A number of battery states which get activated on certain capacity levels. See *waybar-states(5)*.
|
||||||
@@ -109,6 +124,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
|
|||||||
default: true ++
|
default: true ++
|
||||||
Option to disable tooltip on hover.
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {timeTo} ++
|
||||||
|
The tooltip format. See *CUSTOM FORMATS* for status/state-specific variants.
|
||||||
|
|
||||||
*bat-compatibility*: ++
|
*bat-compatibility*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -150,6 +170,12 @@ The *battery* module displays the current capacity and state (eg. charging) of y
|
|||||||
|
|
||||||
*{health}*: The percentage of the highest-capacity battery's original maximum charge it can still hold.
|
*{health}*: The percentage of the highest-capacity battery's original maximum charge it can still hold.
|
||||||
|
|
||||||
|
The following additional replacement is available in *tooltip-format* (and its
|
||||||
|
custom variants) only:
|
||||||
|
|
||||||
|
*{timeTo}*: Either an estimate of time until full or empty, or "Full", "Plugged"
|
||||||
|
or "Empty" depending on the current battery status.
|
||||||
|
|
||||||
# TIME FORMAT
|
# TIME FORMAT
|
||||||
|
|
||||||
The *battery* module allows you to define how time should be formatted via *format-time*.
|
The *battery* module allows you to define how time should be formatted via *format-time*.
|
||||||
@@ -169,6 +195,11 @@ The *battery* module allows one to define custom formats based on up to two fact
|
|||||||
|
|
||||||
*format-<status>-<state>*: You can also set a custom format depending on both values.
|
*format-<status>-<state>*: You can also set a custom format depending on both values.
|
||||||
|
|
||||||
|
The tooltip format can be customized the same way. The best fitting from
|
||||||
|
*tooltip-format*, *tooltip-format-<state>*, *tooltip-format-<status>* and
|
||||||
|
*tooltip-format-<status>-<state>* will be used (using the same logic as
|
||||||
|
*format-\**).
|
||||||
|
|
||||||
# STATES
|
# STATES
|
||||||
|
|
||||||
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
|
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
|
||||||
@@ -214,6 +245,20 @@ Where:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Custom icon set depending on the status (*format-icons* as an object):
|
||||||
|
|
||||||
|
```
|
||||||
|
"battery": {
|
||||||
|
"bat": "BAT2",
|
||||||
|
"interval": 60,
|
||||||
|
"format": "{capacity}% {icon}",
|
||||||
|
"format-icons": {
|
||||||
|
"default": ["", "", "", "", "", "", "", "", "", "", ""],
|
||||||
|
"charging": ["", "", "", "", "", "", "", "", "", "", ""]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
- *#battery*
|
- *#battery*
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ Addressed by *bluetooth*
|
|||||||
typeof: string ++
|
typeof: string ++
|
||||||
Use the controller with the defined alias. Otherwise, a random controller is used. Recommended to define when there is more than 1 controller available to the system.
|
Use the controller with the defined alias. Otherwise, a random controller is used. Recommended to define when there is more than 1 controller available to the system.
|
||||||
|
|
||||||
|
*controller-alias*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Synonym for *controller*. If both are set, *controller-alias* takes precedence.
|
||||||
|
|
||||||
*format-device-preference*: ++
|
*format-device-preference*: ++
|
||||||
typeof: array ++
|
typeof: array ++
|
||||||
A ranking of bluetooth devices, addressed by their alias. The order is from *first displayed* to *last displayed*. ++
|
A ranking of bluetooth devices, addressed by their alias. The order is from *first displayed* to *last displayed*. ++
|
||||||
@@ -178,6 +182,9 @@ At the time of writing, the experimental features of BlueZ need to be turned on,
|
|||||||
|
|
||||||
*{device_battery_percentage}*: Battery percentage of the displayed device if available. Use only in the config options defined below.
|
*{device_battery_percentage}*: Battery percentage of the displayed device if available. Use only in the config options defined below.
|
||||||
|
|
||||||
|
*{device_battery_percentage_peripheral}*: Battery percentage of the peripheral half of a split keyboard (e.g., ZMK keyboards with separate central and peripheral batteries). ++
|
||||||
|
This is read from GATT Battery Service characteristics that have a User Description descriptor. Use only in the config options defined below.
|
||||||
|
|
||||||
## CONFIGURATION
|
## CONFIGURATION
|
||||||
|
|
||||||
*format-connected-battery*: ++
|
*format-connected-battery*: ++
|
||||||
@@ -220,6 +227,17 @@ At the time of writing, the experimental features of BlueZ need to be turned on,
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Split keyboard with separate central/peripheral batteries (e.g., ZMK):
|
||||||
|
|
||||||
|
```
|
||||||
|
"bluetooth": {
|
||||||
|
"format-device-preference": [ "Keyball44" ],
|
||||||
|
"format": "",
|
||||||
|
"format-connected-battery": " {device_battery_percentage}%|{device_battery_percentage_peripheral}%",
|
||||||
|
"tooltip-format-connected": "{device_alias}\\nCentral: {device_battery_percentage}%\\nPeripheral: {device_battery_percentage_peripheral}%"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
- *#bluetooth*
|
- *#bluetooth*
|
||||||
@@ -227,6 +245,7 @@ At the time of writing, the experimental features of BlueZ need to be turned on,
|
|||||||
- *#bluetooth.off*
|
- *#bluetooth.off*
|
||||||
- *#bluetooth.on*
|
- *#bluetooth.on*
|
||||||
- *#bluetooth.connected*
|
- *#bluetooth.connected*
|
||||||
|
- *#bluetooth.no-controller*
|
||||||
- *#bluetooth.discoverable*
|
- *#bluetooth.discoverable*
|
||||||
- *#bluetooth.discovering*
|
- *#bluetooth.discovering*
|
||||||
- *#bluetooth.pairable*
|
- *#bluetooth.pairable*
|
||||||
|
|||||||
+165
-156
@@ -6,10 +6,10 @@ waybar - cava module
|
|||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
*cava* module for karlstav/cava project. See it on github: https://github.com/karlstav/cava.
|
The *cava* module integrates the *karlstav/cava* audio visualizer into Waybar.
|
||||||
|
It supports two frontends: a text-based *raw* frontend and a GPU-based *GLSL*
|
||||||
Module supports two different frontends starting from the 0.15.0 release. The frontend that
|
frontend. The active frontend is selected by the *method* option in the
|
||||||
will be used is managed by the method parameter in the [output] section of the cava configuration file.
|
*[output]* section of the cava configuration file.
|
||||||
|
|
||||||
# FILES
|
# FILES
|
||||||
|
|
||||||
@@ -27,177 +27,194 @@ libcava lives in:
|
|||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
[- *Option*
|
[- *Option*
|
||||||
:- *Typeof*
|
:[ *Type*
|
||||||
:- *Default*
|
:[ *Default*
|
||||||
:- *Description*
|
:[ *Description*
|
||||||
|[ *cava_config*
|
|[ *cava_config*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
:< Path where cava configuration file is placed to
|
:[ Path to the cava configuration file. When provided, cava settings are read from it first.
|
||||||
|[ *method* \[output\]
|
|
||||||
:[ string
|
|
||||||
:[
|
|
||||||
:< Manages which frontend Waybar cava module should use. Values: raw, sdl_glsl
|
|
||||||
|[ *framerate*
|
|[ *framerate*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 30
|
:[ 30
|
||||||
:[ Frames per second. Is used as a replacement for *interval*
|
:[ Target frames per second. Replaces the generic *interval* option.
|
||||||
|[ *autosens*
|
|[ *autosens*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 1
|
:[ 1
|
||||||
:[ Will attempt to decrease sensitivity if the bars peak
|
:[ Automatically decrease sensitivity when the bars peak.
|
||||||
|[ *sensitivity*
|
|[ *sensitivity*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 100
|
:[ 100
|
||||||
:[ Manual sensitivity in %. If autosens is enabled, this will only be the initial value. 200 means double height. Accepts only non-negative values
|
:[ Manual sensitivity in %. If *autosens* is enabled, this is only the initial value. 200 means double height. Accepts only non-negative values.
|
||||||
|[ *bars*
|
|[ *bars*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 12
|
:[ 12
|
||||||
:[ The number of bars
|
:[ The number of bars.
|
||||||
|[ *lower_cutoff_freq*
|
|[ *lower_cutoff_freq*
|
||||||
:[ long integer
|
:[ long integer
|
||||||
:[ 50
|
:[ 50
|
||||||
:[ Lower cutoff frequencies for lowest bars the bandwidth of the visualizer
|
:[ Lower cutoff frequency for the visualizer bandwidth.
|
||||||
|[ *higher_cutoff_freq*
|
|[ *higher_cutoff_freq*
|
||||||
:[ long integer
|
:[ long integer
|
||||||
:[ 10000
|
:[ 10000
|
||||||
:[ Higher cutoff frequencies for highest bars the bandwidth of the visualizer
|
:[ Higher cutoff frequency for the visualizer bandwidth.
|
||||||
|[ *sleep_timer*
|
|[ *sleep_timer*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 5
|
:[ 5
|
||||||
:[ Seconds with no input before cava main thread goes to sleep mode
|
:[ Seconds of silence before cava enters sleep mode.
|
||||||
|[ *hide_on_silence*
|
|[ *hide_on_silence*
|
||||||
:[ bool
|
:[ bool
|
||||||
:[ false
|
:[ false
|
||||||
:[ Hides the widget if no input (after sleep_timer elapsed)
|
:[ Hide the widget when silence lasts longer than *sleep_timer*.
|
||||||
|[ *format_silent*
|
|[ *format_silent*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
:[ Widget's text after sleep_timer elapsed (hide_on_silence has to be false)
|
:[ Text shown when the module is silent and *hide_on_silence* is false. **Raw frontend only.**
|
||||||
|
|[ *format-icons*
|
||||||
|
:[ array
|
||||||
|
:[
|
||||||
|
:[ Array of characters used to render bar levels in the raw frontend. The number of items determines the dynamic range.
|
||||||
|[ *method* \[input\]
|
|[ *method* \[input\]
|
||||||
:[ string
|
:[ string
|
||||||
:[ pulse
|
:[ pulse
|
||||||
:[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem
|
:[ Audio capture backend. Supported values: pipewire, pulse, alsa, fifo, sndio, shmem.
|
||||||
|[ *source*
|
|[ *source*
|
||||||
:[ string
|
:[ string
|
||||||
:[ auto
|
:[ auto
|
||||||
:[ See cava configuration
|
:[ Audio source identifier. See the cava documentation for details.
|
||||||
|[ *sample_rate*
|
|[ *sample_rate*
|
||||||
:[ long integer
|
:[ long integer
|
||||||
:[ 44100
|
:[ 44100
|
||||||
:[ See cava configuration
|
:[ See the cava documentation.
|
||||||
|[ *sample_bits*
|
|[ *sample_bits*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 16
|
:[ 16
|
||||||
:[ See cava configuration
|
:[ See the cava documentation.
|
||||||
|[ *stereo*
|
|[ *stereo*
|
||||||
:[ bool
|
:[ bool
|
||||||
:[ true
|
:[ true
|
||||||
:[ Visual channels
|
:[ Enable stereo visualization.
|
||||||
|[ *reverse*
|
|[ *reverse*
|
||||||
:[ bool
|
:[ bool
|
||||||
:[ false
|
:[ false
|
||||||
:[ Displays frequencies the other way around
|
:[ Reverse the bar order (highest frequencies on the left).
|
||||||
|[ *bar_delimiter*
|
|[ *bar_delimiter*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 0
|
:[ 0
|
||||||
:[ Each bar is separated by a delimiter. Use decimal value in ascii table(i.e. 59 = ";"). 0 means no delimiter
|
:[ Delimiter placed between bars in the raw output. Use a decimal ASCII value (e.g. 59 = ";"). 0 means no delimiter.
|
||||||
|
|[ *data_format*
|
||||||
|
:[ string
|
||||||
|
:[ ascii
|
||||||
|
:[ Raw data format. Can be 'binary' or 'ascii'. **Raw frontend only.**
|
||||||
|
|[ *raw_target*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Raw output target. A fifo will be created if target does not exist. **Raw frontend only.**
|
||||||
|[ *monstercat*
|
|[ *monstercat*
|
||||||
:[ bool
|
:[ bool
|
||||||
:[ false
|
:[ false
|
||||||
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|
:[ Enable Monstercat smoothing.
|
||||||
|[ *waves*
|
|[ *waves*
|
||||||
:[ bool
|
:[ bool
|
||||||
:[ false
|
:[ false
|
||||||
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|
:[ Enable the waves effect alongside Monstercat smoothing.
|
||||||
|[ *noise_reduction*
|
|[ *noise_reduction*
|
||||||
:[ integer
|
:[ double
|
||||||
:[ 77
|
:[ 0.77
|
||||||
:[ Range between 0 - 100. The raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth. 100 will be very slow and smooth, 0 will be fast but noisy
|
:[ Smoothing factor between 0.0 and 1.0. Higher values produce slower, smoother animation; lower values are more reactive but noisy.
|
||||||
|[ *input_delay*
|
|[ *input_delay*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 2
|
:[ 4
|
||||||
:[ Sets the delay before fetching audio source thread start working. On author's machine, Waybar starts much faster than pipewire audio server, and without a little delay cava module fails because pipewire is not ready
|
:[ Delay in seconds before starting audio capture. Increase this if Waybar starts before the audio server (e.g. PipeWire).
|
||||||
|[ *ascii_max_range*
|
|
||||||
:[ integer
|
|
||||||
:[ 7
|
|
||||||
:[ It's impossible to set it directly. The value is dictated by the number of icons in the array *format-icons*
|
|
||||||
|[ *data_format*
|
|
||||||
:[ string
|
|
||||||
:[ asci
|
|
||||||
:[ Raw data format. Can be 'binary' or 'ascii'
|
|
||||||
|[ *raw_target*
|
|
||||||
:[ string
|
|
||||||
:[ /dev/stdout
|
|
||||||
:[ Raw output target. A fifo will be created if target does not exist
|
|
||||||
|[ *menu*
|
|
||||||
:[ string
|
|
||||||
:[
|
|
||||||
:[ Action that popups the menu.
|
|
||||||
|[ *menu-file*
|
|
||||||
:[ string
|
|
||||||
:[
|
|
||||||
:[ Location of the menu descriptor file. There need to be an element of type GtkMenu with id *menu*
|
|
||||||
|[ *menu-actions*
|
|
||||||
:[ array
|
|
||||||
:[
|
|
||||||
:[ The actions corresponding to the buttons of the menu.
|
|
||||||
|[ *bar_spacing*
|
|
||||||
:[ integer
|
|
||||||
:[
|
|
||||||
:[ Bars' space between bars in number of characters
|
|
||||||
|[ *bar_width*
|
|[ *bar_width*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[
|
:[
|
||||||
:[ Bars' width between bars in number of characters
|
:[ Bar width in pixels. **Used by the GLSL frontend.**
|
||||||
|
|[ *bar_spacing*
|
||||||
|
:[ integer
|
||||||
|
:[
|
||||||
|
:[ Space between bars in pixels. **Used by the GLSL frontend.**
|
||||||
|[ *bar_height*
|
|[ *bar_height*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[
|
:[
|
||||||
:[ Useless. bar_height is only used for output in "noritake" format
|
:[ Ignored by Waybar. Used only by cava's "noritake" output format.
|
||||||
|[ *background*
|
|[ *menu*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
:[ GLSL actual. Support hex code colors only. Must be within ''
|
:[ Action that opens the menu.
|
||||||
|[ *foreground*
|
|[ *menu-file*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
:[ GLSL actual. Support hex code colors only. Must be within ''
|
:[ Location of the menu descriptor file. There must be a GtkMenu element with id *menu*.
|
||||||
|[ *gradient*
|
|[ *menu-actions*
|
||||||
:[ integer
|
:[ array
|
||||||
:[ 0
|
|
||||||
:[ GLSL actual. Gradient mode(0/1 - on/off)
|
|
||||||
|[ *gradient_count*
|
|
||||||
:[ integer
|
|
||||||
:[ 0
|
|
||||||
:[ GLSL actual. The count of colors for the gradient
|
|
||||||
|[ *gradient_color_N*
|
|
||||||
:[ string
|
|
||||||
:[
|
:[
|
||||||
:[ GLSL actual. N - the number of the gradient color between 1 and 8. Only hex defined colors are supported. Must be within ''
|
:[ Actions corresponding to the buttons of the menu.
|
||||||
|
|[ *method* \[output\]
|
||||||
|
:[ string
|
||||||
|
:[ raw
|
||||||
|
:[ Cava output method. Set to *raw* for the text frontend or *sdl_glsl* for the GPU frontend. **This is set inside the *[output]* section of the cava configuration file, not in Waybar's JSON.**
|
||||||
|[ *sdl_width*
|
|[ *sdl_width*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[
|
:[
|
||||||
:[ GLSL actual. Manages the width of the waybar cava GLSL frontend module
|
:[ GLSL frontend width in pixels. **GLSL only.**
|
||||||
|[ *sdl_height*
|
|[ *sdl_height*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[
|
:[
|
||||||
:[ GLSL actual. Manages the height of the waybar cava GLSL frontend module
|
:[ GLSL frontend height in pixels. **GLSL only.**
|
||||||
|
|[ *min-length*
|
||||||
|
:[ integer
|
||||||
|
:[
|
||||||
|
:[ Requested width of the GLSL widget in pixels. If not set, falls back to *max-length*, then *sdl_width*. **GLSL only.**
|
||||||
|
|[ *max-length*
|
||||||
|
:[ integer
|
||||||
|
:[
|
||||||
|
:[ Fallback width of the GLSL widget if *min-length* is not set. **GLSL only.**
|
||||||
|
|[ *vertex_shader*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Path to the vertex shader. **GLSL only; set in the *[output]* section of the cava configuration file.**
|
||||||
|
|[ *fragment_shader*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Path to the fragment shader. **GLSL only; set in the *[output]* section of the cava configuration file.**
|
||||||
|[ *continuous_rendering*
|
|[ *continuous_rendering*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 0
|
:[ 0
|
||||||
:[ GLSL actual. Keep rendering even if no audio. Recommended to set to 1
|
:[ Continue rendering when silent. Set to 1 for smooth animation. **GLSL only; set in the *[output]* section of the cava configuration file.**
|
||||||
|
|[ *background*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Background color as a '#RRGGBB' hex string (must be quoted). **GLSL only; set in the *[color]* section of the cava configuration file.**
|
||||||
|
|[ *foreground*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Foreground color as a '#RRGGBB' hex string (must be quoted). **GLSL only; set in the *[color]* section of the cava configuration file.**
|
||||||
|
|[ *gradient*
|
||||||
|
:[ integer
|
||||||
|
:[ 0
|
||||||
|
:[ Enable gradient mode (0 = off, 1 = on). **GLSL only.** Can also be set in the *[color]* section of the cava configuration file.
|
||||||
|
|[ *gradient_count*
|
||||||
|
:[ integer
|
||||||
|
:[ 0
|
||||||
|
:[ Number of gradient colors (up to 8). **GLSL only.** Can also be set in the *[color]* section of the cava configuration file.
|
||||||
|
|[ *gradient_color_N*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Gradient color N (1–8) as a '#RRGGBB' hex string (must be quoted). **GLSL only; set in the *[color]* section of the cava configuration file.**
|
||||||
|
|
||||||
Configuration can be provided as:
|
Configuration can be provided in three ways:
|
||||||
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped
|
|
||||||
- Without cava configuration file. In such case cava should be configured through provided list of the configuration option
|
- **Cava config only**: set *cava_config* to a cava configuration file and omit all other options.
|
||||||
- Mix. When provided both And cava configuration file And configuration options. In such case, waybar applies configuration file first and then overrides particular options by the provided list of configuration options
|
- **Waybar JSON only**: leave out *cava_config* and set every option in Waybar's module configuration.
|
||||||
|
- **Mixed**: provide a *cava_config* and also set specific options in Waybar's JSON. Waybar reads the file first, then overrides any values present in the JSON.
|
||||||
|
|
||||||
# ACTIONS
|
# ACTIONS
|
||||||
|
|
||||||
[- *String*
|
[- *String*
|
||||||
:- *Action*
|
:[ *Action*
|
||||||
|[ *mode*
|
|[ *mode*
|
||||||
:< Switch main cava thread and fetch audio source thread from/to pause/resume
|
:[ Toggle pause/resume for the audio capture and output threads.
|
||||||
|
|
||||||
# DEPENDENCIES
|
# DEPENDENCIES
|
||||||
|
|
||||||
@@ -207,26 +224,32 @@ Configuration can be provided as:
|
|||||||
|
|
||||||
# SOLVING ISSUES
|
# SOLVING ISSUES
|
||||||
|
|
||||||
. On start Waybar throws an exception "error while loading shared libraries: libcava.so: cannot open shared object file: No such file or directory".
|
. At startup Waybar fails with *"error while loading shared libraries: libcava.so: cannot open shared object file: No such file or directory"*.
|
||||||
It might happen when libcava for some reason hasn't been registered in the system. sudo ldconfig should help
|
This happens when libcava has not been registered in the system library cache. Run *sudo ldconfig* to refresh the cache.
|
||||||
. Waybar is starting but cava module doesn't react to the music
|
This can also occur when Waybar is installed under */usr/local* but libcava is elsewhere. To fix it:
|
||||||
1. In such cases at first need to make sure usual cava application is working as well
|
1. Remove the local libcava installation: *sudo rm -rfv /usr/local/include/cava /usr/local/lib64/pkgconfig/cava.pc /usr/local/lib64/libcava.so*
|
||||||
2. If so, need to comment all configuration options. Uncomment cava_config and provide the path to the working cava config
|
2. Reconfigure Waybar to use the system prefix: *meson configure build -Dprefix="/usr"*
|
||||||
3. You might set too huge or too small input_delay. Try to setup to 4 seconds, restart waybar, and check again 4 seconds past. Usual even on weak machines it should be enough
|
3. Rebuild Waybar: *ninja -C build*
|
||||||
4. You might accidentally switch action mode to pause mode
|
4. Install Waybar: *sudo meson install -C build*
|
||||||
|
|
||||||
# RISING ISSUES
|
. Waybar starts but the cava module does not react to audio.
|
||||||
|
1. First, verify that standalone cava works correctly.
|
||||||
|
2. If it does, comment out all Waybar cava options, uncomment *cava_config*, and point it to the working cava configuration file.
|
||||||
|
3. The *input_delay* may be too large or too small. Try setting it to 4 seconds, restart Waybar, and check again after that delay. This is usually sufficient, even on slower machines.
|
||||||
|
4. You may have accidentally toggled pause mode via an action.
|
||||||
|
|
||||||
For clear understanding: this module is a cava API's consumer. So for any bugs related to cava engine you should contact Cava upstream(https://github.com/karlstav/cava) ++
|
# REPORTING ISSUES
|
||||||
with the one Exception. Cava upstream doesn't provide cava as a shared library. For that, this module author made a fork libcava(https://github.com/LukashonakV/cava). ++
|
|
||||||
So the order is:
|
This module is a consumer of the cava API. For bugs in the cava engine itself, please report them to [cava upstream](https://github.com/karlstav/cava) first.
|
||||||
. cava upstream
|
|
||||||
. libcava upstream.
|
Upstream cava does not provide a shared library. The Waybar cava module uses [libcava](https://github.com/LukashonakV/cava), a fork maintained by the module author, to provide one. If the issue is specific to the shared library packaging, report it to libcava.
|
||||||
In case when cava releases new version and you're wanna get it, it should be raised an issue to libcava(https://github.com/LukashonakV/cava) with title ++
|
|
||||||
\[Bump\]x.x.x where x.x.x is cava release version.
|
When requesting a new upstream cava release to be packaged in libcava, open an issue at libcava with the title `[Bump] x.x.x`, where `x.x.x` is the desired cava version.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
|
## Raw frontend
|
||||||
|
|
||||||
```
|
```
|
||||||
"cava": {
|
"cava": {
|
||||||
//"cava_config": "$XDG_CONFIG_HOME/cava/cava.conf",
|
//"cava_config": "$XDG_CONFIG_HOME/cava/cava.conf",
|
||||||
@@ -240,7 +263,6 @@ In case when cava releases new version and you're wanna get it, it should be rai
|
|||||||
"source": "auto",
|
"source": "auto",
|
||||||
"stereo": true,
|
"stereo": true,
|
||||||
"reverse": false,
|
"reverse": false,
|
||||||
"bar_delimiter": 0,
|
|
||||||
"monstercat": false,
|
"monstercat": false,
|
||||||
"waves": false,
|
"waves": false,
|
||||||
"noise_reduction": 0.77,
|
"noise_reduction": 0.77,
|
||||||
@@ -251,36 +273,6 @@ In case when cava releases new version and you're wanna get it, it should be rai
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
# STYLE
|
|
||||||
|
|
||||||
- *#cava*
|
|
||||||
- *#cava.silent* Applied after no sound has been detected for sleep_timer seconds
|
|
||||||
- *#cava.updated* Applied when a new frame is shown
|
|
||||||
# FRONTENDS
|
|
||||||
|
|
||||||
## RAW
|
|
||||||
The cava raw frontend uses ASCII characters to visualize incoming audio data. Each ASCII symbol position corresponds to the value of the audio power pulse.
|
|
||||||
|
|
||||||
Under the hood:
|
|
||||||
```
|
|
||||||
. Incoming audio power pulse list is : 12684
|
|
||||||
. Configured array of ASCII codes is: ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ]. See `format-icons` https://github.com/Alexays/Waybar/wiki/Module:-Cava#example
|
|
||||||
```
|
|
||||||
As a result cava frontend will give ▁▂▆█▄
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
waybar config
|
|
||||||
```
|
|
||||||
"cava": {
|
|
||||||
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_raw.conf",
|
|
||||||
"input_delay": 2,
|
|
||||||
"format-icons" : ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ],
|
|
||||||
"actions": {
|
|
||||||
"on-click-right": "mode"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
waybar_raw.conf
|
waybar_raw.conf
|
||||||
```
|
```
|
||||||
@@ -351,6 +343,7 @@ sleep_timer = 5
|
|||||||
# README.md contains further information on how to setup CAVA for JACK.
|
# README.md contains further information on how to setup CAVA for JACK.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods:
|
# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods:
|
||||||
# sample_rate: fifo, pipewire, sndio, oss
|
# sample_rate: fifo, pipewire, sndio, oss
|
||||||
# sample_bits: fifo, pipewire, sndio, oss
|
# sample_bits: fifo, pipewire, sndio, oss
|
||||||
@@ -452,7 +445,7 @@ bar_delimiter = 0
|
|||||||
|
|
||||||
# Noise reduction, int 0 - 100. default 77
|
# Noise reduction, int 0 - 100. default 77
|
||||||
# the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth
|
# the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth
|
||||||
# 100 will be very slow and smooth, 0 will be fast but noisy.
|
# 100 will be very slow and smooth, 0 will be fast and noisy.
|
||||||
|
|
||||||
|
|
||||||
[eq]
|
[eq]
|
||||||
@@ -461,33 +454,32 @@ bar_delimiter = 0
|
|||||||
# Remember to uncomment more than one key! More keys = more precision.
|
# Remember to uncomment more than one key! More keys = more precision.
|
||||||
# Look at readme.md on github for further explanations and examples.
|
# Look at readme.md on github for further explanations and examples.
|
||||||
```
|
```
|
||||||
## GLSL
|
|
||||||
The Cava GLSL frontend delegates the visualization of incoming audio data to the GPU via OpenGL.
|
|
||||||
|
|
||||||
There are some mandatory dependencies that need to be satisfied in order for Cava GLSL to be built and function properly:
|
## GLSL frontend
|
||||||
|
|
||||||
. epoxy library must be installed on the system
|
The GLSL frontend requires:
|
||||||
. Vertex and fragment shaders from the original project must be used. They should be downloaded, and the file paths must be configured correctly in the Waybar Cava configuration:
|
|
||||||
1. cava shaders [cava shaders](https://github.com/karlstav/cava/tree/master/output/shaders)
|
|
||||||
2. libcava shaders [libcava shaders](https://github.com/LukashonakV/cava/tree/master/output/shaders)
|
|
||||||
. It is highly recommended to have a separate cava configuration for the Waybar Cava GLSL module and to use this as the cava_config in the Waybar configuration.
|
|
||||||
. It is common for cava configurations to be placed in the XDG_CONFIG_HOME directory, including shaders as well. Consider keeping them in the $XDG_CONFIG_HOME/cava/shaders folder.
|
|
||||||
|
|
||||||
Key configuration options:
|
. The *epoxy* library.
|
||||||
|
. Vertex and fragment shaders from the cava project. Download them and place under _$XDG_CONFIG_HOME/cava/shaders_, then reference them in the cava configuration:
|
||||||
|
1. [cava shaders](https://github.com/karlstav/cava/tree/master/output/shaders)
|
||||||
|
2. [libcava shaders](https://github.com/LukashonakV/cava/tree/master/output/shaders)
|
||||||
|
. A separate cava configuration file is highly recommended.
|
||||||
|
|
||||||
. bars. The more values the parameter has, the more interesting the visualization becomes.
|
Key cava configuration options for GLSL:
|
||||||
. method in output section must be set to sdl_glsl
|
|
||||||
. sdl_width and sdl_height manage the size of the module. Adjust them according to your needs.
|
. *bars* — higher values produce more detailed visualization.
|
||||||
. Shaders for sdl_glsl, located in $HOME/.config/cava/shaders. Example: "vertex_shader" = "pass_through.vert" "fragment_shader" = "spectrogram.frag"
|
. *method* in *[output]* must be set to *sdl_glsl*.
|
||||||
. Set continuous_rendering to 1 to enable smooth rendering; set it to 0 otherwise. It is recommended to keep it set to 1.
|
. *sdl_width* and *sdl_height* control the module size.
|
||||||
. background, foreground, and gradient_color_N (where N is a number between 1 and 8) must be defined using hex code
|
. *vertex_shader* and *fragment_shader* point to the shader files under _$HOME/.config/cava/shaders_.
|
||||||
|
. *continuous_rendering* — set to 1 for smooth animation.
|
||||||
|
. *background*, *foreground*, and *gradient_color_N* must use hex codes inside single quotes.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
waybar config
|
waybar config
|
||||||
```
|
```
|
||||||
"cava": {
|
"cava": {
|
||||||
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_cava#3.conf",
|
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_cava.conf",
|
||||||
"input_delay": 2,
|
"input_delay": 2,
|
||||||
"actions": {
|
"actions": {
|
||||||
"on-click-right": "mode"
|
"on-click-right": "mode"
|
||||||
@@ -495,7 +487,7 @@ waybar config
|
|||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
waybar_raw.conf
|
waybar_cava.conf
|
||||||
```
|
```
|
||||||
## Configuration file for CAVA.
|
## Configuration file for CAVA.
|
||||||
# Remove the ; to change parameters.
|
# Remove the ; to change parameters.
|
||||||
@@ -641,7 +633,7 @@ vertex_shader = pass_through.vert
|
|||||||
fragment_shader = bar_spectrum.frag
|
fragment_shader = bar_spectrum.frag
|
||||||
|
|
||||||
; for glsl output mode, keep rendering even if no audio
|
; for glsl output mode, keep rendering even if no audio
|
||||||
continuous_rendering = 1;
|
continuous_rendering = 1
|
||||||
|
|
||||||
# disable console blank (screen saver) in tty
|
# disable console blank (screen saver) in tty
|
||||||
# (Not supported on FreeBSD)
|
# (Not supported on FreeBSD)
|
||||||
@@ -705,4 +697,21 @@ gradient_color_2 = '#45475A'
|
|||||||
# Look at readme.md on github for further explanations and examples.
|
# Look at readme.md on github for further explanations and examples.
|
||||||
```
|
```
|
||||||
|
|
||||||
Different waybar_cava#N.conf see at [cava GLSL](https://github.com/Alexays/Waybar/wiki/Module:-Cava:-GLSL)
|
More GLSL examples are available on the [cava GLSL wiki page](https://github.com/Alexays/Waybar/wiki/Module:-Cava:-GLSL).
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#cava* Raw frontend widget
|
||||||
|
- *#cava.silent* Applied after no sound has been detected for *sleep_timer* seconds
|
||||||
|
- *#cava.updated* Applied when a new frame is shown
|
||||||
|
- *#cavaGLSL* GLSL frontend widget (used instead of *#cava* when the cava *method* is *sdl_glsl*)
|
||||||
|
- *#cavaGLSL.silent* Applied after no sound has been detected for *sleep_timer* seconds
|
||||||
|
- *#cavaGLSL.updated* Applied when a new frame is shown
|
||||||
|
|
||||||
|
# FRONTENDS
|
||||||
|
|
||||||
|
## RAW
|
||||||
|
The raw frontend maps each bar's amplitude to a character from *format-icons*. The final widget text is the concatenation of all characters, optionally separated by *bar_delimiter*. See the EXAMPLES section above for a complete configuration.
|
||||||
|
|
||||||
|
## GLSL
|
||||||
|
The GLSL frontend renders the visualization with OpenGL ES using user-provided shaders. It is selected by setting *method = sdl_glsl* in the cava configuration. See the EXAMPLES section above for a complete configuration.
|
||||||
|
|||||||
@@ -37,6 +37,19 @@ Waybar config to enable the module:
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# DEVELOPING CFFI MODULES
|
||||||
|
|
||||||
|
CFFI modules require a handful of functions and constants to be defined with C
|
||||||
|
linkage. The way to achieve this depends on the programming language being used
|
||||||
|
(search for FFI / Foreign Function Interface for that language).
|
||||||
|
|
||||||
|
The complete list of symbols to define can be found in the header file shipped with
|
||||||
|
Waybar at *resources/custom_modules/cffi_example/waybar_cffi_module.h*, and a full
|
||||||
|
example written in C is provided in *resources/custom_modules/cffi_example/*.
|
||||||
|
|
||||||
|
Language bindings exist for several languages, including Rust (the *waybar-cffi*
|
||||||
|
crate) and Zig.
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
The classes and IDs are managed by the cffi dynamic library.
|
The classes and IDs are managed by the cffi dynamic library.
|
||||||
|
|||||||
+54
-6
@@ -6,7 +6,16 @@ waybar - clock module
|
|||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
*clock* module displays current date and time
|
*clock* module displays current date and time.
|
||||||
|
|
||||||
|
There are two implementations:
|
||||||
|
|
||||||
|
- *clock*: Full-featured implementation, including the calendar and timezone
|
||||||
|
support described below. Enabled at build time when either C++20 concepts
|
||||||
|
(\_\_cpp\_concepts >= 201907, gcc >= 13) are available, or the HowardHinnant date
|
||||||
|
library <https://github.com/HowardHinnant/date> is installed.
|
||||||
|
- *simpleclock*: Fallback that provides date and time display only. Used when the
|
||||||
|
above build conditions are not met.
|
||||||
|
|
||||||
# FILES
|
# FILES
|
||||||
|
|
||||||
@@ -27,7 +36,8 @@ $XDG_CONFIG_HOME/waybar/config ++
|
|||||||
|[ *format*
|
|[ *format*
|
||||||
:[ string
|
:[ string
|
||||||
:[ *{:%H:%M}*
|
:[ *{:%H:%M}*
|
||||||
:[ The format, how the date and time should be displayed. See format options below
|
:[ The format, how the date and time should be displayed. See format options
|
||||||
|
below. Split the braces to insert literal text, e.g. *{0:%H}text{0:%M}*
|
||||||
|[ *timezone*
|
|[ *timezone*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
@@ -120,8 +130,9 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|
|||||||
:[ Calendar view mode. Possible values: year|month
|
:[ Calendar view mode. Possible values: year|month
|
||||||
|[ *mode-mon-col*
|
|[ *mode-mon-col*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 3
|
:[ 1
|
||||||
:[ Relevant for *mode=year*. Count of months per row
|
:[ Relevant for *mode=year*. Count of months per row. Must be a divisor of 12
|
||||||
|
(one of 1, 2, 3, 4, 6, 12); an invalid value falls back to 3
|
||||||
|[ *weeks-pos*
|
|[ *weeks-pos*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
@@ -138,6 +149,18 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|
|||||||
:[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on
|
:[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on
|
||||||
Monday, and the first week of the year is numbered 1. The default week format is
|
Monday, and the first week of the year is numbered 1. The default week format is
|
||||||
'{:%V}'.
|
'{:%V}'.
|
||||||
|
|[ *weeks-numbering*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Override the week number calculation method, independent of *iso8601* and
|
||||||
|
locale settings. Possible values: *iso* (ISO 8601, {:%V}), *monday*
|
||||||
|
(Monday-based, {:%W}), *sunday* (Sunday-based, {:%U}). When not set, the
|
||||||
|
method is derived from *iso8601* or the locale.
|
||||||
|
|[ *first-day-of-week*
|
||||||
|
:[ integer
|
||||||
|
:[
|
||||||
|
:[ The first day of the week, where 0 is Sunday and 6 is Saturday.
|
||||||
|
When not set, the first day of the week is determined by the locale settings.
|
||||||
|
|
||||||
3. Addressed by *clock: calendar: format*
|
3. Addressed by *clock: calendar: format*
|
||||||
[- *Option*
|
[- *Option*
|
||||||
@@ -155,8 +178,9 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|
|||||||
|[ *weeks*
|
|[ *weeks*
|
||||||
:[ string
|
:[ string
|
||||||
:[ *{:%U}*
|
:[ *{:%U}*
|
||||||
:[ Format is applied to week numbers. When weekday format is not provided then
|
:[ Format is applied to week numbers. The *{}* placeholder is replaced with the
|
||||||
is used default format: '{:%W}' when week starts with Monday, '{:%U}' otherwise
|
format determined by *weeks-numbering* (if set), otherwise by *iso8601* or the
|
||||||
|
locale: '{:%V}' for ISO 8601, '{:%W}' when week starts with Monday, '{:%U}' otherwise
|
||||||
|[ *weekdays*
|
|[ *weekdays*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
@@ -180,6 +204,10 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|
|||||||
:[ Switch to the next calendar month/year
|
:[ Switch to the next calendar month/year
|
||||||
|[ *shift_down*
|
|[ *shift_down*
|
||||||
:[ Switch to the previous calendar month/year
|
:[ Switch to the previous calendar month/year
|
||||||
|
|[ *shift_reset*
|
||||||
|
:[ Reset the calendar shift back to the current month/year
|
||||||
|
|[ *exec <cmd>*
|
||||||
|
:[ Execute the specified command
|
||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
@@ -210,6 +238,7 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|
|||||||
"mode" : "year",
|
"mode" : "year",
|
||||||
"mode-mon-col" : 3,
|
"mode-mon-col" : 3,
|
||||||
"weeks-pos" : "right",
|
"weeks-pos" : "right",
|
||||||
|
"first-day-of-week": 1,
|
||||||
"on-scroll" : 1,
|
"on-scroll" : 1,
|
||||||
"on-click-right" : "mode",
|
"on-click-right" : "mode",
|
||||||
"format": {
|
"format": {
|
||||||
@@ -276,6 +305,21 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
|
|||||||
|
|
||||||
- *#clock*
|
- *#clock*
|
||||||
|
|
||||||
|
If displaying seconds causes other modules to shift side to side, the cause is
|
||||||
|
usually proportional-width digits. If your font supports it, add
|
||||||
|
*font-feature-settings: "tnum";* to the *#clock* style (or wherever you set the bar
|
||||||
|
font) to use fixed-width numbers.
|
||||||
|
|
||||||
|
The following classes are used only inside the *{calendar}* tooltip. Their
|
||||||
|
foreground *color* is read and applied to the corresponding calendar cells in
|
||||||
|
the tooltip markup:
|
||||||
|
|
||||||
|
- *.calendar-today*: The current day
|
||||||
|
- *.calendar-days*: The day numbers
|
||||||
|
- *.calendar-weeks*: The week numbers
|
||||||
|
- *.calendar-weekdays*: The weekday header (Su, Mo, ...)
|
||||||
|
- *.calendar-months*: The month header (January, February, ...)
|
||||||
|
|
||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
If clock module is disabled at startup with locale::facet::\_S\_create\_c\_locale ++
|
If clock module is disabled at startup with locale::facet::\_S\_create\_c\_locale ++
|
||||||
@@ -284,6 +328,10 @@ name not valid error message try one of the following:
|
|||||||
- check if LC_TIME is set properly (glibc)
|
- check if LC_TIME is set properly (glibc)
|
||||||
- set locale to C in the config file (musl)
|
- set locale to C in the config file (musl)
|
||||||
|
|
||||||
|
When using *clock* instead of *simpleclock*, the locale defaults to *C* regardless
|
||||||
|
of the locale settings. To override this, prepend *L* to the format string, e.g.
|
||||||
|
*{:%a %m %d}* becomes *{:L%a %m %d}*.
|
||||||
|
|
||||||
The locale option must be set for {calendar} to use the correct start-of-week, regardless of system locale.
|
The locale option must be set for {calendar} to use the correct start-of-week, regardless of system locale.
|
||||||
|
|
||||||
## Calendar in Chinese. Alignment
|
## Calendar in Chinese. Alignment
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
waybar-cpu-graph(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - cpu graph module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The *cpu graph* module displays a line graph with the CPU utilization.
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
*interval*: ++
|
||||||
|
typeof: integer or float ++
|
||||||
|
default: 5 ++
|
||||||
|
The interval in which the information gets polled.
|
||||||
|
|
||||||
|
*graph_type*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: line ++
|
||||||
|
The rendering style of the graph. One of 'line', 'bar', or 'gauge'.
|
||||||
|
|
||||||
|
*width*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
The length in pixels the module should display.
|
||||||
|
|
||||||
|
*datapoints*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
How many data points to show.
|
||||||
|
|
||||||
|
*on-click*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when clicked on the module.
|
||||||
|
|
||||||
|
*on-click-middle*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when middle-clicked on the module using mousewheel.
|
||||||
|
|
||||||
|
*on-click-right*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when you right-click on the module.
|
||||||
|
|
||||||
|
*on-update*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when the module is updated.
|
||||||
|
|
||||||
|
*on-scroll-up*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling up on the module.
|
||||||
|
|
||||||
|
*on-scroll-down*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling down on the module.
|
||||||
|
|
||||||
|
*smooth-scrolling-threshold*: ++
|
||||||
|
typeof: double ++
|
||||||
|
Threshold to be used when scrolling.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
|
*expand*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
Basic configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
"cpu_graph": {
|
||||||
|
"interval": 2,
|
||||||
|
"width": 10
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#cpu_graph*
|
||||||
|
- *.cpu-intensive*
|
||||||
|
- *.cpu-high*
|
||||||
|
- *.cpu-moderate*
|
||||||
@@ -83,6 +83,18 @@ The *cpu* module displays the current CPU utilization.
|
|||||||
default: true ++
|
default: true ++
|
||||||
Option to disable tooltip on hover.
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The format of the tooltip shown on hover. Supports the same replacements as *format*.
|
||||||
|
|
||||||
|
*format-<state>*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The format to use when the given *state* (see *states*) is active. Supports the same replacements as *format*.
|
||||||
|
|
||||||
|
*tooltip-format-<state>*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The tooltip format to use when the given *state* (see *states*) is active. Takes precedence over *tooltip-format*.
|
||||||
|
|
||||||
*expand*: ++
|
*expand*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -92,6 +104,12 @@ The *cpu* module displays the current CPU utilization.
|
|||||||
|
|
||||||
*{load}*: Current CPU load.
|
*{load}*: Current CPU load.
|
||||||
|
|
||||||
|
*{load1}*: CPU load average over the last minute.
|
||||||
|
|
||||||
|
*{load5}*: CPU load average over the last 5 minutes.
|
||||||
|
|
||||||
|
*{load15}*: CPU load average over the last 15 minutes.
|
||||||
|
|
||||||
*{usage}*: Current overall CPU usage.
|
*{usage}*: Current overall CPU usage.
|
||||||
|
|
||||||
*{usage*{n}*}*: Current CPU core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}.
|
*{usage*{n}*}*: Current CPU core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}.
|
||||||
@@ -106,6 +124,8 @@ The *cpu* module displays the current CPU utilization.
|
|||||||
|
|
||||||
*{icon*{n}*}*: Icon for CPU core n usage. Use like {icon0}.
|
*{icon*{n}*}*: Icon for CPU core n usage. Use like {icon0}.
|
||||||
|
|
||||||
|
*{icons}*: All per-core icons concatenated. Equivalent to {icon0}{icon1}...{icon*N*} but adapts to the number of cores automatically.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
Basic configuration:
|
Basic configuration:
|
||||||
@@ -128,6 +148,16 @@ CPU usage per core rendered as icons:
|
|||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Automatically determine number of icons according to number of logical cores:
|
||||||
|
|
||||||
|
```
|
||||||
|
"cpu": {
|
||||||
|
"interval": 1,
|
||||||
|
"format": "{icons} {usage:>2}% ",
|
||||||
|
"format-icons": ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"],
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
- *#cpu*
|
- *#cpu*
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
waybar-custom-graph(5)
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - custom graph module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The *custom-graph* module displays a graph with the percentage output of a script.
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
Addressed by *custom-graph/<name>*
|
||||||
|
|
||||||
|
*exec*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The path to the script, which should be executed.
|
||||||
|
|
||||||
|
*exec-if*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The path to a script, which determines if the script in *exec* should be executed. ++
|
||||||
|
*exec* will be executed if the exit code of *exec-if* equals 0.
|
||||||
|
|
||||||
|
*exec-on-event*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
If an event command is set (e.g. *on-click* or *on-scroll-up*) then re-execute the script after executing the event command.
|
||||||
|
|
||||||
|
*return-type*: ++
|
||||||
|
typeof: string ++
|
||||||
|
See *return-type*
|
||||||
|
|
||||||
|
*interval*: ++
|
||||||
|
typeof: integer or float ++
|
||||||
|
The interval (in seconds) in which the information gets polled. ++
|
||||||
|
Minimum value is 0.001 (1ms). Values smaller than 1ms will be set to 1ms. ++
|
||||||
|
Use *once* if you want to execute the module only on startup. ++
|
||||||
|
You can update it manually with a signal. If no *interval* or *signal* is defined, it is assumed that the out script loops itself. ++
|
||||||
|
If a *signal* is defined then the script will run once on startup and will only update with a signal.
|
||||||
|
|
||||||
|
*restart-interval*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
The restart interval (in whole seconds). ++
|
||||||
|
Can't be used with the *interval* option, so only with continuous scripts. ++
|
||||||
|
Once the script exits, it'll be re-executed after the *restart-interval*.
|
||||||
|
|
||||||
|
*signal*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
The signal number used to update the module. ++
|
||||||
|
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*. ++
|
||||||
|
If no interval is defined then a signal will be the only way to update the module.
|
||||||
|
|
||||||
|
*graph_type*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: line ++
|
||||||
|
The style of graph to render. One of *line*, *bar* or *gauge*.
|
||||||
|
|
||||||
|
*width*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
default: 100 ++
|
||||||
|
The width of the graph in pixels.
|
||||||
|
|
||||||
|
*datapoints*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
default: 20 ++
|
||||||
|
The number of most recent values to retain and plot on the graph.
|
||||||
|
|
||||||
|
*on-click*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when clicked on the module.
|
||||||
|
|
||||||
|
*on-click-middle*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when middle-clicked on the module using mousewheel.
|
||||||
|
|
||||||
|
*on-click-right*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when you right-click on the module.
|
||||||
|
|
||||||
|
*on-update*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when the module is updated.
|
||||||
|
|
||||||
|
*on-scroll-up*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling up on the module.
|
||||||
|
|
||||||
|
*on-scroll-down*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling down on the module.
|
||||||
|
|
||||||
|
*smooth-scrolling-threshold*: ++
|
||||||
|
typeof: double ++
|
||||||
|
Threshold to be used when scrolling.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The tooltip format. If specified, overrides any tooltip output from the script in *exec*. ++
|
||||||
|
See *FORMAT REPLACEMENTS*.
|
||||||
|
|
||||||
|
*escape*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Option to enable escaping of script output.
|
||||||
|
|
||||||
|
*menu*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Action that popups the menu.
|
||||||
|
|
||||||
|
*menu-file*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Location of the menu descriptor file. There need to be an element of type
|
||||||
|
GtkMenu with id *menu*
|
||||||
|
|
||||||
|
*menu-actions*: ++
|
||||||
|
typeof: array ++
|
||||||
|
The actions corresponding to the buttons of the menu.
|
||||||
|
|
||||||
|
*expand*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
# RETURN-TYPE
|
||||||
|
|
||||||
|
When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format.
|
||||||
|
This should look like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
{"text": "$text", "tooltip": "$tooltip", "class": "$class", "percentage": $percentage }
|
||||||
|
```
|
||||||
|
|
||||||
|
The *class* parameter also accepts an array of strings.
|
||||||
|
|
||||||
|
If nothing or an invalid option is specified, Waybar expects i3blocks style output. Values are *newline* separated.
|
||||||
|
This should look like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
$text\\n$tooltip\\n$class*
|
||||||
|
```
|
||||||
|
|
||||||
|
*class* is a CSS class, to apply different styles in *style.css*
|
||||||
|
|
||||||
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
These replacements are available in *tooltip-format*.
|
||||||
|
|
||||||
|
*{text}*: Output of the script.
|
||||||
|
|
||||||
|
*{alt}*: The *alt* value from a json return type.
|
||||||
|
|
||||||
|
*{percentage}* Percentage which can be set via a json return type.
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
## Memory:
|
||||||
|
|
||||||
|
```
|
||||||
|
"custom-graph/memory": {
|
||||||
|
"interval": 60,
|
||||||
|
"graph_type": "gauge",
|
||||||
|
"width": 52,
|
||||||
|
"exec": "/path/mem.sh",
|
||||||
|
"signal": 8,
|
||||||
|
"return-type": "json"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
mem.sh:
|
||||||
|
|
||||||
|
```
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
mem_info=$(cat /proc/meminfo)
|
||||||
|
mem_total=$(echo "$mem_info" | grep '^MemTotal:' | awk '{print $2}')
|
||||||
|
mem_available=$(echo "$mem_info" | grep '^MemAvailable:' | awk '{print $2}')
|
||||||
|
|
||||||
|
mem_used=$((mem_total - mem_available))
|
||||||
|
mem_percent=$((mem_used * 100 / mem_total))
|
||||||
|
|
||||||
|
echo "{\"text\": \"${mem_percent}%\", \"percentage\": ${mem_percent},\"tooltip\": \"Memory: ${mem_used}KB used / ${mem_total}KB total\"}'"
|
||||||
|
```
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#custom-graph-<name>*
|
||||||
|
- *#custom-graph-<name>.<class>*
|
||||||
|
- *<class>* can be set by the script. For more information see *return-type*
|
||||||
+67
-3
@@ -61,8 +61,11 @@ Addressed by *custom/<name>*
|
|||||||
The format, how information should be displayed. On {text} data gets inserted.
|
The format, how information should be displayed. On {text} data gets inserted.
|
||||||
|
|
||||||
*format-icons*: ++
|
*format-icons*: ++
|
||||||
typeof: array ++
|
typeof: array or object or string ++
|
||||||
Based on the set percentage, the corresponding icon gets selected. The order is *low* to *high*.
|
If the type is an array, then based on the set percentage, the corresponding icon gets selected (the order is *low* to *high*). ++
|
||||||
|
If the type is an object, then the icon is selected according to the *alt* string from the output. ++
|
||||||
|
If the type is a string, it is pasted as is. ++
|
||||||
|
Arrays can be nested into objects: icons are then selected first according to *alt*, then percentage.
|
||||||
|
|
||||||
*rotate*: ++
|
*rotate*: ++
|
||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
@@ -145,17 +148,36 @@ Addressed by *custom/<name>*
|
|||||||
default: false ++
|
default: false ++
|
||||||
Enables this module to consume all left over space dynamically.
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
*image-path*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Path to an image file to display in the module.
|
||||||
|
|
||||||
|
*image-name*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Name of a themed icon to display in the module.
|
||||||
|
|
||||||
|
*icon-size*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
The size (in pixels) of the image set via *image-path* or *image-name*.
|
||||||
|
|
||||||
# RETURN-TYPE
|
# RETURN-TYPE
|
||||||
|
|
||||||
When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format.
|
When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format.
|
||||||
This should look like this:
|
This should look like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
{"text": "$text", "tooltip": "$tooltip", "class": "$class", "percentage": $percentage }
|
{"text": "$text", "alt": "$alt", "tooltip": "$tooltip", "class": "$class", "percentage": $percentage }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The whole JSON object must be printed on a single line. This can be achieved by
|
||||||
|
piping the output of your script through *jq --unbuffered --compact-output*.
|
||||||
|
|
||||||
The *class* parameter also accepts an array of strings.
|
The *class* parameter also accepts an array of strings.
|
||||||
|
|
||||||
|
To have multiline tooltips, use *\\r* in your script to separate the lines. If
|
||||||
|
using PowerShell for scripting, use the standard newline operator "\`n" in double
|
||||||
|
quotes; *\\r* and *\\n* will not work.
|
||||||
|
|
||||||
If nothing or an invalid option is specified, Waybar expects i3blocks style output. Values are *newline* separated.
|
If nothing or an invalid option is specified, Waybar expects i3blocks style output. Values are *newline* separated.
|
||||||
This should look like this:
|
This should look like this:
|
||||||
|
|
||||||
@@ -167,12 +189,21 @@ $text\\n$tooltip\\n$class*
|
|||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
*{}*: Output of the script. Equivalent to *{text}*.
|
||||||
|
|
||||||
*{text}*: Output of the script.
|
*{text}*: Output of the script.
|
||||||
|
|
||||||
|
*{alt}*: The *alt* value from a json return type.
|
||||||
|
|
||||||
*{percentage}* Percentage which can be set via a json return type.
|
*{percentage}* Percentage which can be set via a json return type.
|
||||||
|
|
||||||
*{icon}*: An icon from 'format-icons' according to percentage.
|
*{icon}*: An icon from 'format-icons' according to percentage.
|
||||||
|
|
||||||
|
The *{}* placeholder is special: it automatically displays the text output of your
|
||||||
|
script, but it cannot be combined with other placeholders like *{icon}* in the same
|
||||||
|
format string. To display both an icon and text, use *{icon}* together with *{text}*
|
||||||
|
explicitly (e.g. *"format": "{icon} {text}"*).
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
## Spotify:
|
## Spotify:
|
||||||
@@ -248,3 +279,36 @@ Under the premise that interval is not defined, you can use the signal and updat
|
|||||||
- *#custom-<name>*
|
- *#custom-<name>*
|
||||||
- *#custom-<name>.<class>*
|
- *#custom-<name>.<class>*
|
||||||
- *<class>* can be set by the script. For more information see *return-type*
|
- *<class>* can be set by the script. For more information see *return-type*
|
||||||
|
- *.flat* and *.text-button* are always applied to the module's label.
|
||||||
|
- *.image-button* is always applied to the module's image (see *image-path*/*image-name*).
|
||||||
|
|
||||||
|
# CONTINUOUS SCRIPTS
|
||||||
|
|
||||||
|
The *exec* script may be continuous (i.e. contain some kind of infinite loop). The
|
||||||
|
display is updated for each new line of data printed on stdout (following the chosen
|
||||||
|
*return-type*). The *interval* option does not apply to a continuous script; use
|
||||||
|
*restart-interval* instead to restart the script if it stops after some time.
|
||||||
|
|
||||||
|
Be aware that some languages buffer their output. If your module displays nothing
|
||||||
|
even though your script works as expected, the output may be held in a buffer. Look
|
||||||
|
up how to flush the output buffer for your language of choice (for example, in Ruby
|
||||||
|
call *$stdout.flush* after each print).
|
||||||
|
|
||||||
|
# OUTPUT NAME
|
||||||
|
|
||||||
|
The *exec* script is run with the *WAYBAR_OUTPUT_NAME* environment variable set to
|
||||||
|
the name of the output (monitor) the bar is displayed on.
|
||||||
|
|
||||||
|
# TROUBLESHOOTING
|
||||||
|
|
||||||
|
*Self-looping module does not show up*
|
||||||
|
|
||||||
|
If your module is self-looping and it does not even show up in the bar, check that:
|
||||||
|
|
||||||
|
- Its configuration does *not* include an *interval* parameter.
|
||||||
|
- Output to stdout is not buffered.
|
||||||
|
|
||||||
|
*Custom json class not displayed*
|
||||||
|
|
||||||
|
If a class set in your custom script is not picked up by *style.css*, ensure that
|
||||||
|
the output carrying the most variables is emitted first.
|
||||||
|
|||||||
+61
-11
@@ -6,17 +6,12 @@ waybar - disk module
|
|||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
The *disk* module displays the current disk space used.
|
The *disk* module displays information of multiple disks.
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
Addressed by *disk*
|
Addressed by *disk*
|
||||||
|
|
||||||
*path*: ++
|
|
||||||
typeof: string ++
|
|
||||||
default: "/" ++
|
|
||||||
Any path residing in the filesystem or mountpoint for which the information should be displayed.
|
|
||||||
|
|
||||||
*interval*: ++
|
*interval*: ++
|
||||||
typeof: integer++
|
typeof: integer++
|
||||||
default: 30 ++
|
default: 30 ++
|
||||||
@@ -24,8 +19,8 @@ Addressed by *disk*
|
|||||||
|
|
||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: "{percentage_used}%" ++
|
default: "{}%" ++
|
||||||
The format, how information should be displayed.
|
The format, how information for each disk should be displayed. Note: in the default the positional field "{}" resolves to *{percentage_free}*.
|
||||||
|
|
||||||
*rotate*: ++
|
*rotate*: ++
|
||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
@@ -75,6 +70,26 @@ Addressed by *disk*
|
|||||||
typeof: string ++
|
typeof: string ++
|
||||||
Command to execute when scrolling down on the module.
|
Command to execute when scrolling down on the module.
|
||||||
|
|
||||||
|
*path*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: "/" ++
|
||||||
|
Deprecated path of filesystem or mountpoint to monitor.
|
||||||
|
|
||||||
|
*paths*: ++
|
||||||
|
typeof: array ++
|
||||||
|
default: ["/"] ++
|
||||||
|
Array of paths residing in the filesystem or mountpoint for which the information should be displayed.
|
||||||
|
|
||||||
|
*header*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: "" ++
|
||||||
|
Text to appear before the disk information defined in the format.
|
||||||
|
|
||||||
|
*separator*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: " " ++
|
||||||
|
Separator string between multiple disk information.
|
||||||
|
|
||||||
*smooth-scrolling-threshold*: ++
|
*smooth-scrolling-threshold*: ++
|
||||||
typeof: double ++
|
typeof: double ++
|
||||||
Threshold to be used when scrolling.
|
Threshold to be used when scrolling.
|
||||||
@@ -86,7 +101,7 @@ Addressed by *disk*
|
|||||||
|
|
||||||
*tooltip-format*: ++
|
*tooltip-format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: "{used} out of {total} used ({percentage_used}%)" ++
|
default: "{used} used out of {total} on {path} ({percentage_used}%)" ++
|
||||||
The format of the information displayed in the tooltip.
|
The format of the information displayed in the tooltip.
|
||||||
|
|
||||||
*unit*: ++
|
*unit*: ++
|
||||||
@@ -123,7 +138,7 @@ Addressed by *disk*
|
|||||||
|
|
||||||
*{free}*: Amount of available disk space for normal users. Automatically selects unit based on size remaining.
|
*{free}*: Amount of available disk space for normal users. Automatically selects unit based on size remaining.
|
||||||
|
|
||||||
*{path}*: The path specified in the configuration.
|
*{path}*: The path for each disk specified in the configuration.
|
||||||
|
|
||||||
*{specific_total}*: Total amount of space on the disk, partition, or mountpoint in a specific unit. Defaults to bytes.
|
*{specific_total}*: Total amount of space on the disk, partition, or mountpoint in a specific unit. Defaults to bytes.
|
||||||
|
|
||||||
@@ -131,6 +146,29 @@ Addressed by *disk*
|
|||||||
|
|
||||||
*{specific_free}*: Amount of available disk space for normal users in a specific unit. Defaults to bytes.
|
*{specific_free}*: Amount of available disk space for normal users in a specific unit. Defaults to bytes.
|
||||||
|
|
||||||
|
# NUMBER FORMAT MODIFIERS
|
||||||
|
|
||||||
|
*{total}*, *{used}* and *{free}* auto-scale with a binary prefix (KiB, GiB, …).
|
||||||
|
Their rendering can be tuned with fmt-style modifiers, e.g. *"{free:>}"* or
|
||||||
|
*"{free:G}"*, combined in any order:
|
||||||
|
|
||||||
|
*<*, *=*, *>*: Alignment/padding (left, column-align, right).
|
||||||
|
|
||||||
|
*u* / *U*: Hide (*u*) or show (*U*) the unit suffix. Shown by default with an auto
|
||||||
|
scale, hidden by default when a scale is forced.
|
||||||
|
|
||||||
|
*#*, *k*, *M*, *G*, *T*, *P*: Force a fixed scale instead of auto-selecting
|
||||||
|
(*#* = base scale). Forcing a scale hides the scale prefix and, by default, the
|
||||||
|
unit. E.g. *"{free:G}"* always shows gibibytes.
|
||||||
|
|
||||||
|
*i*: Force integer display (no decimals).
|
||||||
|
|
||||||
|
*b* / *B*: Force decimal base 1000 (*b*) or binary base 1024 (*B*); disk values
|
||||||
|
are binary by default.
|
||||||
|
|
||||||
|
A trailing number is a fixed width for the coefficient when a scale is forced;
|
||||||
|
overflow is shown as *#* characters (e.g. *"{free:=3#}"* → *###*).
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -143,10 +181,22 @@ Addressed by *disk*
|
|||||||
```
|
```
|
||||||
"disk": {
|
"disk": {
|
||||||
"interval": 30,
|
"interval": 30,
|
||||||
|
"format": "{percentage_free}% free on {path}",
|
||||||
|
"header": "Disks: ",
|
||||||
|
"paths": ["/", "/home"],
|
||||||
|
"separator": " ",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"disk": {
|
||||||
|
"interval": 30,
|
||||||
|
"paths": ["/"],
|
||||||
"format": "{specific_free:0.2f} GB out of {specific_total:0.2f} GB available. Alternatively {free} out of {total} available",
|
"format": "{specific_free:0.2f} GB out of {specific_total:0.2f} GB available. Alternatively {free} out of {total} available",
|
||||||
"unit": "GB"
|
"unit": "GB"
|
||||||
// 1434.25 GB out of 2000.00 GB available. Alternatively 1.4TiB out of 1.9TiB available.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1434.25 GB out of 2000.00 GB available. Alternatively 1.4TiB out of 1.9TiB available.
|
||||||
```
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ waybar - dwl tags module
|
|||||||
|
|
||||||
The *tags* module displays the current state of tags in dwl.
|
The *tags* module displays the current state of tags in dwl.
|
||||||
|
|
||||||
|
Using this module requires patching dwl with the IPC patch
|
||||||
|
<https://codeberg.org/dwl/dwl-patches/wiki/ipc>.
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
Addressed by *dwl/tags*
|
Addressed by *dwl/tags*
|
||||||
@@ -15,12 +18,18 @@ Addressed by *dwl/tags*
|
|||||||
*num-tags*: ++
|
*num-tags*: ++
|
||||||
typeof: uint ++
|
typeof: uint ++
|
||||||
default: 9 ++
|
default: 9 ++
|
||||||
The number of tags that should be displayed. Max 32.
|
The number of tags that should be displayed. Max 32. This should match the
|
||||||
|
number of tags configured in dwl.
|
||||||
|
|
||||||
*tag-labels*: ++
|
*tag-labels*: ++
|
||||||
typeof: array ++
|
typeof: array ++
|
||||||
The label to display for each tag.
|
The label to display for each tag.
|
||||||
|
|
||||||
|
*hide-vacant*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If set to true, tags without clients and that are not active will be hidden.
|
||||||
|
|
||||||
*disable-click*: ++
|
*disable-click*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -46,8 +55,9 @@ Addressed by *dwl/tags*
|
|||||||
- *#tags button.empty*
|
- *#tags button.empty*
|
||||||
- *#tags button.focused*
|
- *#tags button.focused*
|
||||||
- *#tags button.urgent*
|
- *#tags button.urgent*
|
||||||
|
- *#tags button.output*
|
||||||
|
|
||||||
Note that occupied/focused/urgent status may overlap. That is, a tag may be
|
Note that occupied/focused/urgent/output status may overlap. That is, a tag may be
|
||||||
both occupied and focused at the same time.
|
both occupied and focused at the same time.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|||||||
@@ -8,15 +8,28 @@ waybar - dwl window module
|
|||||||
|
|
||||||
The *window* module displays the title of the currently focused window in DWL
|
The *window* module displays the title of the currently focused window in DWL
|
||||||
|
|
||||||
|
Using this module requires patching dwl with the IPC patch
|
||||||
|
<https://codeberg.org/dwl/dwl-patches/wiki/ipc>.
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
Addressed by *dwl/window*
|
Addressed by *dwl/window*
|
||||||
|
|
||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: {title} ++
|
default: {} ++
|
||||||
The format, how information should be displayed.
|
The format, how information should be displayed.
|
||||||
|
|
||||||
|
*hide-empty*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Option to hide the module when the content would be empty.
|
||||||
|
|
||||||
|
*hide-inactive*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
Option to hide the module when the window is unfocused.
|
||||||
|
|
||||||
*rotate*: ++
|
*rotate*: ++
|
||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
Positive value to rotate the text label (in 90 degree increments).
|
Positive value to rotate the text label (in 90 degree increments).
|
||||||
@@ -109,6 +122,10 @@ If no expression matches, the format output is left unchanged.
|
|||||||
|
|
||||||
Invalid expressions (e.g., mismatched parentheses) are skipped.
|
Invalid expressions (e.g., mismatched parentheses) are skipped.
|
||||||
|
|
||||||
|
# STYLE
|
||||||
|
|
||||||
|
- *#window.active*
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ waybar - wlr workspaces module
|
|||||||
|
|
||||||
The *workspaces* module displays the currently used workspaces in wayland compositor.
|
The *workspaces* module displays the currently used workspaces in wayland compositor.
|
||||||
|
|
||||||
|
To use this module, your compositor must implement the *ext-workspace-v1*
|
||||||
|
Wayland protocol.
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
Addressed by *ext/workspaces*
|
Addressed by *ext/workspaces*
|
||||||
@@ -37,6 +40,10 @@ Addressed by *ext/workspaces*
|
|||||||
default: false ++
|
default: false ++
|
||||||
Should workspaces be sorted by ID. Workspace ID will be sorted numerically when all ID are numbers. Takes precedence over any other sort-by option.
|
Should workspaces be sorted by ID. Workspace ID will be sorted numerically when all ID are numbers. Takes precedence over any other sort-by option.
|
||||||
|
|
||||||
|
*sort-by-number*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
Deprecated alias of *sort-by-id*. Setting it emits a warning; prefer *sort-by-id*.
|
||||||
|
|
||||||
*all-outputs*: ++
|
*all-outputs*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -52,6 +59,18 @@ Addressed by *ext/workspaces*
|
|||||||
default: true ++
|
default: true ++
|
||||||
If set to false hidden workspaces will be shown.
|
If set to false hidden workspaces will be shown.
|
||||||
|
|
||||||
|
*on-click*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The action to perform on left-click. See *CLICK ACTIONS* for the possible values.
|
||||||
|
|
||||||
|
*on-click-middle*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The action to perform on middle-click. See *CLICK ACTIONS* for the possible values.
|
||||||
|
|
||||||
|
*on-click-right*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The action to perform on right-click. See *CLICK ACTIONS* for the possible values.
|
||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
*{name}*: Name of workspace assigned by compositor.
|
*{name}*: Name of workspace assigned by compositor.
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Feral Gamemode optimizations.
|
|||||||
|
|
||||||
*tooltip-format*: ++
|
*tooltip-format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: Games running: {glyph} ++
|
default: Games running: {count} ++
|
||||||
The text format of the tooltip.
|
The text format of the tooltip.
|
||||||
|
|
||||||
*hide-not-running*: ++
|
*hide-not-running*: ++
|
||||||
@@ -54,7 +54,7 @@ Feral Gamemode optimizations.
|
|||||||
*icon-size*: ++
|
*icon-size*: ++
|
||||||
typeof: unsigned integer ++
|
typeof: unsigned integer ++
|
||||||
default: 20 ++
|
default: 20 ++
|
||||||
Defines the size of the icons.
|
Defines the size of the icons. Set to *0* for auto size.
|
||||||
|
|
||||||
*icon-spacing*: ++
|
*icon-spacing*: ++
|
||||||
typeof: unsigned integer ++
|
typeof: unsigned integer ++
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ libgps lives in:
|
|||||||
|
|
||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: {glyph} ++
|
default: {mode} ++
|
||||||
The text format.
|
The text format.
|
||||||
|
|
||||||
*tooltip*: ++
|
*tooltip*: ++
|
||||||
@@ -36,7 +36,7 @@ libgps lives in:
|
|||||||
|
|
||||||
*tooltip-format*: ++
|
*tooltip-format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: Games running: {glyph} ++
|
default: The value of *format* ++
|
||||||
The text format of the tooltip.
|
The text format of the tooltip.
|
||||||
|
|
||||||
*interval*: ++
|
*interval*: ++
|
||||||
@@ -93,10 +93,10 @@ libgps lives in:
|
|||||||
"gps": {
|
"gps": {
|
||||||
"format": "{mode}",
|
"format": "{mode}",
|
||||||
"format-disabled": "", // an empty format will hide the module
|
"format-disabled": "", // an empty format will hide the module
|
||||||
"format-no-fix": "No fix",
|
"format-fix-none": "No fix",
|
||||||
"format-fix-3d": "{status}",
|
"format-fix-3d": "{status}",
|
||||||
"tooltip-format": "{mode}",
|
"tooltip-format": "{mode}",
|
||||||
"tooltip-format-no-fix": "{satellites_visible} satellites visible",
|
"tooltip-format-fix-none": "{satellites_visible} satellites visible",
|
||||||
"tooltip-format-fix-2d": "{satellites_used}/{satellites_visible} satellites used",
|
"tooltip-format-fix-2d": "{satellites_used}/{satellites_visible} satellites used",
|
||||||
"tooltip-format-fix-3d": "Altitude: {altitude_hae}m",
|
"tooltip-format-fix-3d": "Altitude: {altitude_hae}m",
|
||||||
"hide-disconnected": false
|
"hide-disconnected": false
|
||||||
@@ -106,6 +106,7 @@ libgps lives in:
|
|||||||
|
|
||||||
- *#gps*
|
- *#gps*
|
||||||
- *#gps.disabled* Applied when GPS is disabled.
|
- *#gps.disabled* Applied when GPS is disabled.
|
||||||
|
- *#gps.disconnected* Applied when no GPS receiver is present.
|
||||||
- *#gps.fix-none* Applied when GPS is present, but there is no fix.
|
- *#gps.fix-none* Applied when GPS is present, but there is no fix.
|
||||||
- *#gps.fix-2d* Applied when there is a 2D fix.
|
- *#gps.fix-2d* Applied when there is a 2D fix.
|
||||||
- *#gps.fix-3d* Applied when there is a 3D fix.
|
- *#gps.fix-3d* Applied when there is a 3D fix.
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ Addressed by *hyprland/language*
|
|||||||
typeof: string++
|
typeof: string++
|
||||||
Provide an alternative name to display per language where <lang> is the language of your choosing. Can be passed multiple times with multiple languages as shown by the example below.
|
Provide an alternative name to display per language where <lang> is the language of your choosing. Can be passed multiple times with multiple languages as shown by the example below.
|
||||||
|
|
||||||
|
*format-<lang>-<variant>* ++
|
||||||
|
typeof: string ++
|
||||||
|
Like *format-<lang>* but also matches the layout variant, taking precedence over *format-<lang>* when both the language and variant match.
|
||||||
|
|
||||||
*keyboard-name*: ++
|
*keyboard-name*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
Specifies which keyboard to use from hyprctl devices output. Using the option that begins with "at-translated-set..." is recommended.
|
Specifies which keyboard to use from hyprctl devices output. Using the option that begins with "at-translated-set..." is recommended.
|
||||||
@@ -38,6 +42,24 @@ Addressed by *hyprland/language*
|
|||||||
typeof: array ++
|
typeof: array ++
|
||||||
The actions corresponding to the buttons of the menu.
|
The actions corresponding to the buttons of the menu.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: boolean ++
|
||||||
|
default: true ++
|
||||||
|
Enables or disables the tooltip for the language module. By default, the tooltip is enabled. Set to *false* to disable.
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {long} ++
|
||||||
|
Specifies the format of the tooltip when it is enabled. It follows the same format replacement rules as the *format* key.
|
||||||
|
|
||||||
|
*tooltip-format-<lang>*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Allows specifying a different tooltip format for each language. The *<lang>* should be replaced with the language code. This can be used to provide a custom tooltip for each language.
|
||||||
|
|
||||||
|
*tooltip-format-<lang>-<variant>*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Like *tooltip-format-<lang>* but also matches the layout variant, taking precedence over *tooltip-format-<lang>* when both the language and variant match.
|
||||||
|
|
||||||
*expand*: ++
|
*expand*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -46,7 +68,7 @@ Addressed by *hyprland/language*
|
|||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
*{short}*: Short name of layout (e.g. "us"). Equals to {}.
|
*{short}*: Short name of layout (e.g. "us").
|
||||||
|
|
||||||
*{shortDescription}*: Short description of layout (e.g. "en").
|
*{shortDescription}*: Short description of layout (e.g. "en").
|
||||||
|
|
||||||
@@ -66,6 +88,29 @@ Addressed by *hyprland/language*
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"hyprland/language": {
|
||||||
|
"format": "{}",
|
||||||
|
"format-en": "US",
|
||||||
|
"format-es": "ES",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-format": "{long}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"hyprland/language": {
|
||||||
|
"format": "{}",
|
||||||
|
"format-en": "US",
|
||||||
|
"format-es": "ES",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-format": "{}",
|
||||||
|
"tooltip-format-es": "{Español}",
|
||||||
|
"tooltip-format-en": "{English (american)}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
- *#language*
|
- *#language*
|
||||||
|
- *#language.<layout>* (per-layout class derived from the layout short name, e.g. '.us')
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Addressed by *hyprland/submap*
|
|||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: {} ++
|
default: {} ++
|
||||||
The format, how information should be displayed. On {} the currently active submap is displayed.
|
The format, how information should be displayed. This format supports two placeholders: *{submap}* for the currently active submap name and *{icon}* for the icon associated with the submap.
|
||||||
|
|
||||||
*rotate*: ++
|
*rotate*: ++
|
||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
@@ -80,6 +80,10 @@ Addressed by *hyprland/submap*
|
|||||||
default: Default ++
|
default: Default ++
|
||||||
Option to set the submap name to display when not in an active submap.
|
Option to set the submap name to display when not in an active submap.
|
||||||
|
|
||||||
|
*icons*: ++
|
||||||
|
typeof: object ++
|
||||||
|
Based on the submap name, the corresponding icon will be selected from this map and made available as the *{icon}* placeholder in the format string. The keys are submap names, and the values are the icons or strings to display for those submaps.
|
||||||
|
|
||||||
*menu*: ++
|
*menu*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
Action that popups the menu.
|
Action that popups the menu.
|
||||||
@@ -103,9 +107,13 @@ Addressed by *hyprland/submap*
|
|||||||
|
|
||||||
```
|
```
|
||||||
"hyprland/submap": {
|
"hyprland/submap": {
|
||||||
"format": "✌️ {}",
|
"format": "{icon} {submap}",
|
||||||
"max-length": 8,
|
"max-length": 8,
|
||||||
"tooltip": false
|
"tooltip": false,
|
||||||
|
"icons": {
|
||||||
|
"resize": "",
|
||||||
|
"pause": "",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ Addressed by *hyprland/window*
|
|||||||
default: {title} ++
|
default: {title} ++
|
||||||
The format, how information should be displayed. On {} the current window title is displayed.
|
The format, how information should be displayed. On {} the current window title is displayed.
|
||||||
|
|
||||||
|
*max-length*: ++
|
||||||
|
typeof: integer ++
|
||||||
|
The maximum length in character the module should display.
|
||||||
|
|
||||||
*rewrite*: ++
|
*rewrite*: ++
|
||||||
typeof: object ++
|
typeof: object ++
|
||||||
Rules to rewrite window title. See *rewrite rules*.
|
Rules to rewrite window title. See *rewrite rules*.
|
||||||
@@ -25,6 +29,15 @@ Addressed by *hyprland/window*
|
|||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
Show the active window of the monitor the bar belongs to, instead of the focused window.
|
Show the active window of the monitor the bar belongs to, instead of the focused window.
|
||||||
|
|
||||||
|
*fallback*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Text to display when the focused window title is empty (for example when no window is focused).
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
The format of the tooltip shown on hover. Supports the same replacements as *format*. Requires *tooltip* to be enabled. When unset, the tooltip falls back to the formatted label text. ++
|
||||||
|
default: (the formatted label text)
|
||||||
|
|
||||||
*icon*: ++
|
*icon*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ Addressed by *hyprland/workspaces*
|
|||||||
|
|
||||||
*format*: ++
|
*format*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: {id} ++
|
default: {name} ++
|
||||||
The format, how information should be displayed.
|
The format, how information should be displayed.
|
||||||
|
|
||||||
*format-icons*: ++
|
*format-icons*: ++
|
||||||
typeof: array ++
|
typeof: object ++
|
||||||
Based on the workspace ID and state, the corresponding icon gets selected. See *icons*.
|
Based on the workspace ID and state, the corresponding icon gets selected. See *icons*.
|
||||||
|
|
||||||
*window-rewrite*: ++
|
*window-rewrite*: ++
|
||||||
@@ -41,6 +41,19 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
The separator to be used between windows in a workspace. ++
|
The separator to be used between windows in a workspace. ++
|
||||||
This setting is ignored if *workspace-taskbar.enable* is set to true.
|
This setting is ignored if *workspace-taskbar.enable* is set to true.
|
||||||
|
|
||||||
|
*window-rewrite-group-threshold*: ++
|
||||||
|
typeof: int ++
|
||||||
|
default: 0 ++
|
||||||
|
When a workspace contains at least this many windows with the same rewrite result, they are collapsed into a single one using *window-rewrite-group-format*. ++
|
||||||
|
Set to 0 to disable grouping. ++
|
||||||
|
This setting is ignored if *workspace-taskbar.enable* is set to true.
|
||||||
|
|
||||||
|
*window-rewrite-group-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: "{icon}×{count}" ++
|
||||||
|
The format used to represent a group of collapsed windows. Available placeholders are {icon} (the icon being grouped) and {count} (how many windows share it). ++
|
||||||
|
This setting is ignored if *workspace-taskbar.enable* is set to true.
|
||||||
|
|
||||||
*workspace-taskbar*: ++
|
*workspace-taskbar*: ++
|
||||||
typeof: object ++
|
typeof: object ++
|
||||||
Contains settings for the workspace taskbar, an alternative mode for the workspaces module which displays the window icons as images instead of text.
|
Contains settings for the workspace taskbar, an alternative mode for the workspaces module which displays the window icons as images instead of text.
|
||||||
@@ -75,6 +88,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
default: 16 ++
|
default: 16 ++
|
||||||
Size of the icons in the workspace taskbar.
|
Size of the icons in the workspace taskbar.
|
||||||
|
|
||||||
|
*max-icons*: ++
|
||||||
|
typeof: int ++
|
||||||
|
default: 0 (unlimited) ++
|
||||||
|
Maximum number of icons to show per workspace. When set, duplicate icons (windows with the same class) are removed first, then the list is trimmed to this limit. Set to 0 for unlimited icons.
|
||||||
|
|
||||||
*icon-theme*: ++
|
*icon-theme*: ++
|
||||||
typeof: string | array ++
|
typeof: string | array ++
|
||||||
default: [] ++
|
default: [] ++
|
||||||
@@ -98,6 +116,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
- {button} Pressed button number, see https://api.gtkd.org/gdk.c.types.GdkEventButton.button.html. ++
|
- {button} Pressed button number, see https://api.gtkd.org/gdk.c.types.GdkEventButton.button.html. ++
|
||||||
See https://github.com/Alexays/Waybar/wiki/Module:-Hyprland#workspace-taskbars-example for a full example.
|
See https://github.com/Alexays/Waybar/wiki/Module:-Hyprland#workspace-taskbars-example for a full example.
|
||||||
|
|
||||||
|
*max-windows*: ++
|
||||||
|
typeof: int ++
|
||||||
|
default: 0 (unlimited) ++
|
||||||
|
Maximum number of windows to show per workspace. When set, newest windows beyond the limit are not shown. Set to 0 for unlimited windows.
|
||||||
|
|
||||||
*show-special*: ++
|
*show-special*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -113,6 +136,12 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
default: false ++
|
default: false ++
|
||||||
If set to true, only persistent workspaces will be shown on bar.
|
If set to true, only persistent workspaces will be shown on bar.
|
||||||
|
|
||||||
|
*persistent-workspaces*: ++
|
||||||
|
typeof: object ++
|
||||||
|
default: empty ++
|
||||||
|
Lists workspaces that should always be shown, even when they do not exist. Keys are workspace names and values are arrays of output names on which the workspace should be shown (an empty array means all outputs). See the examples below. ++
|
||||||
|
Note: for persistent workspaces to actually work you must also declare them in your Hyprland config, e.g. *workspace = 1, monitor:eDP-1, persistent:true*.
|
||||||
|
|
||||||
*all-outputs*: ++
|
*all-outputs*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -123,6 +152,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
default: false ++
|
default: false ++
|
||||||
If set to true, only the active workspace will be shown.
|
If set to true, only the active workspace will be shown.
|
||||||
|
|
||||||
|
*hide-active*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If set to true, the active workspace will be hidden. Unless a workspace is persistent or special.
|
||||||
|
|
||||||
*move-to-monitor*: ++
|
*move-to-monitor*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -130,11 +164,24 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
Otherwise, the workspace will open on the monitor where it was previously assigned.
|
Otherwise, the workspace will open on the monitor where it was previously assigned.
|
||||||
Analog to using `focusworkspaceoncurrentmonitor` dispatcher instead of `workspace` in Hyprland.
|
Analog to using `focusworkspaceoncurrentmonitor` dispatcher instead of `workspace` in Hyprland.
|
||||||
|
|
||||||
|
*unique-icons*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: false ++
|
||||||
|
If set to true, only one instance of each window icon will be shown per workspace.
|
||||||
|
|
||||||
*enable-bar-scroll*: ++
|
*enable-bar-scroll*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
|
If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
|
||||||
|
|
||||||
|
*on-scroll-up*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling up on the module. This replaces the default behaviour of workspace cycling.
|
||||||
|
|
||||||
|
*on-scroll-down*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling down on the module. This replaces the default behaviour of workspace cycling.
|
||||||
|
|
||||||
*ignore-workspaces*: ++
|
*ignore-workspaces*: ++
|
||||||
typeof: array ++
|
typeof: array ++
|
||||||
default: [] ++
|
default: [] ++
|
||||||
@@ -149,6 +196,15 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
If set to special-centered, workspaces will sort by default with special workspaces in the center.
|
If set to special-centered, workspaces will sort by default with special workspaces in the center.
|
||||||
If none of those, workspaces will sort with default behavior.
|
If none of those, workspaces will sort with default behavior.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Option to disable tooltip on hover.
|
||||||
|
|
||||||
|
*tooltips*: ++
|
||||||
|
typeof: object ++
|
||||||
|
Based on the workspace ID and state, the corresponding tooltip gets selected. Selection works the same as *format-icons* do. Format replacements are supported. See *icons*.
|
||||||
|
|
||||||
*expand*: ++
|
*expand*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -162,6 +218,34 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
|
|
||||||
*{icon}*: Icon, as defined in *format-icons*.
|
*{icon}*: Icon, as defined in *format-icons*.
|
||||||
|
|
||||||
|
*{windows}*: The windows in the workspace, formatted according to *window-rewrite* and joined with *format-window-separator*.
|
||||||
|
|
||||||
|
# WINDOW REWRITE RULES
|
||||||
|
|
||||||
|
The rules in *window-rewrite* are regexes that may match against a window's
|
||||||
|
class, title, or both. There are four categories of rule, distinguished by how
|
||||||
|
they are written in the config:
|
||||||
|
|
||||||
|
[- *Rule*
|
||||||
|
:- *Category*
|
||||||
|
|[ *something*
|
||||||
|
:[ Vague
|
||||||
|
|[ *class<something>*
|
||||||
|
:[ Class-only
|
||||||
|
|[ *title<something>*
|
||||||
|
:[ Title-only
|
||||||
|
|[ *class<something1> title<something2>*
|
||||||
|
:[ Hybrid
|
||||||
|
|
||||||
|
When the config contains only "vague" rules, they are matched against window
|
||||||
|
*classes* only. This is both for backwards compatibility and for performance:
|
||||||
|
matching against the title requires listening to window title changes via
|
||||||
|
Hyprland's IPC, which is unnecessary when no title rule is in use.
|
||||||
|
|
||||||
|
When the config contains *at least one* "title-only" or "hybrid" rule, then all
|
||||||
|
"vague" rules match against *both* class and title. This lets you define vague
|
||||||
|
rules where it does not matter whether the class or the title matched.
|
||||||
|
|
||||||
# ICONS
|
# ICONS
|
||||||
|
|
||||||
Additional to workspace name matching, the following *format-icons* can be set.
|
Additional to workspace name matching, the following *format-icons* can be set.
|
||||||
@@ -172,6 +256,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||||||
- *empty*: Will be shown on non-active, non-special empty persistent workspaces
|
- *empty*: Will be shown on non-active, non-special empty persistent workspaces
|
||||||
- *visible*: Will be shown on workspaces that are visible but not active. For example: this is useful if you want your visible workspaces on other monitors to have the same look as active.
|
- *visible*: Will be shown on workspaces that are visible but not active. For example: this is useful if you want your visible workspaces on other monitors to have the same look as active.
|
||||||
- *persistent*: Will be shown on non-empty persistent workspaces
|
- *persistent*: Will be shown on non-empty persistent workspaces
|
||||||
|
- *urgent*: Will be shown on non-active urgent workspaces
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
@@ -238,6 +323,51 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"hyprland/workspaces": {
|
||||||
|
"format": "{icon}",
|
||||||
|
"format-window-separator": ", ",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltips": {
|
||||||
|
"default": "{name}: {windows}",
|
||||||
|
"empty": "" // Will result in no tooltip
|
||||||
|
}
|
||||||
|
"format-icons": {
|
||||||
|
"1": "",
|
||||||
|
"2": "",
|
||||||
|
"3": "",
|
||||||
|
"4": "",
|
||||||
|
"5": "",
|
||||||
|
"active": "",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
// Window rewrites omitted for brevity
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"hyprland/workspaces": {
|
||||||
|
"format": "{icon}",
|
||||||
|
"format-window-separator": ", ",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltips": {
|
||||||
|
"1": "This is the first workspace",
|
||||||
|
"2": "This is the second",
|
||||||
|
"2": "And this is the third"
|
||||||
|
}
|
||||||
|
"format-icons": {
|
||||||
|
"1": "",
|
||||||
|
"2": "",
|
||||||
|
"3": "",
|
||||||
|
"4": "",
|
||||||
|
"5": "",
|
||||||
|
"active": "",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
// Window rewrites omitted for brevity
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# Style
|
# Style
|
||||||
|
|
||||||
- *#workspaces*
|
- *#workspaces*
|
||||||
@@ -248,6 +378,8 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||||||
- *#workspaces button.persistent*
|
- *#workspaces button.persistent*
|
||||||
- *#workspaces button.special*
|
- *#workspaces button.special*
|
||||||
- *#workspaces button.urgent*
|
- *#workspaces button.urgent*
|
||||||
|
- *#workspaces button.workspace-hover* (applied while the pointer is over the button)
|
||||||
|
- *#workspaces button.<workspace-name>* (per-workspace class derived from the workspace name, sanitized to a valid CSS class name, e.g. a workspace named "1" yields '.ws-1'; special workspaces also get the raw name class)
|
||||||
- *#workspaces button.hosting-monitor* (gets applied if workspace-monitor == waybar-monitor)
|
- *#workspaces button.hosting-monitor* (gets applied if workspace-monitor == waybar-monitor)
|
||||||
- *#workspaces .workspace-label*
|
- *#workspaces .workspace-label*
|
||||||
- *#workspaces .taskbar-window* (each window in the taskbar, only if 'workspace-taskbar.enable' is true)
|
- *#workspaces .taskbar-window* (each window in the taskbar, only if 'workspace-taskbar.enable' is true)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user