conflict
This commit is contained in:
12
.github/workflows/clang-format.yml
vendored
12
.github/workflows/clang-format.yml
vendored
@@ -10,13 +10,9 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
# TODO: bump to clang 19 release
|
||||
# - uses: DoozyX/clang-format-lint-action@v0.18.2
|
||||
- uses: DoozyX/clang-format-lint-action@558090054b3f39e3d6af24f0cd73b319535da809
|
||||
- uses: actions/checkout@v6
|
||||
- uses: RafikFarhad/clang-format-github-action@v6
|
||||
name: clang-format
|
||||
with:
|
||||
source: "."
|
||||
extensions: "hpp,h,cpp,c"
|
||||
style: "file:.clang-format"
|
||||
clangFormatVersion: 19
|
||||
sources: "src/**/*.hpp,src/**/*.cpp"
|
||||
style: "file"
|
||||
|
||||
2
.github/workflows/clang-tidy.yml.bak
vendored
2
.github/workflows/clang-tidy.yml.bak
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
container:
|
||||
image: alexays/waybar:debian
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
- name: configure
|
||||
run: |
|
||||
meson -Dcpp_std=c++20 build # necessary to generate compile_commands.json
|
||||
|
||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
|
||||
2
.github/workflows/freebsd.yml
vendored
2
.github/workflows/freebsd.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
- name: Test in FreeBSD VM
|
||||
uses: cross-platform-actions/action@v0.28.0
|
||||
timeout-minutes: 180
|
||||
|
||||
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
image: alexays/waybar:${{ matrix.distro }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
- name: configure
|
||||
run: meson setup -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build
|
||||
- name: build
|
||||
|
||||
7
.github/workflows/nix-tests.yml
vendored
7
.github/workflows/nix-tests.yml
vendored
@@ -2,12 +2,15 @@ name: "Nix-Tests"
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-nix-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
nix-flake-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v27
|
||||
- uses: actions/checkout@v6
|
||||
- uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
|
||||
6
.github/workflows/nix-update-flake-lock.yml
vendored
6
.github/workflows/nix-update-flake-lock.yml
vendored
@@ -12,11 +12,11 @@ jobs:
|
||||
if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Update flake.lock
|
||||
uses: DeterminateSystems/update-flake-lock@v21
|
||||
uses: DeterminateSystems/update-flake-lock@v28
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,6 +7,7 @@ vgcore.*
|
||||
*.swp
|
||||
packagecache
|
||||
/subprojects/**/
|
||||
/subprojects/.wraplock
|
||||
/build*
|
||||
/dist
|
||||
/meson.egg-info
|
||||
@@ -50,3 +51,4 @@ result
|
||||
result-*
|
||||
|
||||
.ccls-cache
|
||||
_codeql_detected_source_root
|
||||
|
||||
@@ -119,7 +119,7 @@ sudo apt install \
|
||||
On Arch, you can use this command:
|
||||
|
||||
```
|
||||
pacman -S \
|
||||
pacman -S --asdeps \
|
||||
gtkmm3 \
|
||||
jsoncpp \
|
||||
libsigc++ \
|
||||
@@ -151,6 +151,10 @@ Contributions welcome!<br>
|
||||
Have fun :)<br>
|
||||
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
|
||||
|
||||
> [!CAUTION]
|
||||
> 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.
|
||||
|
||||
## License
|
||||
|
||||
Waybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/Alexays/Waybar/blob/master/LICENSE).
|
||||
|
||||
1
_codeql_detected_source_root
Symbolic link
1
_codeql_detected_source_root
Symbolic link
@@ -0,0 +1 @@
|
||||
.
|
||||
12
flake.lock
generated
12
flake.lock
generated
@@ -3,11 +3,11 @@
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"lastModified": 1767039857,
|
||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1760878510,
|
||||
"narHash": "sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs=",
|
||||
"lastModified": 1769461804,
|
||||
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5e2a59a5b1a82f89f2c7e598302a9cacebb72a67",
|
||||
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -56,6 +56,8 @@ class Client {
|
||||
std::list<struct waybar_output> outputs_;
|
||||
std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
|
||||
std::string m_cssFile;
|
||||
sigc::connection monitor_added_connection_;
|
||||
sigc::connection monitor_removed_connection_;
|
||||
};
|
||||
|
||||
} // namespace waybar
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#if defined(__linux__)
|
||||
#include <sys/inotify.h>
|
||||
#endif
|
||||
#include <poll.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
@@ -15,6 +16,7 @@
|
||||
#include "ALabel.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#include "util/udev_deleter.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
@@ -37,15 +39,17 @@ class Battery : public ALabel {
|
||||
void setBarClass(std::string&);
|
||||
void processEvents(std::string& state, std::string& status, uint8_t capacity);
|
||||
|
||||
int global_watch;
|
||||
std::map<fs::path, int> batteries_;
|
||||
std::unique_ptr<udev, util::UdevDeleter> udev_;
|
||||
std::array<pollfd, 1> poll_fds_;
|
||||
std::unique_ptr<udev_monitor, util::UdevMonitorDeleter> mon_;
|
||||
fs::path adapter_;
|
||||
int battery_watch_fd_;
|
||||
int global_watch_fd_;
|
||||
std::mutex battery_list_mutex_;
|
||||
std::string old_status_;
|
||||
std::string last_event_;
|
||||
bool warnFirstTime_{true};
|
||||
bool weightedAverage_{true};
|
||||
const Bar& bar_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
|
||||
43
include/modules/cava/cavaGLSL.hpp
Normal file
43
include/modules/cava/cavaGLSL.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "cava_backend.hpp"
|
||||
|
||||
namespace waybar::modules::cava {
|
||||
|
||||
class CavaGLSL final : public AModule, public Gtk::GLArea {
|
||||
public:
|
||||
CavaGLSL(const std::string&, const Json::Value&);
|
||||
~CavaGLSL() = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr<CavaBackend> backend_;
|
||||
struct ::cava::config_params prm_;
|
||||
int frame_counter{0};
|
||||
bool silence_{false};
|
||||
bool hide_on_silence_{false};
|
||||
// Cava method
|
||||
auto onUpdate(const ::cava::audio_raw& input) -> void;
|
||||
auto onSilence() -> void;
|
||||
// Member variable to store the shared pointer
|
||||
std::shared_ptr<::cava::audio_raw> m_data_;
|
||||
GLuint shaderProgram_;
|
||||
// OpenGL variables
|
||||
GLuint fbo_;
|
||||
GLuint texture_;
|
||||
GLint uniform_bars_;
|
||||
GLint uniform_previous_bars_;
|
||||
GLint uniform_bars_count_;
|
||||
GLint uniform_time_;
|
||||
// Methods
|
||||
void onRealize();
|
||||
bool onRender(const Glib::RefPtr<Gdk::GLContext>& context);
|
||||
|
||||
void initShaders();
|
||||
void initSurface();
|
||||
void initGLSL();
|
||||
GLuint loadShader(const std::string& fileName, GLenum type);
|
||||
};
|
||||
} // namespace waybar::modules::cava
|
||||
@@ -9,20 +9,20 @@ class Cava final : public ALabel, public sigc::trackable {
|
||||
public:
|
||||
Cava(const std::string&, const Json::Value&);
|
||||
~Cava() = default;
|
||||
auto onUpdate(const std::string& input) -> void;
|
||||
auto onSilence() -> void;
|
||||
auto doAction(const std::string& name) -> void override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<CavaBackend> backend_;
|
||||
// Text to display
|
||||
std::string label_text_{""};
|
||||
Glib::ustring label_text_{""};
|
||||
bool silence_{false};
|
||||
bool hide_on_silence_{false};
|
||||
std::string format_silent_{""};
|
||||
int ascii_range_{0};
|
||||
bool silence_{false};
|
||||
// Cava method
|
||||
void pause_resume();
|
||||
auto onUpdate(const std::string& input) -> void;
|
||||
auto onSilence() -> void;
|
||||
// ModuleActionMap
|
||||
static inline std::map<const std::string, void (waybar::modules::cava::Cava::* const)()>
|
||||
actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}};
|
||||
@@ -32,16 +32,22 @@ class CavaBackend final {
|
||||
int getAsciiRange();
|
||||
void doPauseResume();
|
||||
void Update();
|
||||
const struct ::cava::config_params* getPrm();
|
||||
std::chrono::milliseconds getFrameTimeMilsec();
|
||||
|
||||
// Signal accessor
|
||||
using type_signal_update = sigc::signal<void(const std::string&)>;
|
||||
type_signal_update signal_update();
|
||||
using type_signal_audio_raw_update = sigc::signal<void(const ::cava::audio_raw&)>;
|
||||
type_signal_audio_raw_update signal_audio_raw_update();
|
||||
using type_signal_silence = sigc::signal<void()>;
|
||||
type_signal_silence signal_silence();
|
||||
|
||||
private:
|
||||
CavaBackend(const Json::Value& config);
|
||||
util::SleeperThread thread_;
|
||||
util::SleeperThread read_thread_;
|
||||
util::SleeperThread out_thread_;
|
||||
|
||||
// Cava API to read audio source
|
||||
::cava::ptr input_source_{NULL};
|
||||
|
||||
@@ -55,6 +61,7 @@ class CavaBackend final {
|
||||
// Delay to handle audio source
|
||||
std::chrono::milliseconds frame_time_milsec_{1s};
|
||||
|
||||
const Json::Value& config_;
|
||||
int re_paint_{0};
|
||||
bool silence_{false};
|
||||
bool silence_prev_{false};
|
||||
@@ -66,9 +73,12 @@ class CavaBackend final {
|
||||
void execute();
|
||||
bool isSilence();
|
||||
void doUpdate(bool force = false);
|
||||
void loadConfig();
|
||||
void freeBackend();
|
||||
|
||||
// Signal
|
||||
type_signal_update m_signal_update_;
|
||||
type_signal_audio_raw_update m_signal_audio_raw_;
|
||||
type_signal_silence m_signal_silence_;
|
||||
};
|
||||
} // namespace waybar::modules::cava
|
||||
|
||||
27
include/modules/cava/cava_frontend.hpp
Normal file
27
include/modules/cava/cava_frontend.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef HAVE_LIBCAVA
|
||||
#include "cavaRaw.hpp"
|
||||
#include "cava_backend.hpp"
|
||||
#ifdef HAVE_LIBCAVAGLSL
|
||||
#include "cavaGLSL.hpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace waybar::modules::cava {
|
||||
AModule* getModule(const std::string& id, const Json::Value& config) {
|
||||
#ifdef HAVE_LIBCAVA
|
||||
const std::shared_ptr<CavaBackend> backend_{waybar::modules::cava::CavaBackend::inst(config)};
|
||||
switch (backend_->getPrm()->output) {
|
||||
#ifdef HAVE_LIBCAVAGLSL
|
||||
case ::cava::output_method::OUTPUT_SDL_GLSL:
|
||||
return new waybar::modules::cava::CavaGLSL(id, config);
|
||||
#endif
|
||||
default:
|
||||
return new waybar::modules::cava::Cava(id, config);
|
||||
}
|
||||
#else
|
||||
throw std::runtime_error("Unknown module");
|
||||
#endif
|
||||
};
|
||||
} // namespace waybar::modules::cava
|
||||
@@ -26,6 +26,7 @@ class Submap : public waybar::ALabel, public EventHandler {
|
||||
const Bar& bar_;
|
||||
util::JsonParser parser_;
|
||||
std::string submap_;
|
||||
std::string prev_submap_;
|
||||
bool always_on_ = false;
|
||||
std::string default_submap_ = "Default";
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ class Workspaces : public AModule, public EventHandler {
|
||||
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
|
||||
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
|
||||
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
|
||||
auto barScroll() const -> bool { return m_barScroll; }
|
||||
|
||||
auto getBarOutput() const -> std::string { return m_bar.output->name; }
|
||||
auto formatBefore() const -> std::string { return m_formatBefore; }
|
||||
@@ -122,6 +123,8 @@ class Workspaces : public AModule, public EventHandler {
|
||||
static std::pair<std::string, std::string> splitDoublePayload(std::string const& payload);
|
||||
static std::tuple<std::string, std::string, std::string> splitTriplePayload(
|
||||
std::string const& payload);
|
||||
// scroll events
|
||||
bool handleScroll(GdkEventScroll* e) override;
|
||||
|
||||
// Update methods
|
||||
void doUpdate();
|
||||
@@ -145,6 +148,7 @@ class Workspaces : public AModule, public EventHandler {
|
||||
bool m_specialVisibleOnly = false;
|
||||
bool m_persistentOnly = false;
|
||||
bool m_moveToMonitor = false;
|
||||
bool m_barScroll = false;
|
||||
Json::Value m_persistentWorkspaceConfig;
|
||||
|
||||
// Map for windows stored in workspaces not present in the current bar.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <fmt/chrono.h>
|
||||
#include <gtkmm/label.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -41,6 +42,7 @@ class KeyboardState : public AModule {
|
||||
|
||||
struct libinput* libinput_;
|
||||
std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
|
||||
std::mutex devices_mutex_; // protects libinput_devices_
|
||||
std::set<int> binding_keys;
|
||||
|
||||
util::SleeperThread libinput_thread_, hotplug_thread_;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "ipc.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#include "util/SafeSignal.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
@@ -27,8 +28,8 @@ class Ipc {
|
||||
std::string payload;
|
||||
};
|
||||
|
||||
sigc::signal<void, const struct ipc_response &> signal_event;
|
||||
sigc::signal<void, const struct ipc_response &> signal_cmd;
|
||||
::waybar::SafeSignal<const struct ipc_response&> signal_event;
|
||||
::waybar::SafeSignal<const struct ipc_response&> signal_cmd;
|
||||
|
||||
void sendCmd(uint32_t type, const std::string& payload = "");
|
||||
void subscribe(const std::string& payload);
|
||||
|
||||
@@ -33,8 +33,8 @@ class Taskbar;
|
||||
|
||||
class Task {
|
||||
public:
|
||||
Task(const waybar::Bar &, const Json::Value &, Taskbar *,
|
||||
struct zwlr_foreign_toplevel_handle_v1 *, struct wl_seat *);
|
||||
Task(const waybar::Bar&, const Json::Value&, Taskbar*, struct zwlr_foreign_toplevel_handle_v1*,
|
||||
struct wl_seat*);
|
||||
~Task();
|
||||
|
||||
public:
|
||||
|
||||
@@ -109,7 +109,7 @@ inline FILE* open(const std::string& cmd, int& pid, const std::string& output_na
|
||||
::close(fd[0]);
|
||||
dup2(fd[1], 1);
|
||||
setpgid(child_pid, child_pid);
|
||||
if (output_name != "") {
|
||||
if (!output_name.empty()) {
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
@@ -138,7 +138,7 @@ inline struct res execNoRead(const std::string& cmd) {
|
||||
return {WEXITSTATUS(stat), ""};
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) {
|
||||
inline int32_t forkExec(const std::string& cmd, const std::string& output_name) {
|
||||
if (cmd == "") return -1;
|
||||
|
||||
pid_t pid = fork();
|
||||
@@ -157,6 +157,9 @@ inline int32_t forkExec(const std::string& cmd) {
|
||||
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
|
||||
if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err));
|
||||
setpgid(pid, pid);
|
||||
if (!output_name.empty()) {
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
} else {
|
||||
@@ -169,4 +172,6 @@ inline int32_t forkExec(const std::string& cmd) {
|
||||
return pid;
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) { return forkExec(cmd, ""); }
|
||||
|
||||
} // namespace waybar::util::command
|
||||
|
||||
@@ -30,15 +30,16 @@ class JsonParser {
|
||||
|
||||
std::istringstream jsonStream(modifiedJsonStr);
|
||||
std::string errs;
|
||||
if (!Json::parseFromStream(m_readerBuilder, jsonStream, &root, &errs)) {
|
||||
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
||||
// parser can be called concurrently from multiple module threads
|
||||
Json::CharReaderBuilder readerBuilder;
|
||||
if (!Json::parseFromStream(readerBuilder, jsonStream, &root, &errs)) {
|
||||
throw std::runtime_error("Error parsing JSON: " + errs);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
private:
|
||||
Json::CharReaderBuilder m_readerBuilder;
|
||||
|
||||
static std::string replaceHexadecimalEscape(const std::string& str) {
|
||||
static std::regex re("\\\\x");
|
||||
return std::regex_replace(str, re, "\\u00");
|
||||
|
||||
21
include/util/udev_deleter.hpp
Normal file
21
include/util/udev_deleter.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
namespace waybar::util {
|
||||
struct UdevDeleter {
|
||||
void operator()(udev* ptr) const { udev_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevDeviceDeleter {
|
||||
void operator()(udev_device* ptr) const { udev_device_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevEnumerateDeleter {
|
||||
void operator()(udev_enumerate* ptr) const { udev_enumerate_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevMonitorDeleter {
|
||||
void operator()(udev_monitor* ptr) const { udev_monitor_unref(ptr); }
|
||||
};
|
||||
} // namespace waybar::util
|
||||
@@ -91,6 +91,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*weighted-average*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to combine multiple batteries with different capacities.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
@@ -177,6 +182,7 @@ Every entry in the *events* object consists of a *<event-name>* (typeof: *string
|
||||
|
||||
- *on-<status>-<state>*
|
||||
- *on-<status>-<capacity>*
|
||||
- *on-<status>*
|
||||
|
||||
Where:
|
||||
|
||||
@@ -198,7 +204,9 @@ Where:
|
||||
"events": {
|
||||
"on-discharging-warning": "notify-send -u normal 'Low Battery'",
|
||||
"on-discharging-critical": "notify-send -u critical 'Very Low Battery'",
|
||||
"on-charging-100": "notify-send -u normal 'Battery Full!'"
|
||||
"on-charging-100": "notify-send -u normal 'Battery Full!'",
|
||||
"on-discharging": "notify-send -u normal 'Power Switch' Discharging",
|
||||
"on-charging": "notify-send -u normal 'Power Switch' Charging'"
|
||||
},
|
||||
"format": "{capacity}% {icon}",
|
||||
"format-icons": ["", "", "", "", ""],
|
||||
|
||||
@@ -8,6 +8,8 @@ waybar - cava module
|
||||
|
||||
*cava* module for karlstav/cava project. See it on github: https://github.com/karlstav/cava.
|
||||
|
||||
Module supports two different frontends starting from the 0.15.0 release. The frontend that
|
||||
will be used is managed by the method parameter in the [output] section of the cava configuration file.
|
||||
|
||||
# FILES
|
||||
|
||||
@@ -32,6 +34,10 @@ libcava lives in:
|
||||
:[ string
|
||||
:[
|
||||
:< Path where cava configuration file is placed to
|
||||
|[ *method* \[output\]
|
||||
:[ string
|
||||
:[
|
||||
:< Manages which frontend Waybar cava module should use. Values: raw, sdl_glsl
|
||||
|[ *framerate*
|
||||
:[ integer
|
||||
:[ 30
|
||||
@@ -43,7 +49,7 @@ libcava lives in:
|
||||
|[ *sensitivity*
|
||||
:[ integer
|
||||
:[ 100
|
||||
:[ Manual sensitivity in %. It's recommended to be omitted when *autosens* = 1
|
||||
:[ Manual sensitivity in %. If autosens is enabled, this will only be the initial value. 200 means double height. Accepts only non-negative values
|
||||
|[ *bars*
|
||||
:[ integer
|
||||
:[ 12
|
||||
@@ -68,7 +74,7 @@ libcava lives in:
|
||||
:[ string
|
||||
:[
|
||||
:[ Widget's text after sleep_timer elapsed (hide_on_silence has to be false)
|
||||
|[ *method*
|
||||
|[ *method* \[input\]
|
||||
:[ string
|
||||
:[ pulse
|
||||
:[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem
|
||||
@@ -105,9 +111,9 @@ libcava lives in:
|
||||
:[ false
|
||||
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|
||||
|[ *noise_reduction*
|
||||
:[ double
|
||||
:[ 0.77
|
||||
:[ Range between 0 - 1. The raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth. 1 - will be very slow and smooth, 0 - will be fast but noisy
|
||||
:[ integer
|
||||
:[ 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
|
||||
|[ *input_delay*
|
||||
:[ integer
|
||||
:[ 2
|
||||
@@ -119,11 +125,11 @@ libcava lives in:
|
||||
|[ *data_format*
|
||||
:[ string
|
||||
:[ asci
|
||||
:[ It's impossible to set it. Waybar sets it to = asci for internal needs
|
||||
:[ Raw data format. Can be 'binary' or 'ascii'
|
||||
|[ *raw_target*
|
||||
:[ string
|
||||
:[ /dev/stdout
|
||||
:[ It's impossible to set it. Waybar sets it to = /dev/stdout for internal needs
|
||||
:[ Raw output target. A fifo will be created if target does not exist
|
||||
|[ *menu*
|
||||
:[ string
|
||||
:[
|
||||
@@ -136,6 +142,50 @@ libcava lives in:
|
||||
:[ array
|
||||
:[
|
||||
:[ The actions corresponding to the buttons of the menu.
|
||||
|[ *bar_spacing*
|
||||
:[ integer
|
||||
:[
|
||||
:[ Bars' space between bars in number of characters
|
||||
|[ *bar_width*
|
||||
:[ integer
|
||||
:[
|
||||
:[ Bars' width between bars in number of characters
|
||||
|[ *bar_height*
|
||||
:[ integer
|
||||
:[
|
||||
:[ Useless. bar_height is only used for output in "noritake" format
|
||||
|[ *background*
|
||||
:[ string
|
||||
:[
|
||||
:[ GLSL actual. Support hex code colors only. Must be within ''
|
||||
|[ *foreground*
|
||||
:[ string
|
||||
:[
|
||||
:[ GLSL actual. Support hex code colors only. Must be within ''
|
||||
|[ *gradient*
|
||||
:[ integer
|
||||
:[ 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 ''
|
||||
|[ *sdl_width*
|
||||
:[ integer
|
||||
:[
|
||||
:[ GLSL actual. Manages the width of the waybar cava GLSL frontend module
|
||||
|[ *sdl_height*
|
||||
:[ integer
|
||||
:[
|
||||
:[ GLSL actual. Manages the height of the waybar cava GLSL frontend module
|
||||
|[ *continuous_rendering*
|
||||
:[ integer
|
||||
:[ 0
|
||||
:[ GLSL actual. Keep rendering even if no audio. Recommended to set to 1
|
||||
|
||||
Configuration can be provided as:
|
||||
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped
|
||||
@@ -153,6 +203,7 @@ Configuration can be provided as:
|
||||
|
||||
- iniparser
|
||||
- fftw3
|
||||
- epoxy (GLSL frontend only)
|
||||
|
||||
# SOLVING ISSUES
|
||||
|
||||
@@ -205,3 +256,453 @@ In case when cava releases new version and you're wanna get it, it should be rai
|
||||
- *#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
|
||||
```
|
||||
## Configuration file for CAVA.
|
||||
# Remove the ; to change parameters.
|
||||
|
||||
|
||||
[general]
|
||||
|
||||
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
|
||||
|
||||
# Accepts only non-negative values.
|
||||
|
||||
# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off
|
||||
# new as of 0.6.0 autosens of low values (dynamic range)
|
||||
# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0
|
||||
|
||||
# Manual sensitivity in %. If autosens is enabled, this will only be the initial value.
|
||||
# 200 means double height. Accepts only non-negative values.
|
||||
|
||||
# The number of bars (0-512). 0 sets it to auto (fill up console).
|
||||
# Bars' width and space between bars in number of characters.
|
||||
bars = 12
|
||||
# bar_height is only used for output in "noritake" format
|
||||
|
||||
# For SDL width and space between bars is in pixels, defaults are:
|
||||
|
||||
# sdl_glsl have these default values, they are only used to calculate max number of bars.
|
||||
|
||||
|
||||
# Lower and higher cutoff frequencies for lowest and highest bars
|
||||
# the bandwidth of the visualizer.
|
||||
# Note: there is a minimum total bandwidth of 43Mhz x number of bars.
|
||||
# Cava will automatically increase the higher cutoff if a too low band is specified.
|
||||
|
||||
# Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and
|
||||
# only check for input once per second. Cava will wake up once input is detected. 0 = disable.
|
||||
sleep_timer = 5
|
||||
|
||||
|
||||
[input]
|
||||
|
||||
# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem'
|
||||
# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with.
|
||||
# On Mac it defaults to 'portaudio' or 'fifo'
|
||||
# On windows this is automatic and no input settings are needed.
|
||||
#
|
||||
# All input methods uses the same config variable 'source'
|
||||
# to define where it should get the audio.
|
||||
#
|
||||
# For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink
|
||||
# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them).
|
||||
#
|
||||
# For pipewire 'source' will be the object name or object.serial of the device to capture from.
|
||||
# Both input and output devices are supported.
|
||||
#
|
||||
# For alsa 'source' will be the capture device.
|
||||
# For fifo 'source' will be the path to fifo-file.
|
||||
# For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address
|
||||
#
|
||||
# For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'.
|
||||
# README.md contains further information on how to setup CAVA for sndio.
|
||||
#
|
||||
# For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device.
|
||||
# README.md contains further information on how to setup CAVA for OSS on FreeBSD.
|
||||
#
|
||||
# For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'.
|
||||
# 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:
|
||||
# sample_rate: fifo, pipewire, sndio, oss
|
||||
# sample_bits: fifo, pipewire, sndio, oss
|
||||
# channels: sndio, oss, jack
|
||||
# autoconnect: jack
|
||||
# Other methods ignore these settings.
|
||||
#
|
||||
# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported
|
||||
# by the chosen audio device, the device will use other supported values instead.
|
||||
# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it
|
||||
# will use 44100, 16 and 1.
|
||||
#
|
||||
|
||||
|
||||
[output]
|
||||
|
||||
# Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl'
|
||||
# or 'sdl_glsl'.
|
||||
# 'noncurses' (default) uses a buffer and cursor movements to only print
|
||||
# changes from frame to frame in the terminal. Uses less resources and is less
|
||||
# prone to tearing (vsync issues) than 'ncurses'.
|
||||
#
|
||||
# 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data
|
||||
# stream of the bar heights that can be used to send to other applications.
|
||||
# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above.
|
||||
#
|
||||
# 'noritake' outputs a bitmap in the format expected by a Noritake VFD display
|
||||
# in graphic mode. It only support the 3000 series graphical VFDs for now.
|
||||
#
|
||||
# 'sdl' uses the Simple DirectMedia Layer to render in a graphical context.
|
||||
# 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or
|
||||
# use one of the predefined ones.
|
||||
method = raw
|
||||
|
||||
# Orientation of the visualization. Can be 'bottom', 'top', 'left', 'right' or
|
||||
# 'horizontal'. Default is 'bottom'. 'left and 'right' are only supported on sdl
|
||||
# and ncruses output. 'horizontal' (bars go up and down from center) is only supported
|
||||
# on noncurses output.
|
||||
# Note: many fonts have weird or missing glyphs for characters used in orientations
|
||||
# other than 'bottom', which can make output not look right.
|
||||
|
||||
# Visual channels. Can be 'stereo' or 'mono'.
|
||||
# 'stereo' mirrors both channels with low frequencies in center.
|
||||
# 'mono' outputs left to right lowest to highest frequencies.
|
||||
# 'mono_option' set mono to either take input from 'left', 'right' or 'average'.
|
||||
# set 'reverse' to 1 to display frequencies the other way around.
|
||||
|
||||
# Raw output target. A fifo will be created if target does not exist.
|
||||
raw_target = /dev/stdout
|
||||
|
||||
# Raw data format. Can be 'binary' or 'ascii'.
|
||||
data_format = ascii
|
||||
|
||||
# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530).
|
||||
|
||||
# Ascii max value. In 'ascii' mode range will run from 0 to value specified here
|
||||
|
||||
# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters.
|
||||
# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)).
|
||||
bar_delimiter = 0
|
||||
|
||||
# sdl window size and position. -1,-1 is centered.
|
||||
|
||||
# set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none'
|
||||
# 'frequency' displays the lower cut off frequency of the bar above.
|
||||
# Only supported on ncurses and noncurses output.
|
||||
|
||||
# enable synchronized sync. 1 = on, 0 = off
|
||||
# removes flickering in alacritty terminal emulator.
|
||||
# defaults to off since the behaviour in other terminal emulators is unknown
|
||||
|
||||
# Shaders for sdl_glsl, located in $HOME/.config/cava/shaders
|
||||
|
||||
; for glsl output mode, keep rendering even if no audio
|
||||
|
||||
# disable console blank (screen saver) in tty
|
||||
# (Not supported on FreeBSD)
|
||||
|
||||
# show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off
|
||||
|
||||
# show waveform instead of frequency spectrum, 1 = on, 0 = off
|
||||
|
||||
[color]
|
||||
|
||||
# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow.
|
||||
# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires
|
||||
# a terminal that can change color definitions such as Gnome-terminal or rxvt.
|
||||
# default is to keep current terminal color
|
||||
|
||||
# SDL and sdl_glsl only support hex code colors, these are the default:
|
||||
|
||||
# Gradient mode, only hex defined colors are supported,
|
||||
# background must also be defined in hex or remain commented out. 1 = on, 0 = off.
|
||||
# You can define as many as 8 different colors. They range from bottom to top of screen
|
||||
|
||||
[smoothing]
|
||||
|
||||
# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable.
|
||||
|
||||
# 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
|
||||
# 100 will be very slow and smooth, 0 will be fast but noisy.
|
||||
|
||||
|
||||
[eq]
|
||||
|
||||
# This one is tricky. You can have as much keys as you want.
|
||||
# Remember to uncomment more than one key! More keys = more precision.
|
||||
# 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:
|
||||
|
||||
. epoxy library must be installed on the system
|
||||
. 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:
|
||||
|
||||
. bars. The more values the parameter has, the more interesting the visualization becomes.
|
||||
. 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.
|
||||
. Shaders for sdl_glsl, located in $HOME/.config/cava/shaders. Example: "vertex_shader" = "pass_through.vert" "fragment_shader" = "spectrogram.frag"
|
||||
. Set continuous_rendering to 1 to enable smooth rendering; set it to 0 otherwise. It is recommended to keep it set to 1.
|
||||
. background, foreground, and gradient_color_N (where N is a number between 1 and 8) must be defined using hex code
|
||||
|
||||
Example:
|
||||
|
||||
waybar config
|
||||
```
|
||||
"cava": {
|
||||
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_cava#3.conf",
|
||||
"input_delay": 2,
|
||||
"actions": {
|
||||
"on-click-right": "mode"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
waybar_raw.conf
|
||||
```
|
||||
## Configuration file for CAVA.
|
||||
# Remove the ; to change parameters.
|
||||
|
||||
|
||||
[general]
|
||||
|
||||
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
|
||||
|
||||
# Accepts only non-negative values.
|
||||
|
||||
# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off
|
||||
# new as of 0.6.0 autosens of low values (dynamic range)
|
||||
# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0
|
||||
|
||||
# Manual sensitivity in %. If autosens is enabled, this will only be the initial value.
|
||||
# 200 means double height. Accepts only non-negative values.
|
||||
|
||||
# The number of bars (0-512). 0 sets it to auto (fill up console).
|
||||
# Bars' width and space between bars in number of characters.
|
||||
bars = 50
|
||||
|
||||
# bar_height is only used for output in "noritake" format
|
||||
|
||||
# For SDL width and space between bars is in pixels, defaults are:
|
||||
|
||||
# sdl_glsl have these default values, they are only used to calculate max number of bars.
|
||||
|
||||
# Lower and higher cutoff frequencies for lowest and highest bars
|
||||
# the bandwidth of the visualizer.
|
||||
# Note: there is a minimum total bandwidth of 43Mhz x number of bars.
|
||||
# Cava will automatically increase the higher cutoff if a too low band is specified.
|
||||
|
||||
# Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and
|
||||
# only check for input once per second. Cava will wake up once input is detected. 0 = disable.
|
||||
sleep_timer = 5
|
||||
|
||||
|
||||
[input]
|
||||
|
||||
# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem'
|
||||
# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with.
|
||||
# On Mac it defaults to 'portaudio' or 'fifo'
|
||||
# On windows this is automatic and no input settings are needed.
|
||||
#
|
||||
# All input methods uses the same config variable 'source'
|
||||
# to define where it should get the audio.
|
||||
#
|
||||
# For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink
|
||||
# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them).
|
||||
#
|
||||
# For pipewire 'source' will be the object name or object.serial of the device to capture from.
|
||||
# Both input and output devices are supported.
|
||||
#
|
||||
# For alsa 'source' will be the capture device.
|
||||
# For fifo 'source' will be the path to fifo-file.
|
||||
# For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address
|
||||
#
|
||||
# For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'.
|
||||
# README.md contains further information on how to setup CAVA for sndio.
|
||||
#
|
||||
# For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device.
|
||||
# README.md contains further information on how to setup CAVA for OSS on FreeBSD.
|
||||
#
|
||||
# For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'.
|
||||
# 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:
|
||||
# sample_rate: fifo, pipewire, sndio, oss
|
||||
# sample_bits: fifo, pipewire, sndio, oss
|
||||
# channels: sndio, oss, jack
|
||||
# autoconnect: jack
|
||||
# Other methods ignore these settings.
|
||||
#
|
||||
# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported
|
||||
# by the chosen audio device, the device will use other supported values instead.
|
||||
# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it
|
||||
# will use 44100, 16 and 1.
|
||||
#
|
||||
|
||||
|
||||
[output]
|
||||
|
||||
# Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl'
|
||||
# or 'sdl_glsl'.
|
||||
# 'noncurses' (default) uses a buffer and cursor movements to only print
|
||||
# changes from frame to frame in the terminal. Uses less resources and is less
|
||||
# prone to tearing (vsync issues) than 'ncurses'.
|
||||
#
|
||||
# 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data
|
||||
# stream of the bar heights that can be used to send to other applications.
|
||||
# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above.
|
||||
#
|
||||
# 'noritake' outputs a bitmap in the format expected by a Noritake VFD display
|
||||
# in graphic mode. It only support the 3000 series graphical VFDs for now.
|
||||
#
|
||||
# 'sdl' uses the Simple DirectMedia Layer to render in a graphical context.
|
||||
# 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or
|
||||
# use one of the predefined ones.
|
||||
method = sdl_glsl
|
||||
|
||||
# Orientation of the visualization. Can be 'bottom', 'top', 'left', 'right' or
|
||||
# 'horizontal'. Default is 'bottom'. 'left and 'right' are only supported on sdl
|
||||
# and ncruses output. 'horizontal' (bars go up and down from center) is only supported
|
||||
# on noncurses output.
|
||||
# Note: many fonts have weird or missing glyphs for characters used in orientations
|
||||
# other than 'bottom', which can make output not look right.
|
||||
|
||||
# Visual channels. Can be 'stereo' or 'mono'.
|
||||
# 'stereo' mirrors both channels with low frequencies in center.
|
||||
# 'mono' outputs left to right lowest to highest frequencies.
|
||||
# 'mono_option' set mono to either take input from 'left', 'right' or 'average'.
|
||||
# set 'reverse' to 1 to display frequencies the other way around.
|
||||
|
||||
# Raw output target. A fifo will be created if target does not exist.
|
||||
|
||||
# Raw data format. Can be 'binary' or 'ascii'.
|
||||
|
||||
# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530).
|
||||
|
||||
# Ascii max value. In 'ascii' mode range will run from 0 to value specified here
|
||||
|
||||
# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters.
|
||||
# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)).
|
||||
bar_delimiter = 0
|
||||
|
||||
# sdl window size and position. -1,-1 is centered.
|
||||
sdl_width = 150
|
||||
sdl_height = 39
|
||||
|
||||
# set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none'
|
||||
# 'frequency' displays the lower cut off frequency of the bar above.
|
||||
# Only supported on ncurses and noncurses output.
|
||||
|
||||
# enable synchronized sync. 1 = on, 0 = off
|
||||
# removes flickering in alacritty terminal emulator.
|
||||
# defaults to off since the behaviour in other terminal emulators is unknown
|
||||
|
||||
# Shaders for sdl_glsl, located in $HOME/.config/cava/shaders
|
||||
vertex_shader = pass_through.vert
|
||||
fragment_shader = bar_spectrum.frag
|
||||
|
||||
; for glsl output mode, keep rendering even if no audio
|
||||
continuous_rendering = 1;
|
||||
|
||||
# disable console blank (screen saver) in tty
|
||||
# (Not supported on FreeBSD)
|
||||
|
||||
# show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off
|
||||
|
||||
# show waveform instead of frequency spectrum, 1 = on, 0 = off
|
||||
|
||||
[color]
|
||||
|
||||
|
||||
# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow.
|
||||
# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires
|
||||
# a terminal that can change color definitions such as Gnome-terminal or rxvt.
|
||||
# default is to keep current terminal color
|
||||
|
||||
# SDL and sdl_glsl only support hex code colors, these are the default:
|
||||
background = '#282C34'
|
||||
|
||||
# Gradient mode, only hex defined colors are supported,
|
||||
# background must also be defined in hex or remain commented out. 1 = on, 0 = off.
|
||||
# You can define as many as 8 different colors. They range from bottom to top of screen
|
||||
gradient = 1
|
||||
gradient_count = 2
|
||||
gradient_color_1 = '#282C34'
|
||||
gradient_color_2 = '#45475A'
|
||||
|
||||
; gradient_color_1 = '#59cc33'
|
||||
; gradient_color_2 = '#80cc33'
|
||||
gradient_color_3 = '#a6cc33'
|
||||
gradient_color_4 = '#cccc33'
|
||||
gradient_color_5 = '#cca633'
|
||||
gradient_color_6 = '#cc8033'
|
||||
gradient_color_7 = '#cc5933'
|
||||
gradient_color_8 = '#cc3333'
|
||||
|
||||
[smoothing]
|
||||
|
||||
# Percentage value for integral smoothing. Takes values from 0 - 100.
|
||||
# Higher values means smoother, but less precise. 0 to disable.
|
||||
# DEPRECATED as of 0.8.0, use noise_reduction instead
|
||||
|
||||
# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable.
|
||||
|
||||
# Set gravity percentage for "drop off". Higher values means bars will drop faster.
|
||||
# Accepts only non-negative values. 50 means half gravity, 200 means double. Set to 0 to disable "drop off".
|
||||
# DEPRECATED as of 0.8.0, use noise_reduction instead
|
||||
|
||||
|
||||
# In bar height, bars that would have been lower that this will not be drawn.
|
||||
# DEPRECATED as of 0.8.0
|
||||
|
||||
# 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
|
||||
# 100 will be very slow and smooth, 0 will be fast but noisy.
|
||||
|
||||
[eq]
|
||||
|
||||
# This one is tricky. You can have as much keys as you want.
|
||||
# Remember to uncomment more than one key! More keys = more precision.
|
||||
# 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)
|
||||
|
||||
@@ -234,7 +234,6 @@ $text\\n$tooltip\\n$class*
|
||||
```
|
||||
"custom/pacman": {
|
||||
"format": "{text} ",
|
||||
"interval": 3600, // every hour
|
||||
"exec": "checkupdates | wc -l", // # of updates
|
||||
"exec-if": "exit 0", // always run; consider advanced run conditions
|
||||
"on-click": "termite -e 'sudo pacman -Syu'; pkill -SIGRTMIN+8 waybar", // update system
|
||||
@@ -242,7 +241,7 @@ $text\\n$tooltip\\n$class*
|
||||
}
|
||||
```
|
||||
|
||||
You can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*.
|
||||
Under the premise that interval is not defined, you can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*.
|
||||
|
||||
# STYLE
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ Addressed by *dwl/tags*
|
||||
|
||||
- *#tags button*
|
||||
- *#tags button.occupied*
|
||||
- *#tags button.empty*
|
||||
- *#tags button.focused*
|
||||
- *#tags button.urgent*
|
||||
|
||||
|
||||
@@ -130,6 +130,11 @@ 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.
|
||||
Analog to using `focusworkspaceoncurrentmonitor` dispatcher instead of `workspace` in Hyprland.
|
||||
|
||||
*enable-bar-scroll*: ++
|
||||
typeof: bool ++
|
||||
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.
|
||||
|
||||
*ignore-workspaces*: ++
|
||||
typeof: array ++
|
||||
default: [] ++
|
||||
|
||||
@@ -26,7 +26,8 @@ The *image* module displays an image from a path.
|
||||
*interval*: ++
|
||||
typeof: integer or float ++
|
||||
The interval (in seconds) to re-render the image. ++
|
||||
Minimum value is 0.001 (1ms). Values smaller than 1ms will be set to 1ms. ++
|
||||
If set to a positive value, the minimum is 0.001 (1ms). Values smaller than 1ms will be set to 1ms. ++
|
||||
Zero or negative values are treated as "once". ++
|
||||
This is useful if the contents of *path* changes. ++
|
||||
If no *interval* is defined, the image will only be rendered once.
|
||||
|
||||
|
||||
@@ -97,7 +97,11 @@ Additionally, you can control the volume by scrolling *up* or *down* while the c
|
||||
|
||||
*reverse-scrolling*: ++
|
||||
typeof: bool ++
|
||||
Option to reverse the scroll direction.
|
||||
Option to reverse the scroll direction for touchpads.
|
||||
|
||||
*reverse-mouse-scrolling*: ++
|
||||
typeof: bool ++
|
||||
Option to reverse the scroll direction for mice.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
@@ -173,8 +177,8 @@ to be selected when the corresponding audio device is muted. This applies to *de
|
||||
"format-icons": {
|
||||
"alsa_output.pci-0000_00_1f.3.analog-stereo": "",
|
||||
"alsa_output.pci-0000_00_1f.3.analog-stereo-muted": "",
|
||||
"headphones": "",
|
||||
"handsfree": "",
|
||||
"headphone": "",
|
||||
"hands-free": "",
|
||||
"headset": "",
|
||||
"phone": "",
|
||||
"phone-muted": "",
|
||||
|
||||
@@ -179,7 +179,6 @@ n.b.: the list of outputs can be obtained from command line using *swaymsg -t ge
|
||||
"format": "<span size='larger'>{name}</span> {windows}",
|
||||
"format-window-separator": " | ",
|
||||
"window-rewrite-default": "{name}",
|
||||
"window-format": "<span color='#e0e0e0'>{name}</span>",
|
||||
"window-rewrite": {
|
||||
"class<firefox>": "",
|
||||
"class<kitty>": "k",
|
||||
|
||||
@@ -36,7 +36,7 @@ The visual display elements for waybar use a CSS stylesheet, see *waybar-styles(
|
||||
*expand-right* ++
|
||||
typeof: bool ++
|
||||
default: false ++
|
||||
Enables the modules-left to consume all left over space dynamically.
|
||||
Enables the modules-right to consume all left over space dynamically.
|
||||
|
||||
*layer* ++
|
||||
typeof: string ++
|
||||
|
||||
19
meson.build
19
meson.build
@@ -1,6 +1,6 @@
|
||||
project(
|
||||
'waybar', 'cpp', 'c',
|
||||
version: '0.14.0',
|
||||
version: '0.15.0',
|
||||
license: 'MIT',
|
||||
meson_version: '>= 0.59.0',
|
||||
default_options : [
|
||||
@@ -497,16 +497,24 @@ else
|
||||
man_files += files('man/waybar-clock.5.scd')
|
||||
endif
|
||||
|
||||
cava = dependency('cava',
|
||||
version : '>=0.10.6',
|
||||
cava = dependency('libcava',
|
||||
version : '>=0.10.7',
|
||||
required: get_option('cava'),
|
||||
fallback : ['cava', 'cava_dep'],
|
||||
fallback : ['libcava', 'cava_dep'],
|
||||
not_found_message: 'cava is not found. Building waybar without cava')
|
||||
|
||||
eproxy = dependency('epoxy', required: false)
|
||||
|
||||
if cava.found()
|
||||
add_project_arguments('-DHAVE_LIBCAVA', language: 'cpp')
|
||||
src_files += files('src/modules/cava/cava.cpp', 'src/modules/cava/cava_backend.cpp')
|
||||
src_files += files('src/modules/cava/cavaRaw.cpp',
|
||||
'src/modules/cava/cava_backend.cpp')
|
||||
man_files += files('man/waybar-cava.5.scd')
|
||||
|
||||
if eproxy.found()
|
||||
add_project_arguments('-DHAVE_LIBCAVAGLSL', language: 'cpp')
|
||||
src_files += files('src/modules/cava/cavaGLSL.cpp')
|
||||
endif
|
||||
endif
|
||||
|
||||
if libgps.found()
|
||||
@@ -554,6 +562,7 @@ executable(
|
||||
tz_dep,
|
||||
xkbregistry,
|
||||
cava,
|
||||
eproxy,
|
||||
libgps
|
||||
],
|
||||
include_directories: inc_dirs,
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
version,
|
||||
}:
|
||||
let
|
||||
libcava = {
|
||||
libcava = rec {
|
||||
version = "0.10.7-beta";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "LukashonakV";
|
||||
repo = "cava";
|
||||
# NOTE: Needs to match the cava.wrap
|
||||
rev = "23efcced43b5a395747b18a2e5f2171fc0925d18";
|
||||
hash = "sha256-CNspaoK5KuME0GfaNijpC24BfALngzNi04/VNwPqMvo=";
|
||||
tag = "v${version}";
|
||||
hash = "sha256-IX1B375gTwVDRjpRfwKGuzTAZOV2pgDWzUd4bW2cTDU=";
|
||||
};
|
||||
};
|
||||
in
|
||||
@@ -39,7 +40,7 @@ waybar.overrideAttrs (oldAttrs: {
|
||||
|
||||
postUnpack = ''
|
||||
pushd "$sourceRoot"
|
||||
cp -R --no-preserve=mode,ownership ${libcava.src} subprojects/cava
|
||||
cp -R --no-preserve=mode,ownership ${libcava.src} subprojects/cava-${libcava.version}
|
||||
patchShebangs .
|
||||
popd
|
||||
'';
|
||||
|
||||
@@ -151,7 +151,7 @@ void AAppIconLabel::updateAppIconName(const std::string& app_identifier,
|
||||
}
|
||||
|
||||
void AAppIconLabel::updateAppIcon() {
|
||||
if (update_app_icon_) {
|
||||
if (update_app_icon_ || (!iconEnabled() && image_.get_visible())) {
|
||||
update_app_icon_ = false;
|
||||
if (app_icon_name_.empty()) {
|
||||
image_.set_visible(false);
|
||||
|
||||
@@ -190,7 +190,7 @@ bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
|
||||
}
|
||||
|
||||
void ALabel::handleGtkMenuEvent(GtkMenuItem* /*menuitem*/, gpointer data) {
|
||||
waybar::util::command::res res = waybar::util::command::exec((char*)data, "GtkMenu");
|
||||
waybar::util::command::forkExec((char*)data, "GtkMenu");
|
||||
}
|
||||
|
||||
std::string ALabel::getState(uint8_t value, bool lesser) {
|
||||
|
||||
@@ -229,7 +229,8 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||
gtk_layer_init_for_window(gtk_window);
|
||||
gtk_layer_set_keyboard_mode(gtk_window, GTK_LAYER_SHELL_KEYBOARD_MODE_NONE);
|
||||
gtk_layer_set_monitor(gtk_window, output->monitor->gobj());
|
||||
gtk_layer_set_namespace(gtk_window, "waybar");
|
||||
gtk_layer_set_namespace(gtk_window,
|
||||
config["name"].isString() ? config["name"].asCString() : "waybar");
|
||||
|
||||
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, margins_.left);
|
||||
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right);
|
||||
|
||||
@@ -219,13 +219,22 @@ void waybar::Client::bindInterfaces() {
|
||||
if (xdg_output_manager == nullptr) {
|
||||
throw std::runtime_error("Failed to acquire required resources.");
|
||||
}
|
||||
|
||||
// Disconnect previous signal handlers to prevent duplicate handlers on reload
|
||||
monitor_added_connection_.disconnect();
|
||||
monitor_removed_connection_.disconnect();
|
||||
|
||||
// Clear stale outputs from previous run
|
||||
outputs_.clear();
|
||||
|
||||
// add existing outputs and subscribe to updates
|
||||
for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) {
|
||||
auto monitor = gdk_display->get_monitor(i);
|
||||
handleMonitorAdded(monitor);
|
||||
}
|
||||
gdk_display->signal_monitor_added().connect(sigc::mem_fun(*this, &Client::handleMonitorAdded));
|
||||
gdk_display->signal_monitor_removed().connect(
|
||||
monitor_added_connection_ = gdk_display->signal_monitor_added().connect(
|
||||
sigc::mem_fun(*this, &Client::handleMonitorAdded));
|
||||
monitor_removed_connection_ = gdk_display->signal_monitor_removed().connect(
|
||||
sigc::mem_fun(*this, &Client::handleMonitorRemoved));
|
||||
}
|
||||
|
||||
|
||||
@@ -108,15 +108,13 @@
|
||||
#ifdef HAVE_LIBWIREPLUMBER
|
||||
#include "modules/wireplumber.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBCAVA
|
||||
#include "modules/cava/cava.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_SYSTEMD_MONITOR
|
||||
#include "modules/systemd_failed_units.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBGPS
|
||||
#include "modules/gps.hpp"
|
||||
#endif
|
||||
#include "modules/cava/cava_frontend.hpp"
|
||||
#include "modules/cffi.hpp"
|
||||
#include "modules/custom.hpp"
|
||||
#include "modules/image.hpp"
|
||||
@@ -341,11 +339,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
||||
return new waybar::modules::Wireplumber(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBCAVA
|
||||
if (ref == "cava") {
|
||||
return new waybar::modules::cava::Cava(id, config_[name]);
|
||||
return waybar::modules::cava::getModule(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SYSTEMD_MONITOR
|
||||
if (ref == "systemd-failed-units") {
|
||||
return new waybar::modules::SystemdFailedUnits(id, config_[name]);
|
||||
|
||||
@@ -26,7 +26,7 @@ Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical) {
|
||||
|
||||
Group::Group(const std::string& name, const std::string& id, const Json::Value& config,
|
||||
bool vertical)
|
||||
: AModule(config, name, id, true, true),
|
||||
: AModule(config, name, id, true, false),
|
||||
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
|
||||
revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
|
||||
box.set_name(name_);
|
||||
|
||||
@@ -58,11 +58,11 @@ auto waybar::modules::Backlight::update() -> void {
|
||||
tooltip_format = config_["tooltip-format"].asString();
|
||||
}
|
||||
if (!tooltip_format.empty()) {
|
||||
label_.set_tooltip_text(fmt::format(fmt::runtime(tooltip_format),
|
||||
label_.set_tooltip_markup(fmt::format(fmt::runtime(tooltip_format),
|
||||
fmt::arg("percent", percent),
|
||||
fmt::arg("icon", getIcon(percent))));
|
||||
} else {
|
||||
label_.set_tooltip_text(desc);
|
||||
label_.set_tooltip_markup(desc);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <libudev.h>
|
||||
#include <poll.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
waybar::modules::Battery::Battery(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||
: ALabel(config, "battery", id, "{capacity}%", 60), last_event_(""), bar_(bar) {
|
||||
@@ -16,17 +19,21 @@ waybar::modules::Battery::Battery(const std::string& id, const Bar& bar, const J
|
||||
if (battery_watch_fd_ == -1) {
|
||||
throw std::runtime_error("Unable to listen batteries.");
|
||||
}
|
||||
|
||||
global_watch_fd_ = inotify_init1(IN_CLOEXEC);
|
||||
if (global_watch_fd_ == -1) {
|
||||
throw std::runtime_error("Unable to listen batteries.");
|
||||
udev_ = std::unique_ptr<udev, util::UdevDeleter>(udev_new());
|
||||
if (udev_ == nullptr) {
|
||||
throw std::runtime_error("udev_new failed");
|
||||
}
|
||||
|
||||
// Watch the directory for any added or removed batteries
|
||||
global_watch = inotify_add_watch(global_watch_fd_, data_dir_.c_str(), IN_CREATE | IN_DELETE);
|
||||
if (global_watch < 0) {
|
||||
throw std::runtime_error("Could not watch for battery plug/unplug");
|
||||
mon_ = std::unique_ptr<udev_monitor, util::UdevMonitorDeleter>(
|
||||
udev_monitor_new_from_netlink(udev_.get(), "kernel"));
|
||||
if (mon_ == nullptr) {
|
||||
throw std::runtime_error("udev monitor new failed");
|
||||
}
|
||||
if (udev_monitor_filter_add_match_subsystem_devtype(mon_.get(), "power_supply", nullptr) < 0) {
|
||||
throw std::runtime_error("udev failed to add monitor filter");
|
||||
}
|
||||
udev_monitor_enable_receiving(mon_.get());
|
||||
|
||||
if (config_["weighted-average"].isBool()) weightedAverage_ = config_["weighted-average"].asBool();
|
||||
#endif
|
||||
spdlog::debug("battery: worker interval is {}", interval_.count());
|
||||
worker();
|
||||
@@ -36,11 +43,6 @@ waybar::modules::Battery::~Battery() {
|
||||
#if defined(__linux__)
|
||||
std::lock_guard<std::mutex> guard(battery_list_mutex_);
|
||||
|
||||
if (global_watch >= 0) {
|
||||
inotify_rm_watch(global_watch_fd_, global_watch);
|
||||
}
|
||||
close(global_watch_fd_);
|
||||
|
||||
for (auto it = batteries_.cbegin(), next_it = it; it != batteries_.cend(); it = next_it) {
|
||||
++next_it;
|
||||
auto watch_id = (*it).second;
|
||||
@@ -77,12 +79,18 @@ void waybar::modules::Battery::worker() {
|
||||
dp.emit();
|
||||
};
|
||||
thread_battery_update_ = [this] {
|
||||
struct inotify_event event = {0};
|
||||
int nbytes = read(global_watch_fd_, &event, sizeof(event));
|
||||
if (nbytes != sizeof(event) || event.mask & IN_IGNORED) {
|
||||
poll_fds_[0].revents = 0;
|
||||
poll_fds_[0].events = POLLIN;
|
||||
poll_fds_[0].fd = udev_monitor_get_fd(mon_.get());
|
||||
int ret = poll(poll_fds_.data(), poll_fds_.size(), -1);
|
||||
if (ret < 0) {
|
||||
thread_.stop();
|
||||
return;
|
||||
}
|
||||
if ((poll_fds_[0].revents & POLLIN) != 0) {
|
||||
signalfd_siginfo signal_info;
|
||||
read(poll_fds_[0].fd, &signal_info, sizeof(signal_info));
|
||||
}
|
||||
refreshBatteries();
|
||||
dp.emit();
|
||||
};
|
||||
@@ -585,8 +593,7 @@ waybar::modules::Battery::getInfos() {
|
||||
}
|
||||
|
||||
// Handle weighted-average
|
||||
if ((config_["weighted-average"].isBool() ? config_["weighted-average"].asBool() : false) &&
|
||||
total_energy_exists && total_energy_full_exists) {
|
||||
if (weightedAverage_ && total_energy_exists && total_energy_full_exists) {
|
||||
if (total_energy_full > 0.0f)
|
||||
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
|
||||
}
|
||||
@@ -679,6 +686,7 @@ auto waybar::modules::Battery::update() -> void {
|
||||
status = getAdapterStatus(capacity);
|
||||
}
|
||||
auto status_pretty = status;
|
||||
|
||||
// Transform to lowercase and replace space with dash
|
||||
std::ranges::transform(status.begin(), status.end(), status.begin(),
|
||||
[](char ch) { return ch == ' ' ? '-' : std::tolower(ch); });
|
||||
@@ -782,16 +790,19 @@ void waybar::modules::Battery::processEvents(std::string& state, std::string& st
|
||||
if (!events.isObject() || events.empty()) {
|
||||
return;
|
||||
}
|
||||
std::string event_name = fmt::format("on-{}-{}", status == "discharging" ? status : "charging",
|
||||
state.empty() ? std::to_string(capacity) : state);
|
||||
auto exec = [](Json::Value const& event) {
|
||||
if (!event.isString()) return;
|
||||
if (auto command = event.asString(); !command.empty()) {
|
||||
util::command::exec(command, "");
|
||||
}
|
||||
};
|
||||
std::string status_name = status == "discharging" ? "on-discharging" : "on-charging";
|
||||
std::string event_name = status_name + '-' + (state.empty() ? std::to_string(capacity) : state);
|
||||
if (last_event_ != event_name) {
|
||||
spdlog::debug("battery: triggering event {}", event_name);
|
||||
if (events[event_name].isString()) {
|
||||
std::string exec = events[event_name].asString();
|
||||
// Execute the command if it is not empty
|
||||
if (!exec.empty()) {
|
||||
util::command::exec(exec, "");
|
||||
}
|
||||
exec(events[event_name]);
|
||||
if (!last_event_.empty() && last_event_[3] != event_name[3]) {
|
||||
exec(events[status_name]);
|
||||
}
|
||||
last_event_ = event_name;
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ auto waybar::modules::Bluetooth::update() -> void {
|
||||
device_enumerate_.erase(0, 1);
|
||||
}
|
||||
}
|
||||
label_.set_tooltip_text(fmt::format(
|
||||
label_.set_tooltip_markup(fmt::format(
|
||||
fmt::runtime(tooltip_format), fmt::arg("status", state_),
|
||||
fmt::arg("num_connections", connected_devices_.size()),
|
||||
fmt::arg("controller_address", cur_controller_ ? cur_controller_->address : "null"),
|
||||
|
||||
271
src/modules/cava/cavaGLSL.cpp
Normal file
271
src/modules/cava/cavaGLSL.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
#include "modules/cava/cavaGLSL.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
waybar::modules::cava::CavaGLSL::CavaGLSL(const std::string& id, const Json::Value& config)
|
||||
: AModule(config, "cavaGLSL", id, false, false),
|
||||
backend_{waybar::modules::cava::CavaBackend::inst(config)} {
|
||||
set_name(name_);
|
||||
if (config_["hide_on_silence"].isBool()) hide_on_silence_ = config_["hide_on_silence"].asBool();
|
||||
if (!id.empty()) {
|
||||
get_style_context()->add_class(id);
|
||||
}
|
||||
get_style_context()->add_class(MODULE_CLASS);
|
||||
|
||||
set_use_es(true);
|
||||
// set_auto_render(true);
|
||||
signal_realize().connect(sigc::mem_fun(*this, &CavaGLSL::onRealize));
|
||||
signal_render().connect(sigc::mem_fun(*this, &CavaGLSL::onRender), false);
|
||||
|
||||
// Get parameters_config struct from the backend
|
||||
prm_ = *backend_->getPrm();
|
||||
|
||||
// Set widget length
|
||||
int length{0};
|
||||
if (config_["min-length"].isUInt())
|
||||
length = config_["min-length"].asUInt();
|
||||
else if (config_["max-length"].isUInt())
|
||||
length = config_["max-length"].asUInt();
|
||||
else
|
||||
length = prm_.sdl_width;
|
||||
|
||||
set_size_request(length, prm_.sdl_height);
|
||||
|
||||
// Subscribe for changes
|
||||
backend_->signal_audio_raw_update().connect(sigc::mem_fun(*this, &CavaGLSL::onUpdate));
|
||||
// Subscribe for silence
|
||||
backend_->signal_silence().connect(sigc::mem_fun(*this, &CavaGLSL::onSilence));
|
||||
event_box_.add(*this);
|
||||
}
|
||||
|
||||
auto waybar::modules::cava::CavaGLSL::onUpdate(const ::cava::audio_raw& input) -> void {
|
||||
Glib::signal_idle().connect_once([this, input]() {
|
||||
m_data_ = std::make_shared<::cava::audio_raw>(input);
|
||||
if (silence_) {
|
||||
get_style_context()->remove_class("silent");
|
||||
if (!get_style_context()->has_class("updated")) get_style_context()->add_class("updated");
|
||||
show();
|
||||
silence_ = false;
|
||||
}
|
||||
|
||||
queue_render();
|
||||
});
|
||||
}
|
||||
|
||||
auto waybar::modules::cava::CavaGLSL::onSilence() -> void {
|
||||
Glib::signal_idle().connect_once([this]() {
|
||||
if (!silence_) {
|
||||
if (get_style_context()->has_class("updated")) get_style_context()->remove_class("updated");
|
||||
|
||||
if (hide_on_silence_) hide();
|
||||
silence_ = true;
|
||||
get_style_context()->add_class("silent");
|
||||
// Set clear color to black
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
queue_render();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool waybar::modules::cava::CavaGLSL::onRender(const Glib::RefPtr<Gdk::GLContext>& context) {
|
||||
if (!m_data_) return true;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
glUniform1i(glGetUniformLocation(shaderProgram_, "inputTexture"), 0);
|
||||
|
||||
glUniform1fv(uniform_bars_, m_data_->number_of_bars, m_data_->bars_raw);
|
||||
glUniform1fv(uniform_previous_bars_, m_data_->number_of_bars, m_data_->previous_bars_raw);
|
||||
glUniform1i(uniform_bars_count_, m_data_->number_of_bars);
|
||||
++frame_counter;
|
||||
glUniform1f(uniform_time_, (frame_counter / backend_->getFrameTimeMilsec().count()) / 1e3);
|
||||
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, nullptr);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, nullptr);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::onRealize() {
|
||||
make_current();
|
||||
initShaders();
|
||||
initGLSL();
|
||||
initSurface();
|
||||
}
|
||||
|
||||
struct colors {
|
||||
uint16_t R;
|
||||
uint16_t G;
|
||||
uint16_t B;
|
||||
};
|
||||
|
||||
static void parse_color(char* color_string, struct colors* color) {
|
||||
if (color_string[0] == '#') {
|
||||
sscanf(++color_string, "%02hx%02hx%02hx", &color->R, &color->G, &color->B);
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::initGLSL() {
|
||||
GLint gVertexPos2DLocation{glGetAttribLocation(shaderProgram_, "vertexPosition_modelspace")};
|
||||
if (gVertexPos2DLocation == -1) {
|
||||
spdlog::error("{0}. Could not find vertex position shader variable", name_);
|
||||
}
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
GLfloat vertexData[]{-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
|
||||
GLint indexData[]{0, 1, 2, 3};
|
||||
|
||||
GLuint gVBO{0};
|
||||
glGenBuffers(1, &gVBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), vertexData, GL_STATIC_DRAW);
|
||||
|
||||
GLuint gIBO{0};
|
||||
glGenBuffers(1, &gIBO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLuint), indexData, GL_STATIC_DRAW);
|
||||
|
||||
GLuint gVAO{0};
|
||||
glGenVertexArrays(1, &gVAO);
|
||||
glBindVertexArray(gVAO);
|
||||
glEnableVertexAttribArray(gVertexPos2DLocation);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gVBO);
|
||||
glVertexAttribPointer(gVertexPos2DLocation, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIBO);
|
||||
|
||||
glGenFramebuffers(1, &fbo_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
|
||||
// Create a texture to attach the framebuffer
|
||||
glGenTextures(1, &texture_);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, prm_.sdl_width, prm_.sdl_height, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
|
||||
|
||||
// Check is framebuffer is complete
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
spdlog::error("{0}. Framebuffer not complete", name_);
|
||||
}
|
||||
|
||||
// Unbind the framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
uniform_bars_ = glGetUniformLocation(shaderProgram_, "bars");
|
||||
uniform_previous_bars_ = glGetUniformLocation(shaderProgram_, "previous_bars");
|
||||
uniform_bars_count_ = glGetUniformLocation(shaderProgram_, "bars_count");
|
||||
uniform_time_ = glGetUniformLocation(shaderProgram_, "shader_time");
|
||||
|
||||
GLuint err{glGetError()};
|
||||
if (err != 0) {
|
||||
spdlog::error("{0}. Error on initGLSL: {1}", name_, err);
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::initSurface() {
|
||||
colors color = {0};
|
||||
GLint uniform_bg_col{glGetUniformLocation(shaderProgram_, "bg_color")};
|
||||
parse_color(prm_.bcolor, &color);
|
||||
glUniform3f(uniform_bg_col, (float)color.R / 255.0, (float)color.G / 255.0,
|
||||
(float)color.B / 255.0);
|
||||
GLint uniform_fg_col{glGetUniformLocation(shaderProgram_, "fg_color")};
|
||||
parse_color(prm_.color, &color);
|
||||
glUniform3f(uniform_fg_col, (float)color.R / 255.0, (float)color.G / 255.0,
|
||||
(float)color.B / 255.0);
|
||||
GLint uniform_res{glGetUniformLocation(shaderProgram_, "u_resolution")};
|
||||
glUniform3f(uniform_res, (float)prm_.sdl_width, (float)prm_.sdl_height, 0.0f);
|
||||
GLint uniform_bar_width{glGetUniformLocation(shaderProgram_, "bar_width")};
|
||||
glUniform1i(uniform_bar_width, prm_.bar_width);
|
||||
GLint uniform_bar_spacing{glGetUniformLocation(shaderProgram_, "bar_spacing")};
|
||||
glUniform1i(uniform_bar_spacing, prm_.bar_spacing);
|
||||
GLint uniform_gradient_count{glGetUniformLocation(shaderProgram_, "gradient_count")};
|
||||
glUniform1i(uniform_gradient_count, prm_.gradient_count);
|
||||
GLint uniform_gradient_colors{glGetUniformLocation(shaderProgram_, "gradient_colors")};
|
||||
GLfloat gradient_colors[8][3];
|
||||
for (int i{0}; i < prm_.gradient_count; ++i) {
|
||||
parse_color(prm_.gradient_colors[i], &color);
|
||||
gradient_colors[i][0] = (float)color.R / 255.0;
|
||||
gradient_colors[i][1] = (float)color.G / 255.0;
|
||||
gradient_colors[i][2] = (float)color.B / 255.0;
|
||||
}
|
||||
glUniform3fv(uniform_gradient_colors, 8, (const GLfloat*)gradient_colors);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::initShaders() {
|
||||
shaderProgram_ = glCreateProgram();
|
||||
|
||||
GLuint vertexShader{loadShader(prm_.vertex_shader, GL_VERTEX_SHADER)};
|
||||
GLuint fragmentShader{loadShader(prm_.fragment_shader, GL_FRAGMENT_SHADER)};
|
||||
|
||||
glAttachShader(shaderProgram_, vertexShader);
|
||||
glAttachShader(shaderProgram_, fragmentShader);
|
||||
|
||||
glLinkProgram(shaderProgram_);
|
||||
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
|
||||
// Check for linking errors
|
||||
GLint success, len;
|
||||
glGetProgramiv(shaderProgram_, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetProgramiv(shaderProgram_, GL_INFO_LOG_LENGTH, &len);
|
||||
GLchar* infoLog{(char*)'\0'};
|
||||
glGetProgramInfoLog(shaderProgram_, len, &len, infoLog);
|
||||
spdlog::error("{0}. Shader linking error: {1}", name_, infoLog);
|
||||
}
|
||||
|
||||
glReleaseShaderCompiler();
|
||||
glUseProgram(shaderProgram_);
|
||||
}
|
||||
|
||||
GLuint waybar::modules::cava::CavaGLSL::loadShader(const std::string& fileName, GLenum type) {
|
||||
spdlog::debug("{0}. loadShader: {1}", name_, fileName);
|
||||
|
||||
// Read shader source code from the file
|
||||
std::ifstream shaderFile{fileName};
|
||||
|
||||
if (!shaderFile.is_open()) {
|
||||
spdlog::error("{0}. Could not open shader file: {1}", name_, fileName);
|
||||
}
|
||||
|
||||
std::ostringstream buffer;
|
||||
buffer << shaderFile.rdbuf(); // read file content into stringstream
|
||||
std::string str{buffer.str()};
|
||||
const char* shaderSource = str.c_str();
|
||||
shaderFile.close();
|
||||
|
||||
GLuint shaderID{glCreateShader(type)};
|
||||
if (shaderID == 0) spdlog::error("{0}. Error creating shader type: {0}", type);
|
||||
glShaderSource(shaderID, 1, &shaderSource, nullptr);
|
||||
glCompileShader(shaderID);
|
||||
|
||||
// Check for compilation errors
|
||||
GLint success, len;
|
||||
|
||||
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
|
||||
|
||||
if (!success) {
|
||||
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &len);
|
||||
|
||||
GLchar* infoLog{(char*)'\0'};
|
||||
glGetShaderInfoLog(shaderID, len, nullptr, infoLog);
|
||||
spdlog::error("{0}. Shader compilation error in {1}: {2}", name_, fileName, infoLog);
|
||||
}
|
||||
|
||||
return shaderID;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "modules/cava/cava.hpp"
|
||||
#include "modules/cava/cavaRaw.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
@@ -24,8 +24,11 @@ auto waybar::modules::cava::Cava::doAction(const std::string& name) -> void {
|
||||
// Cava actions
|
||||
void waybar::modules::cava::Cava::pause_resume() { backend_->doPauseResume(); }
|
||||
auto waybar::modules::cava::Cava::onUpdate(const std::string& input) -> void {
|
||||
Glib::signal_idle().connect_once([this, input]() {
|
||||
if (silence_) {
|
||||
silence_ = false;
|
||||
label_.get_style_context()->remove_class("silent");
|
||||
if (!label_.get_style_context()->has_class("updated"))
|
||||
label_.get_style_context()->add_class("updated");
|
||||
}
|
||||
label_text_.clear();
|
||||
@@ -35,17 +38,23 @@ auto waybar::modules::cava::Cava::onUpdate(const std::string& input) -> void {
|
||||
label_.set_markup(label_text_);
|
||||
label_.show();
|
||||
ALabel::update();
|
||||
silence_ = false;
|
||||
});
|
||||
}
|
||||
|
||||
auto waybar::modules::cava::Cava::onSilence() -> void {
|
||||
Glib::signal_idle().connect_once([this]() {
|
||||
if (!silence_) {
|
||||
if (label_.get_style_context()->has_class("updated"))
|
||||
label_.get_style_context()->remove_class("updated");
|
||||
|
||||
if (hide_on_silence_)
|
||||
if (hide_on_silence_) {
|
||||
// Clear the label markup before hiding to prevent GTK from rendering a NULL Pango layout
|
||||
label_.set_markup("");
|
||||
label_.hide();
|
||||
else if (config_["format_silent"].isString())
|
||||
} else if (config_["format_silent"].isString())
|
||||
label_.set_markup(format_silent_);
|
||||
silence_ = true;
|
||||
label_.get_style_context()->add_class("silent");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -9,91 +9,9 @@ std::shared_ptr<waybar::modules::cava::CavaBackend> waybar::modules::cava::CavaB
|
||||
return backend_ptr;
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::CavaBackend(const Json::Value& config) {
|
||||
waybar::modules::cava::CavaBackend::CavaBackend(const Json::Value& config) : config_(config) {
|
||||
// Load waybar module config
|
||||
char cfgPath[PATH_MAX];
|
||||
cfgPath[0] = '\0';
|
||||
|
||||
if (config["cava_config"].isString()) strcpy(cfgPath, config["cava_config"].asString().data());
|
||||
// Load cava config
|
||||
error_.length = 0;
|
||||
|
||||
if (!load_config(cfgPath, &prm_, false, &error_, 0)) {
|
||||
spdlog::error("cava backend. Error loading config. {0}", error_.message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Override cava parameters by the user config
|
||||
prm_.inAtty = 0;
|
||||
prm_.output = ::cava::output_method::OUTPUT_RAW;
|
||||
if (prm_.data_format) free(prm_.data_format);
|
||||
prm_.data_format = strdup("ascii");
|
||||
if (prm_.raw_target) free(prm_.raw_target);
|
||||
prm_.raw_target = strdup("/dev/stdout");
|
||||
prm_.ascii_range = config["format-icons"].size() - 1;
|
||||
|
||||
prm_.bar_width = 2;
|
||||
prm_.bar_spacing = 0;
|
||||
prm_.bar_height = 32;
|
||||
prm_.bar_width = 1;
|
||||
prm_.orientation = ::cava::ORIENT_TOP;
|
||||
prm_.xaxis = ::cava::xaxis_scale::NONE;
|
||||
prm_.mono_opt = ::cava::AVERAGE;
|
||||
prm_.autobars = 0;
|
||||
prm_.gravity = 0;
|
||||
prm_.integral = 1;
|
||||
|
||||
if (config["framerate"].isInt()) prm_.framerate = config["framerate"].asInt();
|
||||
// Calculate delay for Update() thread
|
||||
frame_time_milsec_ = std::chrono::milliseconds((int)(1e3 / prm_.framerate));
|
||||
if (config["autosens"].isInt()) prm_.autosens = config["autosens"].asInt();
|
||||
if (config["sensitivity"].isInt()) prm_.sens = config["sensitivity"].asInt();
|
||||
if (config["bars"].isInt()) prm_.fixedbars = config["bars"].asInt();
|
||||
if (config["lower_cutoff_freq"].isNumeric())
|
||||
prm_.lower_cut_off = config["lower_cutoff_freq"].asLargestInt();
|
||||
if (config["higher_cutoff_freq"].isNumeric())
|
||||
prm_.upper_cut_off = config["higher_cutoff_freq"].asLargestInt();
|
||||
if (config["sleep_timer"].isInt()) prm_.sleep_timer = config["sleep_timer"].asInt();
|
||||
if (config["method"].isString())
|
||||
prm_.input = ::cava::input_method_by_name(config["method"].asString().c_str());
|
||||
if (config["source"].isString()) {
|
||||
if (prm_.audio_source) free(prm_.audio_source);
|
||||
prm_.audio_source = config["source"].asString().data();
|
||||
}
|
||||
if (config["sample_rate"].isNumeric()) prm_.samplerate = config["sample_rate"].asLargestInt();
|
||||
if (config["sample_bits"].isInt()) prm_.samplebits = config["sample_bits"].asInt();
|
||||
if (config["stereo"].isBool()) prm_.stereo = config["stereo"].asBool();
|
||||
if (config["reverse"].isBool()) prm_.reverse = config["reverse"].asBool();
|
||||
if (config["bar_delimiter"].isInt()) prm_.bar_delim = config["bar_delimiter"].asInt();
|
||||
if (config["monstercat"].isBool()) prm_.monstercat = config["monstercat"].asBool();
|
||||
if (config["waves"].isBool()) prm_.waves = config["waves"].asBool();
|
||||
if (config["noise_reduction"].isDouble())
|
||||
prm_.noise_reduction = config["noise_reduction"].asDouble();
|
||||
if (config["input_delay"].isInt())
|
||||
fetch_input_delay_ = std::chrono::seconds(config["input_delay"].asInt());
|
||||
|
||||
audio_raw_.height = prm_.ascii_range;
|
||||
audio_data_.format = -1;
|
||||
audio_data_.rate = 0;
|
||||
audio_data_.samples_counter = 0;
|
||||
audio_data_.channels = 2;
|
||||
audio_data_.IEEE_FLOAT = 0;
|
||||
audio_data_.input_buffer_size = BUFFER_SIZE * audio_data_.channels;
|
||||
audio_data_.cava_buffer_size = audio_data_.input_buffer_size * 8;
|
||||
audio_data_.terminate = 0;
|
||||
audio_data_.suspendFlag = false;
|
||||
input_source_ = get_input(&audio_data_, &prm_);
|
||||
|
||||
if (!input_source_) {
|
||||
spdlog::error("cava backend API didn't provide input audio source method");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Make cava parameters configuration
|
||||
// Init cava plan, audio_raw structure
|
||||
audio_raw_init(&audio_data_, &audio_raw_, &prm_, &plan_);
|
||||
if (!plan_) spdlog::error("cava backend plan is not provided");
|
||||
audio_raw_.previous_frame[0] = -1; // For first Update() call need to rePaint text message
|
||||
loadConfig();
|
||||
// Read audio source trough cava API. Cava orginizes this process via infinity loop
|
||||
read_thread_ = [this] {
|
||||
try {
|
||||
@@ -102,41 +20,38 @@ waybar::modules::cava::CavaBackend::CavaBackend(const Json::Value& config) {
|
||||
spdlog::warn("Cava backend. Read source error: {0}", e.what());
|
||||
}
|
||||
read_thread_.sleep_for(fetch_input_delay_);
|
||||
loadConfig();
|
||||
};
|
||||
|
||||
thread_ = [this] {
|
||||
doUpdate();
|
||||
thread_.sleep_for(frame_time_milsec_);
|
||||
// Write outcoming data. Emit signals
|
||||
out_thread_ = [this] {
|
||||
doUpdate(false);
|
||||
out_thread_.sleep_for(frame_time_milsec_);
|
||||
};
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::~CavaBackend() {
|
||||
thread_.stop();
|
||||
out_thread_.stop();
|
||||
read_thread_.stop();
|
||||
cava_destroy(plan_);
|
||||
delete plan_;
|
||||
plan_ = nullptr;
|
||||
audio_raw_clean(&audio_raw_);
|
||||
pthread_mutex_lock(&audio_data_.lock);
|
||||
audio_data_.terminate = 1;
|
||||
pthread_mutex_unlock(&audio_data_.lock);
|
||||
config_clean(&prm_);
|
||||
free(audio_data_.source);
|
||||
free(audio_data_.cava_in);
|
||||
|
||||
freeBackend();
|
||||
}
|
||||
|
||||
static void upThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
static bool upThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
if (delta == std::chrono::seconds{0}) {
|
||||
delta += std::chrono::seconds{1};
|
||||
delay += delta;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void downThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
static bool downThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
if (delta > std::chrono::seconds{0}) {
|
||||
delay -= delta;
|
||||
delta -= std::chrono::seconds{1};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool waybar::modules::cava::CavaBackend::isSilence() {
|
||||
@@ -186,6 +101,7 @@ void waybar::modules::cava::CavaBackend::doPauseResume() {
|
||||
upThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||
}
|
||||
pthread_mutex_unlock(&audio_data_.lock);
|
||||
Update();
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::type_signal_update
|
||||
@@ -193,6 +109,11 @@ waybar::modules::cava::CavaBackend::signal_update() {
|
||||
return m_signal_update_;
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::type_signal_audio_raw_update
|
||||
waybar::modules::cava::CavaBackend::signal_audio_raw_update() {
|
||||
return m_signal_audio_raw_;
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::type_signal_silence
|
||||
waybar::modules::cava::CavaBackend::signal_silence() {
|
||||
return m_signal_silence_;
|
||||
@@ -215,12 +136,138 @@ void waybar::modules::cava::CavaBackend::doUpdate(bool force) {
|
||||
}
|
||||
|
||||
if (!silence_ || prm_.sleep_timer == 0) {
|
||||
downThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||
if (downThreadDelay(frame_time_milsec_, suspend_silence_delay_)) Update();
|
||||
execute();
|
||||
if (re_paint_ == 1 || force) m_signal_update_.emit(output_);
|
||||
if (re_paint_ == 1 || force || prm_.continuous_rendering) {
|
||||
m_signal_update_.emit(output_);
|
||||
m_signal_audio_raw_.emit(audio_raw_);
|
||||
}
|
||||
} else {
|
||||
upThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||
if (upThreadDelay(frame_time_milsec_, suspend_silence_delay_)) Update();
|
||||
if (silence_ != silence_prev_ || force) m_signal_silence_.emit();
|
||||
}
|
||||
silence_prev_ = silence_;
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaBackend::freeBackend() {
|
||||
if (plan_ != NULL) {
|
||||
cava_destroy(plan_);
|
||||
plan_ = NULL;
|
||||
}
|
||||
|
||||
audio_raw_clean(&audio_raw_);
|
||||
pthread_mutex_lock(&audio_data_.lock);
|
||||
audio_data_.terminate = 1;
|
||||
pthread_mutex_unlock(&audio_data_.lock);
|
||||
free_config(&prm_);
|
||||
free(audio_data_.source);
|
||||
free(audio_data_.cava_in);
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaBackend::loadConfig() {
|
||||
freeBackend();
|
||||
// Load waybar module config
|
||||
char cfgPath[PATH_MAX];
|
||||
cfgPath[0] = '\0';
|
||||
|
||||
if (config_["cava_config"].isString()) strcpy(cfgPath, config_["cava_config"].asString().data());
|
||||
// Load cava config
|
||||
error_.length = 0;
|
||||
|
||||
if (!load_config(cfgPath, &prm_, &error_)) {
|
||||
spdlog::error("cava backend. Error loading config. {0}", error_.message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Override cava parameters by the user config
|
||||
prm_.inAtty = 0;
|
||||
auto const output{prm_.output};
|
||||
// prm_.output = ::cava::output_method::OUTPUT_RAW;
|
||||
if (prm_.data_format) free(prm_.data_format);
|
||||
// Default to ascii for format-icons output; allow user override
|
||||
prm_.data_format = strdup(
|
||||
config_["data_format"].isString() ? config_["data_format"].asString().c_str() : "ascii");
|
||||
if (config_["raw_target"].isString()) {
|
||||
if (prm_.raw_target) free(prm_.raw_target);
|
||||
prm_.raw_target = strdup(config_["raw_target"].asString().c_str());
|
||||
}
|
||||
prm_.ascii_range = config_["format-icons"].size() - 1;
|
||||
|
||||
if (config_["bar_spacing"].isInt()) prm_.bar_spacing = config_["bar_spacing"].asInt();
|
||||
if (config_["bar_width"].isInt()) prm_.bar_width = config_["bar_width"].asInt();
|
||||
if (config_["bar_height"].isInt()) prm_.bar_height = config_["bar_height"].asInt();
|
||||
prm_.orientation = ::cava::ORIENT_TOP;
|
||||
prm_.xaxis = ::cava::xaxis_scale::NONE;
|
||||
prm_.mono_opt = ::cava::AVERAGE;
|
||||
prm_.autobars = 0;
|
||||
if (config_["gravity"].isInt()) prm_.gravity = config_["gravity"].asInt();
|
||||
if (config_["integral"].isInt()) prm_.integral = config_["integral"].asInt();
|
||||
|
||||
if (config_["framerate"].isInt()) prm_.framerate = config_["framerate"].asInt();
|
||||
// Calculate delay for Update() thread
|
||||
frame_time_milsec_ = std::chrono::milliseconds((int)(1e3 / prm_.framerate));
|
||||
if (config_["autosens"].isInt()) prm_.autosens = config_["autosens"].asInt();
|
||||
if (config_["sensitivity"].isInt()) prm_.sens = config_["sensitivity"].asInt();
|
||||
if (config_["bars"].isInt()) prm_.fixedbars = config_["bars"].asInt();
|
||||
if (config_["lower_cutoff_freq"].isNumeric())
|
||||
prm_.lower_cut_off = config_["lower_cutoff_freq"].asLargestInt();
|
||||
if (config_["higher_cutoff_freq"].isNumeric())
|
||||
prm_.upper_cut_off = config_["higher_cutoff_freq"].asLargestInt();
|
||||
if (config_["sleep_timer"].isInt()) prm_.sleep_timer = config_["sleep_timer"].asInt();
|
||||
if (config_["method"].isString())
|
||||
prm_.input = ::cava::input_method_by_name(config_["method"].asString().c_str());
|
||||
if (config_["source"].isString()) {
|
||||
if (prm_.audio_source) free(prm_.audio_source);
|
||||
prm_.audio_source = config_["source"].asString().data();
|
||||
}
|
||||
if (config_["sample_rate"].isNumeric()) prm_.samplerate = config_["sample_rate"].asLargestInt();
|
||||
if (config_["sample_bits"].isInt()) prm_.samplebits = config_["sample_bits"].asInt();
|
||||
if (config_["stereo"].isBool()) prm_.stereo = config_["stereo"].asBool();
|
||||
if (config_["reverse"].isBool()) prm_.reverse = config_["reverse"].asBool();
|
||||
if (config_["bar_delimiter"].isInt()) prm_.bar_delim = config_["bar_delimiter"].asInt();
|
||||
if (config_["monstercat"].isBool()) prm_.monstercat = config_["monstercat"].asBool();
|
||||
if (config_["waves"].isBool()) prm_.waves = config_["waves"].asBool();
|
||||
if (config_["noise_reduction"].isDouble())
|
||||
prm_.noise_reduction = config_["noise_reduction"].asDouble();
|
||||
if (config_["input_delay"].isInt())
|
||||
fetch_input_delay_ = std::chrono::seconds(config_["input_delay"].asInt());
|
||||
if (config_["gradient"].isInt()) prm_.gradient = config_["gradient"].asInt();
|
||||
if (prm_.gradient == 0)
|
||||
prm_.gradient_count = 0;
|
||||
else if (config_["gradient_count"].isInt())
|
||||
prm_.gradient_count = config_["gradient_count"].asInt();
|
||||
if (config_["sdl_width"].isInt()) prm_.sdl_width = config_["sdl_width"].asInt();
|
||||
if (config_["sdl_height"].isInt()) prm_.sdl_height = config_["sdl_height"].asInt();
|
||||
|
||||
audio_raw_.height = prm_.ascii_range;
|
||||
audio_data_.format = -1;
|
||||
audio_data_.rate = 0;
|
||||
audio_data_.samples_counter = 0;
|
||||
audio_data_.channels = 2;
|
||||
audio_data_.IEEE_FLOAT = 0;
|
||||
audio_data_.input_buffer_size = BUFFER_SIZE * audio_data_.channels;
|
||||
audio_data_.cava_buffer_size = audio_data_.input_buffer_size * 8;
|
||||
audio_data_.terminate = 0;
|
||||
audio_data_.suspendFlag = false;
|
||||
input_source_ = get_input(&audio_data_, &prm_);
|
||||
|
||||
if (!input_source_) {
|
||||
spdlog::error("cava backend API didn't provide input audio source method");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
prm_.output = ::cava::output_method::OUTPUT_RAW;
|
||||
|
||||
// Make cava parameters configuration
|
||||
// Init cava plan, audio_raw structure
|
||||
audio_raw_init(&audio_data_, &audio_raw_, &prm_, &plan_);
|
||||
if (!plan_) spdlog::error("cava backend plan is not provided");
|
||||
audio_raw_.previous_frame[0] = -1; // For first Update() call need to rePaint text message
|
||||
|
||||
prm_.output = output;
|
||||
}
|
||||
|
||||
const struct ::cava::config_params* waybar::modules::cava::CavaBackend::getPrm() { return &prm_; }
|
||||
std::chrono::milliseconds waybar::modules::cava::CavaBackend::getFrameTimeMilsec() {
|
||||
return frame_time_milsec_;
|
||||
};
|
||||
|
||||
@@ -26,9 +26,7 @@ auto waybar::modules::Cpu::update() -> void {
|
||||
auto [load1, load5, load15] = Load::getLoad();
|
||||
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
|
||||
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(tooltip);
|
||||
}
|
||||
|
||||
auto format = format_;
|
||||
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
|
||||
auto state = getState(total_usage);
|
||||
@@ -56,6 +54,15 @@ auto waybar::modules::Cpu::update() -> void {
|
||||
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
|
||||
}
|
||||
label_.set_markup(fmt::vformat(format, store));
|
||||
|
||||
if (tooltipEnabled()) {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
tooltip = config_["tooltip-format"].asString();
|
||||
label_.set_tooltip_markup(fmt::vformat(tooltip, store));
|
||||
} else {
|
||||
label_.set_tooltip_markup(tooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent update
|
||||
|
||||
@@ -20,12 +20,7 @@ waybar::modules::CpuFrequency::CpuFrequency(const std::string& id, const Json::V
|
||||
auto waybar::modules::CpuFrequency::update() -> void {
|
||||
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
||||
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
|
||||
if (tooltipEnabled()) {
|
||||
auto tooltip =
|
||||
fmt::format("Minimum frequency: {}\nAverage frequency: {}\nMaximum frequency: {}\n",
|
||||
min_frequency, avg_frequency, max_frequency);
|
||||
label_.set_tooltip_text(tooltip);
|
||||
}
|
||||
|
||||
auto format = format_;
|
||||
auto state = getState(avg_frequency);
|
||||
if (!state.empty() && config_["format-" + state].isString()) {
|
||||
@@ -43,6 +38,18 @@ auto waybar::modules::CpuFrequency::update() -> void {
|
||||
store.push_back(fmt::arg("min_frequency", min_frequency));
|
||||
store.push_back(fmt::arg("avg_frequency", avg_frequency));
|
||||
label_.set_markup(fmt::vformat(format, store));
|
||||
|
||||
if (tooltipEnabled()) {
|
||||
std::string tooltip;
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
tooltip = config_["tooltip-format"].asString();
|
||||
label_.set_tooltip_markup(fmt::vformat(tooltip, store));
|
||||
} else {
|
||||
tooltip = "Minimum frequency: {}\nAverage frequency: {}\nMaximum frequency: {}\n";
|
||||
label_.set_tooltip_markup(
|
||||
fmt::format(fmt::runtime(tooltip), min_frequency, avg_frequency, max_frequency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent update
|
||||
|
||||
@@ -20,9 +20,7 @@ waybar::modules::CpuUsage::CpuUsage(const std::string& id, const Json::Value& co
|
||||
auto waybar::modules::CpuUsage::update() -> void {
|
||||
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
||||
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(tooltip);
|
||||
}
|
||||
|
||||
auto format = format_;
|
||||
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
|
||||
auto state = getState(total_usage);
|
||||
@@ -46,6 +44,15 @@ auto waybar::modules::CpuUsage::update() -> void {
|
||||
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
|
||||
}
|
||||
label_.set_markup(fmt::vformat(format, store));
|
||||
|
||||
if (tooltipEnabled()) {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
tooltip = config_["tooltip-format"].asString();
|
||||
label_.set_tooltip_markup(fmt::vformat(tooltip, store));
|
||||
} else {
|
||||
label_.set_tooltip_markup(tooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent update
|
||||
|
||||
@@ -136,7 +136,7 @@ void waybar::modules::Custom::waitingWorker() {
|
||||
}
|
||||
|
||||
void waybar::modules::Custom::refresh(int sig) {
|
||||
if (sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
if (config_["signal"].isInt() && sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
thread_.wake_up();
|
||||
}
|
||||
}
|
||||
@@ -187,15 +187,11 @@ auto waybar::modules::Custom::update() -> void {
|
||||
fmt::arg("icon", getIcon(percentage_, alt_)), fmt::arg("percentage", percentage_));
|
||||
label_.set_tooltip_markup(tooltip);
|
||||
} else if (text_ == tooltip_) {
|
||||
if (label_.get_tooltip_markup() != str) {
|
||||
label_.set_tooltip_markup(str);
|
||||
}
|
||||
} else {
|
||||
if (label_.get_tooltip_markup() != tooltip_) {
|
||||
label_.set_tooltip_markup(tooltip_);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto style = label_.get_style_context();
|
||||
auto classes = style->list_classes();
|
||||
for (auto const& c : classes) {
|
||||
|
||||
@@ -81,7 +81,7 @@ auto waybar::modules::Disk::update() -> void {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
tooltip_format = config_["tooltip-format"].asString();
|
||||
}
|
||||
label_.set_tooltip_text(fmt::format(
|
||||
label_.set_tooltip_markup(fmt::format(
|
||||
fmt::runtime(tooltip_format), stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free),
|
||||
fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), fmt::arg("used", used),
|
||||
fmt::arg("percentage_used", percentage_used), fmt::arg("total", total),
|
||||
|
||||
@@ -76,8 +76,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
}
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Tags *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Tags*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +187,12 @@ void Tags::handle_view_tags(uint32_t tag, uint32_t state, uint32_t clients, uint
|
||||
button.get_style_context()->remove_class("occupied");
|
||||
}
|
||||
|
||||
if (clients & TAG_INACTIVE) {
|
||||
button.get_style_context()->remove_class("empty");
|
||||
} else {
|
||||
button.get_style_context()->add_class("empty");
|
||||
}
|
||||
|
||||
if (state & TAG_ACTIVE) {
|
||||
button.get_style_context()->add_class("focused");
|
||||
} else {
|
||||
|
||||
@@ -116,7 +116,7 @@ void Window::handle_frame() {
|
||||
updateAppIconName(appid_, "");
|
||||
updateAppIcon();
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(title_);
|
||||
label_.set_tooltip_markup(title_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ auto Gamemode::update() -> void {
|
||||
// Tooltip
|
||||
if (tooltip) {
|
||||
std::string text = fmt::format(fmt::runtime(tooltip_format), fmt::arg("count", gameCount));
|
||||
box_.set_tooltip_text(text);
|
||||
box_.set_tooltip_markup(text);
|
||||
}
|
||||
|
||||
// Label format
|
||||
|
||||
@@ -44,12 +44,23 @@ auto Submap::parseConfig(const Json::Value& config) -> void {
|
||||
auto Submap::update() -> void {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
|
||||
// Handle style class changes
|
||||
if (!prev_submap_.empty()) {
|
||||
label_.get_style_context()->remove_class(prev_submap_);
|
||||
}
|
||||
|
||||
if (!submap_.empty()) {
|
||||
label_.get_style_context()->add_class(submap_);
|
||||
}
|
||||
|
||||
prev_submap_ = submap_;
|
||||
|
||||
if (submap_.empty()) {
|
||||
event_box_.hide();
|
||||
} else {
|
||||
label_.set_markup(fmt::format(fmt::runtime(format_), submap_));
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(submap_);
|
||||
label_.set_tooltip_markup(submap_);
|
||||
}
|
||||
event_box_.show();
|
||||
}
|
||||
@@ -66,18 +77,12 @@ void Submap::onEvent(const std::string& ev) {
|
||||
|
||||
auto submapName = ev.substr(ev.find_first_of('>') + 2);
|
||||
|
||||
if (!submap_.empty()) {
|
||||
label_.get_style_context()->remove_class(submap_);
|
||||
}
|
||||
|
||||
submap_ = submapName;
|
||||
|
||||
if (submap_.empty() && always_on_) {
|
||||
submap_ = default_submap_;
|
||||
}
|
||||
|
||||
label_.get_style_context()->add_class(submap_);
|
||||
|
||||
spdlog::debug("hyprland submap onevent with {}", submap_);
|
||||
|
||||
dp.emit();
|
||||
|
||||
@@ -45,6 +45,8 @@ Window::~Window() {
|
||||
auto Window::update() -> void {
|
||||
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
||||
|
||||
queryActiveWorkspace();
|
||||
|
||||
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
|
||||
std::string windowAddress = workspace_.last_window;
|
||||
|
||||
@@ -70,13 +72,13 @@ auto Window::update() -> void {
|
||||
tooltip_format = config_["tooltip-format"].asString();
|
||||
}
|
||||
if (!tooltip_format.empty()) {
|
||||
label_.set_tooltip_text(
|
||||
label_.set_tooltip_markup(
|
||||
fmt::format(fmt::runtime(tooltip_format), fmt::arg("title", windowName),
|
||||
fmt::arg("initialTitle", windowData_.initial_title),
|
||||
fmt::arg("class", windowData_.class_name),
|
||||
fmt::arg("initialClass", windowData_.initial_class_name)));
|
||||
} else if (!label_text.empty()) {
|
||||
label_.set_tooltip_text(label_text);
|
||||
label_.set_tooltip_markup(label_text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,11 +237,7 @@ void Window::queryActiveWorkspace() {
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onEvent(const std::string& ev) {
|
||||
queryActiveWorkspace();
|
||||
|
||||
dp.emit();
|
||||
}
|
||||
void Window::onEvent(const std::string& ev) { dp.emit(); }
|
||||
|
||||
void Window::setClass(const std::string& classname, bool enable) {
|
||||
if (enable) {
|
||||
|
||||
@@ -39,6 +39,8 @@ WindowCount::~WindowCount() {
|
||||
auto WindowCount::update() -> void {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
|
||||
queryActiveWorkspace();
|
||||
|
||||
std::string format = config_["format"].asString();
|
||||
std::string formatEmpty = config_["format-empty"].asString();
|
||||
std::string formatWindowed = config_["format-windowed"].asString();
|
||||
@@ -56,7 +58,7 @@ auto WindowCount::update() -> void {
|
||||
} else if (!format.empty()) {
|
||||
label_.set_markup(fmt::format(fmt::runtime(format), workspace_.windows));
|
||||
} else {
|
||||
label_.set_text(fmt::format("{}", workspace_.windows));
|
||||
label_.set_markup(fmt::format("{}", workspace_.windows));
|
||||
}
|
||||
|
||||
label_.show();
|
||||
@@ -116,8 +118,6 @@ auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Wor
|
||||
}
|
||||
|
||||
void WindowCount::queryActiveWorkspace() {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
|
||||
if (separateOutputs_) {
|
||||
workspace_ = getActiveWorkspace(this->bar_.output->name);
|
||||
} else {
|
||||
@@ -125,10 +125,7 @@ void WindowCount::queryActiveWorkspace() {
|
||||
}
|
||||
}
|
||||
|
||||
void WindowCount::onEvent(const std::string& ev) {
|
||||
queryActiveWorkspace();
|
||||
dp.emit();
|
||||
}
|
||||
void WindowCount::onEvent(const std::string& ev) { dp.emit(); }
|
||||
|
||||
void WindowCount::setClass(const std::string& classname, bool enable) {
|
||||
if (enable) {
|
||||
|
||||
@@ -284,9 +284,7 @@ bool Workspace::isEmpty() const {
|
||||
// Otherwise, check if every window in the map should be skipped (ignored)
|
||||
return std::all_of(
|
||||
m_windowMap.begin(), m_windowMap.end(),
|
||||
[this, &ignore_list](const auto &window_repr) {
|
||||
return shouldSkipWindow(window_repr);
|
||||
});
|
||||
[this, &ignore_list](const auto& window_repr) { return shouldSkipWindow(window_repr); });
|
||||
}
|
||||
|
||||
void Workspace::updateTaskbar(const std::string& workspace_icon) {
|
||||
@@ -310,7 +308,7 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) {
|
||||
}
|
||||
|
||||
auto window_box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL);
|
||||
window_box->set_tooltip_text(window_repr.window_title);
|
||||
window_box->set_tooltip_markup(window_repr.window_title);
|
||||
window_box->get_style_context()->add_class("taskbar-window");
|
||||
if (window_repr.isActive) {
|
||||
window_box->get_style_context()->add_class("active");
|
||||
|
||||
@@ -43,6 +43,13 @@ void Workspaces::init() {
|
||||
m_activeWorkspaceId = m_ipc.getSocket1JsonReply("activeworkspace")["id"].asInt();
|
||||
|
||||
initializeWorkspaces();
|
||||
|
||||
if (barScroll()) {
|
||||
auto &window = const_cast<Bar &>(m_bar).window;
|
||||
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||
window.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
|
||||
}
|
||||
|
||||
dp.emit();
|
||||
}
|
||||
|
||||
@@ -296,6 +303,11 @@ void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &c
|
||||
auto workspace = rule.isMember("defaultName") ? rule["defaultName"].asString()
|
||||
: rule["workspaceString"].asString();
|
||||
|
||||
// There could be persistent special workspaces, only show those when show-special is enabled.
|
||||
if (workspace.starts_with("special:") && !showSpecial()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The prefix "name:" cause mismatches with workspace names taken anywhere else.
|
||||
if (workspace.starts_with("name:")) {
|
||||
workspace = workspace.substr(5);
|
||||
@@ -631,6 +643,7 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
|
||||
populateBoolConfig(config, "persistent-only", m_persistentOnly);
|
||||
populateBoolConfig(config, "active-only", m_activeOnly);
|
||||
populateBoolConfig(config, "move-to-monitor", m_moveToMonitor);
|
||||
populateBoolConfig(config, "enable-bar-scroll", m_barScroll);
|
||||
|
||||
m_persistentWorkspaceConfig = config.get("persistent-workspaces", Json::Value());
|
||||
populateSortByConfig(config);
|
||||
@@ -934,7 +947,7 @@ void Workspaces::sortWorkspaces() {
|
||||
case SortMethod::NUMBER:
|
||||
try {
|
||||
return std::stoi(a->name()) < std::stoi(b->name());
|
||||
} catch (const std::invalid_argument &) {
|
||||
} catch (const std::exception& e) {
|
||||
// Handle the exception if necessary.
|
||||
break;
|
||||
}
|
||||
@@ -1146,4 +1159,31 @@ std::optional<int> Workspaces::parseWorkspaceId(std::string const &workspaceIdSt
|
||||
}
|
||||
}
|
||||
|
||||
bool Workspaces::handleScroll(GdkEventScroll *e) {
|
||||
// Ignore emulated scroll events on window
|
||||
if (gdk_event_get_pointer_emulated((GdkEvent *)e)) {
|
||||
return false;
|
||||
}
|
||||
auto dir = AModule::getScrollDir(e);
|
||||
if (dir == SCROLL_DIR::NONE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dir == SCROLL_DIR::DOWN || dir == SCROLL_DIR::RIGHT) {
|
||||
if (allOutputs()) {
|
||||
m_ipc.getSocket1Reply("dispatch workspace e+1");
|
||||
} else {
|
||||
m_ipc.getSocket1Reply("dispatch workspace m+1");
|
||||
}
|
||||
} else if (dir == SCROLL_DIR::UP || dir == SCROLL_DIR::LEFT) {
|
||||
if (allOutputs()) {
|
||||
m_ipc.getSocket1Reply("dispatch workspace e-1");
|
||||
} else {
|
||||
m_ipc.getSocket1Reply("dispatch workspace m-1");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace waybar::modules::hyprland
|
||||
|
||||
@@ -14,22 +14,27 @@ waybar::modules::Image::Image(const std::string& id, const Json::Value& config)
|
||||
|
||||
size_ = config["size"].asInt();
|
||||
|
||||
interval_ = config_["interval"] == "once"
|
||||
? std::chrono::milliseconds::max()
|
||||
: std::chrono::milliseconds(std::max(
|
||||
1L, // Minimum 1ms due to millisecond precision
|
||||
static_cast<long>(
|
||||
(config_["interval"].isNumeric() ? config_["interval"].asDouble() : 0) *
|
||||
1000)));
|
||||
const auto once = std::chrono::milliseconds::max();
|
||||
if (!config_.isMember("interval") || config_["interval"].isNull() ||
|
||||
config_["interval"] == "once") {
|
||||
interval_ = once;
|
||||
} else if (config_["interval"].isNumeric()) {
|
||||
const auto interval_seconds = config_["interval"].asDouble();
|
||||
if (interval_seconds <= 0) {
|
||||
interval_ = once;
|
||||
} else {
|
||||
interval_ =
|
||||
std::chrono::milliseconds(std::max(1L, // Minimum 1ms due to millisecond precision
|
||||
static_cast<long>(interval_seconds * 1000)));
|
||||
}
|
||||
} else {
|
||||
interval_ = once;
|
||||
}
|
||||
|
||||
if (size_ == 0) {
|
||||
size_ = 16;
|
||||
}
|
||||
|
||||
if (interval_.count() == 0) {
|
||||
interval_ = std::chrono::milliseconds::max();
|
||||
}
|
||||
|
||||
delayWorker();
|
||||
}
|
||||
|
||||
@@ -41,7 +46,7 @@ void waybar::modules::Image::delayWorker() {
|
||||
}
|
||||
|
||||
void waybar::modules::Image::refresh(int sig) {
|
||||
if (sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
if (config_["signal"].isInt() && sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
thread_.wake_up();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ auto Inhibitor::update() -> void {
|
||||
label_.get_style_context()->add_class(status_text);
|
||||
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(status_text);
|
||||
label_.set_tooltip_markup(status_text);
|
||||
}
|
||||
|
||||
return ALabel::update();
|
||||
|
||||
@@ -80,7 +80,7 @@ auto JACK::update() -> void {
|
||||
if (tooltipEnabled()) {
|
||||
std::string tooltip_format = "{bufsize}/{samplerate} {latency}ms";
|
||||
if (config_["tooltip-format"].isString()) tooltip_format = config_["tooltip-format"].asString();
|
||||
label_.set_tooltip_text(fmt::format(
|
||||
label_.set_tooltip_markup(fmt::format(
|
||||
fmt::runtime(tooltip_format), fmt::arg("load", std::round(load_)),
|
||||
fmt::arg("bufsize", bufsize_), fmt::arg("samplerate", samplerate_),
|
||||
fmt::arg("latency", fmt::format("{:.2f}", latency)), fmt::arg("xruns", xruns_)));
|
||||
|
||||
@@ -232,9 +232,12 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
||||
}
|
||||
tryAddDevice(dev_path);
|
||||
} else if (event->mask & IN_DELETE) {
|
||||
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||
auto it = libinput_devices_.find(dev_path);
|
||||
if (it != libinput_devices_.end()) {
|
||||
spdlog::info("Keyboard {} has been removed.", dev_path);
|
||||
libinput_path_remove_device(it->second);
|
||||
libinput_device_unref(it->second);
|
||||
libinput_devices_.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -245,6 +248,7 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
||||
}
|
||||
|
||||
waybar::modules::KeyboardState::~KeyboardState() {
|
||||
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||
for (const auto& [_, dev_ptr] : libinput_devices_) {
|
||||
libinput_path_remove_device(dev_ptr);
|
||||
}
|
||||
@@ -256,12 +260,18 @@ auto waybar::modules::KeyboardState::update() -> void {
|
||||
|
||||
try {
|
||||
std::string dev_path;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||
if (libinput_devices_.empty()) {
|
||||
return;
|
||||
}
|
||||
if (config_["device-path"].isString() &&
|
||||
libinput_devices_.find(config_["device-path"].asString()) != libinput_devices_.end()) {
|
||||
dev_path = config_["device-path"].asString();
|
||||
} else {
|
||||
dev_path = libinput_devices_.begin()->first;
|
||||
}
|
||||
}
|
||||
int fd = openFile(dev_path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
||||
auto dev = openDevice(fd);
|
||||
numl = libevdev_get_event_value(dev, EV_LED, LED_NUML);
|
||||
@@ -308,10 +318,15 @@ auto waybar::modules ::KeyboardState::tryAddDevice(const std::string& dev_path)
|
||||
auto dev = openDevice(fd);
|
||||
if (supportsLockStates(dev)) {
|
||||
spdlog::info("Found device {} at '{}'", libevdev_get_name(dev), dev_path);
|
||||
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||
if (libinput_devices_.find(dev_path) == libinput_devices_.end()) {
|
||||
auto device = libinput_path_add_device(libinput_, dev_path.c_str());
|
||||
if (device) {
|
||||
libinput_device_ref(device);
|
||||
libinput_devices_[dev_path] = device;
|
||||
} else {
|
||||
spdlog::warn("keyboard-state: Failed to add device to libinput: {}", dev_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
libevdev_free(dev);
|
||||
|
||||
@@ -22,7 +22,7 @@ auto waybar::modules::Load::update() -> void {
|
||||
auto [load1, load5, load15] = Load::getLoad();
|
||||
if (tooltipEnabled()) {
|
||||
auto tooltip = fmt::format("Load 1: {}\nLoad 5: {}\nLoad 15: {}", load1, load5, load15);
|
||||
label_.set_tooltip_text(tooltip);
|
||||
label_.set_tooltip_markup(tooltip);
|
||||
}
|
||||
auto format = format_;
|
||||
auto state = getState(load1);
|
||||
|
||||
@@ -36,7 +36,7 @@ auto waybar::modules::Memory::update() -> void {
|
||||
float total_swap_gigabytes = 0.01 * round(swaptotal / 10485.76);
|
||||
int used_ram_percentage = 100 * (memtotal - memfree) / memtotal;
|
||||
int used_swap_percentage = 0;
|
||||
if (swaptotal && swapfree) {
|
||||
if (swaptotal) {
|
||||
used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal;
|
||||
}
|
||||
float used_ram_gigabytes = 0.01 * round((memtotal - memfree) / 10485.76);
|
||||
@@ -69,7 +69,7 @@ auto waybar::modules::Memory::update() -> void {
|
||||
if (tooltipEnabled()) {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
auto tooltip_format = config_["tooltip-format"].asString();
|
||||
label_.set_tooltip_text(fmt::format(
|
||||
label_.set_tooltip_markup(fmt::format(
|
||||
fmt::runtime(tooltip_format), used_ram_percentage,
|
||||
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
|
||||
fmt::arg("percentage", used_ram_percentage),
|
||||
@@ -78,7 +78,7 @@ auto waybar::modules::Memory::update() -> void {
|
||||
fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
|
||||
fmt::arg("swapAvail", available_swap_gigabytes)));
|
||||
} else {
|
||||
label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1));
|
||||
label_.set_tooltip_markup(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -112,7 +112,7 @@ void waybar::modules::MPD::setLabel() {
|
||||
? config_["tooltip-format-disconnected"].asString()
|
||||
: "MPD (disconnected)";
|
||||
// Nothing to format
|
||||
label_.set_tooltip_text(tooltip_format);
|
||||
label_.set_tooltip_markup(tooltip_format);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -229,7 +229,7 @@ void waybar::modules::MPD::setLabel() {
|
||||
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon),
|
||||
fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon),
|
||||
fmt::arg("singleIcon", singleIcon), fmt::arg("filename", filename), fmt::arg("uri", uri));
|
||||
label_.set_tooltip_text(tooltip_text);
|
||||
label_.set_tooltip_markup(tooltip_text);
|
||||
} catch (fmt::format_error const& e) {
|
||||
spdlog::warn("mpd: format error (tooltip): {}", e.what());
|
||||
}
|
||||
|
||||
@@ -734,7 +734,7 @@ auto Mpris::update() -> void {
|
||||
fmt::arg("player_icon", getIconFromJson(config_["player-icons"], info.name)),
|
||||
fmt::arg("status_icon", getIconFromJson(config_["status-icons"], info.status_string)));
|
||||
|
||||
label_.set_tooltip_text(tooltip_text);
|
||||
label_.set_tooltip_markup(tooltip_text);
|
||||
} catch (fmt::format_error const& e) {
|
||||
spdlog::warn("mpris: format error (tooltip): {}", e.what());
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ void Window::doUpdate() {
|
||||
|
||||
updateAppIconName(appId, "");
|
||||
|
||||
if (tooltipEnabled()) label_.set_tooltip_text(title);
|
||||
if (tooltipEnabled()) label_.set_tooltip_markup(title);
|
||||
|
||||
const auto id = window["id"].asUInt64();
|
||||
const auto workspaceId = window["workspace_id"].asUInt64();
|
||||
|
||||
@@ -174,11 +174,11 @@ std::string Workspaces::getIcon(const std::string &value, const Json::Value &ws)
|
||||
|
||||
if (ws["is_urgent"].asBool() && icons["urgent"]) return icons["urgent"].asString();
|
||||
|
||||
if (ws["active_window_id"].isNull() && icons["empty"]) return icons["empty"].asString();
|
||||
if (ws["is_active"].asBool() && icons["active"]) return icons["active"].asString();
|
||||
|
||||
if (ws["is_focused"].asBool() && icons["focused"]) return icons["focused"].asString();
|
||||
|
||||
if (ws["is_active"].asBool() && icons["active"]) return icons["active"].asString();
|
||||
if (ws["active_window_id"].isNull() && icons["empty"]) return icons["empty"].asString();
|
||||
|
||||
if (ws["name"]) {
|
||||
const auto& name = ws["name"].asString();
|
||||
|
||||
@@ -157,7 +157,7 @@ auto PowerProfilesDaemon::update() -> void {
|
||||
store.push_back(fmt::arg("icon", getIcon(0, profile.name)));
|
||||
label_.set_markup(fmt::vformat(format_, store));
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(fmt::vformat(tooltipFormat_, store));
|
||||
label_.set_tooltip_markup(fmt::vformat(tooltipFormat_, store));
|
||||
}
|
||||
|
||||
// Set CSS class
|
||||
|
||||
@@ -138,7 +138,7 @@ auto waybar::modules::Pulseaudio::update() -> void {
|
||||
fmt::arg("source_volume", source_volume), fmt::arg("source_desc", source_desc),
|
||||
fmt::arg("icon", getIcon(sink_volume, getPulseIcon()))));
|
||||
} else {
|
||||
label_.set_tooltip_text(sink_desc);
|
||||
label_.set_tooltip_markup(sink_desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Layout *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Layout*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, version));
|
||||
} else if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Mode *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Mode*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min(version, 1u);
|
||||
static_cast<Tags *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Tags*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Window *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Window*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ auto waybar::modules::Clock::update() -> void {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
auto tooltip_format = config_["tooltip-format"].asString();
|
||||
auto tooltip_text = fmt::format(fmt::runtime(tooltip_format), localtime);
|
||||
label_.set_tooltip_text(tooltip_text);
|
||||
label_.set_tooltip_markup(tooltip_text);
|
||||
} else {
|
||||
label_.set_tooltip_text(text);
|
||||
label_.set_tooltip_markup(text);
|
||||
}
|
||||
}
|
||||
// Call parent update
|
||||
|
||||
@@ -79,6 +79,10 @@ Item::~Item() {
|
||||
this->gtk_menu->popdown();
|
||||
this->gtk_menu->detach();
|
||||
}
|
||||
if (this->dbus_menu != nullptr) {
|
||||
g_object_weak_unref(G_OBJECT(this->dbus_menu), (GWeakNotify)onMenuDestroyed, this);
|
||||
this->dbus_menu = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Item::handleMouseEnter(GdkEventCrossing* const& e) {
|
||||
@@ -233,9 +237,13 @@ void Item::setCustomIcon(const std::string& id) {
|
||||
std::string custom_icon = IconManager::instance().getIconForApp(id);
|
||||
if (!custom_icon.empty()) {
|
||||
if (std::filesystem::exists(custom_icon)) {
|
||||
try {
|
||||
Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
|
||||
icon_name = ""; // icon_name has priority over pixmap
|
||||
icon_pixmap = custom_pixbuf;
|
||||
} catch (const Glib::Error& e) {
|
||||
spdlog::error("Failed to load custom icon {}: {}", custom_icon, e.what());
|
||||
}
|
||||
} else { // if file doesn't exist it's most likely an icon_name
|
||||
icon_name = custom_icon;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ auto Mode::update() -> void {
|
||||
} else {
|
||||
label_.set_markup(fmt::format(fmt::runtime(format_), mode_));
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(mode_);
|
||||
label_.set_tooltip_markup(mode_);
|
||||
}
|
||||
event_box_.show();
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ auto Window::update() -> void {
|
||||
fmt::arg("shell", shell_), fmt::arg("marks", marks_)),
|
||||
config_["rewrite"]));
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(window_);
|
||||
label_.set_tooltip_markup(window_);
|
||||
}
|
||||
|
||||
updateAppIcon();
|
||||
|
||||
@@ -331,7 +331,7 @@ auto Workspaces::update() -> void {
|
||||
}
|
||||
std::string output = (*it)["name"].asString();
|
||||
std::string windows = "";
|
||||
if (config_["window-format"].isString()) {
|
||||
if (config_["window-rewrite"].isObject()) {
|
||||
updateWindows((*it), windows);
|
||||
}
|
||||
if (config_["format"].isString()) {
|
||||
|
||||
@@ -101,7 +101,7 @@ auto waybar::modules::Temperature::update() -> void {
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
tooltip_format = config_["tooltip-format"].asString();
|
||||
}
|
||||
label_.set_tooltip_text(fmt::format(
|
||||
label_.set_tooltip_markup(fmt::format(
|
||||
fmt::runtime(tooltip_format), fmt::arg("temperatureC", temperature_c),
|
||||
fmt::arg("temperatureF", temperature_f), fmt::arg("temperatureK", temperature_k)));
|
||||
}
|
||||
|
||||
@@ -14,16 +14,18 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
|
||||
mixer_api_(nullptr),
|
||||
def_nodes_api_(nullptr),
|
||||
default_node_name_(nullptr),
|
||||
default_source_name_(nullptr),
|
||||
pending_plugins_(0),
|
||||
muted_(false),
|
||||
source_muted_(false),
|
||||
volume_(0.0),
|
||||
source_volume_(0.0),
|
||||
min_step_(0.0),
|
||||
node_id_(0),
|
||||
node_name_(""),
|
||||
source_name_(""),
|
||||
type_(nullptr),
|
||||
source_node_id_(0),
|
||||
type_(nullptr) {
|
||||
source_muted_(false),
|
||||
source_volume_(0.0),
|
||||
default_source_name_(nullptr) {
|
||||
waybar::modules::Wireplumber::modules.push_back(this);
|
||||
|
||||
wp_init(WP_INIT_PIPEWIRE);
|
||||
@@ -477,12 +479,12 @@ auto waybar::modules::Wireplumber::update() -> void {
|
||||
}
|
||||
|
||||
if (!tooltipFormat.empty()) {
|
||||
label_.set_tooltip_text(fmt::format(
|
||||
label_.set_tooltip_markup(fmt::format(
|
||||
fmt::runtime(tooltipFormat), fmt::arg("node_name", node_name_), fmt::arg("volume", vol),
|
||||
fmt::arg("icon", getIcon(vol)), fmt::arg("format_source", formatted_source),
|
||||
fmt::arg("source_volume", source_vol), fmt::arg("source_desc", source_name_)));
|
||||
} else {
|
||||
label_.set_tooltip_text(node_name_);
|
||||
label_.set_tooltip_markup(node_name_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -509,7 +509,7 @@ void Task::update() {
|
||||
if (markup)
|
||||
button.set_tooltip_markup(txt);
|
||||
else
|
||||
button.set_tooltip_text(txt);
|
||||
button.set_tooltip_markup(txt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "util/udev_deleter.hpp"
|
||||
|
||||
namespace {
|
||||
class FileDescriptor {
|
||||
public:
|
||||
@@ -29,22 +31,6 @@ class FileDescriptor {
|
||||
int fd_;
|
||||
};
|
||||
|
||||
struct UdevDeleter {
|
||||
void operator()(udev *ptr) { udev_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevDeviceDeleter {
|
||||
void operator()(udev_device *ptr) { udev_device_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevEnumerateDeleter {
|
||||
void operator()(udev_enumerate *ptr) { udev_enumerate_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevMonitorDeleter {
|
||||
void operator()(udev_monitor *ptr) { udev_monitor_unref(ptr); }
|
||||
};
|
||||
|
||||
void check_eq(int rc, int expected, const char* message = "eq, rc was: ") {
|
||||
if (rc != expected) {
|
||||
throw std::runtime_error(fmt::format(fmt::runtime(message), rc));
|
||||
@@ -287,7 +273,7 @@ int BacklightBackend::get_scaled_brightness(const std::string &preferred_device)
|
||||
GET_BEST_DEVICE(best, (*this), preferred_device);
|
||||
|
||||
if (best != nullptr) {
|
||||
return best->get_actual() * 100 / best->get_max();
|
||||
return static_cast<int>(std::round(best->get_actual() * 100.0F / best->get_max()));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/LukashonakV/cava.git
|
||||
revision = 23efcced43b5a395747b18a2e5f2171fc0925d18
|
||||
depth = 1
|
||||
|
||||
#directory = cava-0.10.6
|
||||
#source_url = https://github.com/LukashonakV/cava/archive/0.10.6.tar.gz
|
||||
#source_filename = cava-0.10.6.tar.gz
|
||||
#source_hash = e715c4c6a625b8dc063e57e8e81c80e4d1015ec1b98db69a283b2c6770f839f4
|
||||
[provide]
|
||||
cava = cava_dep
|
||||
12
subprojects/libcava.wrap
Normal file
12
subprojects/libcava.wrap
Normal file
@@ -0,0 +1,12 @@
|
||||
#[wrap-git]
|
||||
#url = https://github.com/LukashonakV/cava.git
|
||||
#revision = 866cfec40b7b9d38e97148d004d3134c1385b52f
|
||||
#depth = 1
|
||||
|
||||
[wrap-file]
|
||||
directory = cava-0.10.7-beta
|
||||
source_url = https://github.com/LukashonakV/cava/archive/v0.10.7-beta.tar.gz
|
||||
source_filename = cava-0.10.7.tar.gz
|
||||
source_hash = 8915d7214f2046554c158fe6f2ae518881dfb573e421ea848727be11a5dfa8c4
|
||||
[provide]
|
||||
libcava = cava_dep
|
||||
Reference in New Issue
Block a user