Compare commits
111 Commits
0abbf221a2
...
4d2fb11a05
| Author | SHA1 | Date | |
|---|---|---|---|
|
4d2fb11a05
|
|||
| 90b209add8 | |||
| a8bbc90efe | |||
| 429d7df52b | |||
| 26c09f1e2e | |||
| 65e708779b | |||
| 04766452b4 | |||
| c4982efa95 | |||
| dad6e8a257 | |||
| 98c2ace0ec | |||
| 68d3e13fdd | |||
| 2b29c9a5d6 | |||
| 08baa3fd40 | |||
| 717cc4a4d1 | |||
| be9d9c87e6 | |||
| e8558dd696 | |||
| 7921ab4008 | |||
| 4c5167083d | |||
| 7261d00c31 | |||
| cb54b98fd5 | |||
| da8fd864c6 | |||
| 0a8b7b096a | |||
| c1240a98aa | |||
| e0a2cb8f8f | |||
| 74fb2f252f | |||
| 330c77c87a | |||
| 19ede92d7f | |||
| 03de38b4d0 | |||
| 4cadae83b3 | |||
| 1466ca8bef | |||
| c34b1b6a19 | |||
| 2c3aab88de | |||
| f16a6c7dcf | |||
| 68e1e6dc26 | |||
| 39e59e557f | |||
| 47fb21a2c1 | |||
| 6cecaf56b9 | |||
| 60e73e8d12 | |||
| 0d27c093b1 | |||
| 5ab28b901c | |||
| ddab2971fa | |||
| 09cbec0a3c | |||
| c12658dea5 | |||
| 2f94435014 | |||
| 1639dec7d8 | |||
| 762c4f2e27 | |||
| b4854f96a3 | |||
| 8f5fc990a5 | |||
| a02180a815 | |||
| af7eebba5e | |||
| 479ea9f3e8 | |||
| f990486a40 | |||
| d0f5fab52b | |||
| a05e6c6f74 | |||
| 99867005a0 | |||
| 959f41ca9c | |||
| 19bb89874e | |||
| 06484547d1 | |||
| 46a6f60138 | |||
| 83a6998fcb | |||
| 386036a67a | |||
| e3186abdce | |||
| c8c3287be3 | |||
| 601b5f0241 | |||
| 97eb60677e | |||
| 3d0b942956 | |||
| c3d29b1185 | |||
| c6844781ea | |||
| c1218fa889 | |||
| 11c4e55376 | |||
| 6b05d73a64 | |||
| 374ccbb878 | |||
| d012de3cde | |||
| 7ecad3229d | |||
| 278e8822ff | |||
| a23cef457f | |||
| a9ef11a2b3 | |||
| 07cb2c02d2 | |||
| e03119fe94 | |||
| 5ee3bd5325 | |||
| 3773021546 | |||
| 52f4db1154 | |||
| e362550e27 | |||
| cb0ee665a3 | |||
| e189649c33 | |||
| 13519ca5bf | |||
| 097c00c7bd | |||
| 73808dfacc | |||
| ce1da5a178 | |||
| 4e25871655 | |||
| ca62481dc9 | |||
| b701d7f70b | |||
| 68cbb507d9 | |||
| 161367d961 | |||
| a62455e1b9 | |||
| 588c344c8a | |||
| bf0ccfd90c | |||
| 8b0a82ad34 | |||
| 37ac2daac8 | |||
| 97682a1332 | |||
| 4beb7ddac7 | |||
| 84ec25bbeb | |||
| b475399a22 | |||
| 15a503ae21 | |||
| 46d3e80bce | |||
| 9221508e51 | |||
| 9d37dedb57 | |||
| 6021261383 | |||
| 966da11f3b | |||
| 7add8b2726 | |||
| bef35e48fe |
@ -2,4 +2,5 @@
|
||||
;;; For more information see (info "(emacs) Directory Variables")
|
||||
|
||||
((nil . ((ff-search-directories . ("../include/*/" "../../include/*/"
|
||||
"../src/*/" "../../src/*/")))))
|
||||
"../src/*/" "../../src/*/"))
|
||||
(apheleia-inhibit . t))))
|
||||
|
||||
10
.github/workflows/clang-format.yml
vendored
10
.github/workflows/clang-format.yml
vendored
@ -11,12 +11,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
# TODO: bump to clang 19 release
|
||||
# - uses: DoozyX/clang-format-lint-action@v0.18.2
|
||||
- uses: DoozyX/clang-format-lint-action@558090054b3f39e3d6af24f0cd73b319535da809
|
||||
- uses: RafikFarhad/clang-format-github-action@v6
|
||||
name: clang-format
|
||||
with:
|
||||
source: "."
|
||||
extensions: "hpp,h,cpp,c"
|
||||
style: "file:.clang-format"
|
||||
clangFormatVersion: 19
|
||||
sources: "src/**/*.hpp,src/**/*.cpp"
|
||||
style: "file"
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -7,6 +7,7 @@ vgcore.*
|
||||
*.swp
|
||||
packagecache
|
||||
/subprojects/**/
|
||||
/subprojects/.wraplock
|
||||
/build*
|
||||
/dist
|
||||
/meson.egg-info
|
||||
@ -50,5 +51,4 @@ result
|
||||
result-*
|
||||
|
||||
.ccls-cache
|
||||
|
||||
.wraplock
|
||||
_codeql_detected_source_root
|
||||
|
||||
@ -125,7 +125,7 @@ sudo apt install \
|
||||
On Arch, you can use this command:
|
||||
|
||||
```
|
||||
pacman -S \
|
||||
pacman -S --asdeps \
|
||||
gtkmm3 \
|
||||
jsoncpp \
|
||||
libsigc++ \
|
||||
@ -157,6 +157,10 @@ Contributions welcome!<br>
|
||||
Have fun :)<br>
|
||||
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
|
||||
|
||||
> [!CAUTION]
|
||||
> Distributions of Waybar are only released on the [official GitHub page](https://github.com/Alexays/Waybar).<br/>
|
||||
> Waybar does **not** have an official website. Do not trust any sites that claim to be official.
|
||||
|
||||
## License
|
||||
|
||||
Waybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/Alexays/Waybar/blob/master/LICENSE).
|
||||
|
||||
1
_codeql_detected_source_root
Symbolic link
1
_codeql_detected_source_root
Symbolic link
@ -0,0 +1 @@
|
||||
.
|
||||
12
flake.lock
generated
12
flake.lock
generated
@ -3,11 +3,11 @@
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"lastModified": 1767039857,
|
||||
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -18,11 +18,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1759036355,
|
||||
"narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
|
||||
"lastModified": 1769461804,
|
||||
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
|
||||
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@ -63,6 +63,8 @@ class Client {
|
||||
std::string m_cssFile;
|
||||
|
||||
std::map<int, bool> signal_toggle_state;
|
||||
sigc::connection monitor_added_connection_;
|
||||
sigc::connection monitor_removed_connection_;
|
||||
};
|
||||
|
||||
} // namespace waybar
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#if defined(__linux__)
|
||||
#include <sys/inotify.h>
|
||||
#endif
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
@ -15,6 +16,7 @@
|
||||
#include "ALabel.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#include "util/udev_deleter.hpp"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
@ -37,15 +39,17 @@ class Battery : public ALabel {
|
||||
void setBarClass(std::string&);
|
||||
void processEvents(std::string& state, std::string& status, uint8_t capacity);
|
||||
|
||||
int global_watch;
|
||||
std::map<fs::path, int> batteries_;
|
||||
std::unique_ptr<udev, util::UdevDeleter> udev_;
|
||||
std::array<pollfd, 1> poll_fds_;
|
||||
std::unique_ptr<udev_monitor, util::UdevMonitorDeleter> mon_;
|
||||
fs::path adapter_;
|
||||
int battery_watch_fd_;
|
||||
int global_watch_fd_;
|
||||
std::mutex battery_list_mutex_;
|
||||
std::string old_status_;
|
||||
std::string last_event_;
|
||||
bool warnFirstTime_{true};
|
||||
bool weightedAverage_{true};
|
||||
const Bar& bar_;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
|
||||
43
include/modules/cava/cavaGLSL.hpp
Normal file
43
include/modules/cava/cavaGLSL.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "cava_backend.hpp"
|
||||
|
||||
namespace waybar::modules::cava {
|
||||
|
||||
class CavaGLSL final : public AModule, public Gtk::GLArea {
|
||||
public:
|
||||
CavaGLSL(const std::string&, const Json::Value&);
|
||||
~CavaGLSL() = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr<CavaBackend> backend_;
|
||||
struct ::cava::config_params prm_;
|
||||
int frame_counter{0};
|
||||
bool silence_{false};
|
||||
bool hide_on_silence_{false};
|
||||
// Cava method
|
||||
auto onUpdate(const ::cava::audio_raw& input) -> void;
|
||||
auto onSilence() -> void;
|
||||
// Member variable to store the shared pointer
|
||||
std::shared_ptr<::cava::audio_raw> m_data_;
|
||||
GLuint shaderProgram_;
|
||||
// OpenGL variables
|
||||
GLuint fbo_;
|
||||
GLuint texture_;
|
||||
GLint uniform_bars_;
|
||||
GLint uniform_previous_bars_;
|
||||
GLint uniform_bars_count_;
|
||||
GLint uniform_time_;
|
||||
// Methods
|
||||
void onRealize();
|
||||
bool onRender(const Glib::RefPtr<Gdk::GLContext>& context);
|
||||
|
||||
void initShaders();
|
||||
void initSurface();
|
||||
void initGLSL();
|
||||
GLuint loadShader(const std::string& fileName, GLenum type);
|
||||
};
|
||||
} // namespace waybar::modules::cava
|
||||
@ -9,20 +9,20 @@ class Cava final : public ALabel, public sigc::trackable {
|
||||
public:
|
||||
Cava(const std::string&, const Json::Value&);
|
||||
~Cava() = default;
|
||||
auto onUpdate(const std::string& input) -> void;
|
||||
auto onSilence() -> void;
|
||||
auto doAction(const std::string& name) -> void override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<CavaBackend> backend_;
|
||||
// Text to display
|
||||
std::string label_text_{""};
|
||||
Glib::ustring label_text_{""};
|
||||
bool silence_{false};
|
||||
bool hide_on_silence_{false};
|
||||
std::string format_silent_{""};
|
||||
int ascii_range_{0};
|
||||
bool silence_{false};
|
||||
// Cava method
|
||||
void pause_resume();
|
||||
auto onUpdate(const std::string& input) -> void;
|
||||
auto onSilence() -> void;
|
||||
// ModuleActionMap
|
||||
static inline std::map<const std::string, void (waybar::modules::cava::Cava::* const)()>
|
||||
actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}};
|
||||
@ -32,29 +32,36 @@ class CavaBackend final {
|
||||
int getAsciiRange();
|
||||
void doPauseResume();
|
||||
void Update();
|
||||
const struct ::cava::config_params* getPrm();
|
||||
std::chrono::milliseconds getFrameTimeMilsec();
|
||||
|
||||
// Signal accessor
|
||||
using type_signal_update = sigc::signal<void(const std::string&)>;
|
||||
type_signal_update signal_update();
|
||||
using type_signal_audio_raw_update = sigc::signal<void(const ::cava::audio_raw&)>;
|
||||
type_signal_audio_raw_update signal_audio_raw_update();
|
||||
using type_signal_silence = sigc::signal<void()>;
|
||||
type_signal_silence signal_silence();
|
||||
|
||||
private:
|
||||
CavaBackend(const Json::Value& config);
|
||||
util::SleeperThread thread_;
|
||||
util::SleeperThread read_thread_;
|
||||
util::SleeperThread out_thread_;
|
||||
|
||||
// Cava API to read audio source
|
||||
::cava::ptr input_source_;
|
||||
::cava::ptr input_source_{NULL};
|
||||
|
||||
struct ::cava::error_s error_{}; // cava errors
|
||||
struct ::cava::config_params prm_{}; // cava parameters
|
||||
struct ::cava::audio_raw audio_raw_{}; // cava handled raw audio data(is based on audio_data)
|
||||
struct ::cava::audio_data audio_data_{}; // cava audio data
|
||||
struct ::cava::cava_plan* plan_; //{new cava_plan{}};
|
||||
struct ::cava::cava_plan* plan_{NULL}; //{new cava_plan{}};
|
||||
|
||||
std::chrono::seconds fetch_input_delay_{4};
|
||||
// Delay to handle audio source
|
||||
std::chrono::milliseconds frame_time_milsec_{1s};
|
||||
|
||||
const Json::Value& config_;
|
||||
int re_paint_{0};
|
||||
bool silence_{false};
|
||||
bool silence_prev_{false};
|
||||
@ -66,9 +73,12 @@ class CavaBackend final {
|
||||
void execute();
|
||||
bool isSilence();
|
||||
void doUpdate(bool force = false);
|
||||
void loadConfig();
|
||||
void freeBackend();
|
||||
|
||||
// Signal
|
||||
type_signal_update m_signal_update_;
|
||||
type_signal_audio_raw_update m_signal_audio_raw_;
|
||||
type_signal_silence m_signal_silence_;
|
||||
};
|
||||
} // namespace waybar::modules::cava
|
||||
|
||||
27
include/modules/cava/cava_frontend.hpp
Normal file
27
include/modules/cava/cava_frontend.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef HAVE_LIBCAVA
|
||||
#include "cavaRaw.hpp"
|
||||
#include "cava_backend.hpp"
|
||||
#ifdef HAVE_LIBCAVAGLSL
|
||||
#include "cavaGLSL.hpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace waybar::modules::cava {
|
||||
AModule* getModule(const std::string& id, const Json::Value& config) {
|
||||
#ifdef HAVE_LIBCAVA
|
||||
const std::shared_ptr<CavaBackend> backend_{waybar::modules::cava::CavaBackend::inst(config)};
|
||||
switch (backend_->getPrm()->output) {
|
||||
#ifdef HAVE_LIBCAVAGLSL
|
||||
case ::cava::output_method::OUTPUT_SDL_GLSL:
|
||||
return new waybar::modules::cava::CavaGLSL(id, config);
|
||||
#endif
|
||||
default:
|
||||
return new waybar::modules::cava::Cava(id, config);
|
||||
}
|
||||
#else
|
||||
throw std::runtime_error("Unknown module");
|
||||
#endif
|
||||
};
|
||||
} // namespace waybar::modules::cava
|
||||
@ -26,6 +26,7 @@ class Submap : public waybar::ALabel, public EventHandler {
|
||||
const Bar& bar_;
|
||||
util::JsonParser parser_;
|
||||
std::string submap_;
|
||||
std::string prev_submap_;
|
||||
bool always_on_ = false;
|
||||
std::string default_submap_ = "Default";
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ class Window : public waybar::ALabel {
|
||||
virtual ~Window();
|
||||
|
||||
// Handlers for wayland events
|
||||
void handle_focused_view(const char *title, uint32_t);
|
||||
void handle_focused_view(const char* title, uint32_t tags);
|
||||
void handle_focused_output(struct wl_output* output);
|
||||
void handle_unfocused_output(struct wl_output* output);
|
||||
|
||||
|
||||
@ -33,8 +33,8 @@ class Taskbar;
|
||||
|
||||
class Task {
|
||||
public:
|
||||
Task(const waybar::Bar &, const Json::Value &, Taskbar *,
|
||||
struct zwlr_foreign_toplevel_handle_v1 *, struct wl_seat *);
|
||||
Task(const waybar::Bar&, const Json::Value&, Taskbar*, struct zwlr_foreign_toplevel_handle_v1*,
|
||||
struct wl_seat*);
|
||||
~Task();
|
||||
|
||||
public:
|
||||
|
||||
@ -109,7 +109,7 @@ inline FILE* open(const std::string& cmd, int& pid, const std::string& output_na
|
||||
::close(fd[0]);
|
||||
dup2(fd[1], 1);
|
||||
setpgid(child_pid, child_pid);
|
||||
if (output_name != "") {
|
||||
if (!output_name.empty()) {
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
@ -138,7 +138,7 @@ inline struct res execNoRead(const std::string& cmd) {
|
||||
return {WEXITSTATUS(stat), ""};
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) {
|
||||
inline int32_t forkExec(const std::string& cmd, const std::string& output_name) {
|
||||
if (cmd == "") return -1;
|
||||
|
||||
pid_t pid = fork();
|
||||
@ -157,6 +157,9 @@ inline int32_t forkExec(const std::string& cmd) {
|
||||
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
|
||||
if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err));
|
||||
setpgid(pid, pid);
|
||||
if (!output_name.empty()) {
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
} else {
|
||||
@ -169,4 +172,8 @@ inline int32_t forkExec(const std::string& cmd) {
|
||||
return pid;
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) {
|
||||
return forkExec(cmd, "");
|
||||
}
|
||||
|
||||
} // namespace waybar::util::command
|
||||
|
||||
@ -30,15 +30,16 @@ class JsonParser {
|
||||
|
||||
std::istringstream jsonStream(modifiedJsonStr);
|
||||
std::string errs;
|
||||
if (!Json::parseFromStream(m_readerBuilder, jsonStream, &root, &errs)) {
|
||||
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
||||
// parser can be called concurrently from multiple module threads
|
||||
Json::CharReaderBuilder readerBuilder;
|
||||
if (!Json::parseFromStream(readerBuilder, jsonStream, &root, &errs)) {
|
||||
throw std::runtime_error("Error parsing JSON: " + errs);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
private:
|
||||
Json::CharReaderBuilder m_readerBuilder;
|
||||
|
||||
static std::string replaceHexadecimalEscape(const std::string& str) {
|
||||
static std::regex re("\\\\x");
|
||||
return std::regex_replace(str, re, "\\u00");
|
||||
|
||||
21
include/util/udev_deleter.hpp
Normal file
21
include/util/udev_deleter.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
namespace waybar::util {
|
||||
struct UdevDeleter {
|
||||
void operator()(udev* ptr) const { udev_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevDeviceDeleter {
|
||||
void operator()(udev_device* ptr) const { udev_device_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevEnumerateDeleter {
|
||||
void operator()(udev_enumerate* ptr) const { udev_enumerate_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevMonitorDeleter {
|
||||
void operator()(udev_monitor* ptr) const { udev_monitor_unref(ptr); }
|
||||
};
|
||||
} // namespace waybar::util
|
||||
@ -91,6 +91,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
|
||||
typeof: string ++
|
||||
Command to execute when scrolling up on the module.
|
||||
|
||||
*weighted-average*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Option to combine multiple batteries with different capacities.
|
||||
|
||||
*on-scroll-down*: ++
|
||||
typeof: string ++
|
||||
Command to execute when scrolling down on the module.
|
||||
|
||||
@ -8,6 +8,8 @@ waybar - cava module
|
||||
|
||||
*cava* module for karlstav/cava project. See it on github: https://github.com/karlstav/cava.
|
||||
|
||||
Module supports two different frontends starting from the 0.15.0 release. The frontend that
|
||||
will be used is managed by the method parameter in the [output] section of the cava configuration file.
|
||||
|
||||
# FILES
|
||||
|
||||
@ -32,6 +34,10 @@ libcava lives in:
|
||||
:[ string
|
||||
:[
|
||||
:< Path where cava configuration file is placed to
|
||||
|[ *method* \[output\]
|
||||
:[ string
|
||||
:[
|
||||
:< Manages which frontend Waybar cava module should use. Values: raw, sdl_glsl
|
||||
|[ *framerate*
|
||||
:[ integer
|
||||
:[ 30
|
||||
@ -43,7 +49,7 @@ libcava lives in:
|
||||
|[ *sensitivity*
|
||||
:[ integer
|
||||
:[ 100
|
||||
:[ Manual sensitivity in %. It's recommended to be omitted when *autosens* = 1
|
||||
:[ Manual sensitivity in %. If autosens is enabled, this will only be the initial value. 200 means double height. Accepts only non-negative values
|
||||
|[ *bars*
|
||||
:[ integer
|
||||
:[ 12
|
||||
@ -68,7 +74,7 @@ libcava lives in:
|
||||
:[ string
|
||||
:[
|
||||
:[ Widget's text after sleep_timer elapsed (hide_on_silence has to be false)
|
||||
|[ *method*
|
||||
|[ *method* \[input\]
|
||||
:[ string
|
||||
:[ pulse
|
||||
:[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem
|
||||
@ -105,9 +111,9 @@ libcava lives in:
|
||||
:[ false
|
||||
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|
||||
|[ *noise_reduction*
|
||||
:[ double
|
||||
:[ 0.77
|
||||
:[ Range between 0 - 1. The raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth. 1 - will be very slow and smooth, 0 - will be fast but noisy
|
||||
:[ integer
|
||||
:[ 77
|
||||
:[ Range between 0 - 100. The raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth. 100 will be very slow and smooth, 0 will be fast but noisy
|
||||
|[ *input_delay*
|
||||
:[ integer
|
||||
:[ 2
|
||||
@ -119,11 +125,11 @@ libcava lives in:
|
||||
|[ *data_format*
|
||||
:[ string
|
||||
:[ asci
|
||||
:[ It's impossible to set it. Waybar sets it to = asci for internal needs
|
||||
:[ Raw data format. Can be 'binary' or 'ascii'
|
||||
|[ *raw_target*
|
||||
:[ string
|
||||
:[ /dev/stdout
|
||||
:[ It's impossible to set it. Waybar sets it to = /dev/stdout for internal needs
|
||||
:[ Raw output target. A fifo will be created if target does not exist
|
||||
|[ *menu*
|
||||
:[ string
|
||||
:[
|
||||
@ -136,6 +142,50 @@ libcava lives in:
|
||||
:[ array
|
||||
:[
|
||||
:[ The actions corresponding to the buttons of the menu.
|
||||
|[ *bar_spacing*
|
||||
:[ integer
|
||||
:[
|
||||
:[ Bars' space between bars in number of characters
|
||||
|[ *bar_width*
|
||||
:[ integer
|
||||
:[
|
||||
:[ Bars' width between bars in number of characters
|
||||
|[ *bar_height*
|
||||
:[ integer
|
||||
:[
|
||||
:[ Useless. bar_height is only used for output in "noritake" format
|
||||
|[ *background*
|
||||
:[ string
|
||||
:[
|
||||
:[ GLSL actual. Support hex code colors only. Must be within ''
|
||||
|[ *foreground*
|
||||
:[ string
|
||||
:[
|
||||
:[ GLSL actual. Support hex code colors only. Must be within ''
|
||||
|[ *gradient*
|
||||
:[ integer
|
||||
:[ 0
|
||||
:[ GLSL actual. Gradient mode(0/1 - on/off)
|
||||
|[ *gradient_count*
|
||||
:[ integer
|
||||
:[ 0
|
||||
:[ GLSL actual. The count of colors for the gradient
|
||||
|[ *gradient_color_N*
|
||||
:[ string
|
||||
:[
|
||||
:[ GLSL actual. N - the number of the gradient color between 1 and 8. Only hex defined colors are supported. Must be within ''
|
||||
|[ *sdl_width*
|
||||
:[ integer
|
||||
:[
|
||||
:[ GLSL actual. Manages the width of the waybar cava GLSL frontend module
|
||||
|[ *sdl_height*
|
||||
:[ integer
|
||||
:[
|
||||
:[ GLSL actual. Manages the height of the waybar cava GLSL frontend module
|
||||
|[ *continuous_rendering*
|
||||
:[ integer
|
||||
:[ 0
|
||||
:[ GLSL actual. Keep rendering even if no audio. Recommended to set to 1
|
||||
|
||||
Configuration can be provided as:
|
||||
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped
|
||||
@ -153,6 +203,7 @@ Configuration can be provided as:
|
||||
|
||||
- iniparser
|
||||
- fftw3
|
||||
- epoxy (GLSL frontend only)
|
||||
|
||||
# SOLVING ISSUES
|
||||
|
||||
@ -205,3 +256,453 @@ In case when cava releases new version and you're wanna get it, it should be rai
|
||||
- *#cava*
|
||||
- *#cava.silent* Applied after no sound has been detected for sleep_timer seconds
|
||||
- *#cava.updated* Applied when a new frame is shown
|
||||
# FRONTENDS
|
||||
|
||||
## RAW
|
||||
The cava raw frontend uses ASCII characters to visualize incoming audio data. Each ASCII symbol position corresponds to the value of the audio power pulse.
|
||||
|
||||
Under the hood:
|
||||
```
|
||||
. Incoming audio power pulse list is : 12684
|
||||
. Configured array of ASCII codes is: ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ]. See `format-icons` https://github.com/Alexays/Waybar/wiki/Module:-Cava#example
|
||||
```
|
||||
As a result cava frontend will give ▁▂▆█▄
|
||||
|
||||
Examples:
|
||||
|
||||
waybar config
|
||||
```
|
||||
"cava": {
|
||||
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_raw.conf",
|
||||
"input_delay": 2,
|
||||
"format-icons" : ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ],
|
||||
"actions": {
|
||||
"on-click-right": "mode"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
waybar_raw.conf
|
||||
```
|
||||
## Configuration file for CAVA.
|
||||
# Remove the ; to change parameters.
|
||||
|
||||
|
||||
[general]
|
||||
|
||||
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
|
||||
|
||||
# Accepts only non-negative values.
|
||||
|
||||
# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off
|
||||
# new as of 0.6.0 autosens of low values (dynamic range)
|
||||
# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0
|
||||
|
||||
# Manual sensitivity in %. If autosens is enabled, this will only be the initial value.
|
||||
# 200 means double height. Accepts only non-negative values.
|
||||
|
||||
# The number of bars (0-512). 0 sets it to auto (fill up console).
|
||||
# Bars' width and space between bars in number of characters.
|
||||
bars = 12
|
||||
# bar_height is only used for output in "noritake" format
|
||||
|
||||
# For SDL width and space between bars is in pixels, defaults are:
|
||||
|
||||
# sdl_glsl have these default values, they are only used to calculate max number of bars.
|
||||
|
||||
|
||||
# Lower and higher cutoff frequencies for lowest and highest bars
|
||||
# the bandwidth of the visualizer.
|
||||
# Note: there is a minimum total bandwidth of 43Mhz x number of bars.
|
||||
# Cava will automatically increase the higher cutoff if a too low band is specified.
|
||||
|
||||
# Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and
|
||||
# only check for input once per second. Cava will wake up once input is detected. 0 = disable.
|
||||
sleep_timer = 5
|
||||
|
||||
|
||||
[input]
|
||||
|
||||
# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem'
|
||||
# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with.
|
||||
# On Mac it defaults to 'portaudio' or 'fifo'
|
||||
# On windows this is automatic and no input settings are needed.
|
||||
#
|
||||
# All input methods uses the same config variable 'source'
|
||||
# to define where it should get the audio.
|
||||
#
|
||||
# For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink
|
||||
# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them).
|
||||
#
|
||||
# For pipewire 'source' will be the object name or object.serial of the device to capture from.
|
||||
# Both input and output devices are supported.
|
||||
#
|
||||
# For alsa 'source' will be the capture device.
|
||||
# For fifo 'source' will be the path to fifo-file.
|
||||
# For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address
|
||||
#
|
||||
# For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'.
|
||||
# README.md contains further information on how to setup CAVA for sndio.
|
||||
#
|
||||
# For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device.
|
||||
# README.md contains further information on how to setup CAVA for OSS on FreeBSD.
|
||||
#
|
||||
# For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'.
|
||||
# README.md contains further information on how to setup CAVA for JACK.
|
||||
#
|
||||
|
||||
# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods:
|
||||
# sample_rate: fifo, pipewire, sndio, oss
|
||||
# sample_bits: fifo, pipewire, sndio, oss
|
||||
# channels: sndio, oss, jack
|
||||
# autoconnect: jack
|
||||
# Other methods ignore these settings.
|
||||
#
|
||||
# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported
|
||||
# by the chosen audio device, the device will use other supported values instead.
|
||||
# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it
|
||||
# will use 44100, 16 and 1.
|
||||
#
|
||||
|
||||
|
||||
[output]
|
||||
|
||||
# Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl'
|
||||
# or 'sdl_glsl'.
|
||||
# 'noncurses' (default) uses a buffer and cursor movements to only print
|
||||
# changes from frame to frame in the terminal. Uses less resources and is less
|
||||
# prone to tearing (vsync issues) than 'ncurses'.
|
||||
#
|
||||
# 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data
|
||||
# stream of the bar heights that can be used to send to other applications.
|
||||
# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above.
|
||||
#
|
||||
# 'noritake' outputs a bitmap in the format expected by a Noritake VFD display
|
||||
# in graphic mode. It only support the 3000 series graphical VFDs for now.
|
||||
#
|
||||
# 'sdl' uses the Simple DirectMedia Layer to render in a graphical context.
|
||||
# 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or
|
||||
# use one of the predefined ones.
|
||||
method = raw
|
||||
|
||||
# Orientation of the visualization. Can be 'bottom', 'top', 'left', 'right' or
|
||||
# 'horizontal'. Default is 'bottom'. 'left and 'right' are only supported on sdl
|
||||
# and ncruses output. 'horizontal' (bars go up and down from center) is only supported
|
||||
# on noncurses output.
|
||||
# Note: many fonts have weird or missing glyphs for characters used in orientations
|
||||
# other than 'bottom', which can make output not look right.
|
||||
|
||||
# Visual channels. Can be 'stereo' or 'mono'.
|
||||
# 'stereo' mirrors both channels with low frequencies in center.
|
||||
# 'mono' outputs left to right lowest to highest frequencies.
|
||||
# 'mono_option' set mono to either take input from 'left', 'right' or 'average'.
|
||||
# set 'reverse' to 1 to display frequencies the other way around.
|
||||
|
||||
# Raw output target. A fifo will be created if target does not exist.
|
||||
raw_target = /dev/stdout
|
||||
|
||||
# Raw data format. Can be 'binary' or 'ascii'.
|
||||
data_format = ascii
|
||||
|
||||
# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530).
|
||||
|
||||
# Ascii max value. In 'ascii' mode range will run from 0 to value specified here
|
||||
|
||||
# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters.
|
||||
# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)).
|
||||
bar_delimiter = 0
|
||||
|
||||
# sdl window size and position. -1,-1 is centered.
|
||||
|
||||
# set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none'
|
||||
# 'frequency' displays the lower cut off frequency of the bar above.
|
||||
# Only supported on ncurses and noncurses output.
|
||||
|
||||
# enable synchronized sync. 1 = on, 0 = off
|
||||
# removes flickering in alacritty terminal emulator.
|
||||
# defaults to off since the behaviour in other terminal emulators is unknown
|
||||
|
||||
# Shaders for sdl_glsl, located in $HOME/.config/cava/shaders
|
||||
|
||||
; for glsl output mode, keep rendering even if no audio
|
||||
|
||||
# disable console blank (screen saver) in tty
|
||||
# (Not supported on FreeBSD)
|
||||
|
||||
# show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off
|
||||
|
||||
# show waveform instead of frequency spectrum, 1 = on, 0 = off
|
||||
|
||||
[color]
|
||||
|
||||
# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow.
|
||||
# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires
|
||||
# a terminal that can change color definitions such as Gnome-terminal or rxvt.
|
||||
# default is to keep current terminal color
|
||||
|
||||
# SDL and sdl_glsl only support hex code colors, these are the default:
|
||||
|
||||
# Gradient mode, only hex defined colors are supported,
|
||||
# background must also be defined in hex or remain commented out. 1 = on, 0 = off.
|
||||
# You can define as many as 8 different colors. They range from bottom to top of screen
|
||||
|
||||
[smoothing]
|
||||
|
||||
# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable.
|
||||
|
||||
# Noise reduction, int 0 - 100. default 77
|
||||
# the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth
|
||||
# 100 will be very slow and smooth, 0 will be fast but noisy.
|
||||
|
||||
|
||||
[eq]
|
||||
|
||||
# This one is tricky. You can have as much keys as you want.
|
||||
# Remember to uncomment more than one key! More keys = more precision.
|
||||
# Look at readme.md on github for further explanations and examples.
|
||||
```
|
||||
## GLSL
|
||||
The Cava GLSL frontend delegates the visualization of incoming audio data to the GPU via OpenGL.
|
||||
|
||||
There are some mandatory dependencies that need to be satisfied in order for Cava GLSL to be built and function properly:
|
||||
|
||||
. epoxy library must be installed on the system
|
||||
. Vertex and fragment shaders from the original project must be used. They should be downloaded, and the file paths must be configured correctly in the Waybar Cava configuration:
|
||||
1. cava shaders [cava shaders](https://github.com/karlstav/cava/tree/master/output/shaders)
|
||||
2. libcava shaders [libcava shaders](https://github.com/LukashonakV/cava/tree/master/output/shaders)
|
||||
. It is highly recommended to have a separate cava configuration for the Waybar Cava GLSL module and to use this as the cava_config in the Waybar configuration.
|
||||
. It is common for cava configurations to be placed in the XDG_CONFIG_HOME directory, including shaders as well. Consider keeping them in the $XDG_CONFIG_HOME/cava/shaders folder.
|
||||
|
||||
Key configuration options:
|
||||
|
||||
. bars. The more values the parameter has, the more interesting the visualization becomes.
|
||||
. method in output section must be set to sdl_glsl
|
||||
. sdl_width and sdl_height manage the size of the module. Adjust them according to your needs.
|
||||
. Shaders for sdl_glsl, located in $HOME/.config/cava/shaders. Example: "vertex_shader" = "pass_through.vert" "fragment_shader" = "spectrogram.frag"
|
||||
. Set continuous_rendering to 1 to enable smooth rendering; set it to 0 otherwise. It is recommended to keep it set to 1.
|
||||
. background, foreground, and gradient_color_N (where N is a number between 1 and 8) must be defined using hex code
|
||||
|
||||
Example:
|
||||
|
||||
waybar config
|
||||
```
|
||||
"cava": {
|
||||
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_cava#3.conf",
|
||||
"input_delay": 2,
|
||||
"actions": {
|
||||
"on-click-right": "mode"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
waybar_raw.conf
|
||||
```
|
||||
## Configuration file for CAVA.
|
||||
# Remove the ; to change parameters.
|
||||
|
||||
|
||||
[general]
|
||||
|
||||
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
|
||||
|
||||
# Accepts only non-negative values.
|
||||
|
||||
# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off
|
||||
# new as of 0.6.0 autosens of low values (dynamic range)
|
||||
# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0
|
||||
|
||||
# Manual sensitivity in %. If autosens is enabled, this will only be the initial value.
|
||||
# 200 means double height. Accepts only non-negative values.
|
||||
|
||||
# The number of bars (0-512). 0 sets it to auto (fill up console).
|
||||
# Bars' width and space between bars in number of characters.
|
||||
bars = 50
|
||||
|
||||
# bar_height is only used for output in "noritake" format
|
||||
|
||||
# For SDL width and space between bars is in pixels, defaults are:
|
||||
|
||||
# sdl_glsl have these default values, they are only used to calculate max number of bars.
|
||||
|
||||
# Lower and higher cutoff frequencies for lowest and highest bars
|
||||
# the bandwidth of the visualizer.
|
||||
# Note: there is a minimum total bandwidth of 43Mhz x number of bars.
|
||||
# Cava will automatically increase the higher cutoff if a too low band is specified.
|
||||
|
||||
# Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and
|
||||
# only check for input once per second. Cava will wake up once input is detected. 0 = disable.
|
||||
sleep_timer = 5
|
||||
|
||||
|
||||
[input]
|
||||
|
||||
# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem'
|
||||
# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with.
|
||||
# On Mac it defaults to 'portaudio' or 'fifo'
|
||||
# On windows this is automatic and no input settings are needed.
|
||||
#
|
||||
# All input methods uses the same config variable 'source'
|
||||
# to define where it should get the audio.
|
||||
#
|
||||
# For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink
|
||||
# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them).
|
||||
#
|
||||
# For pipewire 'source' will be the object name or object.serial of the device to capture from.
|
||||
# Both input and output devices are supported.
|
||||
#
|
||||
# For alsa 'source' will be the capture device.
|
||||
# For fifo 'source' will be the path to fifo-file.
|
||||
# For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address
|
||||
#
|
||||
# For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'.
|
||||
# README.md contains further information on how to setup CAVA for sndio.
|
||||
#
|
||||
# For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device.
|
||||
# README.md contains further information on how to setup CAVA for OSS on FreeBSD.
|
||||
#
|
||||
# For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'.
|
||||
# README.md contains further information on how to setup CAVA for JACK.
|
||||
#
|
||||
|
||||
|
||||
# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods:
|
||||
# sample_rate: fifo, pipewire, sndio, oss
|
||||
# sample_bits: fifo, pipewire, sndio, oss
|
||||
# channels: sndio, oss, jack
|
||||
# autoconnect: jack
|
||||
# Other methods ignore these settings.
|
||||
#
|
||||
# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported
|
||||
# by the chosen audio device, the device will use other supported values instead.
|
||||
# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it
|
||||
# will use 44100, 16 and 1.
|
||||
#
|
||||
|
||||
|
||||
[output]
|
||||
|
||||
# Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl'
|
||||
# or 'sdl_glsl'.
|
||||
# 'noncurses' (default) uses a buffer and cursor movements to only print
|
||||
# changes from frame to frame in the terminal. Uses less resources and is less
|
||||
# prone to tearing (vsync issues) than 'ncurses'.
|
||||
#
|
||||
# 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data
|
||||
# stream of the bar heights that can be used to send to other applications.
|
||||
# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above.
|
||||
#
|
||||
# 'noritake' outputs a bitmap in the format expected by a Noritake VFD display
|
||||
# in graphic mode. It only support the 3000 series graphical VFDs for now.
|
||||
#
|
||||
# 'sdl' uses the Simple DirectMedia Layer to render in a graphical context.
|
||||
# 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or
|
||||
# use one of the predefined ones.
|
||||
method = sdl_glsl
|
||||
|
||||
# Orientation of the visualization. Can be 'bottom', 'top', 'left', 'right' or
|
||||
# 'horizontal'. Default is 'bottom'. 'left and 'right' are only supported on sdl
|
||||
# and ncruses output. 'horizontal' (bars go up and down from center) is only supported
|
||||
# on noncurses output.
|
||||
# Note: many fonts have weird or missing glyphs for characters used in orientations
|
||||
# other than 'bottom', which can make output not look right.
|
||||
|
||||
# Visual channels. Can be 'stereo' or 'mono'.
|
||||
# 'stereo' mirrors both channels with low frequencies in center.
|
||||
# 'mono' outputs left to right lowest to highest frequencies.
|
||||
# 'mono_option' set mono to either take input from 'left', 'right' or 'average'.
|
||||
# set 'reverse' to 1 to display frequencies the other way around.
|
||||
|
||||
# Raw output target. A fifo will be created if target does not exist.
|
||||
|
||||
# Raw data format. Can be 'binary' or 'ascii'.
|
||||
|
||||
# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530).
|
||||
|
||||
# Ascii max value. In 'ascii' mode range will run from 0 to value specified here
|
||||
|
||||
# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters.
|
||||
# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)).
|
||||
bar_delimiter = 0
|
||||
|
||||
# sdl window size and position. -1,-1 is centered.
|
||||
sdl_width = 150
|
||||
sdl_height = 39
|
||||
|
||||
# set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none'
|
||||
# 'frequency' displays the lower cut off frequency of the bar above.
|
||||
# Only supported on ncurses and noncurses output.
|
||||
|
||||
# enable synchronized sync. 1 = on, 0 = off
|
||||
# removes flickering in alacritty terminal emulator.
|
||||
# defaults to off since the behaviour in other terminal emulators is unknown
|
||||
|
||||
# Shaders for sdl_glsl, located in $HOME/.config/cava/shaders
|
||||
vertex_shader = pass_through.vert
|
||||
fragment_shader = bar_spectrum.frag
|
||||
|
||||
; for glsl output mode, keep rendering even if no audio
|
||||
continuous_rendering = 1;
|
||||
|
||||
# disable console blank (screen saver) in tty
|
||||
# (Not supported on FreeBSD)
|
||||
|
||||
# show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off
|
||||
|
||||
# show waveform instead of frequency spectrum, 1 = on, 0 = off
|
||||
|
||||
[color]
|
||||
|
||||
|
||||
# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow.
|
||||
# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires
|
||||
# a terminal that can change color definitions such as Gnome-terminal or rxvt.
|
||||
# default is to keep current terminal color
|
||||
|
||||
# SDL and sdl_glsl only support hex code colors, these are the default:
|
||||
background = '#282C34'
|
||||
|
||||
# Gradient mode, only hex defined colors are supported,
|
||||
# background must also be defined in hex or remain commented out. 1 = on, 0 = off.
|
||||
# You can define as many as 8 different colors. They range from bottom to top of screen
|
||||
gradient = 1
|
||||
gradient_count = 2
|
||||
gradient_color_1 = '#282C34'
|
||||
gradient_color_2 = '#45475A'
|
||||
|
||||
; gradient_color_1 = '#59cc33'
|
||||
; gradient_color_2 = '#80cc33'
|
||||
gradient_color_3 = '#a6cc33'
|
||||
gradient_color_4 = '#cccc33'
|
||||
gradient_color_5 = '#cca633'
|
||||
gradient_color_6 = '#cc8033'
|
||||
gradient_color_7 = '#cc5933'
|
||||
gradient_color_8 = '#cc3333'
|
||||
|
||||
[smoothing]
|
||||
|
||||
# Percentage value for integral smoothing. Takes values from 0 - 100.
|
||||
# Higher values means smoother, but less precise. 0 to disable.
|
||||
# DEPRECATED as of 0.8.0, use noise_reduction instead
|
||||
|
||||
# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable.
|
||||
|
||||
# Set gravity percentage for "drop off". Higher values means bars will drop faster.
|
||||
# Accepts only non-negative values. 50 means half gravity, 200 means double. Set to 0 to disable "drop off".
|
||||
# DEPRECATED as of 0.8.0, use noise_reduction instead
|
||||
|
||||
|
||||
# In bar height, bars that would have been lower that this will not be drawn.
|
||||
# DEPRECATED as of 0.8.0
|
||||
|
||||
# Noise reduction, int 0 - 100. default 77
|
||||
# the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth
|
||||
# 100 will be very slow and smooth, 0 will be fast but noisy.
|
||||
|
||||
[eq]
|
||||
|
||||
# This one is tricky. You can have as much keys as you want.
|
||||
# Remember to uncomment more than one key! More keys = more precision.
|
||||
# Look at readme.md on github for further explanations and examples.
|
||||
```
|
||||
|
||||
Different waybar_cava#N.conf see at [cava GLSL](https://github.com/Alexays/Waybar/wiki/Module:-Cava:-GLSL)
|
||||
|
||||
@ -234,7 +234,6 @@ $text\\n$tooltip\\n$class*
|
||||
```
|
||||
"custom/pacman": {
|
||||
"format": "{text} ",
|
||||
"interval": 3600, // every hour
|
||||
"exec": "checkupdates | wc -l", // # of updates
|
||||
"exec-if": "exit 0", // always run; consider advanced run conditions
|
||||
"on-click": "termite -e 'sudo pacman -Syu'; pkill -SIGRTMIN+8 waybar", // update system
|
||||
@ -242,7 +241,7 @@ $text\\n$tooltip\\n$class*
|
||||
}
|
||||
```
|
||||
|
||||
You can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*.
|
||||
Under the premise that interval is not defined, you can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*.
|
||||
|
||||
# STYLE
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@ Addressed by *dwl/tags*
|
||||
|
||||
- *#tags button*
|
||||
- *#tags button.occupied*
|
||||
- *#tags button.empty*
|
||||
- *#tags button.focused*
|
||||
- *#tags button.urgent*
|
||||
|
||||
|
||||
@ -77,12 +77,12 @@ The slider is a component with multiple CSS Nodes, of which the following are ex
|
||||
min-height: 80px;
|
||||
min-width: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: black;
|
||||
background: black;
|
||||
}
|
||||
|
||||
#pulseaudio-slider highlight {
|
||||
min-width: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: green;
|
||||
background: green;
|
||||
}
|
||||
```
|
||||
|
||||
@ -97,7 +97,11 @@ Additionally, you can control the volume by scrolling *up* or *down* while the c
|
||||
|
||||
*reverse-scrolling*: ++
|
||||
typeof: bool ++
|
||||
Option to reverse the scroll direction.
|
||||
Option to reverse the scroll direction for touchpads.
|
||||
|
||||
*reverse-mouse-scrolling*: ++
|
||||
typeof: bool ++
|
||||
Option to reverse the scroll direction for mice.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
@ -173,8 +177,8 @@ to be selected when the corresponding audio device is muted. This applies to *de
|
||||
"format-icons": {
|
||||
"alsa_output.pci-0000_00_1f.3.analog-stereo": "",
|
||||
"alsa_output.pci-0000_00_1f.3.analog-stereo-muted": "",
|
||||
"headphones": "",
|
||||
"handsfree": "",
|
||||
"headphone": "",
|
||||
"hands-free": "",
|
||||
"headset": "",
|
||||
"phone": "",
|
||||
"phone-muted": "",
|
||||
|
||||
@ -179,7 +179,6 @@ n.b.: the list of outputs can be obtained from command line using *swaymsg -t ge
|
||||
"format": "<span size='larger'>{name}</span> {windows}",
|
||||
"format-window-separator": " | ",
|
||||
"window-rewrite-default": "{name}",
|
||||
"window-format": "<span color='#e0e0e0'>{name}</span>",
|
||||
"window-rewrite": {
|
||||
"class<firefox>": "",
|
||||
"class<kitty>": "k",
|
||||
|
||||
19
meson.build
19
meson.build
@ -1,6 +1,6 @@
|
||||
project(
|
||||
'waybar', 'cpp', 'c',
|
||||
version: '0.14.0',
|
||||
version: '0.15.0',
|
||||
license: 'MIT',
|
||||
meson_version: '>= 0.59.0',
|
||||
default_options : [
|
||||
@ -497,16 +497,24 @@ else
|
||||
man_files += files('man/waybar-clock.5.scd')
|
||||
endif
|
||||
|
||||
cava = dependency('cava',
|
||||
version : '>=0.10.4',
|
||||
cava = dependency('libcava',
|
||||
version : '>=0.10.7',
|
||||
required: get_option('cava'),
|
||||
fallback : ['cava', 'cava_dep'],
|
||||
fallback : ['libcava', 'cava_dep'],
|
||||
not_found_message: 'cava is not found. Building waybar without cava')
|
||||
|
||||
eproxy = dependency('epoxy', required: false)
|
||||
|
||||
if cava.found()
|
||||
add_project_arguments('-DHAVE_LIBCAVA', language: 'cpp')
|
||||
src_files += files('src/modules/cava/cava.cpp', 'src/modules/cava/cava_backend.cpp')
|
||||
src_files += files('src/modules/cava/cavaRaw.cpp',
|
||||
'src/modules/cava/cava_backend.cpp')
|
||||
man_files += files('man/waybar-cava.5.scd')
|
||||
|
||||
if eproxy.found()
|
||||
add_project_arguments('-DHAVE_LIBCAVAGLSL', language: 'cpp')
|
||||
src_files += files('src/modules/cava/cavaGLSL.cpp')
|
||||
endif
|
||||
endif
|
||||
|
||||
if libgps.found()
|
||||
@ -554,6 +562,7 @@ executable(
|
||||
tz_dep,
|
||||
xkbregistry,
|
||||
cava,
|
||||
eproxy,
|
||||
libgps
|
||||
],
|
||||
include_directories: inc_dirs,
|
||||
|
||||
@ -6,16 +6,17 @@
|
||||
}:
|
||||
let
|
||||
libcava = rec {
|
||||
version = "0.10.4";
|
||||
version = "0.10.7-beta";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "LukashonakV";
|
||||
repo = "cava";
|
||||
tag = version;
|
||||
hash = "sha256-9eTDqM+O1tA/3bEfd1apm8LbEcR9CVgELTIspSVPMKM=";
|
||||
# NOTE: Needs to match the cava.wrap
|
||||
tag = "v${version}";
|
||||
hash = "sha256-IX1B375gTwVDRjpRfwKGuzTAZOV2pgDWzUd4bW2cTDU=";
|
||||
};
|
||||
};
|
||||
in
|
||||
(waybar.overrideAttrs (oldAttrs: {
|
||||
waybar.overrideAttrs (oldAttrs: {
|
||||
inherit version;
|
||||
|
||||
src = lib.cleanSourceWith {
|
||||
@ -43,4 +44,4 @@ in
|
||||
patchShebangs .
|
||||
popd
|
||||
'';
|
||||
}))
|
||||
})
|
||||
|
||||
@ -190,7 +190,7 @@ bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
|
||||
}
|
||||
|
||||
void ALabel::handleGtkMenuEvent(GtkMenuItem* /*menuitem*/, gpointer data) {
|
||||
waybar::util::command::res res = waybar::util::command::exec((char*)data, "GtkMenu");
|
||||
waybar::util::command::forkExec((char*)data, "GtkMenu");
|
||||
}
|
||||
|
||||
std::string ALabel::getState(uint8_t value, bool lesser) {
|
||||
|
||||
@ -229,7 +229,8 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
||||
gtk_layer_init_for_window(gtk_window);
|
||||
gtk_layer_set_keyboard_mode(gtk_window, GTK_LAYER_SHELL_KEYBOARD_MODE_NONE);
|
||||
gtk_layer_set_monitor(gtk_window, output->monitor->gobj());
|
||||
gtk_layer_set_namespace(gtk_window, "waybar");
|
||||
gtk_layer_set_namespace(gtk_window,
|
||||
config["name"].isString() ? config["name"].asCString() : "waybar");
|
||||
|
||||
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, margins_.left);
|
||||
gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right);
|
||||
|
||||
@ -184,15 +184,23 @@ const std::string waybar::Client::getStyle(const std::string& style,
|
||||
};
|
||||
|
||||
auto waybar::Client::setupCss(const std::string& css_file) -> void {
|
||||
css_provider_ = Gtk::CssProvider::create();
|
||||
style_context_ = Gtk::StyleContext::create();
|
||||
auto screen = Gdk::Screen::get_default();
|
||||
if (!screen) {
|
||||
throw std::runtime_error("No default screen");
|
||||
}
|
||||
|
||||
// Load our css file, wherever that may be hiding
|
||||
if (css_provider_) {
|
||||
Gtk::StyleContext::remove_provider_for_screen(screen, css_provider_);
|
||||
css_provider_.reset();
|
||||
}
|
||||
|
||||
css_provider_ = Gtk::CssProvider::create();
|
||||
if (!css_provider_->load_from_path(css_file)) {
|
||||
css_provider_.reset();
|
||||
throw std::runtime_error("Can't open style file");
|
||||
}
|
||||
// there's always only one screen
|
||||
style_context_->add_provider_for_screen(Gdk::Screen::get_default(), css_provider_,
|
||||
|
||||
Gtk::StyleContext::add_provider_for_screen(screen, css_provider_,
|
||||
GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
|
||||
@ -212,13 +220,22 @@ void waybar::Client::bindInterfaces() {
|
||||
if (xdg_output_manager == nullptr) {
|
||||
throw std::runtime_error("Failed to acquire required resources.");
|
||||
}
|
||||
|
||||
// Disconnect previous signal handlers to prevent duplicate handlers on reload
|
||||
monitor_added_connection_.disconnect();
|
||||
monitor_removed_connection_.disconnect();
|
||||
|
||||
// Clear stale outputs from previous run
|
||||
outputs_.clear();
|
||||
|
||||
// add existing outputs and subscribe to updates
|
||||
for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) {
|
||||
auto monitor = gdk_display->get_monitor(i);
|
||||
handleMonitorAdded(monitor);
|
||||
}
|
||||
gdk_display->signal_monitor_added().connect(sigc::mem_fun(*this, &Client::handleMonitorAdded));
|
||||
gdk_display->signal_monitor_removed().connect(
|
||||
monitor_added_connection_ = gdk_display->signal_monitor_added().connect(
|
||||
sigc::mem_fun(*this, &Client::handleMonitorAdded));
|
||||
monitor_removed_connection_ = gdk_display->signal_monitor_removed().connect(
|
||||
sigc::mem_fun(*this, &Client::handleMonitorRemoved));
|
||||
}
|
||||
|
||||
|
||||
@ -108,15 +108,13 @@
|
||||
#ifdef HAVE_LIBWIREPLUMBER
|
||||
#include "modules/wireplumber.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBCAVA
|
||||
#include "modules/cava/cava.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_SYSTEMD_MONITOR
|
||||
#include "modules/systemd_failed_units.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBGPS
|
||||
#include "modules/gps.hpp"
|
||||
#endif
|
||||
#include "modules/cava/cava_frontend.hpp"
|
||||
#include "modules/cffi.hpp"
|
||||
#include "modules/custom.hpp"
|
||||
#include "modules/image.hpp"
|
||||
@ -341,11 +339,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
|
||||
return new waybar::modules::Wireplumber(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LIBCAVA
|
||||
if (ref == "cava") {
|
||||
return new waybar::modules::cava::Cava(id, config_[name]);
|
||||
return waybar::modules::cava::getModule(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SYSTEMD_MONITOR
|
||||
if (ref == "systemd-failed-units") {
|
||||
return new waybar::modules::SystemdFailedUnits(id, config_[name]);
|
||||
|
||||
@ -27,7 +27,7 @@ Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical) {
|
||||
|
||||
Group::Group(const std::string& name, const std::string& id, const Json::Value& config,
|
||||
bool vertical)
|
||||
: AModule(config, name, id, true, true),
|
||||
: AModule(config, name, id, true, false),
|
||||
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
|
||||
revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
|
||||
box.set_name(name_);
|
||||
|
||||
@ -7,7 +7,10 @@
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <libudev.h>
|
||||
#include <poll.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
waybar::modules::Battery::Battery(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||
: ALabel(config, "battery", id, "{capacity}%", 60), last_event_(""), bar_(bar) {
|
||||
@ -16,17 +19,21 @@ waybar::modules::Battery::Battery(const std::string& id, const Bar& bar, const J
|
||||
if (battery_watch_fd_ == -1) {
|
||||
throw std::runtime_error("Unable to listen batteries.");
|
||||
}
|
||||
|
||||
global_watch_fd_ = inotify_init1(IN_CLOEXEC);
|
||||
if (global_watch_fd_ == -1) {
|
||||
throw std::runtime_error("Unable to listen batteries.");
|
||||
udev_ = std::unique_ptr<udev, util::UdevDeleter>(udev_new());
|
||||
if (udev_ == nullptr) {
|
||||
throw std::runtime_error("udev_new failed");
|
||||
}
|
||||
|
||||
// Watch the directory for any added or removed batteries
|
||||
global_watch = inotify_add_watch(global_watch_fd_, data_dir_.c_str(), IN_CREATE | IN_DELETE);
|
||||
if (global_watch < 0) {
|
||||
throw std::runtime_error("Could not watch for battery plug/unplug");
|
||||
mon_ = std::unique_ptr<udev_monitor, util::UdevMonitorDeleter>(
|
||||
udev_monitor_new_from_netlink(udev_.get(), "kernel"));
|
||||
if (mon_ == nullptr) {
|
||||
throw std::runtime_error("udev monitor new failed");
|
||||
}
|
||||
if (udev_monitor_filter_add_match_subsystem_devtype(mon_.get(), "power_supply", nullptr) < 0) {
|
||||
throw std::runtime_error("udev failed to add monitor filter");
|
||||
}
|
||||
udev_monitor_enable_receiving(mon_.get());
|
||||
|
||||
if (config_["weighted-average"].isBool()) weightedAverage_ = config_["weighted-average"].asBool();
|
||||
#endif
|
||||
spdlog::debug("battery: worker interval is {}", interval_.count());
|
||||
worker();
|
||||
@ -36,11 +43,6 @@ waybar::modules::Battery::~Battery() {
|
||||
#if defined(__linux__)
|
||||
std::lock_guard<std::mutex> guard(battery_list_mutex_);
|
||||
|
||||
if (global_watch >= 0) {
|
||||
inotify_rm_watch(global_watch_fd_, global_watch);
|
||||
}
|
||||
close(global_watch_fd_);
|
||||
|
||||
for (auto it = batteries_.cbegin(), next_it = it; it != batteries_.cend(); it = next_it) {
|
||||
++next_it;
|
||||
auto watch_id = (*it).second;
|
||||
@ -77,12 +79,18 @@ void waybar::modules::Battery::worker() {
|
||||
dp.emit();
|
||||
};
|
||||
thread_battery_update_ = [this] {
|
||||
struct inotify_event event = {0};
|
||||
int nbytes = read(global_watch_fd_, &event, sizeof(event));
|
||||
if (nbytes != sizeof(event) || event.mask & IN_IGNORED) {
|
||||
poll_fds_[0].revents = 0;
|
||||
poll_fds_[0].events = POLLIN;
|
||||
poll_fds_[0].fd = udev_monitor_get_fd(mon_.get());
|
||||
int ret = poll(poll_fds_.data(), poll_fds_.size(), -1);
|
||||
if (ret < 0) {
|
||||
thread_.stop();
|
||||
return;
|
||||
}
|
||||
if ((poll_fds_[0].revents & POLLIN) != 0) {
|
||||
signalfd_siginfo signal_info;
|
||||
read(poll_fds_[0].fd, &signal_info, sizeof(signal_info));
|
||||
}
|
||||
refreshBatteries();
|
||||
dp.emit();
|
||||
};
|
||||
@ -585,8 +593,7 @@ waybar::modules::Battery::getInfos() {
|
||||
}
|
||||
|
||||
// Handle weighted-average
|
||||
if ((config_["weighted-average"].isBool() ? config_["weighted-average"].asBool() : false) &&
|
||||
total_energy_exists && total_energy_full_exists) {
|
||||
if (weightedAverage_ && total_energy_exists && total_energy_full_exists) {
|
||||
if (total_energy_full > 0.0f)
|
||||
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
|
||||
}
|
||||
@ -679,6 +686,7 @@ auto waybar::modules::Battery::update() -> void {
|
||||
status = getAdapterStatus(capacity);
|
||||
}
|
||||
auto status_pretty = status;
|
||||
puts(status.c_str());
|
||||
// Transform to lowercase and replace space with dash
|
||||
std::ranges::transform(status.begin(), status.end(), status.begin(),
|
||||
[](char ch) { return ch == ' ' ? '-' : std::tolower(ch); });
|
||||
|
||||
@ -264,7 +264,7 @@ auto waybar::modules::Bluetooth::update() -> void {
|
||||
device_enumerate_.erase(0, 1);
|
||||
}
|
||||
}
|
||||
label_.set_tooltip_text(fmt::format(
|
||||
label_.set_tooltip_markup(fmt::format(
|
||||
fmt::runtime(tooltip_format), fmt::arg("status", state_),
|
||||
fmt::arg("num_connections", connected_devices_.size()),
|
||||
fmt::arg("controller_address", cur_controller_ ? cur_controller_->address : "null"),
|
||||
|
||||
271
src/modules/cava/cavaGLSL.cpp
Normal file
271
src/modules/cava/cavaGLSL.cpp
Normal file
@ -0,0 +1,271 @@
|
||||
#include "modules/cava/cavaGLSL.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
waybar::modules::cava::CavaGLSL::CavaGLSL(const std::string& id, const Json::Value& config)
|
||||
: AModule(config, "cavaGLSL", id, false, false),
|
||||
backend_{waybar::modules::cava::CavaBackend::inst(config)} {
|
||||
set_name(name_);
|
||||
if (config_["hide_on_silence"].isBool()) hide_on_silence_ = config_["hide_on_silence"].asBool();
|
||||
if (!id.empty()) {
|
||||
get_style_context()->add_class(id);
|
||||
}
|
||||
get_style_context()->add_class(MODULE_CLASS);
|
||||
|
||||
set_use_es(true);
|
||||
// set_auto_render(true);
|
||||
signal_realize().connect(sigc::mem_fun(*this, &CavaGLSL::onRealize));
|
||||
signal_render().connect(sigc::mem_fun(*this, &CavaGLSL::onRender), false);
|
||||
|
||||
// Get parameters_config struct from the backend
|
||||
prm_ = *backend_->getPrm();
|
||||
|
||||
// Set widget length
|
||||
int length{0};
|
||||
if (config_["min-length"].isUInt())
|
||||
length = config_["min-length"].asUInt();
|
||||
else if (config_["max-length"].isUInt())
|
||||
length = config_["max-length"].asUInt();
|
||||
else
|
||||
length = prm_.sdl_width;
|
||||
|
||||
set_size_request(length, prm_.sdl_height);
|
||||
|
||||
// Subscribe for changes
|
||||
backend_->signal_audio_raw_update().connect(sigc::mem_fun(*this, &CavaGLSL::onUpdate));
|
||||
// Subscribe for silence
|
||||
backend_->signal_silence().connect(sigc::mem_fun(*this, &CavaGLSL::onSilence));
|
||||
event_box_.add(*this);
|
||||
}
|
||||
|
||||
auto waybar::modules::cava::CavaGLSL::onUpdate(const ::cava::audio_raw& input) -> void {
|
||||
Glib::signal_idle().connect_once([this, input]() {
|
||||
m_data_ = std::make_shared<::cava::audio_raw>(input);
|
||||
if (silence_) {
|
||||
get_style_context()->remove_class("silent");
|
||||
if (!get_style_context()->has_class("updated")) get_style_context()->add_class("updated");
|
||||
show();
|
||||
silence_ = false;
|
||||
}
|
||||
|
||||
queue_render();
|
||||
});
|
||||
}
|
||||
|
||||
auto waybar::modules::cava::CavaGLSL::onSilence() -> void {
|
||||
Glib::signal_idle().connect_once([this]() {
|
||||
if (!silence_) {
|
||||
if (get_style_context()->has_class("updated")) get_style_context()->remove_class("updated");
|
||||
|
||||
if (hide_on_silence_) hide();
|
||||
silence_ = true;
|
||||
get_style_context()->add_class("silent");
|
||||
// Set clear color to black
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
queue_render();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool waybar::modules::cava::CavaGLSL::onRender(const Glib::RefPtr<Gdk::GLContext>& context) {
|
||||
if (!m_data_) return true;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
glUniform1i(glGetUniformLocation(shaderProgram_, "inputTexture"), 0);
|
||||
|
||||
glUniform1fv(uniform_bars_, m_data_->number_of_bars, m_data_->bars_raw);
|
||||
glUniform1fv(uniform_previous_bars_, m_data_->number_of_bars, m_data_->previous_bars_raw);
|
||||
glUniform1i(uniform_bars_count_, m_data_->number_of_bars);
|
||||
++frame_counter;
|
||||
glUniform1f(uniform_time_, (frame_counter / backend_->getFrameTimeMilsec().count()) / 1e3);
|
||||
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, nullptr);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, nullptr);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::onRealize() {
|
||||
make_current();
|
||||
initShaders();
|
||||
initGLSL();
|
||||
initSurface();
|
||||
}
|
||||
|
||||
struct colors {
|
||||
uint16_t R;
|
||||
uint16_t G;
|
||||
uint16_t B;
|
||||
};
|
||||
|
||||
static void parse_color(char* color_string, struct colors* color) {
|
||||
if (color_string[0] == '#') {
|
||||
sscanf(++color_string, "%02hx%02hx%02hx", &color->R, &color->G, &color->B);
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::initGLSL() {
|
||||
GLint gVertexPos2DLocation{glGetAttribLocation(shaderProgram_, "vertexPosition_modelspace")};
|
||||
if (gVertexPos2DLocation == -1) {
|
||||
spdlog::error("{0}. Could not find vertex position shader variable", name_);
|
||||
}
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
GLfloat vertexData[]{-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
|
||||
GLint indexData[]{0, 1, 2, 3};
|
||||
|
||||
GLuint gVBO{0};
|
||||
glGenBuffers(1, &gVBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), vertexData, GL_STATIC_DRAW);
|
||||
|
||||
GLuint gIBO{0};
|
||||
glGenBuffers(1, &gIBO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * sizeof(GLuint), indexData, GL_STATIC_DRAW);
|
||||
|
||||
GLuint gVAO{0};
|
||||
glGenVertexArrays(1, &gVAO);
|
||||
glBindVertexArray(gVAO);
|
||||
glEnableVertexAttribArray(gVertexPos2DLocation);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gVBO);
|
||||
glVertexAttribPointer(gVertexPos2DLocation, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gIBO);
|
||||
|
||||
glGenFramebuffers(1, &fbo_);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
|
||||
|
||||
// Create a texture to attach the framebuffer
|
||||
glGenTextures(1, &texture_);
|
||||
glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, prm_.sdl_width, prm_.sdl_height, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
|
||||
|
||||
// Check is framebuffer is complete
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
spdlog::error("{0}. Framebuffer not complete", name_);
|
||||
}
|
||||
|
||||
// Unbind the framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
uniform_bars_ = glGetUniformLocation(shaderProgram_, "bars");
|
||||
uniform_previous_bars_ = glGetUniformLocation(shaderProgram_, "previous_bars");
|
||||
uniform_bars_count_ = glGetUniformLocation(shaderProgram_, "bars_count");
|
||||
uniform_time_ = glGetUniformLocation(shaderProgram_, "shader_time");
|
||||
|
||||
GLuint err{glGetError()};
|
||||
if (err != 0) {
|
||||
spdlog::error("{0}. Error on initGLSL: {1}", name_, err);
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::initSurface() {
|
||||
colors color = {0};
|
||||
GLint uniform_bg_col{glGetUniformLocation(shaderProgram_, "bg_color")};
|
||||
parse_color(prm_.bcolor, &color);
|
||||
glUniform3f(uniform_bg_col, (float)color.R / 255.0, (float)color.G / 255.0,
|
||||
(float)color.B / 255.0);
|
||||
GLint uniform_fg_col{glGetUniformLocation(shaderProgram_, "fg_color")};
|
||||
parse_color(prm_.color, &color);
|
||||
glUniform3f(uniform_fg_col, (float)color.R / 255.0, (float)color.G / 255.0,
|
||||
(float)color.B / 255.0);
|
||||
GLint uniform_res{glGetUniformLocation(shaderProgram_, "u_resolution")};
|
||||
glUniform3f(uniform_res, (float)prm_.sdl_width, (float)prm_.sdl_height, 0.0f);
|
||||
GLint uniform_bar_width{glGetUniformLocation(shaderProgram_, "bar_width")};
|
||||
glUniform1i(uniform_bar_width, prm_.bar_width);
|
||||
GLint uniform_bar_spacing{glGetUniformLocation(shaderProgram_, "bar_spacing")};
|
||||
glUniform1i(uniform_bar_spacing, prm_.bar_spacing);
|
||||
GLint uniform_gradient_count{glGetUniformLocation(shaderProgram_, "gradient_count")};
|
||||
glUniform1i(uniform_gradient_count, prm_.gradient_count);
|
||||
GLint uniform_gradient_colors{glGetUniformLocation(shaderProgram_, "gradient_colors")};
|
||||
GLfloat gradient_colors[8][3];
|
||||
for (int i{0}; i < prm_.gradient_count; ++i) {
|
||||
parse_color(prm_.gradient_colors[i], &color);
|
||||
gradient_colors[i][0] = (float)color.R / 255.0;
|
||||
gradient_colors[i][1] = (float)color.G / 255.0;
|
||||
gradient_colors[i][2] = (float)color.B / 255.0;
|
||||
}
|
||||
glUniform3fv(uniform_gradient_colors, 8, (const GLfloat*)gradient_colors);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaGLSL::initShaders() {
|
||||
shaderProgram_ = glCreateProgram();
|
||||
|
||||
GLuint vertexShader{loadShader(prm_.vertex_shader, GL_VERTEX_SHADER)};
|
||||
GLuint fragmentShader{loadShader(prm_.fragment_shader, GL_FRAGMENT_SHADER)};
|
||||
|
||||
glAttachShader(shaderProgram_, vertexShader);
|
||||
glAttachShader(shaderProgram_, fragmentShader);
|
||||
|
||||
glLinkProgram(shaderProgram_);
|
||||
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
|
||||
// Check for linking errors
|
||||
GLint success, len;
|
||||
glGetProgramiv(shaderProgram_, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetProgramiv(shaderProgram_, GL_INFO_LOG_LENGTH, &len);
|
||||
GLchar* infoLog{(char*)'\0'};
|
||||
glGetProgramInfoLog(shaderProgram_, len, &len, infoLog);
|
||||
spdlog::error("{0}. Shader linking error: {1}", name_, infoLog);
|
||||
}
|
||||
|
||||
glReleaseShaderCompiler();
|
||||
glUseProgram(shaderProgram_);
|
||||
}
|
||||
|
||||
GLuint waybar::modules::cava::CavaGLSL::loadShader(const std::string& fileName, GLenum type) {
|
||||
spdlog::debug("{0}. loadShader: {1}", name_, fileName);
|
||||
|
||||
// Read shader source code from the file
|
||||
std::ifstream shaderFile{fileName};
|
||||
|
||||
if (!shaderFile.is_open()) {
|
||||
spdlog::error("{0}. Could not open shader file: {1}", name_, fileName);
|
||||
}
|
||||
|
||||
std::ostringstream buffer;
|
||||
buffer << shaderFile.rdbuf(); // read file content into stringstream
|
||||
std::string str{buffer.str()};
|
||||
const char* shaderSource = str.c_str();
|
||||
shaderFile.close();
|
||||
|
||||
GLuint shaderID{glCreateShader(type)};
|
||||
if (shaderID == 0) spdlog::error("{0}. Error creating shader type: {0}", type);
|
||||
glShaderSource(shaderID, 1, &shaderSource, nullptr);
|
||||
glCompileShader(shaderID);
|
||||
|
||||
// Check for compilation errors
|
||||
GLint success, len;
|
||||
|
||||
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
|
||||
|
||||
if (!success) {
|
||||
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &len);
|
||||
|
||||
GLchar* infoLog{(char*)'\0'};
|
||||
glGetShaderInfoLog(shaderID, len, nullptr, infoLog);
|
||||
spdlog::error("{0}. Shader compilation error in {1}: {2}", name_, fileName, infoLog);
|
||||
}
|
||||
|
||||
return shaderID;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
#include "modules/cava/cava.hpp"
|
||||
#include "modules/cava/cavaRaw.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
@ -24,8 +24,10 @@ auto waybar::modules::cava::Cava::doAction(const std::string& name) -> void {
|
||||
// Cava actions
|
||||
void waybar::modules::cava::Cava::pause_resume() { backend_->doPauseResume(); }
|
||||
auto waybar::modules::cava::Cava::onUpdate(const std::string& input) -> void {
|
||||
Glib::signal_idle().connect_once([this, input]() {
|
||||
if (silence_) {
|
||||
label_.get_style_context()->remove_class("silent");
|
||||
if (!label_.get_style_context()->has_class("updated"))
|
||||
label_.get_style_context()->add_class("updated");
|
||||
}
|
||||
label_text_.clear();
|
||||
@ -35,17 +37,24 @@ auto waybar::modules::cava::Cava::onUpdate(const std::string& input) -> void {
|
||||
label_.set_markup(label_text_);
|
||||
label_.show();
|
||||
ALabel::update();
|
||||
});
|
||||
silence_ = false;
|
||||
}
|
||||
|
||||
auto waybar::modules::cava::Cava::onSilence() -> void {
|
||||
Glib::signal_idle().connect_once([this]() {
|
||||
if (!silence_) {
|
||||
if (label_.get_style_context()->has_class("updated"))
|
||||
label_.get_style_context()->remove_class("updated");
|
||||
|
||||
if (hide_on_silence_)
|
||||
if (hide_on_silence_) {
|
||||
// Clear the label markup before hiding to prevent GTK from rendering a NULL Pango layout
|
||||
label_.set_markup("");
|
||||
label_.hide();
|
||||
else if (config_["format_silent"].isString())
|
||||
} else if (config_["format_silent"].isString())
|
||||
label_.set_markup(format_silent_);
|
||||
silence_ = true;
|
||||
label_.get_style_context()->add_class("silent");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -9,96 +9,9 @@ std::shared_ptr<waybar::modules::cava::CavaBackend> waybar::modules::cava::CavaB
|
||||
return backend_ptr;
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::CavaBackend(const Json::Value& config) {
|
||||
waybar::modules::cava::CavaBackend::CavaBackend(const Json::Value& config) : config_(config) {
|
||||
// Load waybar module config
|
||||
char cfgPath[PATH_MAX];
|
||||
cfgPath[0] = '\0';
|
||||
|
||||
if (config["cava_config"].isString()) strcpy(cfgPath, config["cava_config"].asString().data());
|
||||
// Load cava config
|
||||
error_.length = 0;
|
||||
|
||||
if (!load_config(cfgPath, &prm_, false, &error_)) {
|
||||
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;
|
||||
strcpy(prm_.data_format, "ascii");
|
||||
strcpy(prm_.raw_target, "/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()) 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());
|
||||
|
||||
// Make cava parameters configuration
|
||||
plan_ = new ::cava::cava_plan{};
|
||||
|
||||
audio_raw_.height = prm_.ascii_range;
|
||||
audio_data_.format = -1;
|
||||
audio_data_.source = new char[1 + strlen(prm_.audio_source)];
|
||||
audio_data_.source[0] = '\0';
|
||||
strcpy(audio_data_.source, prm_.audio_source);
|
||||
|
||||
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_.cava_in = new double[audio_data_.cava_buffer_size]{0.0};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Init cava plan, audio_raw structure
|
||||
audio_raw_init(&audio_data_, &audio_raw_, &prm_, plan_);
|
||||
if (!plan_) spdlog::error("cava backend plan is not provided");
|
||||
audio_raw_.previous_frame[0] = -1; // For first Update() call need to rePaint text message
|
||||
loadConfig();
|
||||
// Read audio source trough cava API. Cava orginizes this process via infinity loop
|
||||
read_thread_ = [this] {
|
||||
try {
|
||||
@ -107,33 +20,38 @@ waybar::modules::cava::CavaBackend::CavaBackend(const Json::Value& config) {
|
||||
spdlog::warn("Cava backend. Read source error: {0}", e.what());
|
||||
}
|
||||
read_thread_.sleep_for(fetch_input_delay_);
|
||||
loadConfig();
|
||||
};
|
||||
|
||||
thread_ = [this] {
|
||||
doUpdate();
|
||||
thread_.sleep_for(frame_time_milsec_);
|
||||
// Write outcoming data. Emit signals
|
||||
out_thread_ = [this] {
|
||||
doUpdate(false);
|
||||
out_thread_.sleep_for(frame_time_milsec_);
|
||||
};
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::~CavaBackend() {
|
||||
thread_.stop();
|
||||
out_thread_.stop();
|
||||
read_thread_.stop();
|
||||
delete plan_;
|
||||
plan_ = nullptr;
|
||||
|
||||
freeBackend();
|
||||
}
|
||||
|
||||
static void upThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
static bool upThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
if (delta == std::chrono::seconds{0}) {
|
||||
delta += std::chrono::seconds{1};
|
||||
delay += delta;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void downThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
static bool downThreadDelay(std::chrono::milliseconds& delay, std::chrono::seconds& delta) {
|
||||
if (delta > std::chrono::seconds{0}) {
|
||||
delay -= delta;
|
||||
delta -= std::chrono::seconds{1};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool waybar::modules::cava::CavaBackend::isSilence() {
|
||||
@ -183,6 +101,7 @@ void waybar::modules::cava::CavaBackend::doPauseResume() {
|
||||
upThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||
}
|
||||
pthread_mutex_unlock(&audio_data_.lock);
|
||||
Update();
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::type_signal_update
|
||||
@ -190,6 +109,11 @@ waybar::modules::cava::CavaBackend::signal_update() {
|
||||
return m_signal_update_;
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::type_signal_audio_raw_update
|
||||
waybar::modules::cava::CavaBackend::signal_audio_raw_update() {
|
||||
return m_signal_audio_raw_;
|
||||
}
|
||||
|
||||
waybar::modules::cava::CavaBackend::type_signal_silence
|
||||
waybar::modules::cava::CavaBackend::signal_silence() {
|
||||
return m_signal_silence_;
|
||||
@ -212,12 +136,138 @@ void waybar::modules::cava::CavaBackend::doUpdate(bool force) {
|
||||
}
|
||||
|
||||
if (!silence_ || prm_.sleep_timer == 0) {
|
||||
downThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||
if (downThreadDelay(frame_time_milsec_, suspend_silence_delay_)) Update();
|
||||
execute();
|
||||
if (re_paint_ == 1 || force) m_signal_update_.emit(output_);
|
||||
if (re_paint_ == 1 || force || prm_.continuous_rendering) {
|
||||
m_signal_update_.emit(output_);
|
||||
m_signal_audio_raw_.emit(audio_raw_);
|
||||
}
|
||||
} else {
|
||||
upThreadDelay(frame_time_milsec_, suspend_silence_delay_);
|
||||
if (upThreadDelay(frame_time_milsec_, suspend_silence_delay_)) Update();
|
||||
if (silence_ != silence_prev_ || force) m_signal_silence_.emit();
|
||||
}
|
||||
silence_prev_ = silence_;
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaBackend::freeBackend() {
|
||||
if (plan_ != NULL) {
|
||||
cava_destroy(plan_);
|
||||
plan_ = NULL;
|
||||
}
|
||||
|
||||
audio_raw_clean(&audio_raw_);
|
||||
pthread_mutex_lock(&audio_data_.lock);
|
||||
audio_data_.terminate = 1;
|
||||
pthread_mutex_unlock(&audio_data_.lock);
|
||||
free_config(&prm_);
|
||||
free(audio_data_.source);
|
||||
free(audio_data_.cava_in);
|
||||
}
|
||||
|
||||
void waybar::modules::cava::CavaBackend::loadConfig() {
|
||||
freeBackend();
|
||||
// Load waybar module config
|
||||
char cfgPath[PATH_MAX];
|
||||
cfgPath[0] = '\0';
|
||||
|
||||
if (config_["cava_config"].isString()) strcpy(cfgPath, config_["cava_config"].asString().data());
|
||||
// Load cava config
|
||||
error_.length = 0;
|
||||
|
||||
if (!load_config(cfgPath, &prm_, &error_)) {
|
||||
spdlog::error("cava backend. Error loading config. {0}", error_.message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Override cava parameters by the user config
|
||||
prm_.inAtty = 0;
|
||||
auto const output{prm_.output};
|
||||
// prm_.output = ::cava::output_method::OUTPUT_RAW;
|
||||
if (prm_.data_format) free(prm_.data_format);
|
||||
// Default to ascii for format-icons output; allow user override
|
||||
prm_.data_format = strdup(
|
||||
config_["data_format"].isString() ? config_["data_format"].asString().c_str() : "ascii");
|
||||
if (config_["raw_target"].isString()) {
|
||||
if (prm_.raw_target) free(prm_.raw_target);
|
||||
prm_.raw_target = strdup(config_["raw_target"].asString().c_str());
|
||||
}
|
||||
prm_.ascii_range = config_["format-icons"].size() - 1;
|
||||
|
||||
if (config_["bar_spacing"].isInt()) prm_.bar_spacing = config_["bar_spacing"].asInt();
|
||||
if (config_["bar_width"].isInt()) prm_.bar_width = config_["bar_width"].asInt();
|
||||
if (config_["bar_height"].isInt()) prm_.bar_height = config_["bar_height"].asInt();
|
||||
prm_.orientation = ::cava::ORIENT_TOP;
|
||||
prm_.xaxis = ::cava::xaxis_scale::NONE;
|
||||
prm_.mono_opt = ::cava::AVERAGE;
|
||||
prm_.autobars = 0;
|
||||
if (config_["gravity"].isInt()) prm_.gravity = config_["gravity"].asInt();
|
||||
if (config_["integral"].isInt()) prm_.integral = config_["integral"].asInt();
|
||||
|
||||
if (config_["framerate"].isInt()) prm_.framerate = config_["framerate"].asInt();
|
||||
// Calculate delay for Update() thread
|
||||
frame_time_milsec_ = std::chrono::milliseconds((int)(1e3 / prm_.framerate));
|
||||
if (config_["autosens"].isInt()) prm_.autosens = config_["autosens"].asInt();
|
||||
if (config_["sensitivity"].isInt()) prm_.sens = config_["sensitivity"].asInt();
|
||||
if (config_["bars"].isInt()) prm_.fixedbars = config_["bars"].asInt();
|
||||
if (config_["lower_cutoff_freq"].isNumeric())
|
||||
prm_.lower_cut_off = config_["lower_cutoff_freq"].asLargestInt();
|
||||
if (config_["higher_cutoff_freq"].isNumeric())
|
||||
prm_.upper_cut_off = config_["higher_cutoff_freq"].asLargestInt();
|
||||
if (config_["sleep_timer"].isInt()) prm_.sleep_timer = config_["sleep_timer"].asInt();
|
||||
if (config_["method"].isString())
|
||||
prm_.input = ::cava::input_method_by_name(config_["method"].asString().c_str());
|
||||
if (config_["source"].isString()) {
|
||||
if (prm_.audio_source) free(prm_.audio_source);
|
||||
prm_.audio_source = config_["source"].asString().data();
|
||||
}
|
||||
if (config_["sample_rate"].isNumeric()) prm_.samplerate = config_["sample_rate"].asLargestInt();
|
||||
if (config_["sample_bits"].isInt()) prm_.samplebits = config_["sample_bits"].asInt();
|
||||
if (config_["stereo"].isBool()) prm_.stereo = config_["stereo"].asBool();
|
||||
if (config_["reverse"].isBool()) prm_.reverse = config_["reverse"].asBool();
|
||||
if (config_["bar_delimiter"].isInt()) prm_.bar_delim = config_["bar_delimiter"].asInt();
|
||||
if (config_["monstercat"].isBool()) prm_.monstercat = config_["monstercat"].asBool();
|
||||
if (config_["waves"].isBool()) prm_.waves = config_["waves"].asBool();
|
||||
if (config_["noise_reduction"].isDouble())
|
||||
prm_.noise_reduction = config_["noise_reduction"].asDouble();
|
||||
if (config_["input_delay"].isInt())
|
||||
fetch_input_delay_ = std::chrono::seconds(config_["input_delay"].asInt());
|
||||
if (config_["gradient"].isInt()) prm_.gradient = config_["gradient"].asInt();
|
||||
if (prm_.gradient == 0)
|
||||
prm_.gradient_count = 0;
|
||||
else if (config_["gradient_count"].isInt())
|
||||
prm_.gradient_count = config_["gradient_count"].asInt();
|
||||
if (config_["sdl_width"].isInt()) prm_.sdl_width = config_["sdl_width"].asInt();
|
||||
if (config_["sdl_height"].isInt()) prm_.sdl_height = config_["sdl_height"].asInt();
|
||||
|
||||
audio_raw_.height = prm_.ascii_range;
|
||||
audio_data_.format = -1;
|
||||
audio_data_.rate = 0;
|
||||
audio_data_.samples_counter = 0;
|
||||
audio_data_.channels = 2;
|
||||
audio_data_.IEEE_FLOAT = 0;
|
||||
audio_data_.input_buffer_size = BUFFER_SIZE * audio_data_.channels;
|
||||
audio_data_.cava_buffer_size = audio_data_.input_buffer_size * 8;
|
||||
audio_data_.terminate = 0;
|
||||
audio_data_.suspendFlag = false;
|
||||
input_source_ = get_input(&audio_data_, &prm_);
|
||||
|
||||
if (!input_source_) {
|
||||
spdlog::error("cava backend API didn't provide input audio source method");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
prm_.output = ::cava::output_method::OUTPUT_RAW;
|
||||
|
||||
// Make cava parameters configuration
|
||||
// Init cava plan, audio_raw structure
|
||||
audio_raw_init(&audio_data_, &audio_raw_, &prm_, &plan_);
|
||||
if (!plan_) spdlog::error("cava backend plan is not provided");
|
||||
audio_raw_.previous_frame[0] = -1; // For first Update() call need to rePaint text message
|
||||
|
||||
prm_.output = output;
|
||||
}
|
||||
|
||||
const struct ::cava::config_params* waybar::modules::cava::CavaBackend::getPrm() { return &prm_; }
|
||||
std::chrono::milliseconds waybar::modules::cava::CavaBackend::getFrameTimeMilsec() {
|
||||
return frame_time_milsec_;
|
||||
};
|
||||
|
||||
@ -230,7 +230,7 @@ const unsigned cldRowsInMonth(const year_month& ym, const weekday& firstdow) {
|
||||
auto cldGetWeekForLine(const year_month& ym, const weekday& firstdow, const unsigned line)
|
||||
-> const year_month_weekday {
|
||||
const unsigned idx = line - 2;
|
||||
const std::chrono::weekday_indexed indexed_first_day_of_week =
|
||||
const auto indexed_first_day_of_week =
|
||||
weekday{ym / 1} == firstdow ? firstdow[idx + 1] : firstdow[idx];
|
||||
|
||||
return ym / indexed_first_day_of_week;
|
||||
|
||||
@ -136,7 +136,7 @@ void waybar::modules::Custom::waitingWorker() {
|
||||
}
|
||||
|
||||
void waybar::modules::Custom::refresh(int sig) {
|
||||
if (sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
if (config_["signal"].isInt() && sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
thread_.wake_up();
|
||||
}
|
||||
}
|
||||
@ -187,15 +187,11 @@ auto waybar::modules::Custom::update() -> void {
|
||||
fmt::arg("icon", getIcon(percentage_, alt_)), fmt::arg("percentage", percentage_));
|
||||
label_.set_tooltip_markup(tooltip);
|
||||
} else if (text_ == tooltip_) {
|
||||
if (label_.get_tooltip_markup() != str) {
|
||||
label_.set_tooltip_markup(str);
|
||||
}
|
||||
} else {
|
||||
if (label_.get_tooltip_markup() != tooltip_) {
|
||||
label_.set_tooltip_markup(tooltip_);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto style = label_.get_style_context();
|
||||
auto classes = style->list_classes();
|
||||
for (auto const& c : classes) {
|
||||
|
||||
@ -76,8 +76,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
}
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Tags *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Tags*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,6 +187,12 @@ void Tags::handle_view_tags(uint32_t tag, uint32_t state, uint32_t clients, uint
|
||||
button.get_style_context()->remove_class("occupied");
|
||||
}
|
||||
|
||||
if (clients & TAG_INACTIVE) {
|
||||
button.get_style_context()->remove_class("empty");
|
||||
} else {
|
||||
button.get_style_context()->add_class("empty");
|
||||
}
|
||||
|
||||
if (state & TAG_ACTIVE) {
|
||||
button.get_style_context()->add_class("focused");
|
||||
} else {
|
||||
|
||||
@ -44,6 +44,17 @@ auto Submap::parseConfig(const Json::Value& config) -> void {
|
||||
auto Submap::update() -> void {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
|
||||
// Handle style class changes
|
||||
if (!prev_submap_.empty()) {
|
||||
label_.get_style_context()->remove_class(prev_submap_);
|
||||
}
|
||||
|
||||
if (!submap_.empty()) {
|
||||
label_.get_style_context()->add_class(submap_);
|
||||
}
|
||||
|
||||
prev_submap_ = submap_;
|
||||
|
||||
if (submap_.empty()) {
|
||||
event_box_.hide();
|
||||
} else {
|
||||
@ -66,18 +77,12 @@ void Submap::onEvent(const std::string& ev) {
|
||||
|
||||
auto submapName = ev.substr(ev.find_first_of('>') + 2);
|
||||
|
||||
if (!submap_.empty()) {
|
||||
label_.get_style_context()->remove_class(submap_);
|
||||
}
|
||||
|
||||
submap_ = submapName;
|
||||
|
||||
if (submap_.empty() && always_on_) {
|
||||
submap_ = default_submap_;
|
||||
}
|
||||
|
||||
label_.get_style_context()->add_class(submap_);
|
||||
|
||||
spdlog::debug("hyprland submap onevent with {}", submap_);
|
||||
|
||||
dp.emit();
|
||||
|
||||
@ -45,6 +45,8 @@ Window::~Window() {
|
||||
auto Window::update() -> void {
|
||||
std::shared_lock<std::shared_mutex> windowIpcShareLock(windowIpcSmtx);
|
||||
|
||||
queryActiveWorkspace();
|
||||
|
||||
std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title);
|
||||
std::string windowAddress = workspace_.last_window;
|
||||
|
||||
@ -236,8 +238,6 @@ void Window::queryActiveWorkspace() {
|
||||
}
|
||||
|
||||
void Window::onEvent(const std::string& ev) {
|
||||
queryActiveWorkspace();
|
||||
|
||||
dp.emit();
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,8 @@ WindowCount::~WindowCount() {
|
||||
auto WindowCount::update() -> void {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
|
||||
queryActiveWorkspace();
|
||||
|
||||
std::string format = config_["format"].asString();
|
||||
std::string formatEmpty = config_["format-empty"].asString();
|
||||
std::string formatWindowed = config_["format-windowed"].asString();
|
||||
@ -116,8 +118,6 @@ auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Wor
|
||||
}
|
||||
|
||||
void WindowCount::queryActiveWorkspace() {
|
||||
std::lock_guard<std::mutex> lg(mutex_);
|
||||
|
||||
if (separateOutputs_) {
|
||||
workspace_ = getActiveWorkspace(this->bar_.output->name);
|
||||
} else {
|
||||
@ -126,7 +126,6 @@ void WindowCount::queryActiveWorkspace() {
|
||||
}
|
||||
|
||||
void WindowCount::onEvent(const std::string& ev) {
|
||||
queryActiveWorkspace();
|
||||
dp.emit();
|
||||
}
|
||||
|
||||
|
||||
@ -296,6 +296,11 @@ void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value &c
|
||||
auto workspace = rule.isMember("defaultName") ? rule["defaultName"].asString()
|
||||
: rule["workspaceString"].asString();
|
||||
|
||||
// There could be persistent special workspaces, only show those when show-special is enabled.
|
||||
if (workspace.starts_with("special:") && !showSpecial()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The prefix "name:" cause mismatches with workspace names taken anywhere else.
|
||||
if (workspace.starts_with("name:")) {
|
||||
workspace = workspace.substr(5);
|
||||
@ -934,7 +939,7 @@ void Workspaces::sortWorkspaces() {
|
||||
case SortMethod::NUMBER:
|
||||
try {
|
||||
return std::stoi(a->name()) < std::stoi(b->name());
|
||||
} catch (const std::invalid_argument &) {
|
||||
} catch (const std::exception& e) {
|
||||
// Handle the exception if necessary.
|
||||
break;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ void waybar::modules::Image::delayWorker() {
|
||||
}
|
||||
|
||||
void waybar::modules::Image::refresh(int sig) {
|
||||
if (sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
if (config_["signal"].isInt() && sig == SIGRTMIN + config_["signal"].asInt()) {
|
||||
thread_.wake_up();
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ auto waybar::modules::Memory::update() -> void {
|
||||
float total_swap_gigabytes = 0.01 * round(swaptotal / 10485.76);
|
||||
int used_ram_percentage = 100 * (memtotal - memfree) / memtotal;
|
||||
int used_swap_percentage = 0;
|
||||
if (swaptotal && swapfree) {
|
||||
if (swaptotal) {
|
||||
used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal;
|
||||
}
|
||||
float used_ram_gigabytes = 0.01 * round((memtotal - memfree) / 10485.76);
|
||||
|
||||
@ -86,8 +86,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Layout *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Layout*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,8 +46,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, version));
|
||||
} else if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Mode *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Mode*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -107,8 +107,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min(version, 1u);
|
||||
static_cast<Tags *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Tags*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "client.hpp"
|
||||
|
||||
@ -47,8 +46,8 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
||||
|
||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
version = std::min<uint32_t>(version, 1);
|
||||
static_cast<Window *>(data)->seat_ = static_cast<struct wl_seat *>(
|
||||
wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
static_cast<Window*>(data)->seat_ =
|
||||
static_cast<struct wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -79,6 +79,10 @@ Item::~Item() {
|
||||
this->gtk_menu->popdown();
|
||||
this->gtk_menu->detach();
|
||||
}
|
||||
if (this->dbus_menu != nullptr) {
|
||||
g_object_weak_unref(G_OBJECT(this->dbus_menu), (GWeakNotify)onMenuDestroyed, this);
|
||||
this->dbus_menu = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Item::handleMouseEnter(GdkEventCrossing* const& e) {
|
||||
@ -233,9 +237,13 @@ void Item::setCustomIcon(const std::string& id) {
|
||||
std::string custom_icon = IconManager::instance().getIconForApp(id);
|
||||
if (!custom_icon.empty()) {
|
||||
if (std::filesystem::exists(custom_icon)) {
|
||||
try {
|
||||
Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
|
||||
icon_name = ""; // icon_name has priority over pixmap
|
||||
icon_pixmap = custom_pixbuf;
|
||||
} catch (const Glib::Error& e) {
|
||||
spdlog::error("Failed to load custom icon {}: {}", custom_icon, e.what());
|
||||
}
|
||||
} else { // if file doesn't exist it's most likely an icon_name
|
||||
icon_name = custom_icon;
|
||||
}
|
||||
|
||||
@ -331,7 +331,7 @@ auto Workspaces::update() -> void {
|
||||
}
|
||||
std::string output = (*it)["name"].asString();
|
||||
std::string windows = "";
|
||||
if (config_["window-format"].isString()) {
|
||||
if (config_["window-rewrite"].isObject()) {
|
||||
updateWindows((*it), windows);
|
||||
}
|
||||
if (config_["format"].isString()) {
|
||||
|
||||
@ -14,16 +14,18 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
|
||||
mixer_api_(nullptr),
|
||||
def_nodes_api_(nullptr),
|
||||
default_node_name_(nullptr),
|
||||
default_source_name_(nullptr),
|
||||
pending_plugins_(0),
|
||||
muted_(false),
|
||||
source_muted_(false),
|
||||
volume_(0.0),
|
||||
source_volume_(0.0),
|
||||
min_step_(0.0),
|
||||
node_id_(0),
|
||||
node_name_(""),
|
||||
source_name_(""),
|
||||
type_(nullptr),
|
||||
source_node_id_(0),
|
||||
type_(nullptr) {
|
||||
source_muted_(false),
|
||||
source_volume_(0.0),
|
||||
default_source_name_(nullptr) {
|
||||
waybar::modules::Wireplumber::modules.push_back(this);
|
||||
|
||||
wp_init(WP_INIT_PIPEWIRE);
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "util/udev_deleter.hpp"
|
||||
|
||||
namespace {
|
||||
class FileDescriptor {
|
||||
public:
|
||||
@ -29,22 +31,6 @@ class FileDescriptor {
|
||||
int fd_;
|
||||
};
|
||||
|
||||
struct UdevDeleter {
|
||||
void operator()(udev *ptr) { udev_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevDeviceDeleter {
|
||||
void operator()(udev_device *ptr) { udev_device_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevEnumerateDeleter {
|
||||
void operator()(udev_enumerate *ptr) { udev_enumerate_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevMonitorDeleter {
|
||||
void operator()(udev_monitor *ptr) { udev_monitor_unref(ptr); }
|
||||
};
|
||||
|
||||
void check_eq(int rc, int expected, const char* message = "eq, rc was: ") {
|
||||
if (rc != expected) {
|
||||
throw std::runtime_error(fmt::format(fmt::runtime(message), rc));
|
||||
@ -201,7 +187,9 @@ BacklightBackend::BacklightBackend(std::chrono::milliseconds interval,
|
||||
const auto& event = events[i];
|
||||
check_eq(event.data.fd, udev_fd, "unexpected udev fd");
|
||||
std::unique_ptr<udev_device, UdevDeviceDeleter> dev{udev_monitor_receive_device(mon.get())};
|
||||
check_nn(dev.get(), "epoll dev was null");
|
||||
if (!dev) {
|
||||
continue;
|
||||
}
|
||||
upsert_device(devices, dev.get());
|
||||
}
|
||||
|
||||
@ -285,7 +273,7 @@ int BacklightBackend::get_scaled_brightness(const std::string &preferred_device)
|
||||
GET_BEST_DEVICE(best, (*this), preferred_device);
|
||||
|
||||
if (best != nullptr) {
|
||||
return best->get_actual() * 100 / best->get_max();
|
||||
return static_cast<int>(std::round(best->get_actual() * 100.0F / best->get_max()));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
[wrap-file]
|
||||
directory = cava-0.10.4
|
||||
source_url = https://github.com/LukashonakV/cava/archive/0.10.4.tar.gz
|
||||
source_filename = cava-0.10.4.tar.gz
|
||||
source_hash =7bc1c1f9535f2bcc5cd2ae8a2434a2e3a05f5670b1c96316df304137ffc65756
|
||||
[provide]
|
||||
cava = cava_dep
|
||||
@ -1,13 +1,13 @@
|
||||
[wrap-file]
|
||||
directory = fmt-11.0.2
|
||||
source_url = https://github.com/fmtlib/fmt/archive/11.0.2.tar.gz
|
||||
source_filename = fmt-11.0.2.tar.gz
|
||||
source_hash = 6cb1e6d37bdcb756dbbe59be438790db409cdb4868c66e888d5df9f13f7c027f
|
||||
patch_filename = fmt_11.0.2-1_patch.zip
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_11.0.2-1/get_patch
|
||||
patch_hash = 90c9e3b8e8f29713d40ca949f6f93ad115d78d7fb921064112bc6179e6427c5e
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_11.0.2-1/fmt-11.0.2.tar.gz
|
||||
wrapdb_version = 11.0.2-1
|
||||
directory = fmt-12.0.0
|
||||
source_url = https://github.com/fmtlib/fmt/archive/12.0.0.tar.gz
|
||||
source_filename = fmt-12.0.0.tar.gz
|
||||
source_hash = aa3e8fbb6a0066c03454434add1f1fc23299e85758ceec0d7d2d974431481e40
|
||||
patch_filename = fmt_12.0.0-1_patch.zip
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_12.0.0-1/get_patch
|
||||
patch_hash = 307f288ebf3850abf2f0c50ac1fb07de97df9538d39146d802f3c0d6cada8998
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_12.0.0-1/fmt-12.0.0.tar.gz
|
||||
wrapdb_version = 12.0.0-1
|
||||
|
||||
[provide]
|
||||
fmt = fmt_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