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:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v6
|
||||||
# TODO: bump to clang 19 release
|
- uses: RafikFarhad/clang-format-github-action@v6
|
||||||
# - uses: DoozyX/clang-format-lint-action@v0.18.2
|
|
||||||
- uses: DoozyX/clang-format-lint-action@558090054b3f39e3d6af24f0cd73b319535da809
|
|
||||||
name: clang-format
|
name: clang-format
|
||||||
with:
|
with:
|
||||||
source: "."
|
sources: "src/**/*.hpp,src/**/*.cpp"
|
||||||
extensions: "hpp,h,cpp,c"
|
style: "file"
|
||||||
style: "file:.clang-format"
|
|
||||||
clangFormatVersion: 19
|
|
||||||
|
|||||||
2
.github/workflows/clang-tidy.yml.bak
vendored
2
.github/workflows/clang-tidy.yml.bak
vendored
@@ -12,7 +12,7 @@ jobs:
|
|||||||
container:
|
container:
|
||||||
image: alexays/waybar:debian
|
image: alexays/waybar:debian
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v6
|
||||||
- name: configure
|
- name: configure
|
||||||
run: |
|
run: |
|
||||||
meson -Dcpp_std=c++20 build # necessary to generate compile_commands.json
|
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:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
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
|
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v6
|
||||||
- name: Test in FreeBSD VM
|
- name: Test in FreeBSD VM
|
||||||
uses: cross-platform-actions/action@v0.28.0
|
uses: cross-platform-actions/action@v0.28.0
|
||||||
timeout-minutes: 180
|
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 }}
|
image: alexays/waybar:${{ matrix.distro }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v6
|
||||||
- name: configure
|
- name: configure
|
||||||
run: meson setup -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build
|
run: meson setup -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build
|
||||||
- name: 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:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-nix-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
jobs:
|
jobs:
|
||||||
nix-flake-check:
|
nix-flake-check:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- uses: cachix/install-nix-action@v27
|
- uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
experimental-features = nix-command flakes
|
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'
|
if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v27
|
uses: cachix/install-nix-action@v31
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Update flake.lock
|
- 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
|
*.swp
|
||||||
packagecache
|
packagecache
|
||||||
/subprojects/**/
|
/subprojects/**/
|
||||||
|
/subprojects/.wraplock
|
||||||
/build*
|
/build*
|
||||||
/dist
|
/dist
|
||||||
/meson.egg-info
|
/meson.egg-info
|
||||||
@@ -50,3 +51,4 @@ result
|
|||||||
result-*
|
result-*
|
||||||
|
|
||||||
.ccls-cache
|
.ccls-cache
|
||||||
|
_codeql_detected_source_root
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ sudo apt install \
|
|||||||
On Arch, you can use this command:
|
On Arch, you can use this command:
|
||||||
|
|
||||||
```
|
```
|
||||||
pacman -S \
|
pacman -S --asdeps \
|
||||||
gtkmm3 \
|
gtkmm3 \
|
||||||
jsoncpp \
|
jsoncpp \
|
||||||
libsigc++ \
|
libsigc++ \
|
||||||
@@ -151,6 +151,10 @@ Contributions welcome!<br>
|
|||||||
Have fun :)<br>
|
Have fun :)<br>
|
||||||
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
|
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
|
## License
|
||||||
|
|
||||||
Waybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/Alexays/Waybar/blob/master/LICENSE).
|
Waybar is licensed under the MIT license. [See LICENSE for 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-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1747046372,
|
"lastModified": 1767039857,
|
||||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -18,11 +18,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760878510,
|
"lastModified": 1769461804,
|
||||||
"narHash": "sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs=",
|
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "5e2a59a5b1a82f89f2c7e598302a9cacebb72a67",
|
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ class Client {
|
|||||||
std::list<struct waybar_output> outputs_;
|
std::list<struct waybar_output> outputs_;
|
||||||
std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
|
std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
|
||||||
std::string m_cssFile;
|
std::string m_cssFile;
|
||||||
|
sigc::connection monitor_added_connection_;
|
||||||
|
sigc::connection monitor_removed_connection_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
#include "ALabel.hpp"
|
#include "ALabel.hpp"
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "util/sleeper_thread.hpp"
|
#include "util/sleeper_thread.hpp"
|
||||||
|
#include "util/udev_deleter.hpp"
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
@@ -37,15 +39,17 @@ class Battery : public ALabel {
|
|||||||
void setBarClass(std::string&);
|
void setBarClass(std::string&);
|
||||||
void processEvents(std::string& state, std::string& status, uint8_t capacity);
|
void processEvents(std::string& state, std::string& status, uint8_t capacity);
|
||||||
|
|
||||||
int global_watch;
|
|
||||||
std::map<fs::path, int> batteries_;
|
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_;
|
fs::path adapter_;
|
||||||
int battery_watch_fd_;
|
int battery_watch_fd_;
|
||||||
int global_watch_fd_;
|
|
||||||
std::mutex battery_list_mutex_;
|
std::mutex battery_list_mutex_;
|
||||||
std::string old_status_;
|
std::string old_status_;
|
||||||
std::string last_event_;
|
std::string last_event_;
|
||||||
bool warnFirstTime_{true};
|
bool warnFirstTime_{true};
|
||||||
|
bool weightedAverage_{true};
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
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:
|
public:
|
||||||
Cava(const std::string&, const Json::Value&);
|
Cava(const std::string&, const Json::Value&);
|
||||||
~Cava() = default;
|
~Cava() = default;
|
||||||
auto onUpdate(const std::string& input) -> void;
|
|
||||||
auto onSilence() -> void;
|
|
||||||
auto doAction(const std::string& name) -> void override;
|
auto doAction(const std::string& name) -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<CavaBackend> backend_;
|
std::shared_ptr<CavaBackend> backend_;
|
||||||
// Text to display
|
// Text to display
|
||||||
std::string label_text_{""};
|
Glib::ustring label_text_{""};
|
||||||
|
bool silence_{false};
|
||||||
bool hide_on_silence_{false};
|
bool hide_on_silence_{false};
|
||||||
std::string format_silent_{""};
|
std::string format_silent_{""};
|
||||||
int ascii_range_{0};
|
int ascii_range_{0};
|
||||||
bool silence_{false};
|
|
||||||
// Cava method
|
// Cava method
|
||||||
void pause_resume();
|
void pause_resume();
|
||||||
|
auto onUpdate(const std::string& input) -> void;
|
||||||
|
auto onSilence() -> void;
|
||||||
// ModuleActionMap
|
// ModuleActionMap
|
||||||
static inline std::map<const std::string, void (waybar::modules::cava::Cava::* const)()>
|
static inline std::map<const std::string, void (waybar::modules::cava::Cava::* const)()>
|
||||||
actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}};
|
actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}};
|
||||||
@@ -32,16 +32,22 @@ class CavaBackend final {
|
|||||||
int getAsciiRange();
|
int getAsciiRange();
|
||||||
void doPauseResume();
|
void doPauseResume();
|
||||||
void Update();
|
void Update();
|
||||||
|
const struct ::cava::config_params* getPrm();
|
||||||
|
std::chrono::milliseconds getFrameTimeMilsec();
|
||||||
|
|
||||||
// Signal accessor
|
// Signal accessor
|
||||||
using type_signal_update = sigc::signal<void(const std::string&)>;
|
using type_signal_update = sigc::signal<void(const std::string&)>;
|
||||||
type_signal_update signal_update();
|
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()>;
|
using type_signal_silence = sigc::signal<void()>;
|
||||||
type_signal_silence signal_silence();
|
type_signal_silence signal_silence();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CavaBackend(const Json::Value& config);
|
CavaBackend(const Json::Value& config);
|
||||||
util::SleeperThread thread_;
|
|
||||||
util::SleeperThread read_thread_;
|
util::SleeperThread read_thread_;
|
||||||
|
util::SleeperThread out_thread_;
|
||||||
|
|
||||||
// Cava API to read audio source
|
// Cava API to read audio source
|
||||||
::cava::ptr input_source_{NULL};
|
::cava::ptr input_source_{NULL};
|
||||||
|
|
||||||
@@ -55,6 +61,7 @@ class CavaBackend final {
|
|||||||
// Delay to handle audio source
|
// Delay to handle audio source
|
||||||
std::chrono::milliseconds frame_time_milsec_{1s};
|
std::chrono::milliseconds frame_time_milsec_{1s};
|
||||||
|
|
||||||
|
const Json::Value& config_;
|
||||||
int re_paint_{0};
|
int re_paint_{0};
|
||||||
bool silence_{false};
|
bool silence_{false};
|
||||||
bool silence_prev_{false};
|
bool silence_prev_{false};
|
||||||
@@ -66,9 +73,12 @@ class CavaBackend final {
|
|||||||
void execute();
|
void execute();
|
||||||
bool isSilence();
|
bool isSilence();
|
||||||
void doUpdate(bool force = false);
|
void doUpdate(bool force = false);
|
||||||
|
void loadConfig();
|
||||||
|
void freeBackend();
|
||||||
|
|
||||||
// Signal
|
// Signal
|
||||||
type_signal_update m_signal_update_;
|
type_signal_update m_signal_update_;
|
||||||
|
type_signal_audio_raw_update m_signal_audio_raw_;
|
||||||
type_signal_silence m_signal_silence_;
|
type_signal_silence m_signal_silence_;
|
||||||
};
|
};
|
||||||
} // namespace waybar::modules::cava
|
} // 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_;
|
const Bar& bar_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::string submap_;
|
std::string submap_;
|
||||||
|
std::string prev_submap_;
|
||||||
bool always_on_ = false;
|
bool always_on_ = false;
|
||||||
std::string default_submap_ = "Default";
|
std::string default_submap_ = "Default";
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
|
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
|
||||||
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
|
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
|
||||||
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
|
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
|
||||||
|
auto barScroll() const -> bool { return m_barScroll; }
|
||||||
|
|
||||||
auto getBarOutput() const -> std::string { return m_bar.output->name; }
|
auto getBarOutput() const -> std::string { return m_bar.output->name; }
|
||||||
auto formatBefore() const -> std::string { return m_formatBefore; }
|
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::pair<std::string, std::string> splitDoublePayload(std::string const& payload);
|
||||||
static std::tuple<std::string, std::string, std::string> splitTriplePayload(
|
static std::tuple<std::string, std::string, std::string> splitTriplePayload(
|
||||||
std::string const& payload);
|
std::string const& payload);
|
||||||
|
// scroll events
|
||||||
|
bool handleScroll(GdkEventScroll* e) override;
|
||||||
|
|
||||||
// Update methods
|
// Update methods
|
||||||
void doUpdate();
|
void doUpdate();
|
||||||
@@ -145,6 +148,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
bool m_specialVisibleOnly = false;
|
bool m_specialVisibleOnly = false;
|
||||||
bool m_persistentOnly = false;
|
bool m_persistentOnly = false;
|
||||||
bool m_moveToMonitor = false;
|
bool m_moveToMonitor = false;
|
||||||
|
bool m_barScroll = false;
|
||||||
Json::Value m_persistentWorkspaceConfig;
|
Json::Value m_persistentWorkspaceConfig;
|
||||||
|
|
||||||
// Map for windows stored in workspaces not present in the current bar.
|
// Map for windows stored in workspaces not present in the current bar.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
#include <gtkmm/label.h>
|
#include <gtkmm/label.h>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ class KeyboardState : public AModule {
|
|||||||
|
|
||||||
struct libinput* libinput_;
|
struct libinput* libinput_;
|
||||||
std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
|
std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
|
||||||
|
std::mutex devices_mutex_; // protects libinput_devices_
|
||||||
std::set<int> binding_keys;
|
std::set<int> binding_keys;
|
||||||
|
|
||||||
util::SleeperThread libinput_thread_, hotplug_thread_;
|
util::SleeperThread libinput_thread_, hotplug_thread_;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
#include "util/sleeper_thread.hpp"
|
#include "util/sleeper_thread.hpp"
|
||||||
|
#include "util/SafeSignal.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::sway {
|
namespace waybar::modules::sway {
|
||||||
|
|
||||||
@@ -27,8 +28,8 @@ class Ipc {
|
|||||||
std::string payload;
|
std::string payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
sigc::signal<void, const struct ipc_response &> signal_event;
|
::waybar::SafeSignal<const struct ipc_response&> signal_event;
|
||||||
sigc::signal<void, const struct ipc_response &> signal_cmd;
|
::waybar::SafeSignal<const struct ipc_response&> signal_cmd;
|
||||||
|
|
||||||
void sendCmd(uint32_t type, const std::string& payload = "");
|
void sendCmd(uint32_t type, const std::string& payload = "");
|
||||||
void subscribe(const std::string& payload);
|
void subscribe(const std::string& payload);
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ class Taskbar;
|
|||||||
|
|
||||||
class Task {
|
class Task {
|
||||||
public:
|
public:
|
||||||
Task(const waybar::Bar &, const Json::Value &, Taskbar *,
|
Task(const waybar::Bar&, const Json::Value&, Taskbar*, struct zwlr_foreign_toplevel_handle_v1*,
|
||||||
struct zwlr_foreign_toplevel_handle_v1 *, struct wl_seat *);
|
struct wl_seat*);
|
||||||
~Task();
|
~Task();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ inline FILE* open(const std::string& cmd, int& pid, const std::string& output_na
|
|||||||
::close(fd[0]);
|
::close(fd[0]);
|
||||||
dup2(fd[1], 1);
|
dup2(fd[1], 1);
|
||||||
setpgid(child_pid, child_pid);
|
setpgid(child_pid, child_pid);
|
||||||
if (output_name != "") {
|
if (!output_name.empty()) {
|
||||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||||
}
|
}
|
||||||
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
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), ""};
|
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;
|
if (cmd == "") return -1;
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
@@ -157,6 +157,9 @@ inline int32_t forkExec(const std::string& cmd) {
|
|||||||
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
|
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
|
||||||
if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err));
|
if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err));
|
||||||
setpgid(pid, pid);
|
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);
|
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||||
exit(0);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -169,4 +172,6 @@ inline int32_t forkExec(const std::string& cmd) {
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int32_t forkExec(const std::string& cmd) { return forkExec(cmd, ""); }
|
||||||
|
|
||||||
} // namespace waybar::util::command
|
} // namespace waybar::util::command
|
||||||
|
|||||||
@@ -30,15 +30,16 @@ class JsonParser {
|
|||||||
|
|
||||||
std::istringstream jsonStream(modifiedJsonStr);
|
std::istringstream jsonStream(modifiedJsonStr);
|
||||||
std::string errs;
|
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);
|
throw std::runtime_error("Error parsing JSON: " + errs);
|
||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Json::CharReaderBuilder m_readerBuilder;
|
|
||||||
|
|
||||||
static std::string replaceHexadecimalEscape(const std::string& str) {
|
static std::string replaceHexadecimalEscape(const std::string& str) {
|
||||||
static std::regex re("\\\\x");
|
static std::regex re("\\\\x");
|
||||||
return std::regex_replace(str, re, "\\u00");
|
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 ++
|
typeof: string ++
|
||||||
Command to execute when scrolling up on the module.
|
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*: ++
|
*on-scroll-down*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
Command to execute when scrolling down on the module.
|
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>-<state>*
|
||||||
- *on-<status>-<capacity>*
|
- *on-<status>-<capacity>*
|
||||||
|
- *on-<status>*
|
||||||
|
|
||||||
Where:
|
Where:
|
||||||
|
|
||||||
@@ -198,7 +204,9 @@ Where:
|
|||||||
"events": {
|
"events": {
|
||||||
"on-discharging-warning": "notify-send -u normal 'Low Battery'",
|
"on-discharging-warning": "notify-send -u normal 'Low Battery'",
|
||||||
"on-discharging-critical": "notify-send -u critical 'Very 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": "{capacity}% {icon}",
|
||||||
"format-icons": ["", "", "", "", ""],
|
"format-icons": ["", "", "", "", ""],
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ waybar - cava module
|
|||||||
|
|
||||||
*cava* module for karlstav/cava project. See it on github: https://github.com/karlstav/cava.
|
*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
|
# FILES
|
||||||
|
|
||||||
@@ -32,6 +34,10 @@ libcava lives in:
|
|||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
:< Path where cava configuration file is placed to
|
:< Path where cava configuration file is placed to
|
||||||
|
|[ *method* \[output\]
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:< Manages which frontend Waybar cava module should use. Values: raw, sdl_glsl
|
||||||
|[ *framerate*
|
|[ *framerate*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 30
|
:[ 30
|
||||||
@@ -43,7 +49,7 @@ libcava lives in:
|
|||||||
|[ *sensitivity*
|
|[ *sensitivity*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 100
|
:[ 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*
|
|[ *bars*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 12
|
:[ 12
|
||||||
@@ -68,7 +74,7 @@ libcava lives in:
|
|||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
:[ Widget's text after sleep_timer elapsed (hide_on_silence has to be false)
|
:[ Widget's text after sleep_timer elapsed (hide_on_silence has to be false)
|
||||||
|[ *method*
|
|[ *method* \[input\]
|
||||||
:[ string
|
:[ string
|
||||||
:[ pulse
|
:[ pulse
|
||||||
:[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem
|
:[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem
|
||||||
@@ -105,9 +111,9 @@ libcava lives in:
|
|||||||
:[ false
|
:[ false
|
||||||
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|
||||||
|[ *noise_reduction*
|
|[ *noise_reduction*
|
||||||
:[ double
|
:[ integer
|
||||||
:[ 0.77
|
:[ 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
|
:[ 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*
|
|[ *input_delay*
|
||||||
:[ integer
|
:[ integer
|
||||||
:[ 2
|
:[ 2
|
||||||
@@ -119,11 +125,11 @@ libcava lives in:
|
|||||||
|[ *data_format*
|
|[ *data_format*
|
||||||
:[ string
|
:[ string
|
||||||
:[ asci
|
:[ 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*
|
|[ *raw_target*
|
||||||
:[ string
|
:[ string
|
||||||
:[ /dev/stdout
|
:[ /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*
|
|[ *menu*
|
||||||
:[ string
|
:[ string
|
||||||
:[
|
:[
|
||||||
@@ -136,6 +142,50 @@ libcava lives in:
|
|||||||
:[ array
|
:[ array
|
||||||
:[
|
:[
|
||||||
:[ The actions corresponding to the buttons of the menu.
|
:[ 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:
|
Configuration can be provided as:
|
||||||
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped
|
- 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
|
- iniparser
|
||||||
- fftw3
|
- fftw3
|
||||||
|
- epoxy (GLSL frontend only)
|
||||||
|
|
||||||
# SOLVING ISSUES
|
# 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*
|
||||||
- *#cava.silent* Applied after no sound has been detected for sleep_timer seconds
|
- *#cava.silent* Applied after no sound has been detected for sleep_timer seconds
|
||||||
- *#cava.updated* Applied when a new frame is shown
|
- *#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": {
|
"custom/pacman": {
|
||||||
"format": "{text} ",
|
"format": "{text} ",
|
||||||
"interval": 3600, // every hour
|
|
||||||
"exec": "checkupdates | wc -l", // # of updates
|
"exec": "checkupdates | wc -l", // # of updates
|
||||||
"exec-if": "exit 0", // always run; consider advanced run conditions
|
"exec-if": "exit 0", // always run; consider advanced run conditions
|
||||||
"on-click": "termite -e 'sudo pacman -Syu'; pkill -SIGRTMIN+8 waybar", // update system
|
"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
|
# STYLE
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ Addressed by *dwl/tags*
|
|||||||
|
|
||||||
- *#tags button*
|
- *#tags button*
|
||||||
- *#tags button.occupied*
|
- *#tags button.occupied*
|
||||||
|
- *#tags button.empty*
|
||||||
- *#tags button.focused*
|
- *#tags button.focused*
|
||||||
- *#tags button.urgent*
|
- *#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.
|
Otherwise, the workspace will open on the monitor where it was previously assigned.
|
||||||
Analog to using `focusworkspaceoncurrentmonitor` dispatcher instead of `workspace` in Hyprland.
|
Analog to using `focusworkspaceoncurrentmonitor` dispatcher instead of `workspace` in Hyprland.
|
||||||
|
|
||||||
|
*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*: ++
|
*ignore-workspaces*: ++
|
||||||
typeof: array ++
|
typeof: array ++
|
||||||
default: [] ++
|
default: [] ++
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ The *image* module displays an image from a path.
|
|||||||
*interval*: ++
|
*interval*: ++
|
||||||
typeof: integer or float ++
|
typeof: integer or float ++
|
||||||
The interval (in seconds) to re-render the image. ++
|
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. ++
|
This is useful if the contents of *path* changes. ++
|
||||||
If no *interval* is defined, the image will only be rendered once.
|
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*: ++
|
*reverse-scrolling*: ++
|
||||||
typeof: bool ++
|
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*: ++
|
*tooltip*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
@@ -173,8 +177,8 @@ to be selected when the corresponding audio device is muted. This applies to *de
|
|||||||
"format-icons": {
|
"format-icons": {
|
||||||
"alsa_output.pci-0000_00_1f.3.analog-stereo": "",
|
"alsa_output.pci-0000_00_1f.3.analog-stereo": "",
|
||||||
"alsa_output.pci-0000_00_1f.3.analog-stereo-muted": "",
|
"alsa_output.pci-0000_00_1f.3.analog-stereo-muted": "",
|
||||||
"headphones": "",
|
"headphone": "",
|
||||||
"handsfree": "",
|
"hands-free": "",
|
||||||
"headset": "",
|
"headset": "",
|
||||||
"phone": "",
|
"phone": "",
|
||||||
"phone-muted": "",
|
"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": "<span size='larger'>{name}</span> {windows}",
|
||||||
"format-window-separator": " | ",
|
"format-window-separator": " | ",
|
||||||
"window-rewrite-default": "{name}",
|
"window-rewrite-default": "{name}",
|
||||||
"window-format": "<span color='#e0e0e0'>{name}</span>",
|
|
||||||
"window-rewrite": {
|
"window-rewrite": {
|
||||||
"class<firefox>": "",
|
"class<firefox>": "",
|
||||||
"class<kitty>": "k",
|
"class<kitty>": "k",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ The visual display elements for waybar use a CSS stylesheet, see *waybar-styles(
|
|||||||
*expand-right* ++
|
*expand-right* ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
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* ++
|
*layer* ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
|
|||||||
19
meson.build
19
meson.build
@@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.14.0',
|
version: '0.15.0',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>= 0.59.0',
|
meson_version: '>= 0.59.0',
|
||||||
default_options : [
|
default_options : [
|
||||||
@@ -497,16 +497,24 @@ else
|
|||||||
man_files += files('man/waybar-clock.5.scd')
|
man_files += files('man/waybar-clock.5.scd')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
cava = dependency('cava',
|
cava = dependency('libcava',
|
||||||
version : '>=0.10.6',
|
version : '>=0.10.7',
|
||||||
required: get_option('cava'),
|
required: get_option('cava'),
|
||||||
fallback : ['cava', 'cava_dep'],
|
fallback : ['libcava', 'cava_dep'],
|
||||||
not_found_message: 'cava is not found. Building waybar without cava')
|
not_found_message: 'cava is not found. Building waybar without cava')
|
||||||
|
|
||||||
|
eproxy = dependency('epoxy', required: false)
|
||||||
|
|
||||||
if cava.found()
|
if cava.found()
|
||||||
add_project_arguments('-DHAVE_LIBCAVA', language: 'cpp')
|
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')
|
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
|
endif
|
||||||
|
|
||||||
if libgps.found()
|
if libgps.found()
|
||||||
@@ -554,6 +562,7 @@ executable(
|
|||||||
tz_dep,
|
tz_dep,
|
||||||
xkbregistry,
|
xkbregistry,
|
||||||
cava,
|
cava,
|
||||||
|
eproxy,
|
||||||
libgps
|
libgps
|
||||||
],
|
],
|
||||||
include_directories: inc_dirs,
|
include_directories: inc_dirs,
|
||||||
|
|||||||
@@ -5,13 +5,14 @@
|
|||||||
version,
|
version,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
libcava = {
|
libcava = rec {
|
||||||
|
version = "0.10.7-beta";
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
owner = "LukashonakV";
|
owner = "LukashonakV";
|
||||||
repo = "cava";
|
repo = "cava";
|
||||||
# NOTE: Needs to match the cava.wrap
|
# NOTE: Needs to match the cava.wrap
|
||||||
rev = "23efcced43b5a395747b18a2e5f2171fc0925d18";
|
tag = "v${version}";
|
||||||
hash = "sha256-CNspaoK5KuME0GfaNijpC24BfALngzNi04/VNwPqMvo=";
|
hash = "sha256-IX1B375gTwVDRjpRfwKGuzTAZOV2pgDWzUd4bW2cTDU=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
@@ -39,7 +40,7 @@ waybar.overrideAttrs (oldAttrs: {
|
|||||||
|
|
||||||
postUnpack = ''
|
postUnpack = ''
|
||||||
pushd "$sourceRoot"
|
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 .
|
patchShebangs .
|
||||||
popd
|
popd
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ void AAppIconLabel::updateAppIconName(const std::string& app_identifier,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AAppIconLabel::updateAppIcon() {
|
void AAppIconLabel::updateAppIcon() {
|
||||||
if (update_app_icon_) {
|
if (update_app_icon_ || (!iconEnabled() && image_.get_visible())) {
|
||||||
update_app_icon_ = false;
|
update_app_icon_ = false;
|
||||||
if (app_icon_name_.empty()) {
|
if (app_icon_name_.empty()) {
|
||||||
image_.set_visible(false);
|
image_.set_visible(false);
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ALabel::handleGtkMenuEvent(GtkMenuItem* /*menuitem*/, gpointer data) {
|
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) {
|
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_init_for_window(gtk_window);
|
||||||
gtk_layer_set_keyboard_mode(gtk_window, GTK_LAYER_SHELL_KEYBOARD_MODE_NONE);
|
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_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_LEFT, margins_.left);
|
||||||
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right);
|
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) {
|
if (xdg_output_manager == nullptr) {
|
||||||
throw std::runtime_error("Failed to acquire required resources.");
|
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
|
// add existing outputs and subscribe to updates
|
||||||
for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) {
|
for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) {
|
||||||
auto monitor = gdk_display->get_monitor(i);
|
auto monitor = gdk_display->get_monitor(i);
|
||||||
handleMonitorAdded(monitor);
|
handleMonitorAdded(monitor);
|
||||||
}
|
}
|
||||||
gdk_display->signal_monitor_added().connect(sigc::mem_fun(*this, &Client::handleMonitorAdded));
|
monitor_added_connection_ = gdk_display->signal_monitor_added().connect(
|
||||||
gdk_display->signal_monitor_removed().connect(
|
sigc::mem_fun(*this, &Client::handleMonitorAdded));
|
||||||
|
monitor_removed_connection_ = gdk_display->signal_monitor_removed().connect(
|
||||||
sigc::mem_fun(*this, &Client::handleMonitorRemoved));
|
sigc::mem_fun(*this, &Client::handleMonitorRemoved));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,15 +108,13 @@
|
|||||||
#ifdef HAVE_LIBWIREPLUMBER
|
#ifdef HAVE_LIBWIREPLUMBER
|
||||||
#include "modules/wireplumber.hpp"
|
#include "modules/wireplumber.hpp"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBCAVA
|
|
||||||
#include "modules/cava/cava.hpp"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SYSTEMD_MONITOR
|
#ifdef HAVE_SYSTEMD_MONITOR
|
||||||
#include "modules/systemd_failed_units.hpp"
|
#include "modules/systemd_failed_units.hpp"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBGPS
|
#ifdef HAVE_LIBGPS
|
||||||
#include "modules/gps.hpp"
|
#include "modules/gps.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#include "modules/cava/cava_frontend.hpp"
|
||||||
#include "modules/cffi.hpp"
|
#include "modules/cffi.hpp"
|
||||||
#include "modules/custom.hpp"
|
#include "modules/custom.hpp"
|
||||||
#include "modules/image.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]);
|
return new waybar::modules::Wireplumber(id, config_[name]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBCAVA
|
|
||||||
if (ref == "cava") {
|
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
|
#ifdef HAVE_SYSTEMD_MONITOR
|
||||||
if (ref == "systemd-failed-units") {
|
if (ref == "systemd-failed-units") {
|
||||||
return new waybar::modules::SystemdFailedUnits(id, config_[name]);
|
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,
|
Group::Group(const std::string& name, const std::string& id, const Json::Value& config,
|
||||||
bool vertical)
|
bool vertical)
|
||||||
: AModule(config, name, id, true, true),
|
: AModule(config, name, id, true, false),
|
||||||
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
|
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
|
||||||
revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
|
revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
|
||||||
box.set_name(name_);
|
box.set_name(name_);
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ auto waybar::modules::Backlight::update() -> void {
|
|||||||
tooltip_format = config_["tooltip-format"].asString();
|
tooltip_format = config_["tooltip-format"].asString();
|
||||||
}
|
}
|
||||||
if (!tooltip_format.empty()) {
|
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("percent", percent),
|
||||||
fmt::arg("icon", getIcon(percent))));
|
fmt::arg("icon", getIcon(percent))));
|
||||||
} else {
|
} else {
|
||||||
label_.set_tooltip_text(desc);
|
label_.set_tooltip_markup(desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,7 +7,10 @@
|
|||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <libudev.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <sys/signalfd.h>
|
||||||
|
|
||||||
waybar::modules::Battery::Battery(const std::string& id, const Bar& bar, const Json::Value& config)
|
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) {
|
: 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) {
|
if (battery_watch_fd_ == -1) {
|
||||||
throw std::runtime_error("Unable to listen batteries.");
|
throw std::runtime_error("Unable to listen batteries.");
|
||||||
}
|
}
|
||||||
|
udev_ = std::unique_ptr<udev, util::UdevDeleter>(udev_new());
|
||||||
global_watch_fd_ = inotify_init1(IN_CLOEXEC);
|
if (udev_ == nullptr) {
|
||||||
if (global_watch_fd_ == -1) {
|
throw std::runtime_error("udev_new failed");
|
||||||
throw std::runtime_error("Unable to listen batteries.");
|
|
||||||
}
|
}
|
||||||
|
mon_ = std::unique_ptr<udev_monitor, util::UdevMonitorDeleter>(
|
||||||
// Watch the directory for any added or removed batteries
|
udev_monitor_new_from_netlink(udev_.get(), "kernel"));
|
||||||
global_watch = inotify_add_watch(global_watch_fd_, data_dir_.c_str(), IN_CREATE | IN_DELETE);
|
if (mon_ == nullptr) {
|
||||||
if (global_watch < 0) {
|
throw std::runtime_error("udev monitor new failed");
|
||||||
throw std::runtime_error("Could not watch for battery plug/unplug");
|
|
||||||
}
|
}
|
||||||
|
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
|
#endif
|
||||||
spdlog::debug("battery: worker interval is {}", interval_.count());
|
spdlog::debug("battery: worker interval is {}", interval_.count());
|
||||||
worker();
|
worker();
|
||||||
@@ -36,11 +43,6 @@ waybar::modules::Battery::~Battery() {
|
|||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
std::lock_guard<std::mutex> guard(battery_list_mutex_);
|
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) {
|
for (auto it = batteries_.cbegin(), next_it = it; it != batteries_.cend(); it = next_it) {
|
||||||
++next_it;
|
++next_it;
|
||||||
auto watch_id = (*it).second;
|
auto watch_id = (*it).second;
|
||||||
@@ -77,12 +79,18 @@ void waybar::modules::Battery::worker() {
|
|||||||
dp.emit();
|
dp.emit();
|
||||||
};
|
};
|
||||||
thread_battery_update_ = [this] {
|
thread_battery_update_ = [this] {
|
||||||
struct inotify_event event = {0};
|
poll_fds_[0].revents = 0;
|
||||||
int nbytes = read(global_watch_fd_, &event, sizeof(event));
|
poll_fds_[0].events = POLLIN;
|
||||||
if (nbytes != sizeof(event) || event.mask & IN_IGNORED) {
|
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();
|
thread_.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ((poll_fds_[0].revents & POLLIN) != 0) {
|
||||||
|
signalfd_siginfo signal_info;
|
||||||
|
read(poll_fds_[0].fd, &signal_info, sizeof(signal_info));
|
||||||
|
}
|
||||||
refreshBatteries();
|
refreshBatteries();
|
||||||
dp.emit();
|
dp.emit();
|
||||||
};
|
};
|
||||||
@@ -585,8 +593,7 @@ waybar::modules::Battery::getInfos() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle weighted-average
|
// Handle weighted-average
|
||||||
if ((config_["weighted-average"].isBool() ? config_["weighted-average"].asBool() : false) &&
|
if (weightedAverage_ && total_energy_exists && total_energy_full_exists) {
|
||||||
total_energy_exists && total_energy_full_exists) {
|
|
||||||
if (total_energy_full > 0.0f)
|
if (total_energy_full > 0.0f)
|
||||||
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
|
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
|
||||||
}
|
}
|
||||||
@@ -679,6 +686,7 @@ auto waybar::modules::Battery::update() -> void {
|
|||||||
status = getAdapterStatus(capacity);
|
status = getAdapterStatus(capacity);
|
||||||
}
|
}
|
||||||
auto status_pretty = status;
|
auto status_pretty = status;
|
||||||
|
|
||||||
// Transform to lowercase and replace space with dash
|
// Transform to lowercase and replace space with dash
|
||||||
std::ranges::transform(status.begin(), status.end(), status.begin(),
|
std::ranges::transform(status.begin(), status.end(), status.begin(),
|
||||||
[](char ch) { return ch == ' ' ? '-' : std::tolower(ch); });
|
[](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()) {
|
if (!events.isObject() || events.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string event_name = fmt::format("on-{}-{}", status == "discharging" ? status : "charging",
|
auto exec = [](Json::Value const& event) {
|
||||||
state.empty() ? std::to_string(capacity) : state);
|
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) {
|
if (last_event_ != event_name) {
|
||||||
spdlog::debug("battery: triggering event {}", event_name);
|
spdlog::debug("battery: triggering event {}", event_name);
|
||||||
if (events[event_name].isString()) {
|
exec(events[event_name]);
|
||||||
std::string exec = events[event_name].asString();
|
if (!last_event_.empty() && last_event_[3] != event_name[3]) {
|
||||||
// Execute the command if it is not empty
|
exec(events[status_name]);
|
||||||
if (!exec.empty()) {
|
|
||||||
util::command::exec(exec, "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
last_event_ = event_name;
|
last_event_ = event_name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ auto waybar::modules::Bluetooth::update() -> void {
|
|||||||
device_enumerate_.erase(0, 1);
|
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::runtime(tooltip_format), fmt::arg("status", state_),
|
||||||
fmt::arg("num_connections", connected_devices_.size()),
|
fmt::arg("num_connections", connected_devices_.size()),
|
||||||
fmt::arg("controller_address", cur_controller_ ? cur_controller_->address : "null"),
|
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>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
@@ -24,8 +24,11 @@ auto waybar::modules::cava::Cava::doAction(const std::string& name) -> void {
|
|||||||
// Cava actions
|
// Cava actions
|
||||||
void waybar::modules::cava::Cava::pause_resume() { backend_->doPauseResume(); }
|
void waybar::modules::cava::Cava::pause_resume() { backend_->doPauseResume(); }
|
||||||
auto waybar::modules::cava::Cava::onUpdate(const std::string& input) -> void {
|
auto waybar::modules::cava::Cava::onUpdate(const std::string& input) -> void {
|
||||||
|
Glib::signal_idle().connect_once([this, input]() {
|
||||||
if (silence_) {
|
if (silence_) {
|
||||||
|
silence_ = false;
|
||||||
label_.get_style_context()->remove_class("silent");
|
label_.get_style_context()->remove_class("silent");
|
||||||
|
if (!label_.get_style_context()->has_class("updated"))
|
||||||
label_.get_style_context()->add_class("updated");
|
label_.get_style_context()->add_class("updated");
|
||||||
}
|
}
|
||||||
label_text_.clear();
|
label_text_.clear();
|
||||||
@@ -35,17 +38,23 @@ auto waybar::modules::cava::Cava::onUpdate(const std::string& input) -> void {
|
|||||||
label_.set_markup(label_text_);
|
label_.set_markup(label_text_);
|
||||||
label_.show();
|
label_.show();
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
silence_ = false;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::cava::Cava::onSilence() -> void {
|
auto waybar::modules::cava::Cava::onSilence() -> void {
|
||||||
|
Glib::signal_idle().connect_once([this]() {
|
||||||
if (!silence_) {
|
if (!silence_) {
|
||||||
|
if (label_.get_style_context()->has_class("updated"))
|
||||||
label_.get_style_context()->remove_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();
|
label_.hide();
|
||||||
else if (config_["format_silent"].isString())
|
} else if (config_["format_silent"].isString())
|
||||||
label_.set_markup(format_silent_);
|
label_.set_markup(format_silent_);
|
||||||
silence_ = true;
|
silence_ = true;
|
||||||
label_.get_style_context()->add_class("silent");
|
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;
|
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
|
// Load waybar module config
|
||||||
char cfgPath[PATH_MAX];
|
loadConfig();
|
||||||
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
|
|
||||||
// Read audio source trough cava API. Cava orginizes this process via infinity loop
|
// Read audio source trough cava API. Cava orginizes this process via infinity loop
|
||||||
read_thread_ = [this] {
|
read_thread_ = [this] {
|
||||||
try {
|
try {
|
||||||
@@ -102,41 +20,38 @@ waybar::modules::cava::CavaBackend::CavaBackend(const Json::Value& config) {
|
|||||||
spdlog::warn("Cava backend. Read source error: {0}", e.what());
|
spdlog::warn("Cava backend. Read source error: {0}", e.what());
|
||||||
}
|
}
|
||||||
read_thread_.sleep_for(fetch_input_delay_);
|
read_thread_.sleep_for(fetch_input_delay_);
|
||||||
|
loadConfig();
|
||||||
};
|
};
|
||||||
|
// Write outcoming data. Emit signals
|
||||||
thread_ = [this] {
|
out_thread_ = [this] {
|
||||||
doUpdate();
|
doUpdate(false);
|
||||||
thread_.sleep_for(frame_time_milsec_);
|
out_thread_.sleep_for(frame_time_milsec_);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
waybar::modules::cava::CavaBackend::~CavaBackend() {
|
waybar::modules::cava::CavaBackend::~CavaBackend() {
|
||||||
thread_.stop();
|
out_thread_.stop();
|
||||||
read_thread_.stop();
|
read_thread_.stop();
|
||||||
cava_destroy(plan_);
|
|
||||||
delete plan_;
|
freeBackend();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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}) {
|
if (delta == std::chrono::seconds{0}) {
|
||||||
delta += std::chrono::seconds{1};
|
delta += std::chrono::seconds{1};
|
||||||
delay += delta;
|
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}) {
|
if (delta > std::chrono::seconds{0}) {
|
||||||
delay -= delta;
|
delay -= delta;
|
||||||
delta -= std::chrono::seconds{1};
|
delta -= std::chrono::seconds{1};
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool waybar::modules::cava::CavaBackend::isSilence() {
|
bool waybar::modules::cava::CavaBackend::isSilence() {
|
||||||
@@ -186,6 +101,7 @@ void waybar::modules::cava::CavaBackend::doPauseResume() {
|
|||||||
upThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
upThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&audio_data_.lock);
|
pthread_mutex_unlock(&audio_data_.lock);
|
||||||
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
waybar::modules::cava::CavaBackend::type_signal_update
|
waybar::modules::cava::CavaBackend::type_signal_update
|
||||||
@@ -193,6 +109,11 @@ waybar::modules::cava::CavaBackend::signal_update() {
|
|||||||
return m_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::type_signal_silence
|
||||||
waybar::modules::cava::CavaBackend::signal_silence() {
|
waybar::modules::cava::CavaBackend::signal_silence() {
|
||||||
return m_signal_silence_;
|
return m_signal_silence_;
|
||||||
@@ -215,12 +136,138 @@ void waybar::modules::cava::CavaBackend::doUpdate(bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!silence_ || prm_.sleep_timer == 0) {
|
if (!silence_ || prm_.sleep_timer == 0) {
|
||||||
downThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
if (downThreadDelay(frame_time_milsec_, suspend_silence_delay_)) Update();
|
||||||
execute();
|
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 {
|
} 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();
|
if (silence_ != silence_prev_ || force) m_signal_silence_.emit();
|
||||||
}
|
}
|
||||||
silence_prev_ = silence_;
|
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 [load1, load5, load15] = Load::getLoad();
|
||||||
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
|
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
|
||||||
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
|
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
|
||||||
if (tooltipEnabled()) {
|
|
||||||
label_.set_tooltip_text(tooltip);
|
|
||||||
}
|
|
||||||
auto format = format_;
|
auto format = format_;
|
||||||
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
|
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
|
||||||
auto state = getState(total_usage);
|
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)));
|
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
|
||||||
}
|
}
|
||||||
label_.set_markup(fmt::vformat(format, store));
|
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
|
// Call parent update
|
||||||
|
|||||||
@@ -20,12 +20,7 @@ waybar::modules::CpuFrequency::CpuFrequency(const std::string& id, const Json::V
|
|||||||
auto waybar::modules::CpuFrequency::update() -> void {
|
auto waybar::modules::CpuFrequency::update() -> void {
|
||||||
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
||||||
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
|
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 format = format_;
|
||||||
auto state = getState(avg_frequency);
|
auto state = getState(avg_frequency);
|
||||||
if (!state.empty() && config_["format-" + state].isString()) {
|
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("min_frequency", min_frequency));
|
||||||
store.push_back(fmt::arg("avg_frequency", avg_frequency));
|
store.push_back(fmt::arg("avg_frequency", avg_frequency));
|
||||||
label_.set_markup(fmt::vformat(format, store));
|
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
|
// 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 {
|
auto waybar::modules::CpuUsage::update() -> void {
|
||||||
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
|
||||||
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
|
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
|
||||||
if (tooltipEnabled()) {
|
|
||||||
label_.set_tooltip_text(tooltip);
|
|
||||||
}
|
|
||||||
auto format = format_;
|
auto format = format_;
|
||||||
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
|
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
|
||||||
auto state = getState(total_usage);
|
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)));
|
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
|
||||||
}
|
}
|
||||||
label_.set_markup(fmt::vformat(format, store));
|
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
|
// Call parent update
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ void waybar::modules::Custom::waitingWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Custom::refresh(int sig) {
|
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();
|
thread_.wake_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,15 +187,11 @@ auto waybar::modules::Custom::update() -> void {
|
|||||||
fmt::arg("icon", getIcon(percentage_, alt_)), fmt::arg("percentage", percentage_));
|
fmt::arg("icon", getIcon(percentage_, alt_)), fmt::arg("percentage", percentage_));
|
||||||
label_.set_tooltip_markup(tooltip);
|
label_.set_tooltip_markup(tooltip);
|
||||||
} else if (text_ == tooltip_) {
|
} else if (text_ == tooltip_) {
|
||||||
if (label_.get_tooltip_markup() != str) {
|
|
||||||
label_.set_tooltip_markup(str);
|
label_.set_tooltip_markup(str);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (label_.get_tooltip_markup() != tooltip_) {
|
|
||||||
label_.set_tooltip_markup(tooltip_);
|
label_.set_tooltip_markup(tooltip_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
auto style = label_.get_style_context();
|
auto style = label_.get_style_context();
|
||||||
auto classes = style->list_classes();
|
auto classes = style->list_classes();
|
||||||
for (auto const& c : classes) {
|
for (auto const& c : classes) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ auto waybar::modules::Disk::update() -> void {
|
|||||||
if (config_["tooltip-format"].isString()) {
|
if (config_["tooltip-format"].isString()) {
|
||||||
tooltip_format = config_["tooltip-format"].asString();
|
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::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_free", stats.f_bavail * 100 / stats.f_blocks), fmt::arg("used", used),
|
||||||
fmt::arg("percentage_used", percentage_used), fmt::arg("total", total),
|
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) {
|
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||||
version = std::min<uint32_t>(version, 1);
|
version = std::min<uint32_t>(version, 1);
|
||||||
static_cast<Tags *>(data)->seat_ = static_cast<struct wl_seat *>(
|
static_cast<Tags*>(data)->seat_ =
|
||||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
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");
|
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) {
|
if (state & TAG_ACTIVE) {
|
||||||
button.get_style_context()->add_class("focused");
|
button.get_style_context()->add_class("focused");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ void Window::handle_frame() {
|
|||||||
updateAppIconName(appid_, "");
|
updateAppIconName(appid_, "");
|
||||||
updateAppIcon();
|
updateAppIcon();
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
label_.set_tooltip_text(title_);
|
label_.set_tooltip_markup(title_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ auto Gamemode::update() -> void {
|
|||||||
// Tooltip
|
// Tooltip
|
||||||
if (tooltip) {
|
if (tooltip) {
|
||||||
std::string text = fmt::format(fmt::runtime(tooltip_format), fmt::arg("count", gameCount));
|
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
|
// Label format
|
||||||
|
|||||||
@@ -44,12 +44,23 @@ auto Submap::parseConfig(const Json::Value& config) -> void {
|
|||||||
auto Submap::update() -> void {
|
auto Submap::update() -> void {
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
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()) {
|
if (submap_.empty()) {
|
||||||
event_box_.hide();
|
event_box_.hide();
|
||||||
} else {
|
} else {
|
||||||
label_.set_markup(fmt::format(fmt::runtime(format_), submap_));
|
label_.set_markup(fmt::format(fmt::runtime(format_), submap_));
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
label_.set_tooltip_text(submap_);
|
label_.set_tooltip_markup(submap_);
|
||||||
}
|
}
|
||||||
event_box_.show();
|
event_box_.show();
|
||||||
}
|
}
|
||||||
@@ -66,18 +77,12 @@ void Submap::onEvent(const std::string& ev) {
|
|||||||
|
|
||||||
auto submapName = ev.substr(ev.find_first_of('>') + 2);
|
auto submapName = ev.substr(ev.find_first_of('>') + 2);
|
||||||
|
|
||||||
if (!submap_.empty()) {
|
|
||||||
label_.get_style_context()->remove_class(submap_);
|
|
||||||
}
|
|
||||||
|
|
||||||
submap_ = submapName;
|
submap_ = submapName;
|
||||||
|
|
||||||
if (submap_.empty() && always_on_) {
|
if (submap_.empty() && always_on_) {
|
||||||
submap_ = default_submap_;
|
submap_ = default_submap_;
|
||||||
}
|
}
|
||||||
|
|
||||||
label_.get_style_context()->add_class(submap_);
|
|
||||||
|
|
||||||
spdlog::debug("hyprland submap onevent with {}", submap_);
|
spdlog::debug("hyprland submap onevent with {}", submap_);
|
||||||
|
|
||||||
dp.emit();
|
dp.emit();
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ Window::~Window() {
|
|||||||
auto Window::update() -> void {
|
auto Window::update() -> void {
|
||||||
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
||||||
|
|
||||||
|
queryActiveWorkspace();
|
||||||
|
|
||||||
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
|
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
|
||||||
std::string windowAddress = workspace_.last_window;
|
std::string windowAddress = workspace_.last_window;
|
||||||
|
|
||||||
@@ -70,13 +72,13 @@ auto Window::update() -> void {
|
|||||||
tooltip_format = config_["tooltip-format"].asString();
|
tooltip_format = config_["tooltip-format"].asString();
|
||||||
}
|
}
|
||||||
if (!tooltip_format.empty()) {
|
if (!tooltip_format.empty()) {
|
||||||
label_.set_tooltip_text(
|
label_.set_tooltip_markup(
|
||||||
fmt::format(fmt::runtime(tooltip_format), fmt::arg("title", windowName),
|
fmt::format(fmt::runtime(tooltip_format), fmt::arg("title", windowName),
|
||||||
fmt::arg("initialTitle", windowData_.initial_title),
|
fmt::arg("initialTitle", windowData_.initial_title),
|
||||||
fmt::arg("class", windowData_.class_name),
|
fmt::arg("class", windowData_.class_name),
|
||||||
fmt::arg("initialClass", windowData_.initial_class_name)));
|
fmt::arg("initialClass", windowData_.initial_class_name)));
|
||||||
} else if (!label_text.empty()) {
|
} 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) {
|
void Window::onEvent(const std::string& ev) { dp.emit(); }
|
||||||
queryActiveWorkspace();
|
|
||||||
|
|
||||||
dp.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::setClass(const std::string& classname, bool enable) {
|
void Window::setClass(const std::string& classname, bool enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ WindowCount::~WindowCount() {
|
|||||||
auto WindowCount::update() -> void {
|
auto WindowCount::update() -> void {
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
|
||||||
|
queryActiveWorkspace();
|
||||||
|
|
||||||
std::string format = config_["format"].asString();
|
std::string format = config_["format"].asString();
|
||||||
std::string formatEmpty = config_["format-empty"].asString();
|
std::string formatEmpty = config_["format-empty"].asString();
|
||||||
std::string formatWindowed = config_["format-windowed"].asString();
|
std::string formatWindowed = config_["format-windowed"].asString();
|
||||||
@@ -56,7 +58,7 @@ auto WindowCount::update() -> void {
|
|||||||
} else if (!format.empty()) {
|
} else if (!format.empty()) {
|
||||||
label_.set_markup(fmt::format(fmt::runtime(format), workspace_.windows));
|
label_.set_markup(fmt::format(fmt::runtime(format), workspace_.windows));
|
||||||
} else {
|
} else {
|
||||||
label_.set_text(fmt::format("{}", workspace_.windows));
|
label_.set_markup(fmt::format("{}", workspace_.windows));
|
||||||
}
|
}
|
||||||
|
|
||||||
label_.show();
|
label_.show();
|
||||||
@@ -116,8 +118,6 @@ auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Wor
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WindowCount::queryActiveWorkspace() {
|
void WindowCount::queryActiveWorkspace() {
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
|
||||||
|
|
||||||
if (separateOutputs_) {
|
if (separateOutputs_) {
|
||||||
workspace_ = getActiveWorkspace(this->bar_.output->name);
|
workspace_ = getActiveWorkspace(this->bar_.output->name);
|
||||||
} else {
|
} else {
|
||||||
@@ -125,10 +125,7 @@ void WindowCount::queryActiveWorkspace() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowCount::onEvent(const std::string& ev) {
|
void WindowCount::onEvent(const std::string& ev) { dp.emit(); }
|
||||||
queryActiveWorkspace();
|
|
||||||
dp.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowCount::setClass(const std::string& classname, bool enable) {
|
void WindowCount::setClass(const std::string& classname, bool enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
|||||||
@@ -284,9 +284,7 @@ bool Workspace::isEmpty() const {
|
|||||||
// Otherwise, check if every window in the map should be skipped (ignored)
|
// Otherwise, check if every window in the map should be skipped (ignored)
|
||||||
return std::all_of(
|
return std::all_of(
|
||||||
m_windowMap.begin(), m_windowMap.end(),
|
m_windowMap.begin(), m_windowMap.end(),
|
||||||
[this, &ignore_list](const auto &window_repr) {
|
[this, &ignore_list](const auto& window_repr) { return shouldSkipWindow(window_repr); });
|
||||||
return shouldSkipWindow(window_repr);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::updateTaskbar(const std::string& workspace_icon) {
|
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);
|
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");
|
window_box->get_style_context()->add_class("taskbar-window");
|
||||||
if (window_repr.isActive) {
|
if (window_repr.isActive) {
|
||||||
window_box->get_style_context()->add_class("active");
|
window_box->get_style_context()->add_class("active");
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ void Workspaces::init() {
|
|||||||
m_activeWorkspaceId = m_ipc.getSocket1JsonReply("activeworkspace")["id"].asInt();
|
m_activeWorkspaceId = m_ipc.getSocket1JsonReply("activeworkspace")["id"].asInt();
|
||||||
|
|
||||||
initializeWorkspaces();
|
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();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,6 +303,11 @@ void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &c
|
|||||||
auto workspace = rule.isMember("defaultName") ? rule["defaultName"].asString()
|
auto workspace = rule.isMember("defaultName") ? rule["defaultName"].asString()
|
||||||
: rule["workspaceString"].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.
|
// The prefix "name:" cause mismatches with workspace names taken anywhere else.
|
||||||
if (workspace.starts_with("name:")) {
|
if (workspace.starts_with("name:")) {
|
||||||
workspace = workspace.substr(5);
|
workspace = workspace.substr(5);
|
||||||
@@ -631,6 +643,7 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void {
|
|||||||
populateBoolConfig(config, "persistent-only", m_persistentOnly);
|
populateBoolConfig(config, "persistent-only", m_persistentOnly);
|
||||||
populateBoolConfig(config, "active-only", m_activeOnly);
|
populateBoolConfig(config, "active-only", m_activeOnly);
|
||||||
populateBoolConfig(config, "move-to-monitor", m_moveToMonitor);
|
populateBoolConfig(config, "move-to-monitor", m_moveToMonitor);
|
||||||
|
populateBoolConfig(config, "enable-bar-scroll", m_barScroll);
|
||||||
|
|
||||||
m_persistentWorkspaceConfig = config.get("persistent-workspaces", Json::Value());
|
m_persistentWorkspaceConfig = config.get("persistent-workspaces", Json::Value());
|
||||||
populateSortByConfig(config);
|
populateSortByConfig(config);
|
||||||
@@ -934,7 +947,7 @@ void Workspaces::sortWorkspaces() {
|
|||||||
case SortMethod::NUMBER:
|
case SortMethod::NUMBER:
|
||||||
try {
|
try {
|
||||||
return std::stoi(a->name()) < std::stoi(b->name());
|
return std::stoi(a->name()) < std::stoi(b->name());
|
||||||
} catch (const std::invalid_argument &) {
|
} catch (const std::exception& e) {
|
||||||
// Handle the exception if necessary.
|
// Handle the exception if necessary.
|
||||||
break;
|
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
|
} // namespace waybar::modules::hyprland
|
||||||
|
|||||||
@@ -14,22 +14,27 @@ waybar::modules::Image::Image(const std::string& id, const Json::Value& config)
|
|||||||
|
|
||||||
size_ = config["size"].asInt();
|
size_ = config["size"].asInt();
|
||||||
|
|
||||||
interval_ = config_["interval"] == "once"
|
const auto once = std::chrono::milliseconds::max();
|
||||||
? std::chrono::milliseconds::max()
|
if (!config_.isMember("interval") || config_["interval"].isNull() ||
|
||||||
: std::chrono::milliseconds(std::max(
|
config_["interval"] == "once") {
|
||||||
1L, // Minimum 1ms due to millisecond precision
|
interval_ = once;
|
||||||
static_cast<long>(
|
} else if (config_["interval"].isNumeric()) {
|
||||||
(config_["interval"].isNumeric() ? config_["interval"].asDouble() : 0) *
|
const auto interval_seconds = config_["interval"].asDouble();
|
||||||
1000)));
|
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) {
|
if (size_ == 0) {
|
||||||
size_ = 16;
|
size_ = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interval_.count() == 0) {
|
|
||||||
interval_ = std::chrono::milliseconds::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
delayWorker();
|
delayWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +46,7 @@ void waybar::modules::Image::delayWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Image::refresh(int sig) {
|
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();
|
thread_.wake_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ auto Inhibitor::update() -> void {
|
|||||||
label_.get_style_context()->add_class(status_text);
|
label_.get_style_context()->add_class(status_text);
|
||||||
|
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
label_.set_tooltip_text(status_text);
|
label_.set_tooltip_markup(status_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ALabel::update();
|
return ALabel::update();
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ auto JACK::update() -> void {
|
|||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
std::string tooltip_format = "{bufsize}/{samplerate} {latency}ms";
|
std::string tooltip_format = "{bufsize}/{samplerate} {latency}ms";
|
||||||
if (config_["tooltip-format"].isString()) tooltip_format = config_["tooltip-format"].asString();
|
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::runtime(tooltip_format), fmt::arg("load", std::round(load_)),
|
||||||
fmt::arg("bufsize", bufsize_), fmt::arg("samplerate", samplerate_),
|
fmt::arg("bufsize", bufsize_), fmt::arg("samplerate", samplerate_),
|
||||||
fmt::arg("latency", fmt::format("{:.2f}", latency)), fmt::arg("xruns", xruns_)));
|
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);
|
tryAddDevice(dev_path);
|
||||||
} else if (event->mask & IN_DELETE) {
|
} else if (event->mask & IN_DELETE) {
|
||||||
|
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||||
auto it = libinput_devices_.find(dev_path);
|
auto it = libinput_devices_.find(dev_path);
|
||||||
if (it != libinput_devices_.end()) {
|
if (it != libinput_devices_.end()) {
|
||||||
spdlog::info("Keyboard {} has been removed.", dev_path);
|
spdlog::info("Keyboard {} has been removed.", dev_path);
|
||||||
|
libinput_path_remove_device(it->second);
|
||||||
|
libinput_device_unref(it->second);
|
||||||
libinput_devices_.erase(it);
|
libinput_devices_.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,6 +248,7 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
|
|||||||
}
|
}
|
||||||
|
|
||||||
waybar::modules::KeyboardState::~KeyboardState() {
|
waybar::modules::KeyboardState::~KeyboardState() {
|
||||||
|
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||||
for (const auto& [_, dev_ptr] : libinput_devices_) {
|
for (const auto& [_, dev_ptr] : libinput_devices_) {
|
||||||
libinput_path_remove_device(dev_ptr);
|
libinput_path_remove_device(dev_ptr);
|
||||||
}
|
}
|
||||||
@@ -256,12 +260,18 @@ auto waybar::modules::KeyboardState::update() -> void {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
std::string dev_path;
|
std::string dev_path;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(devices_mutex_);
|
||||||
|
if (libinput_devices_.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (config_["device-path"].isString() &&
|
if (config_["device-path"].isString() &&
|
||||||
libinput_devices_.find(config_["device-path"].asString()) != libinput_devices_.end()) {
|
libinput_devices_.find(config_["device-path"].asString()) != libinput_devices_.end()) {
|
||||||
dev_path = config_["device-path"].asString();
|
dev_path = config_["device-path"].asString();
|
||||||
} else {
|
} else {
|
||||||
dev_path = libinput_devices_.begin()->first;
|
dev_path = libinput_devices_.begin()->first;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
int fd = openFile(dev_path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
int fd = openFile(dev_path, O_NONBLOCK | O_CLOEXEC | O_RDONLY);
|
||||||
auto dev = openDevice(fd);
|
auto dev = openDevice(fd);
|
||||||
numl = libevdev_get_event_value(dev, EV_LED, LED_NUML);
|
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);
|
auto dev = openDevice(fd);
|
||||||
if (supportsLockStates(dev)) {
|
if (supportsLockStates(dev)) {
|
||||||
spdlog::info("Found device {} at '{}'", libevdev_get_name(dev), dev_path);
|
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()) {
|
if (libinput_devices_.find(dev_path) == libinput_devices_.end()) {
|
||||||
auto device = libinput_path_add_device(libinput_, dev_path.c_str());
|
auto device = libinput_path_add_device(libinput_, dev_path.c_str());
|
||||||
|
if (device) {
|
||||||
libinput_device_ref(device);
|
libinput_device_ref(device);
|
||||||
libinput_devices_[dev_path] = device;
|
libinput_devices_[dev_path] = device;
|
||||||
|
} else {
|
||||||
|
spdlog::warn("keyboard-state: Failed to add device to libinput: {}", dev_path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
libevdev_free(dev);
|
libevdev_free(dev);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ auto waybar::modules::Load::update() -> void {
|
|||||||
auto [load1, load5, load15] = Load::getLoad();
|
auto [load1, load5, load15] = Load::getLoad();
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
auto tooltip = fmt::format("Load 1: {}\nLoad 5: {}\nLoad 15: {}", load1, load5, load15);
|
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 format = format_;
|
||||||
auto state = getState(load1);
|
auto state = getState(load1);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
float total_swap_gigabytes = 0.01 * round(swaptotal / 10485.76);
|
float total_swap_gigabytes = 0.01 * round(swaptotal / 10485.76);
|
||||||
int used_ram_percentage = 100 * (memtotal - memfree) / memtotal;
|
int used_ram_percentage = 100 * (memtotal - memfree) / memtotal;
|
||||||
int used_swap_percentage = 0;
|
int used_swap_percentage = 0;
|
||||||
if (swaptotal && swapfree) {
|
if (swaptotal) {
|
||||||
used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal;
|
used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal;
|
||||||
}
|
}
|
||||||
float used_ram_gigabytes = 0.01 * round((memtotal - memfree) / 10485.76);
|
float used_ram_gigabytes = 0.01 * round((memtotal - memfree) / 10485.76);
|
||||||
@@ -69,7 +69,7 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
if (config_["tooltip-format"].isString()) {
|
if (config_["tooltip-format"].isString()) {
|
||||||
auto tooltip_format = config_["tooltip-format"].asString();
|
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::runtime(tooltip_format), used_ram_percentage,
|
||||||
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
|
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
|
||||||
fmt::arg("percentage", used_ram_percentage),
|
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("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
|
||||||
fmt::arg("swapAvail", available_swap_gigabytes)));
|
fmt::arg("swapAvail", available_swap_gigabytes)));
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ void waybar::modules::MPD::setLabel() {
|
|||||||
? config_["tooltip-format-disconnected"].asString()
|
? config_["tooltip-format-disconnected"].asString()
|
||||||
: "MPD (disconnected)";
|
: "MPD (disconnected)";
|
||||||
// Nothing to format
|
// Nothing to format
|
||||||
label_.set_tooltip_text(tooltip_format);
|
label_.set_tooltip_markup(tooltip_format);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,7 @@ void waybar::modules::MPD::setLabel() {
|
|||||||
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon),
|
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon),
|
||||||
fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon),
|
fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon),
|
||||||
fmt::arg("singleIcon", singleIcon), fmt::arg("filename", filename), fmt::arg("uri", uri));
|
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) {
|
} catch (fmt::format_error const& e) {
|
||||||
spdlog::warn("mpd: format error (tooltip): {}", e.what());
|
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("player_icon", getIconFromJson(config_["player-icons"], info.name)),
|
||||||
fmt::arg("status_icon", getIconFromJson(config_["status-icons"], info.status_string)));
|
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) {
|
} catch (fmt::format_error const& e) {
|
||||||
spdlog::warn("mpris: format error (tooltip): {}", e.what());
|
spdlog::warn("mpris: format error (tooltip): {}", e.what());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ void Window::doUpdate() {
|
|||||||
|
|
||||||
updateAppIconName(appId, "");
|
updateAppIconName(appId, "");
|
||||||
|
|
||||||
if (tooltipEnabled()) label_.set_tooltip_text(title);
|
if (tooltipEnabled()) label_.set_tooltip_markup(title);
|
||||||
|
|
||||||
const auto id = window["id"].asUInt64();
|
const auto id = window["id"].asUInt64();
|
||||||
const auto workspaceId = window["workspace_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["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_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"]) {
|
if (ws["name"]) {
|
||||||
const auto& name = ws["name"].asString();
|
const auto& name = ws["name"].asString();
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ auto PowerProfilesDaemon::update() -> void {
|
|||||||
store.push_back(fmt::arg("icon", getIcon(0, profile.name)));
|
store.push_back(fmt::arg("icon", getIcon(0, profile.name)));
|
||||||
label_.set_markup(fmt::vformat(format_, store));
|
label_.set_markup(fmt::vformat(format_, store));
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
label_.set_tooltip_text(fmt::vformat(tooltipFormat_, store));
|
label_.set_tooltip_markup(fmt::vformat(tooltipFormat_, store));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set CSS class
|
// 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("source_volume", source_volume), fmt::arg("source_desc", source_desc),
|
||||||
fmt::arg("icon", getIcon(sink_volume, getPulseIcon()))));
|
fmt::arg("icon", getIcon(sink_volume, getPulseIcon()))));
|
||||||
} else {
|
} 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) {
|
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||||
version = std::min<uint32_t>(version, 1);
|
version = std::min<uint32_t>(version, 1);
|
||||||
static_cast<Layout *>(data)->seat_ = static_cast<struct wl_seat *>(
|
static_cast<Layout*>(data)->seat_ =
|
||||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
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));
|
wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, version));
|
||||||
} else if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
} else if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||||
version = std::min<uint32_t>(version, 1);
|
version = std::min<uint32_t>(version, 1);
|
||||||
static_cast<Mode *>(data)->seat_ = static_cast<struct wl_seat *>(
|
static_cast<Mode*>(data)->seat_ =
|
||||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
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) {
|
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||||
version = std::min(version, 1u);
|
version = std::min(version, 1u);
|
||||||
static_cast<Tags *>(data)->seat_ = static_cast<struct wl_seat *>(
|
static_cast<Tags*>(data)->seat_ =
|
||||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
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) {
|
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||||
version = std::min<uint32_t>(version, 1);
|
version = std::min<uint32_t>(version, 1);
|
||||||
static_cast<Window *>(data)->seat_ = static_cast<struct wl_seat *>(
|
static_cast<Window*>(data)->seat_ =
|
||||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
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()) {
|
if (config_["tooltip-format"].isString()) {
|
||||||
auto tooltip_format = config_["tooltip-format"].asString();
|
auto tooltip_format = config_["tooltip-format"].asString();
|
||||||
auto tooltip_text = fmt::format(fmt::runtime(tooltip_format), localtime);
|
auto tooltip_text = fmt::format(fmt::runtime(tooltip_format), localtime);
|
||||||
label_.set_tooltip_text(tooltip_text);
|
label_.set_tooltip_markup(tooltip_text);
|
||||||
} else {
|
} else {
|
||||||
label_.set_tooltip_text(text);
|
label_.set_tooltip_markup(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Call parent update
|
// Call parent update
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ Item::~Item() {
|
|||||||
this->gtk_menu->popdown();
|
this->gtk_menu->popdown();
|
||||||
this->gtk_menu->detach();
|
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) {
|
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);
|
std::string custom_icon = IconManager::instance().getIconForApp(id);
|
||||||
if (!custom_icon.empty()) {
|
if (!custom_icon.empty()) {
|
||||||
if (std::filesystem::exists(custom_icon)) {
|
if (std::filesystem::exists(custom_icon)) {
|
||||||
|
try {
|
||||||
Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
|
Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
|
||||||
icon_name = ""; // icon_name has priority over pixmap
|
icon_name = ""; // icon_name has priority over pixmap
|
||||||
icon_pixmap = custom_pixbuf;
|
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
|
} else { // if file doesn't exist it's most likely an icon_name
|
||||||
icon_name = custom_icon;
|
icon_name = custom_icon;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ auto Mode::update() -> void {
|
|||||||
} else {
|
} else {
|
||||||
label_.set_markup(fmt::format(fmt::runtime(format_), mode_));
|
label_.set_markup(fmt::format(fmt::runtime(format_), mode_));
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
label_.set_tooltip_text(mode_);
|
label_.set_tooltip_markup(mode_);
|
||||||
}
|
}
|
||||||
event_box_.show();
|
event_box_.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ auto Window::update() -> void {
|
|||||||
fmt::arg("shell", shell_), fmt::arg("marks", marks_)),
|
fmt::arg("shell", shell_), fmt::arg("marks", marks_)),
|
||||||
config_["rewrite"]));
|
config_["rewrite"]));
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
label_.set_tooltip_text(window_);
|
label_.set_tooltip_markup(window_);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAppIcon();
|
updateAppIcon();
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ auto Workspaces::update() -> void {
|
|||||||
}
|
}
|
||||||
std::string output = (*it)["name"].asString();
|
std::string output = (*it)["name"].asString();
|
||||||
std::string windows = "";
|
std::string windows = "";
|
||||||
if (config_["window-format"].isString()) {
|
if (config_["window-rewrite"].isObject()) {
|
||||||
updateWindows((*it), windows);
|
updateWindows((*it), windows);
|
||||||
}
|
}
|
||||||
if (config_["format"].isString()) {
|
if (config_["format"].isString()) {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ auto waybar::modules::Temperature::update() -> void {
|
|||||||
if (config_["tooltip-format"].isString()) {
|
if (config_["tooltip-format"].isString()) {
|
||||||
tooltip_format = config_["tooltip-format"].asString();
|
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::runtime(tooltip_format), fmt::arg("temperatureC", temperature_c),
|
||||||
fmt::arg("temperatureF", temperature_f), fmt::arg("temperatureK", temperature_k)));
|
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),
|
mixer_api_(nullptr),
|
||||||
def_nodes_api_(nullptr),
|
def_nodes_api_(nullptr),
|
||||||
default_node_name_(nullptr),
|
default_node_name_(nullptr),
|
||||||
default_source_name_(nullptr),
|
|
||||||
pending_plugins_(0),
|
pending_plugins_(0),
|
||||||
muted_(false),
|
muted_(false),
|
||||||
source_muted_(false),
|
|
||||||
volume_(0.0),
|
volume_(0.0),
|
||||||
source_volume_(0.0),
|
|
||||||
min_step_(0.0),
|
min_step_(0.0),
|
||||||
node_id_(0),
|
node_id_(0),
|
||||||
|
node_name_(""),
|
||||||
|
source_name_(""),
|
||||||
|
type_(nullptr),
|
||||||
source_node_id_(0),
|
source_node_id_(0),
|
||||||
type_(nullptr) {
|
source_muted_(false),
|
||||||
|
source_volume_(0.0),
|
||||||
|
default_source_name_(nullptr) {
|
||||||
waybar::modules::Wireplumber::modules.push_back(this);
|
waybar::modules::Wireplumber::modules.push_back(this);
|
||||||
|
|
||||||
wp_init(WP_INIT_PIPEWIRE);
|
wp_init(WP_INIT_PIPEWIRE);
|
||||||
@@ -477,12 +479,12 @@ auto waybar::modules::Wireplumber::update() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!tooltipFormat.empty()) {
|
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::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("icon", getIcon(vol)), fmt::arg("format_source", formatted_source),
|
||||||
fmt::arg("source_volume", source_vol), fmt::arg("source_desc", source_name_)));
|
fmt::arg("source_volume", source_vol), fmt::arg("source_desc", source_name_)));
|
||||||
} else {
|
} else {
|
||||||
label_.set_tooltip_text(node_name_);
|
label_.set_tooltip_markup(node_name_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -509,7 +509,7 @@ void Task::update() {
|
|||||||
if (markup)
|
if (markup)
|
||||||
button.set_tooltip_markup(txt);
|
button.set_tooltip_markup(txt);
|
||||||
else
|
else
|
||||||
button.set_tooltip_text(txt);
|
button.set_tooltip_markup(txt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "util/udev_deleter.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class FileDescriptor {
|
class FileDescriptor {
|
||||||
public:
|
public:
|
||||||
@@ -29,22 +31,6 @@ class FileDescriptor {
|
|||||||
int fd_;
|
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: ") {
|
void check_eq(int rc, int expected, const char* message = "eq, rc was: ") {
|
||||||
if (rc != expected) {
|
if (rc != expected) {
|
||||||
throw std::runtime_error(fmt::format(fmt::runtime(message), rc));
|
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);
|
GET_BEST_DEVICE(best, (*this), preferred_device);
|
||||||
|
|
||||||
if (best != nullptr) {
|
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;
|
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