Merge branch 'master' into cpu-loadavg

This commit is contained in:
Alexis Rouillard
2026-07-03 22:11:02 +02:00
committed by GitHub
276 changed files with 10748 additions and 4644 deletions
+4 -8
View File
@@ -10,13 +10,9 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# TODO: bump to clang 19 release
# - uses: DoozyX/clang-format-lint-action@v0.18.2
- uses: DoozyX/clang-format-lint-action@558090054b3f39e3d6af24f0cd73b319535da809
- uses: actions/checkout@v6
- uses: RafikFarhad/clang-format-github-action@v6
name: clang-format
with:
source: "."
extensions: "hpp,h,cpp,c"
style: "file:.clang-format"
clangFormatVersion: 19
sources: "src/**/*.hpp,src/**/*.cpp"
style: "file"
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
container:
image: alexays/waybar:debian
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: configure
run: |
meson -Dcpp_std=c++20 build # necessary to generate compile_commands.json
+5 -4
View File
@@ -1,14 +1,15 @@
name: Build and Push Docker Image
on:
workflow_dispatch:
schedule:
# run every night at midnight
- cron: '0 0 * * *'
# run monthly
- cron: '0 0 1 * *'
jobs:
build-and-push:
runs-on: ubuntu-latest
if: github.repository == 'Alexays/Waybar'
if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
strategy:
fail-fast: false # don't fail the other jobs if one of the images fails to build
matrix:
@@ -16,7 +17,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Login to Docker Hub
uses: docker/login-action@v3
+3 -3
View File
@@ -12,16 +12,16 @@ jobs:
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: Test in FreeBSD VM
uses: cross-platform-actions/action@v0.25.0
uses: cross-platform-actions/action@v0.28.0
timeout-minutes: 180
env:
CPPFLAGS: '-isystem/usr/local/include'
LDFLAGS: '-L/usr/local/lib'
with:
operating_system: freebsd
version: "14.1"
version: "14.2"
environment_variables: CPPFLAGS LDFLAGS
sync_files: runner-to-vm
run: |
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
image: alexays/waybar:${{ matrix.distro }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: configure
run: meson setup -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build
- name: build
+5 -2
View File
@@ -2,12 +2,15 @@ name: "Nix-Tests"
on:
pull_request:
push:
concurrency:
group: ${{ github.workflow }}-nix-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
nix-flake-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v27
- uses: actions/checkout@v6
- uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
experimental-features = nix-command flakes
+3 -3
View File
@@ -12,11 +12,11 @@ jobs:
if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Install Nix
uses: cachix/install-nix-action@v27
uses: cachix/install-nix-action@v31
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@v21
uses: DeterminateSystems/update-flake-lock@v28
+3
View File
@@ -7,6 +7,7 @@ vgcore.*
*.swp
packagecache
/subprojects/**/
/subprojects/.wraplock
/build*
/dist
/meson.egg-info
@@ -50,3 +51,5 @@ result
result-*
.ccls-cache
_codeql_detected_source_root
heaptrack*
+1 -1
View File
@@ -1,6 +1,6 @@
# vim: ft=Dockerfile
FROM debian:sid
FROM debian:sid-slim
RUN apt update && \
apt install --no-install-recommends --no-install-suggests -y \
+1 -1
View File
@@ -6,6 +6,6 @@ RUN export FEATURES="-ipc-sandbox -network-sandbox -pid-sandbox -sandbox -usersa
emerge --sync && \
eselect news read --quiet new 1>/dev/null 2>&1 && \
emerge --verbose --update --deep --with-bdeps=y --backtrack=30 --newuse @world && \
USE="wayland gtk3 gtk -doc X pulseaudio minimal" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols =dev-cpp/gtkmm-3.24.6 x11-libs/libxkbcommon \
USE="wayland gtk3 gtk -doc X pulseaudio minimal" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols dev-cpp/gtkmm:3.0 x11-libs/libxkbcommon \
x11-libs/gtk+:3 dev-libs/libdbusmenu dev-libs/libnl sys-power/upower media-libs/libpulse dev-libs/libevdev media-libs/libmpdclient \
media-sound/sndio gui-libs/gtk-layer-shell app-text/scdoc media-sound/playerctl dev-libs/iniparser sci-libs/fftw
+5 -1
View File
@@ -20,8 +20,12 @@ debug-run: build-debug
./build/waybar --log-level debug
test:
meson test -C build --no-rebuild --verbose --suite waybar
meson test -C build --verbose --suite waybar
.PHONY: test
test-detailed:
meson test -C build --verbose --print-errorlogs --test-args='--reporter console -s'
.PHONY: test-detailed
clean:
rm -rf build
+34
View File
@@ -116,11 +116,45 @@ sudo apt install \
libxkbregistry-dev
```
On Arch, you can use this command:
```
pacman -S --asdeps \
gtkmm3 \
jsoncpp \
libsigc++ \
fmt \
wayland \
chrono-date \
spdlog \
gtk3 \
gobject-introspection \
libgirepository \
libpulse \
libnl \
libappindicator-gtk3 \
libdbusmenu-gtk3 \
libmpdclient \
sndio \
libevdev \
libxkbcommon \
upower \
meson \
cmake \
scdoc \
wayland-protocols \
glib2-devel
```
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
View File
@@ -0,0 +1 @@
.
+5
View File
@@ -0,0 +1,5 @@
# Suppress common address sanitizer issues in dependencies, these are often non-fixable or not an issue.
# Use it like this (when in repo root): ASAN_OPTIONS="suppressions=./asan.supp" ./build/waybar
leak:libpangoft2-1.0.so.0
leak:libgtk-3.so.0
leak:libfontconfig.so.1
Generated
+6 -6
View File
@@ -3,11 +3,11 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
@@ -18,11 +18,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1745391562,
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
"lastModified": 1769461804,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"type": "github"
},
"original": {
+4 -6
View File
@@ -65,7 +65,7 @@
nativeBuildInputs =
pkgs.waybar.nativeBuildInputs
++ (with pkgs; [
nixfmt-rfc-style
nixfmt
clang-tools
gdb
]);
@@ -75,8 +75,7 @@
formatter = genSystems (
pkgs:
pkgs.treefmt.withConfig {
settings = [
{
settings = {
formatter = {
clang-format = {
options = [ "-i" ];
@@ -90,13 +89,12 @@
];
};
nixfmt = {
command = lib.getExe pkgs.nixfmt-rfc-style;
command = lib.getExe pkgs.nixfmt;
includes = [ "*.nix" ];
};
};
tree-root-file = ".git/index";
}
];
};
}
);
+10 -1
View File
@@ -4,6 +4,8 @@
#include <gtkmm/label.h>
#include <json/json.h>
#include <optional>
#include "AModule.hpp"
namespace waybar {
@@ -21,16 +23,23 @@ class ALabel : public AModule {
protected:
Gtk::Label label_;
std::string format_;
const std::chrono::seconds interval_;
const std::chrono::milliseconds interval_;
bool alt_ = false;
std::string default_format_;
bool setLabelMarkup(const Glib::ustring& markup);
bool setTooltipMarkup(const Glib::ustring& markup);
bool handleToggle(GdkEventButton* const& e) override;
virtual std::string getState(uint8_t value, bool lesser = false);
std::map<std::string, GtkMenuItem*> submenus_;
std::map<std::string, std::string> menuActionsMap_;
static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
private:
std::optional<Glib::ustring> last_label_markup_;
std::optional<Glib::ustring> last_tooltip_markup_;
};
} // namespace waybar
+9 -2
View File
@@ -25,6 +25,10 @@ class AModule : public IModule {
bool expandEnabled() const;
virtual void suspend() {};
virtual void resume() {};
bool shouldSuspend() const { return disable_on_sleep_; }
protected:
// Don't need to make an object directly
// Derived classes are able to use it
@@ -36,6 +40,7 @@ class AModule : public IModule {
SCROLL_DIR getScrollDir(GdkEventScroll* e);
bool tooltipEnabled() const;
std::vector<int> pid_children_;
const std::string name_;
const Json::Value& config_;
Gtk::EventBox event_box_;
@@ -47,16 +52,18 @@ class AModule : public IModule {
virtual bool handleMouseLeave(GdkEventCrossing* const& ev);
virtual bool handleScroll(GdkEventScroll*);
virtual bool handleRelease(GdkEventButton* const& ev);
GObject *menu_;
bool disable_on_sleep_{false};
GObject* menu_ = nullptr;
private:
bool handleUserEvent(GdkEventButton* const& ev);
const bool isTooltip;
const bool isExpand;
bool hasUserEvents_;
std::vector<int> pid_;
gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_;
sigc::connection cursor_timeout_conn_;
std::map<std::string, std::string> eventActionMap_;
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
+11
View File
@@ -14,6 +14,7 @@
#include "AModule.hpp"
#include "group.hpp"
#include "util/kill_signal.hpp"
#include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar {
@@ -68,7 +69,13 @@ class Bar : public sigc::trackable {
void setMode(const std::string& mode);
void setVisible(bool value);
void toggle();
void show();
void hide();
void handleSignal(int);
util::KillSignalAction getOnSigusr1Action();
util::KillSignalAction getOnSigusr2Action();
void toggleSuspend(bool suspend);
struct waybar_output* output;
Json::Value config;
@@ -94,6 +101,7 @@ class Bar : public sigc::trackable {
void setMode(const bar_mode&);
void setPassThrough(bool passthrough);
void setPosition(Gtk::PositionType position);
void forceLayerCommit();
void onConfigure(GdkEventConfigure* ev);
void configureGlobalOffset(int width, int height);
void onOutputGeometryChanged();
@@ -118,6 +126,9 @@ class Bar : public sigc::trackable {
std::unique_ptr<BarIpcClient> _ipc_client;
#endif
std::vector<std::shared_ptr<waybar::AModule>> modules_all_;
waybar::util::KillSignalAction onSigusr1 = util::SIGNALACTION_DEFAULT_SIGUSR1;
waybar::util::KillSignalAction onSigusr2 = util::SIGNALACTION_DEFAULT_SIGUSR2;
};
} // namespace waybar
+5
View File
@@ -44,6 +44,7 @@ class Client {
const char* interface, uint32_t version);
static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
static void handleOutputDone(void*, struct zxdg_output_v1*);
void createBarsBatch();
static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
static void handleOutputDescription(void*, struct zxdg_output_v1*, const char*);
void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor);
@@ -56,6 +57,10 @@ class Client {
std::list<struct waybar_output> outputs_;
std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
std::string m_cssFile;
sigc::connection monitor_added_connection_;
sigc::connection monitor_removed_connection_;
std::list<waybar_output*> pending_outputs_;
bool bars_scheduled_ = false;
};
} // namespace waybar
+2
View File
@@ -35,6 +35,8 @@ class Config {
void setupConfig(Json::Value& dst, const std::string& config_file, int depth);
void resolveConfigIncludes(Json::Value& config, int depth);
void mergeConfig(Json::Value& a_config_, Json::Value& b_config_);
static std::vector<std::string> findIncludePath(
const std::string& name, const std::vector<std::string>& dirs = CONFIG_DIRS);
std::string config_file_;
+1
View File
@@ -30,6 +30,7 @@ class Group : public AModule {
bool handleMouseEnter(GdkEventCrossing* const& ev) override;
bool handleMouseLeave(GdkEventCrossing* const& ev) override;
bool handleToggle(GdkEventButton* const& ev) override;
bool handleScroll(GdkEventScroll* e) override;
void show_group();
void hide_group();
};
+8 -2
View File
@@ -6,6 +6,7 @@
#if defined(__linux__)
#include <sys/inotify.h>
#endif
#include <poll.h>
#include <algorithm>
#include <fstream>
@@ -15,6 +16,7 @@
#include "ALabel.hpp"
#include "bar.hpp"
#include "util/sleeper_thread.hpp"
#include "util/udev_deleter.hpp"
namespace waybar::modules {
@@ -35,15 +37,19 @@ class Battery : public ALabel {
std::tuple<uint8_t, float, std::string, float, uint16_t, float> getInfos();
const std::string formatTimeRemaining(float hoursRemaining);
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_;
-59
View File
@@ -1,59 +0,0 @@
#pragma once
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace cava {
extern "C" {
// Need sdl_glsl output feature to be enabled on libcava
#ifndef SDL_GLSL
#define SDL_GLSL
#endif
#include <cava/common.h>
#ifdef SDL_GLSL
#undef SDL_GLSL
#endif
}
} // namespace cava
namespace waybar::modules {
using namespace std::literals::chrono_literals;
class Cava final : public ALabel {
public:
Cava(const std::string&, const Json::Value&);
virtual ~Cava();
auto update() -> void override;
auto doAction(const std::string& name) -> void override;
private:
util::SleeperThread thread_;
util::SleeperThread thread_fetch_input_;
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{}};
// Cava API to read audio source
cava::ptr input_source_;
// Delay to handle audio source
std::chrono::milliseconds frame_time_milsec_{1s};
// Text to display
std::string text_{""};
int rePaint_{1};
std::chrono::seconds fetch_input_delay_{4};
std::chrono::seconds suspend_silence_delay_{0};
bool silence_{false};
bool hide_on_silence_{false};
std::string format_silent_{""};
int sleep_counter_{0};
// Cava method
void pause_resume();
// ModuleActionMap
static inline std::map<const std::string, void (waybar::modules::Cava::* const)()> actionMap_{
{"mode", &waybar::modules::Cava::pause_resume}};
};
} // namespace waybar::modules
+43
View 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
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "ALabel.hpp"
#include "cava_backend.hpp"
namespace waybar::modules::cava {
class Cava final : public ALabel, public sigc::trackable {
public:
Cava(const std::string&, const Json::Value&);
~Cava() = default;
auto doAction(const std::string& name) -> void override;
private:
std::shared_ptr<CavaBackend> backend_;
// Text to display
Glib::ustring label_text_{""};
bool silence_{false};
bool hide_on_silence_{false};
std::string format_silent_{""};
int ascii_range_{0};
// 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}};
};
} // namespace waybar::modules::cava
+84
View File
@@ -0,0 +1,84 @@
#pragma once
#include <json/json.h>
#include <sigc++/sigc++.h>
#include "util/sleeper_thread.hpp"
namespace cava {
extern "C" {
// Need sdl_glsl output feature to be enabled on libcava
#ifndef SDL_GLSL
#define SDL_GLSL
#endif
#include <cava/common.h>
#ifdef SDL_GLSL
#undef SDL_GLSL
#endif
}
} // namespace cava
namespace waybar::modules::cava {
using namespace std::literals::chrono_literals;
class CavaBackend final {
public:
static std::shared_ptr<CavaBackend> inst(const Json::Value& config);
virtual ~CavaBackend();
// Methods
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 read_thread_;
util::SleeperThread out_thread_;
// Cava API to read audio 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_{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};
std::chrono::seconds suspend_silence_delay_{0};
int sleep_counter_{0};
std::string output_{};
// Methods
void invoke();
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
View 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
+13 -11
View File
@@ -42,35 +42,37 @@ class Clock final : public ALabel {
int cldWnLen_{3}; // calendar week number length
const int cldMonColLen_{20}; // calendar month column length
WS cldWPos_{WS::HIDDEN}; // calendar week side to print
months cldCurrShift_{0}; // calendar months shift
date::months cldCurrShift_{0}; // calendar months shift
int cldShift_{1}; // calendar months shift factor
year_month_day cldYearShift_; // calendar Year mode. Cached ymd
date::year_month_day cldYearShift_; // calendar Year mode. Cached ymd
std::string cldYearCached_; // calendar Year mode. Cached calendar
year_month cldMonShift_; // calendar Month mode. Cached ym
date::year_month cldMonShift_; // calendar Month mode. Cached ym
std::string cldMonCached_; // calendar Month mode. Cached calendar
day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
date::day cldBaseDay_{0}; // calendar Cached day. Is used when today is changing(midnight)
std::string cldText_{""}; // calendar text to print
bool iso8601Calendar_{false}; // whether the calendar is in ISO8601
CldMode cldMode_{CldMode::MONTH};
auto get_calendar(const year_month_day& today, const year_month_day& ymd, const time_zone* tz)
-> const std::string;
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
const date::time_zone* tz) -> const std::string;
// get local time zone
auto local_zone() -> const time_zone*;
auto local_zone() -> const date::time_zone*;
// time zoned time in tooltip
const bool tzInTooltip_; // if need to print time zones text
std::vector<const time_zone*> tzList_; // time zones list
std::vector<const date::time_zone*> tzList_; // time zones list
int tzCurrIdx_; // current time zone index for tzList_
std::string tzText_{""}; // time zones text to print
std::string tzTooltipFormat_{""}; // optional timezone tooltip format
util::SleeperThread thread_;
// ordinal date in tooltip
const bool ordInTooltip_;
std::string ordText_{""};
auto get_ordinal_date(const year_month_day& today) -> std::string;
auto get_ordinal_date(const date::year_month_day& today) -> std::string;
auto getTZtext(sys_seconds now) -> std::string;
auto first_day_of_week() -> weekday;
auto getTZtext(date::sys_seconds now) -> std::string;
auto first_day_of_week() -> date::weekday;
// Module actions
void cldModeSwitch();
void cldShift_up();
+1
View File
@@ -35,6 +35,7 @@ class Custom : public ALabel {
std::string id_;
std::string alt_;
std::string tooltip_;
std::string last_tooltip_markup_;
const bool tooltip_format_enabled_;
std::vector<std::string> class_;
int percentage_;
+1 -1
View File
@@ -22,7 +22,7 @@ class Disk : public ALabel {
std::string path_;
std::string unit_;
float calc_specific_divisor(const std::string divisor);
float calc_specific_divisor(const std::string& divisor);
};
} // namespace waybar::modules
+141
View File
@@ -0,0 +1,141 @@
#pragma once
#include <fmt/format.h>
#include <gtkmm/button.h>
#include <gtkmm/image.h>
#include <gtkmm/label.h>
#include <map>
#include <memory>
#include <vector>
#include "AModule.hpp"
#include "bar.hpp"
#include "ext-workspace-v1-client-protocol.h"
namespace waybar::modules::ext {
class WorkspaceGroup;
class Workspace;
class WorkspaceManager final : public AModule {
public:
WorkspaceManager(const std::string& id, const waybar::Bar& bar, const Json::Value& config);
~WorkspaceManager() override;
void register_manager(wl_registry* registry, uint32_t name, uint32_t version);
void remove_workspace_group(uint32_t id);
void remove_workspace(uint32_t id);
void set_needs_sorting() { needs_sorting_ = true; }
// wl events
void handle_workspace_group(ext_workspace_group_handle_v1* handle);
void handle_workspace(ext_workspace_handle_v1* handle);
void handle_done();
void handle_finished();
// wl requests
void commit() const;
private:
void update() override;
bool has_button(const Gtk::Button* button);
void sort_workspaces();
void clear_buttons();
void update_buttons();
static uint32_t group_global_id;
static uint32_t workspace_global_id;
uint32_t workspace_name = 0;
bool sort_by_id_ = false;
bool sort_by_name_ = true;
bool sort_by_coordinates_ = false;
bool all_outputs_ = false;
const waybar::Bar& bar_;
Gtk::Box box_;
ext_workspace_manager_v1* ext_manager_ = nullptr;
std::vector<std::unique_ptr<WorkspaceGroup>> groups_;
std::vector<std::unique_ptr<Workspace>> workspaces_;
bool needs_sorting_ = false;
};
class WorkspaceGroup {
public:
WorkspaceGroup(WorkspaceManager& manager, ext_workspace_group_handle_v1* handle, uint32_t id);
~WorkspaceGroup();
u_int32_t id() const { return id_; }
bool has_output(const wl_output* output);
bool has_workspace(const ext_workspace_handle_v1* workspace);
// wl events
void handle_capabilities(uint32_t capabilities);
void handle_output_enter(wl_output* output);
void handle_output_leave(wl_output* output);
void handle_workspace_enter(ext_workspace_handle_v1* handle);
void handle_workspace_leave(ext_workspace_handle_v1* handle);
void handle_removed();
private:
WorkspaceManager& workspaces_manager_;
ext_workspace_group_handle_v1* ext_handle_;
uint32_t id_;
std::vector<wl_output*> outputs_;
std::vector<ext_workspace_handle_v1*> workspaces_;
};
class Workspace {
public:
Workspace(const Json::Value& config, WorkspaceManager& manager, ext_workspace_handle_v1* handle,
uint32_t id, const std::string& name);
~Workspace();
ext_workspace_handle_v1* handle() const { return ext_handle_; }
u_int32_t id() const { return id_; }
std::string& workspace_id() { return workspace_id_; }
std::string& name() { return name_; }
std::vector<u_int32_t>& coordinates() { return coordinates_; }
Gtk::Button& button() { return button_; }
void update();
// wl events
void handle_id(const std::string& id);
void handle_name(const std::string& name);
void handle_coordinates(const std::vector<uint32_t>& coordinates);
void handle_state(uint32_t state);
void handle_capabilities(uint32_t capabilities);
void handle_removed();
// gdk events
bool handle_clicked(const GdkEventButton* button) const;
private:
bool has_state(uint32_t state) const { return (state_ & state) == state; }
std::string icon();
WorkspaceManager& workspace_manager_;
ext_workspace_handle_v1* ext_handle_ = nullptr;
uint32_t id_;
uint32_t state_ = 0;
std::string workspace_id_;
std::string name_;
std::vector<uint32_t> coordinates_;
bool active_only_ = false;
bool ignore_hidden_ = true;
std::string format_;
bool with_icon_ = false;
static std::map<std::string, std::string> icon_map_;
std::string on_click_action_;
std::string on_click_middle_action_;
std::string on_click_right_action_;
Gtk::Button button_;
Gtk::Box content_;
Gtk::Label label_;
};
} // namespace waybar::modules::ext
@@ -0,0 +1,10 @@
#include "ext-workspace-v1-client-protocol.h"
namespace waybar::modules::ext {
void add_registry_listener(void* data);
void add_workspace_listener(ext_workspace_handle_v1* workspace_handle, void* data);
void add_workspace_group_listener(ext_workspace_group_handle_v1* workspace_group_handle,
void* data);
ext_workspace_manager_v1* workspace_manager_bind(wl_registry* registry, uint32_t name,
uint32_t version, void* data);
} // namespace waybar::modules::ext
+1 -1
View File
@@ -26,7 +26,7 @@ class Gamemode : public AModule {
const std::string DEFAULT_FORMAT = "{glyph}";
const std::string DEFAULT_FORMAT_ALT = "{glyph} {count}";
const std::string DEFAULT_TOOLTIP_FORMAT = "Games running: {count}";
const std::string DEFAULT_GLYPH = "";
const std::string DEFAULT_GLYPH = "󰊴";
void appear(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& name,
const Glib::ustring& name_owner);
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <fmt/format.h>
#include <sys/statvfs.h>
#ifdef WANT_RFKILL
#include "util/rfkill.hpp"
#endif
#include <gps.h>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class Gps : public ALabel {
public:
Gps(const std::string&, const Json::Value&);
virtual ~Gps();
auto update() -> void override;
private:
#ifdef WANT_RFKILL
util::Rfkill rfkill_;
#endif
const std::string getFixModeName() const;
const std::string getFixModeString() const;
const std::string getFixStatusString() const;
util::SleeperThread thread_, gps_thread_;
gps_data_t gps_data_;
std::string state_;
bool hideDisconnected = true;
bool hideNoFix = false;
};
} // namespace waybar::modules
+24 -5
View File
@@ -1,8 +1,10 @@
#pragma once
#include <atomic>
#include <filesystem>
#include <list>
#include <mutex>
#include <optional>
#include <string>
#include <thread>
#include <utility>
@@ -17,9 +19,13 @@ class EventHandler {
virtual ~EventHandler() = default;
};
/// If you want to use the Hyprland IPC, simply use IPC::inst() to get the singleton instance.
/// Do not create multiple instances.
class IPC {
protected:
IPC(); // use IPC::inst() instead.
public:
IPC();
~IPC();
static IPC& inst();
@@ -30,20 +36,33 @@ class IPC {
Json::Value getSocket1JsonReply(const std::string& rq);
static std::filesystem::path getSocketFolder(const char* instanceSig);
/// Dispatch a Hyprland command. Automatically uses the correct protocol
/// (legacy text or Lua-based) depending on the running Hyprland version.
static std::string dispatch(const std::string& dispatcher, const std::string& arg);
/// Build a Lua-format dispatch command string.
static std::string buildLuaDispatch(const std::string& dispatcher, const std::string& arg);
protected:
static std::filesystem::path socketFolder_;
/// Detect whether the running Hyprland uses the Lua-based IPC protocol.
/// Returns true for Hyprland >= 0.54 (Lua config), false for older versions.
static bool isLuaProtocol();
static std::optional<bool> s_luaProtocolDetected_; // cached detection result
private:
void socketListener();
void parseIPC(const std::string&);
std::thread ipcThread_;
std::mutex callbackMutex_;
std::mutex socketMutex_;
util::JsonParser parser_;
std::list<std::pair<std::string, EventHandler*>> callbacks_;
int socketfd_; // the hyprland socket file descriptor
bool running_ = true;
int socketfd_ = -1; // the hyprland socket file descriptor
pid_t socketOwnerPid_ = -1;
std::atomic<bool> running_ = true; // the ipcThread will stop running when this is false
};
inline bool modulesReady = false;
}; // namespace waybar::modules::hyprland
+1
View File
@@ -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";
+11 -11
View File
@@ -20,8 +20,8 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
private:
struct Workspace {
int id;
int windows;
int id = 0;
int windows = 0;
std::string last_window;
std::string last_window_title;
@@ -29,14 +29,14 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
};
struct WindowData {
bool floating;
bool floating = false;
int monitor = -1;
std::string class_name;
std::string initial_class_name;
std::string title;
std::string initial_title;
bool fullscreen;
bool grouped;
bool fullscreen = false;
bool grouped = false;
static auto parse(const Json::Value&) -> WindowData;
};
@@ -47,7 +47,7 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
void queryActiveWorkspace();
void setClass(const std::string&, bool enable);
bool separateOutputs_;
bool separateOutputs_ = false;
std::mutex mutex_;
const Bar& bar_;
util::JsonParser parser_;
@@ -55,11 +55,11 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
Workspace workspace_;
std::string soloClass_;
std::string lastSoloClass_;
bool solo_;
bool allFloating_;
bool swallowing_;
bool fullscreen_;
bool focused_;
bool solo_ = false;
bool allFloating_ = false;
bool swallowing_ = false;
bool fullscreen_ = false;
bool focused_ = false;
IPC& m_ipc;
};
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include <fmt/format.h>
#include <string>
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "modules/hyprland/backend.hpp"
namespace waybar::modules::hyprland {
class WindowCount : public waybar::AAppIconLabel, public EventHandler {
public:
WindowCount(const std::string&, const waybar::Bar&, const Json::Value&);
~WindowCount() override;
auto update() -> void override;
private:
struct Workspace {
int id;
int windows;
bool hasfullscreen;
static auto parse(const Json::Value& value) -> Workspace;
};
auto getActiveWorkspace(const std::string&) -> Workspace;
auto getActiveWorkspace() -> Workspace;
void onEvent(const std::string& ev) override;
void queryActiveWorkspace();
void setClass(const std::string&, bool enable);
bool separateOutputs_;
std::mutex mutex_;
const Bar& bar_;
Workspace workspace_;
IPC& m_ipc;
};
} // namespace waybar::modules::hyprland
@@ -26,34 +26,49 @@ namespace waybar::modules::hyprland {
class Workspaces;
struct WindowRepr {
std::string address;
std::string window_class;
std::string window_title;
std::string repr_rewrite;
bool isActive = false;
public:
bool empty() const { return address.empty(); }
void setActive(bool value) { isActive = value; }
};
class WindowCreationPayload {
public:
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
std::string window_repr);
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
std::string window_class, std::string window_title);
WindowCreationPayload(const std::string& workspace_name, WindowAddress window_address,
WindowRepr window_repr);
WindowCreationPayload(const std::string& workspace_name, WindowAddress window_address,
const std::string& window_class, const std::string& window_title,
bool is_active);
WindowCreationPayload(Json::Value const& client_data);
int incrementTimeSpentUncreated();
bool isEmpty(Workspaces& workspace_manager);
bool reprIsReady() const { return std::holds_alternative<Repr>(m_window); }
std::string repr(Workspaces& workspace_manager);
WindowRepr repr(Workspaces& workspace_manager);
void setActive(bool value) { m_isActive = value; }
std::string getWorkspaceName() const { return m_workspaceName; }
WindowAddress getAddress() const { return m_windowAddress; }
void moveToWorksace(std::string& new_workspace_name);
void moveToWorkspace(std::string& new_workspace_name);
private:
void clearAddr();
void clearWorkspaceName();
using Repr = std::string;
using Repr = WindowRepr;
using ClassAndTitle = std::pair<std::string, std::string>;
std::variant<Repr, ClassAndTitle> m_window;
WindowAddress m_windowAddress;
std::string m_workspaceName;
bool m_isActive = false;
int m_timeSpentUncreated = 0;
};
+29 -9
View File
@@ -30,6 +30,7 @@ class Workspace {
public:
explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
const Json::Value& clients_data = Json::Value::nullRef);
~Workspace();
std::string& selectIcon(std::map<std::string, std::string>& icons_map);
Gtk::Button& button() { return m_button; };
@@ -42,10 +43,18 @@ class Workspace {
bool isPersistentConfig() const { return m_isPersistentConfig; };
bool isPersistentRule() const { return m_isPersistentRule; };
bool isVisible() const { return m_isVisible; };
bool isEmpty() const { return m_windows == 0; };
bool isUrgent() const { return m_isUrgent; };
bool handleClicked(GdkEventButton* bt) const;
bool handleEnter(GdkEventCrossing* event);
bool handleLeave(GdkEventCrossing* event);
void startHoverCheck();
void stopHoverCheck();
bool syncHoverClass();
bool pointerInsideButton();
void setActive(bool value = true) { m_isActive = value; };
void setPersistentRule(bool value = true) { m_isPersistentRule = value; };
void setPersistentConfig(bool value = true) { m_isPersistentConfig = value; };
@@ -54,15 +63,18 @@ class Workspace {
void setWindows(uint value) { m_windows = value; };
void setName(std::string const& value) { m_name = value; };
void setOutput(std::string const& value) { m_output = value; };
bool containsWindow(WindowAddress const& addr) const { return m_windowMap.contains(addr); }
void insertWindow(WindowCreationPayload create_window_paylod);
std::string removeWindow(WindowAddress const& addr);
bool containsWindow(WindowAddress const& addr) const {
return std::ranges::any_of(m_windowMap,
[&addr](const auto& window) { return window.address == addr; });
};
void insertWindow(WindowCreationPayload create_window_payload);
void initializeWindowMap(const Json::Value& clients_data);
void setActiveWindow(WindowAddress const& addr);
bool onWindowOpened(WindowCreationPayload const& create_window_paylod);
std::optional<std::string> closeWindow(WindowAddress const& addr);
bool onWindowOpened(WindowCreationPayload const& create_window_payload);
std::optional<WindowRepr> closeWindow(WindowAddress const& addr);
void update(const std::string& format, const std::string& icon);
void update(const std::string& workspace_icon);
private:
Workspaces& m_workspaceManager;
@@ -78,11 +90,19 @@ class Workspace {
bool m_isUrgent = false;
bool m_isVisible = false;
std::map<WindowAddress, std::string> m_windowMap;
sigc::connection m_hoverCheckConnection;
std::vector<WindowRepr> m_windowMap;
Gtk::Button m_button;
Gtk::Box m_content;
Gtk::Label m_label;
Gtk::Label m_labelBefore;
Gtk::Label m_labelAfter;
bool isEmpty() const;
void updateTaskbar(const std::string& workspace_icon);
bool handleClick(const GdkEventButton* event_button, WindowAddress const& addr) const;
bool shouldSkipWindow(const WindowRepr& window_repr) const;
IPC& m_ipc;
};
+56 -5
View File
@@ -1,8 +1,10 @@
#pragma once
#include <gtkmm/button.h>
#include <gtkmm/enums.h>
#include <gtkmm/label.h>
#include <json/value.h>
#include <sigc++/connection.h>
#include <cstdint>
#include <map>
@@ -18,6 +20,7 @@
#include "modules/hyprland/windowcreationpayload.hpp"
#include "modules/hyprland/workspace.hpp"
#include "util/enum.hpp"
#include "util/icon_loader.hpp"
#include "util/regex_collection.hpp"
using WindowAddress = std::string;
@@ -37,19 +40,37 @@ class Workspaces : public AModule, public EventHandler {
auto showSpecial() const -> bool { return m_showSpecial; }
auto activeOnly() const -> bool { return m_activeOnly; }
auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; }
auto persistentOnly() const -> bool { return m_persistentOnly; }
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
auto barScroll() const -> bool { return m_barScroll; }
auto getBarOutput() const -> std::string { return m_bar.output->name; }
auto formatBefore() const -> std::string { return m_formatBefore; }
auto formatAfter() const -> std::string { return m_formatAfter; }
auto taskbarFormatBefore() const -> std::string { return m_taskbarFormatBefore; }
auto taskbarFormatAfter() const -> std::string { return m_taskbarFormatAfter; }
auto taskbarIconSize() const -> int { return m_taskbarIconSize; }
auto taskbarOrientation() const -> Gtk::Orientation { return m_taskbarOrientation; }
auto taskbarReverseDirection() const -> bool { return m_taskbarReverseDirection; }
auto onClickWindow() const -> std::string { return m_onClickWindow; }
auto getIgnoredWindows() const -> std::vector<std::regex> { return m_ignoreWindows; }
std::string getRewrite(std::string window_class, std::string window_title);
enum class ActiveWindowPosition { NONE, FIRST, LAST };
auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; }
std::string getRewrite(const std::string& window_class, const std::string& window_title);
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
bool isWorkspaceIgnored(std::string const& workspace_name);
bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; }
const IconLoader& iconLoader() const { return m_iconLoader; }
private:
void onEvent(const std::string& e) override;
void updateWindowCount();
void sortSpecialCentered();
void sortWorkspaces();
void createWorkspace(Json::Value const& workspace_data,
Json::Value const& clients_data = Json::Value::nullRef);
@@ -68,6 +89,7 @@ class Workspaces : public AModule, public EventHandler {
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
auto populateFormatWindowSeparatorConfig(const Json::Value& config) -> void;
auto populateWindowRewriteConfig(const Json::Value& config) -> void;
auto populateWorkspaceTaskbarConfig(const Json::Value& config) -> void;
void registerIpc();
@@ -90,6 +112,7 @@ class Workspaces : public AModule, public EventHandler {
void onWindowMoved(std::string const& payload);
void onWindowTitleEvent(std::string const& payload);
void onActiveWindowChanged(WindowAddress const& payload);
void onConfigReloaded();
@@ -101,6 +124,8 @@ class Workspaces : public AModule, public EventHandler {
static std::pair<std::string, std::string> splitDoublePayload(std::string const& payload);
static std::tuple<std::string, std::string, std::string> splitTriplePayload(
std::string const& payload);
// scroll events
bool handleScroll(GdkEventScroll* e) override;
// Update methods
void doUpdate();
@@ -122,23 +147,27 @@ class Workspaces : public AModule, public EventHandler {
bool m_showSpecial = false;
bool m_activeOnly = false;
bool m_specialVisibleOnly = false;
bool m_persistentOnly = false;
bool m_moveToMonitor = false;
bool m_barScroll = false;
Json::Value m_persistentWorkspaceConfig;
// Map for windows stored in workspaces not present in the current bar.
// This happens when the user has multiple monitors (hence, multiple bars)
// and doesn't share windows accross bars (a.k.a `all-outputs` = false)
std::map<WindowAddress, std::string> m_orphanWindowMap;
// and doesn't share windows across bars (a.k.a `all-outputs` = false)
std::map<WindowAddress, WindowRepr, std::less<>> m_orphanWindowMap;
enum class SortMethod { ID, NAME, NUMBER, DEFAULT };
enum class SortMethod { ID, NAME, NUMBER, SPECIAL_CENTERED, DEFAULT };
util::EnumParser<SortMethod> m_enumParser;
SortMethod m_sortBy = SortMethod::DEFAULT;
std::map<std::string, SortMethod> m_sortMap = {{"ID", SortMethod::ID},
{"NAME", SortMethod::NAME},
{"NUMBER", SortMethod::NUMBER},
{"SPECIAL-CENTERED", SortMethod::SPECIAL_CENTERED},
{"DEFAULT", SortMethod::DEFAULT}};
std::string m_format;
std::string m_formatBefore;
std::string m_formatAfter;
std::map<std::string, std::string> m_iconsMap;
util::RegexCollection m_windowRewriteRules;
@@ -154,11 +183,33 @@ class Workspaces : public AModule, public EventHandler {
std::vector<std::string> m_workspacesToRemove;
std::vector<WindowCreationPayload> m_windowsToCreate;
IconLoader m_iconLoader;
bool m_enableTaskbar = false;
bool m_updateActiveWindow = false;
bool m_taskbarWithIcon = false;
bool m_taskbarWithTitle = false;
std::string m_taskbarFormatBefore;
std::string m_taskbarFormatAfter;
int m_taskbarIconSize = 16;
Gtk::Orientation m_taskbarOrientation = Gtk::ORIENTATION_HORIZONTAL;
bool m_taskbarReverseDirection = false;
util::EnumParser<ActiveWindowPosition> m_activeWindowEnumParser;
ActiveWindowPosition m_activeWindowPosition = ActiveWindowPosition::NONE;
std::map<std::string, ActiveWindowPosition> m_activeWindowPositionMap = {
{"NONE", ActiveWindowPosition::NONE},
{"FIRST", ActiveWindowPosition::FIRST},
{"LAST", ActiveWindowPosition::LAST},
};
std::string m_onClickWindow;
std::string m_currentActiveWindowAddress;
std::vector<std::regex> m_ignoreWorkspaces;
std::vector<std::regex> m_ignoreWindows;
std::mutex m_mutex;
const Bar& m_bar;
Gtk::Box m_box;
sigc::connection m_scrollEventConnection_;
IPC& m_ipc;
};
+1 -1
View File
@@ -31,7 +31,7 @@ class Image : public AModule {
std::string path_;
std::string tooltip_;
int size_;
int interval_;
std::chrono::milliseconds interval_;
util::command::res output_;
util::SleeperThread thread_;
+2
View File
@@ -3,6 +3,7 @@
#include <fmt/chrono.h>
#include <gtkmm/label.h>
#include <mutex>
#include <set>
#include <unordered_map>
@@ -41,6 +42,7 @@ class KeyboardState : public AModule {
struct libinput* libinput_;
std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
std::mutex devices_mutex_; // protects libinput_devices_
std::set<int> binding_keys;
util::SleeperThread libinput_thread_, hotplug_thread_;
+2
View File
@@ -22,6 +22,8 @@ class Memory : public ALabel {
std::unordered_map<std::string, unsigned long> meminfo_;
util::SleeperThread thread_;
std::string unit_;
};
} // namespace waybar::modules
+6 -2
View File
@@ -33,6 +33,7 @@ class MPD : public ALabel {
detail::unique_status status_;
mpd_state state_;
detail::unique_song song_;
std::string ellipsis_;
public:
MPD(const std::string&, const Json::Value&);
@@ -44,7 +45,11 @@ class MPD : public ALabel {
std::string getFilename() const;
void setLabel();
std::string getStateIcon() const;
std::string getOptionIcon(std::string optionName, bool activated) const;
std::string getOptionIcon(const std::string& optionName, bool activated) const;
std::string getArtistStr(bool truncated) const;
std::string getAlbumArtistStr(bool truncated) const;
std::string getAlbumStr(bool truncated) const;
std::string getTitleStr(bool truncated) const;
// GUI-side methods
bool handlePlayPause(GdkEventButton* const&);
@@ -54,7 +59,6 @@ class MPD : public ALabel {
void tryConnect();
void checkErrors(mpd_connection* conn);
void fetchState();
void queryMPD();
inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; }
inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; }
-1
View File
@@ -197,7 +197,6 @@ class Context {
void tryConnect() const;
void checkErrors(mpd_connection*) const;
void do_update();
void queryMPD() const;
void fetchState() const;
constexpr mpd_state state() const;
void emit() const;
+2 -2
View File
@@ -1,13 +1,14 @@
#pragma once
namespace detail {
using namespace std::literals::chrono_literals;
inline bool Context::is_connected() const { return mpd_module_->connection_ != nullptr; }
inline bool Context::is_playing() const { return mpd_module_->playing(); }
inline bool Context::is_paused() const { return mpd_module_->paused(); }
inline bool Context::is_stopped() const { return mpd_module_->stopped(); }
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_.count(); }
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_ / 1s; }
inline void Context::tryConnect() const { mpd_module_->tryConnect(); }
inline unique_connection& Context::connection() { return mpd_module_->connection_; }
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
@@ -15,7 +16,6 @@ constexpr inline mpd_state Context::state() const { return mpd_module_->state_;
inline void Context::do_update() { mpd_module_->setLabel(); }
inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); }
inline void Context::queryMPD() const { mpd_module_->queryMPD(); }
inline void Context::fetchState() const { mpd_module_->fetchState(); }
inline void Context::emit() const { mpd_module_->emit(); }
+1
View File
@@ -78,6 +78,7 @@ class Mpris : public ALabel {
PlayerctlPlayerManager* manager;
PlayerctlPlayer* player;
PlayerctlPlayer* last_active_player_ = nullptr;
std::string lastStatus;
std::string lastPlayer;
+28 -24
View File
@@ -9,6 +9,7 @@
#include <sys/epoll.h>
#include <optional>
#include <vector>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
@@ -27,8 +28,8 @@ class Network : public ALabel {
auto update() -> void override;
private:
static const uint8_t MAX_RETRY = 5;
static const uint8_t EPOLL_MAX = 200;
static const uint8_t MAX_RETRY{5};
static const uint8_t EPOLL_MAX{200};
static int handleEvents(struct nl_msg*, void*);
static int handleEventsDone(struct nl_msg*, void*);
@@ -44,44 +45,47 @@ class Network : public ALabel {
void parseFreq(struct nlattr**);
void parseBssid(struct nlattr**);
bool associatedOrJoined(struct nlattr**);
bool checkInterface(std::string name);
bool matchInterface(const std::string& ifname, const std::vector<std::string>& altnames,
std::string& matched) const;
auto getInfo() -> void;
const std::string getNetworkState() const;
void clearIface();
bool wildcardMatch(const std::string& pattern, const std::string& text) const;
std::optional<std::pair<unsigned long long, unsigned long long>> readBandwidthUsage();
int ifid_;
ip_addr_pref addr_pref_;
struct sockaddr_nl nladdr_ = {0};
struct nl_sock* sock_ = nullptr;
struct nl_sock* ev_sock_ = nullptr;
int efd_;
int ev_fd_;
int nl80211_id_;
int ifid_{-1};
ip_addr_pref addr_pref_{ip_addr_pref::IPV4};
struct sockaddr_nl nladdr_{0};
struct nl_sock* sock_{nullptr};
struct nl_sock* ev_sock_{nullptr};
int efd_{-1};
int ev_fd_{-1};
int nl80211_id_{-1};
std::mutex mutex_;
bool want_route_dump_;
bool want_link_dump_;
bool want_addr_dump_;
bool dump_in_progress_;
bool is_p2p_;
bool want_route_dump_{false};
bool want_link_dump_{false};
bool want_addr_dump_{false};
bool dump_in_progress_{false};
bool is_p2p_{false};
unsigned long long bandwidth_down_total_;
unsigned long long bandwidth_up_total_;
unsigned long long bandwidth_down_total_{0};
unsigned long long bandwidth_up_total_{0};
unsigned long long bandwidth_down_prev_{0};
unsigned long long bandwidth_up_prev_{0};
std::chrono::steady_clock::time_point bandwidth_last_sample_time_;
std::string state_;
std::string essid_;
std::string bssid_;
bool carrier_;
bool carrier_{false};
std::string ifname_;
std::string ipaddr_;
std::string ipaddr6_;
std::string gwaddr_;
std::string netmask_;
std::string netmask6_;
int cidr_;
int cidr6_;
int cidr_{0};
int cidr6_{0};
int32_t signal_strength_dbm_;
uint8_t signal_strength_;
std::string signal_strength_app_;
@@ -90,9 +94,9 @@ class Network : public ALabel {
util::SleeperThread thread_;
util::SleeperThread thread_timer_;
#ifdef WANT_RFKILL
util::Rfkill rfkill_;
util::Rfkill rfkill_{RFKILL_TYPE_WLAN};
#endif
float frequency_;
float frequency_{0};
};
} // namespace waybar::modules
+1 -1
View File
@@ -17,7 +17,7 @@ class EventHandler {
class IPC {
public:
IPC() { startIPC(); }
IPC();
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
void unregisterForIPC(EventHandler* handler);
+1
View File
@@ -33,6 +33,7 @@ class Language : public ALabel, public EventHandler {
std::vector<Layout> layouts_;
unsigned current_idx_;
std::string last_short_name_;
};
} // namespace waybar::modules::niri
+3
View File
@@ -28,9 +28,12 @@ class Privacy : public AModule {
// Config
Gtk::Box box_;
std::vector<PrivacyItem*> modules_;
uint iconSpacing = 4;
uint iconSize = 20;
uint transition_duration = 250;
std::set<std::pair<PrivacyNodeType, std::string>> ignore;
bool ignore_monitor = true;
std::shared_ptr<util::PipewireBackend::PipewireBackend> backend = nullptr;
};
+9 -6
View File
@@ -6,11 +6,6 @@
#include "util/audio_backend.hpp"
namespace waybar::modules {
enum class PulseaudioSliderTarget {
Sink,
Source,
};
class PulseaudioSlider : public ASlider {
public:
PulseaudioSlider(const std::string&, const Json::Value&);
@@ -21,7 +16,15 @@ class PulseaudioSlider : public ASlider {
private:
std::shared_ptr<util::AudioBackend> backend = nullptr;
PulseaudioSliderTarget target = PulseaudioSliderTarget::Sink;
util::PulseaudioTarget target = util::PulseaudioTarget::Sink;
bool zero_on_mute = true;
bool unmute_on_volume_change = true;
// zero_on_mute and unmute_on_volume_change default to true
// in order to maintain previous behaviour when using a
// config in which these values are undefined
bool previously_muted = false;
};
} // namespace waybar::modules
+1
View File
@@ -24,6 +24,7 @@ class Layout : public waybar::ALabel {
private:
const waybar::Bar& bar_;
std::string name_;
struct wl_output* output_; // stores the output this module belongs to
struct wl_output* focused_output_; // stores the currently focused output
struct zriver_output_status_v1* output_status_;
+1
View File
@@ -21,6 +21,7 @@ class Tags : public waybar::AModule {
void handle_view_tags(struct wl_array* tags);
void handle_urgent_tags(uint32_t tags);
void handle_show();
void handle_primary_clicked(uint32_t tag);
bool handle_button_press(GdkEventButton* event_button, uint32_t tag);
+9 -2
View File
@@ -16,7 +16,7 @@ class Host {
public:
Host(const std::size_t id, const Json::Value&, const Bar&,
const std::function<void(std::unique_ptr<Item>&)>&,
const std::function<void(std::unique_ptr<Item>&)>&);
const std::function<void(std::unique_ptr<Item>&)>&, const std::function<void()>&);
~Host();
private:
@@ -28,9 +28,13 @@ class Host {
static void registerHost(GObject*, GAsyncResult*, gpointer);
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
void itemReady(Item&);
void itemInvalidated(Item&);
void removeItem(std::vector<std::unique_ptr<Item>>::iterator);
void clearItems();
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
void addRegisteredItem(std::string service);
void addRegisteredItem(const std::string& service);
std::vector<std::unique_ptr<Item>> items_;
const std::string bus_name_;
@@ -39,10 +43,13 @@ class Host {
std::size_t watcher_id_;
GCancellable* cancellable_ = nullptr;
SnWatcher* watcher_ = nullptr;
sigc::connection retry_connection_;
unsigned retry_count_ = 0;
const Json::Value& config_;
const Bar& bar_;
const std::function<void(std::unique_ptr<Item>&)> on_add_;
const std::function<void(std::unique_ptr<Item>&)> on_remove_;
const std::function<void()> on_update_;
};
} // namespace waybar::modules::SNI
+23 -3
View File
@@ -11,6 +11,7 @@
#include <libdbusmenu-gtk/dbusmenu-gtk.h>
#include <sigc++/trackable.h>
#include <functional>
#include <set>
#include <string_view>
@@ -25,8 +26,12 @@ struct ToolTip {
class Item : public sigc::trackable {
public:
Item(const std::string&, const std::string&, const Json::Value&, const Bar&);
~Item() = default;
Item(const std::string&, const std::string&, const Json::Value&, const Bar&,
const std::function<void(Item&)>&, const std::function<void(Item&)>&,
const std::function<void()>&);
~Item();
bool isReady() const;
std::string bus_name;
std::string object_path;
@@ -41,9 +46,12 @@ class Item : public sigc::trackable {
std::string title;
std::string icon_name;
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
bool has_custom_icon_ = false;
Glib::RefPtr<Gtk::IconTheme> icon_theme;
std::string overlay_icon_name;
Glib::RefPtr<Gdk::Pixbuf> overlay_icon_pixmap;
std::string attention_icon_name;
Glib::RefPtr<Gdk::Pixbuf> attention_icon_pixmap;
std::string attention_movie_name;
std::string icon_theme_path;
std::string menu;
@@ -62,6 +70,8 @@ class Item : public sigc::trackable {
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
void setProperty(const Glib::ustring& name, Glib::VariantBase& value);
void setStatus(const Glib::ustring& value);
void setReady();
void invalidate();
void setCustomIcon(const std::string& id);
void getUpdatedProperties();
void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result);
@@ -69,8 +79,13 @@ class Item : public sigc::trackable {
const Glib::VariantContainerBase& arguments);
void updateImage();
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
static Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
Glib::RefPtr<Gdk::Pixbuf> getIconPixbuf();
Glib::RefPtr<Gdk::Pixbuf> getAttentionIconPixbuf();
Glib::RefPtr<Gdk::Pixbuf> getOverlayIconPixbuf();
Glib::RefPtr<Gdk::Pixbuf> loadIconFromNameOrFile(const std::string& name, bool log_failure);
static Glib::RefPtr<Gdk::Pixbuf> overlayPixbufs(const Glib::RefPtr<Gdk::Pixbuf>&,
const Glib::RefPtr<Gdk::Pixbuf>&);
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
double getScaledIconSize();
static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
@@ -86,8 +101,13 @@ class Item : public sigc::trackable {
gdouble distance_scrolled_y_ = 0;
// visibility of items with Status == Passive
bool show_passive_ = false;
bool ready_ = false;
Glib::ustring status_ = "active";
const Bar& bar_;
const std::function<void(Item&)> on_ready_;
const std::function<void(Item&)> on_invalidate_;
const std::function<void()> on_updated_;
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
Glib::RefPtr<Gio::Cancellable> cancellable_;
+1
View File
@@ -19,6 +19,7 @@ class Tray : public AModule {
private:
void onAdd(std::unique_ptr<Item>& item);
void onRemove(std::unique_ptr<Item>& item);
void queueUpdate();
static inline std::size_t nb_hosts_ = 0;
Gtk::Box box_;
+1 -1
View File
@@ -37,7 +37,7 @@ class BarIpcClient {
void onModeUpdate(bool visible_by_modifier);
void onUrgencyUpdate(bool visible_by_urgency);
void update();
bool isModuleEnabled(std::string name);
bool isModuleEnabled(const std::string& name);
Bar& bar_;
util::JsonParser parser_;
+6 -4
View File
@@ -12,6 +12,8 @@
#include <string>
#include "ipc.hpp"
#include "util/SafeSignal.hpp"
#include "util/scoped_fd.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@@ -27,8 +29,8 @@ class Ipc {
std::string payload;
};
sigc::signal<void, const struct ipc_response &> signal_event;
sigc::signal<void, const struct ipc_response &> signal_cmd;
::waybar::SafeSignal<const struct ipc_response&> signal_event;
::waybar::SafeSignal<const struct ipc_response&> signal_cmd;
void sendCmd(uint32_t type, const std::string& payload = "");
void subscribe(const std::string& payload);
@@ -44,8 +46,8 @@ class Ipc {
struct ipc_response send(int fd, uint32_t type, const std::string& payload = "");
struct ipc_response recv(int fd);
int fd_;
int fd_event_;
util::ScopedFd fd_;
util::ScopedFd fd_event_;
std::mutex mutex_;
util::SleeperThread thread_;
};
+3 -3
View File
@@ -21,7 +21,7 @@ class Language : public ALabel, public sigc::trackable {
auto update() -> void override;
private:
enum class DispayedShortFlag { None = 0, ShortName = 1, ShortDescription = 1 << 1 };
enum class DisplayedShortFlag { None = 0, ShortName = 1, ShortDescription = 1 << 1 };
struct Layout {
std::string full_name;
@@ -47,7 +47,7 @@ class Language : public ALabel, public sigc::trackable {
void onEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&);
auto set_current_layout(std::string current_layout) -> void;
auto set_current_layout(const std::string& current_layout) -> void;
auto init_layouts_map(const std::vector<std::string>& used_layouts) -> void;
const static std::string XKB_LAYOUT_NAMES_KEY;
@@ -58,7 +58,7 @@ class Language : public ALabel, public sigc::trackable {
std::map<std::string, Layout> layouts_map_;
bool hide_single_;
bool is_variant_displayed;
std::byte displayed_short_flag = static_cast<std::byte>(DispayedShortFlag::None);
std::byte displayed_short_flag = static_cast<std::byte>(DisplayedShortFlag::None);
util::JsonParser parser_;
std::mutex mutex_;
+4 -2
View File
@@ -19,10 +19,11 @@ class Window : public AAppIconLabel, public sigc::trackable {
auto update() -> void override;
private:
void setClass(std::string classname, bool enable);
void setClass(const std::string& classname, bool enable);
void onEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&);
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string>
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string,
std::string>
getFocusedNode(const Json::Value& nodes, std::string& output);
void getTree();
@@ -35,6 +36,7 @@ class Window : public AAppIconLabel, public sigc::trackable {
std::string old_app_id_;
std::size_t app_nb_;
std::string shell_;
std::string marks_;
int floating_count_;
util::JsonParser parser_;
std::mutex mutex_;
+4 -3
View File
@@ -24,10 +24,11 @@ class Workspaces : public AModule, public sigc::trackable {
private:
static constexpr std::string_view workspace_switch_cmd_ = "workspace {} \"{}\"";
static constexpr std::string_view workspace_switch_number_cmd_ = "workspace {} number {}";
static constexpr std::string_view persistent_workspace_switch_cmd_ =
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
static int convertWorkspaceNameToNum(std::string name);
static int convertWorkspaceNameToNum(const std::string& name);
static int windowRewritePriorityFunction(std::string const& window_rule);
void onCmd(const struct Ipc::ipc_response&);
@@ -40,7 +41,7 @@ class Workspaces : public AModule, public sigc::trackable {
std::string getIcon(const std::string&, const Json::Value&);
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
uint16_t getWorkspaceIndex(const std::string& name) const;
static std::string trimWorkspaceName(std::string);
static std::string trimWorkspaceName(const std::string&);
bool handleScroll(GdkEventScroll* /*unused*/) override;
const Bar& bar_;
@@ -48,7 +49,7 @@ class Workspaces : public AModule, public sigc::trackable {
std::vector<std::string> high_priority_named_;
std::vector<std::string> workspaces_order_;
Gtk::Box box_;
std::string m_formatWindowSeperator;
std::string m_formatWindowSeparator;
util::RegexCollection m_windowRewriteRules;
util::JsonParser parser_;
std::unordered_map<std::string, Gtk::Button> buttons_;
+30 -7
View File
@@ -3,6 +3,7 @@
#include <giomm/dbusproxy.h>
#include <string>
#include <vector>
#include "ALabel.hpp"
@@ -11,20 +12,42 @@ namespace waybar::modules {
class SystemdFailedUnits : public ALabel {
public:
SystemdFailedUnits(const std::string&, const Json::Value&);
virtual ~SystemdFailedUnits();
virtual ~SystemdFailedUnits() = default;
auto update() -> void override;
private:
bool hide_on_ok;
std::string format_ok;
struct FailedUnit {
std::string name;
std::string description;
std::string load_state;
std::string active_state;
std::string sub_state;
std::string scope;
};
bool update_pending;
uint32_t nr_failed_system, nr_failed_user;
std::string last_status;
Glib::RefPtr<Gio::DBus::Proxy> system_proxy, user_proxy;
bool hide_on_ok_;
std::string format_ok_;
std::string tooltip_format_;
std::string tooltip_format_ok_;
std::string tooltip_unit_format_;
bool update_pending_;
std::string system_state_, user_state_, overall_state_;
uint32_t nr_failed_system_, nr_failed_user_, nr_failed_;
std::string last_status_;
Glib::RefPtr<Gio::DBus::Proxy> system_props_proxy_, user_props_proxy_;
Glib::RefPtr<Gio::DBus::Proxy> system_manager_proxy_, user_manager_proxy_;
std::vector<FailedUnit> failed_units_;
void notify_cb(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
const Glib::VariantContainerBase& arguments);
void RequestFailedUnits();
void RequestFailedUnitsList();
void RequestSystemState();
std::vector<FailedUnit> LoadFailedUnitsList(const char* kind,
Glib::RefPtr<Gio::DBus::Proxy>& proxy,
const std::string& scope);
std::string BuildTooltipFailedList() const;
void updateData();
};
+2
View File
@@ -14,6 +14,8 @@ class Temperature : public ALabel {
Temperature(const std::string&, const Json::Value&);
virtual ~Temperature() = default;
auto update() -> void override;
void suspend() override;
void resume() override;
private:
float getTemperature();
+108
View File
@@ -0,0 +1,108 @@
#pragma once
#include <json/json.h>
#include <unistd.h>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility>
#include "util/scoped_fd.hpp"
namespace waybar::modules::wayfire {
using EventHandler = std::function<void(const std::string& event)>;
struct State {
/*
┌───────────┐ ┌───────────┐
│ output #1 │ │ output #2 │
└─────┬─────┘ └─────┬─────┘
└─┐ └─────┐─ ─ ─ ─ ─ ─ ─ ─ ┐
┌───────┴───────┐ ┌───────┴──────┐ ┌───────┴───────┐
│ wset #1 │ │ wset #2 │ │ wset #3 │
│┌────────────┐ │ │┌────────────┐│ │┌────────────┐ │
││ workspaces │ │ ││ workspaces ││ ││ workspaces │ │
│└─┬──────────┘ │ │└────────────┘│ │└─┬──────────┘ │
│ │ ┌─────────┐│ └──────────────┘ │ │ ┌─────────┐│
│ ├─┤ view #1 ││ │ └─┤ view #3 ││
│ │ └─────────┘│ │ └─────────┘│
│ │ ┌─────────┐│ └───────────────┘
│ └─┤ view #2 ││
│ └─────────┘│
└───────────────┘
*/
struct Output {
size_t id;
size_t w, h;
size_t wset_idx;
};
struct Workspace {
size_t num_views;
size_t num_sticky_views;
};
struct Wset {
std::optional<std::reference_wrapper<Output>> output;
std::vector<Workspace> wss;
size_t ws_w, ws_h, ws_x, ws_y;
size_t focused_view_id;
auto ws_idx() const { return ws_w * ws_y + ws_x; }
auto count_ws(const Json::Value& pos) -> Workspace&;
auto locate_ws(const Json::Value& geo) -> Workspace&;
auto locate_ws(const Json::Value& geo) const -> const Workspace&;
};
std::unordered_map<std::string, Output> outputs;
std::unordered_map<size_t, Wset> wsets;
std::unordered_map<size_t, Json::Value> views;
std::string focused_output_name;
size_t maybe_empty_focus_wset_idx = {};
size_t vswitch_sticky_view_id = {};
bool new_output_detected = {};
bool vswitching = {};
auto update_view(const Json::Value& view) -> void;
};
using Sock = util::ScopedFd;
class IPC : public std::enable_shared_from_this<IPC> {
static std::weak_ptr<IPC> instance;
Json::CharReaderBuilder reader_builder;
Json::StreamWriterBuilder writer_builder;
std::list<std::pair<std::string, std::reference_wrapper<const EventHandler>>> handlers;
std::mutex handlers_mutex;
State state;
std::mutex state_mutex;
IPC() = default;
static auto connect() -> Sock;
auto receive(Sock& sock) -> Json::Value;
auto start() -> void;
auto root_event_handler(const std::string& event, const Json::Value& data) -> void;
auto update_state_handler(const std::string& event, const Json::Value& data) -> void;
public:
static auto get_instance() -> std::shared_ptr<IPC>;
auto send(const std::string& method, Json::Value&& data) -> Json::Value;
auto register_handler(const std::string& event, const EventHandler& handler) -> void;
auto unregister_handler(EventHandler& handler) -> void;
auto lock_state() -> std::lock_guard<std::mutex> { return std::lock_guard{state_mutex}; }
auto& get_outputs() const { return state.outputs; }
auto& get_wsets() const { return state.wsets; }
auto& get_views() const { return state.views; }
auto& get_focused_output_name() const { return state.focused_output_name; }
};
} // namespace waybar::modules::wayfire
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "modules/wayfire/backend.hpp"
namespace waybar::modules::wayfire {
class Window : public AAppIconLabel {
std::shared_ptr<IPC> ipc;
EventHandler handler;
const Bar& bar_;
std::string old_app_id_;
public:
Window(const std::string& id, const Bar& bar, const Json::Value& config);
~Window() override;
auto update() -> void override;
auto update_icon_label() -> void;
};
} // namespace waybar::modules::wayfire
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <gtkmm/button.h>
#include <json/json.h>
#include <memory>
#include <vector>
#include "AModule.hpp"
#include "bar.hpp"
#include "modules/wayfire/backend.hpp"
namespace waybar::modules::wayfire {
class Workspaces : public AModule {
std::shared_ptr<IPC> ipc;
EventHandler handler;
const Bar& bar_;
Gtk::Box box_;
std::vector<Gtk::Button> buttons_;
auto handleScroll(GdkEventScroll* e) -> bool override;
auto update() -> void override;
auto update_box() -> void;
public:
Workspaces(const std::string& id, const Bar& bar, const Json::Value& config);
~Workspaces() override;
};
} // namespace waybar::modules::wayfire
+7
View File
@@ -22,6 +22,8 @@ class Wireplumber : public ALabel {
void activatePlugins();
static void updateVolume(waybar::modules::Wireplumber* self, uint32_t id);
static void updateNodeName(waybar::modules::Wireplumber* self, uint32_t id);
static void updateSourceVolume(waybar::modules::Wireplumber* self, uint32_t id);
static void updateSourceName(waybar::modules::Wireplumber* self, uint32_t id); // NEW
static void onPluginActivated(WpObject* p, GAsyncResult* res, waybar::modules::Wireplumber* self);
static void onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res,
waybar::modules::Wireplumber* self);
@@ -46,7 +48,12 @@ class Wireplumber : public ALabel {
double min_step_;
uint32_t node_id_{0};
std::string node_name_;
std::string source_name_;
gchar* type_;
uint32_t source_node_id_;
bool source_muted_;
double source_volume_;
gchar* default_source_name_;
};
} // namespace waybar::modules
+5 -7
View File
@@ -19,6 +19,7 @@
#include "bar.hpp"
#include "client.hpp"
#include "giomm/desktopappinfo.h"
#include "util/icon_loader.hpp"
#include "util/json.hpp"
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
@@ -32,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:
@@ -89,9 +90,6 @@ class Task {
std::string state_string(bool = false) const;
void set_minimize_hint();
void on_button_size_allocated(Gtk::Allocation& alloc);
void set_app_info_from_app_id_list(const std::string &app_id_list);
bool image_load_icon(Gtk::Image &image, const Glib::RefPtr<Gtk::IconTheme> &icon_theme,
Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size);
void hide_if_ignored();
public:
@@ -153,7 +151,7 @@ class Taskbar : public waybar::AModule {
Gtk::Box box_;
std::vector<TaskPtr> tasks_;
std::vector<Glib::RefPtr<Gtk::IconTheme>> icon_themes_;
IconLoader icon_loader_;
std::unordered_set<std::string> ignore_list_;
std::map<std::string, std::string> app_ids_replace_map_;
@@ -178,7 +176,7 @@ class Taskbar : public waybar::AModule {
bool show_output(struct wl_output*) const;
bool all_outputs() const;
const std::vector<Glib::RefPtr<Gtk::IconTheme>> &icon_themes() const;
const IconLoader& icon_loader() const;
const std::unordered_set<std::string>& ignore_list() const;
const std::map<std::string, std::string>& app_ids_replace_map() const;
};
-172
View File
@@ -1,172 +0,0 @@
#pragma once
#include <fmt/format.h>
#include <gtkmm/button.h>
#include <gtkmm/image.h>
#include <gtkmm/label.h>
#include <functional>
#include <map>
#include <memory>
#include <vector>
#include "AModule.hpp"
#include "bar.hpp"
#include "ext-workspace-unstable-v1-client-protocol.h"
namespace waybar::modules::wlr {
class WorkspaceManager;
class WorkspaceGroup;
class Workspace {
public:
Workspace(const waybar::Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group,
zext_workspace_handle_v1 *workspace, uint32_t id, std::string name);
~Workspace();
auto update() -> void;
auto id() const -> uint32_t { return id_; }
auto is_active() const -> bool { return state_ & static_cast<uint32_t>(State::ACTIVE); }
auto is_urgent() const -> bool { return state_ & static_cast<uint32_t>(State::URGENT); }
auto is_hidden() const -> bool { return state_ & static_cast<uint32_t>(State::HIDDEN); }
auto is_empty() const -> bool { return state_ & static_cast<uint32_t>(State::EMPTY); }
auto is_persistent() const -> bool { return persistent_; }
// wlr stuff
auto handle_name(const std::string &name) -> void;
auto handle_coordinates(const std::vector<uint32_t> &coordinates) -> void;
auto handle_state(const std::vector<uint32_t> &state) -> void;
auto handle_remove() -> void;
auto make_persistent() -> void;
auto handle_duplicate() -> void;
auto handle_done() -> void;
auto handle_clicked(GdkEventButton *bt) -> bool;
auto show() -> void;
auto hide() -> void;
auto get_button_ref() -> Gtk::Button & { return button_; }
auto get_name() -> std::string & { return name_; }
auto get_coords() -> std::vector<uint32_t> & { return coordinates_; }
enum class State {
ACTIVE = (1 << 0),
URGENT = (1 << 1),
HIDDEN = (1 << 2),
EMPTY = (1 << 3),
};
private:
auto get_icon() -> std::string;
const Bar &bar_;
const Json::Value &config_;
WorkspaceGroup &workspace_group_;
// wlr stuff
zext_workspace_handle_v1 *workspace_handle_;
uint32_t state_ = 0;
uint32_t id_;
std::string name_;
std::vector<uint32_t> coordinates_;
static std::map<std::string, std::string> icons_map_;
std::string format_;
bool with_icon_ = false;
bool persistent_ = false;
Gtk::Button button_;
Gtk::Box content_;
Gtk::Label label_;
};
class WorkspaceGroup {
public:
WorkspaceGroup(const waybar::Bar &bar, Gtk::Box &box, const Json::Value &config,
WorkspaceManager &manager, zext_workspace_group_handle_v1 *workspace_group_handle,
uint32_t id);
~WorkspaceGroup();
auto update() -> void;
auto id() const -> uint32_t { return id_; }
auto is_visible() const -> bool;
auto remove_workspace(uint32_t id_) -> void;
auto active_only() const -> bool;
auto creation_delayed() const -> bool;
auto workspaces() -> std::vector<std::unique_ptr<Workspace>> & { return workspaces_; }
auto persistent_workspaces() -> std::vector<std::string> & { return persistent_workspaces_; }
auto sort_workspaces() -> void;
auto set_need_to_sort() -> void { need_to_sort = true; }
auto add_button(Gtk::Button &button) -> void;
auto remove_button(Gtk::Button &button) -> void;
auto fill_persistent_workspaces() -> void;
auto create_persistent_workspaces() -> void;
// wlr stuff
auto handle_workspace_create(zext_workspace_handle_v1 *workspace_handle) -> void;
auto handle_remove() -> void;
auto handle_output_enter(wl_output *output) -> void;
auto handle_output_leave() -> void;
auto handle_done() -> void;
auto commit() -> void;
private:
static uint32_t workspace_global_id;
const waybar::Bar &bar_;
Gtk::Box &box_;
const Json::Value &config_;
WorkspaceManager &workspace_manager_;
// wlr stuff
zext_workspace_group_handle_v1 *workspace_group_handle_;
wl_output *output_ = nullptr;
uint32_t id_;
std::vector<std::unique_ptr<Workspace>> workspaces_;
bool need_to_sort = false;
std::vector<std::string> persistent_workspaces_;
bool persistent_created_ = false;
};
class WorkspaceManager : public AModule {
public:
WorkspaceManager(const std::string &id, const waybar::Bar &bar, const Json::Value &config);
~WorkspaceManager() override;
auto update() -> void override;
auto all_outputs() const -> bool { return all_outputs_; }
auto active_only() const -> bool { return active_only_; }
auto workspace_comparator() const
-> std::function<bool(std::unique_ptr<Workspace> &, std::unique_ptr<Workspace> &)>;
auto creation_delayed() const -> bool { return creation_delayed_; }
auto sort_workspaces() -> void;
auto remove_workspace_group(uint32_t id_) -> void;
// wlr stuff
auto register_manager(wl_registry *registry, uint32_t name, uint32_t version) -> void;
auto handle_workspace_group_create(zext_workspace_group_handle_v1 *workspace_group_handle)
-> void;
auto handle_done() -> void;
auto handle_finished() -> void;
auto commit() -> void;
private:
const waybar::Bar &bar_;
Gtk::Box box_;
std::vector<std::unique_ptr<WorkspaceGroup>> groups_;
// wlr stuff
zext_workspace_manager_v1 *workspace_manager_ = nullptr;
static uint32_t group_global_id;
bool sort_by_name_ = true;
bool sort_by_coordinates_ = true;
bool sort_by_number_ = false;
bool all_outputs_ = false;
bool active_only_ = false;
bool creation_delayed_ = false;
};
} // namespace waybar::modules::wlr
@@ -1,10 +0,0 @@
#include "ext-workspace-unstable-v1-client-protocol.h"
namespace waybar::modules::wlr {
void add_registry_listener(void *data);
void add_workspace_listener(zext_workspace_handle_v1 *workspace_handle, void *data);
void add_workspace_group_listener(zext_workspace_group_handle_v1 *workspace_group_handle,
void *data);
zext_workspace_manager_v1 *workspace_manager_bind(wl_registry *registry, uint32_t name,
uint32_t version, void *data);
} // namespace waybar::modules::wlr
+20
View File
@@ -3,6 +3,7 @@
#include <glibmm/dispatcher.h>
#include <sigc++/signal.h>
#include <cstddef>
#include <functional>
#include <mutex>
#include <queue>
@@ -22,6 +23,12 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
public:
SafeSignal() { dp_.connect(sigc::mem_fun(*this, &SafeSignal::handle_event)); }
void set_max_queued_events(std::size_t max_queued_events) {
std::unique_lock lock(mutex_);
max_queued_events_ = max_queued_events;
trim_queue_locked();
}
template <typename... EmitArgs>
void emit(EmitArgs&&... args) {
if (main_tid_ == std::this_thread::get_id()) {
@@ -36,6 +43,9 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
} else {
{
std::unique_lock lock(mutex_);
if (max_queued_events_ != 0 && queue_.size() >= max_queued_events_) {
queue_.pop();
}
queue_.emplace(std::forward<EmitArgs>(args)...);
}
dp_.emit();
@@ -55,6 +65,15 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
using signal_t::emit_reverse;
using signal_t::make_slot;
void trim_queue_locked() {
if (max_queued_events_ == 0) {
return;
}
while (queue_.size() > max_queued_events_) {
queue_.pop();
}
}
void handle_event() {
for (std::unique_lock lock(mutex_); !queue_.empty(); lock.lock()) {
auto args = queue_.front();
@@ -67,6 +86,7 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
Glib::Dispatcher dp_;
std::mutex mutex_;
std::queue<arg_tuple_t> queue_;
std::size_t max_queued_events_ = 4096;
const std::thread::id main_tid_ = std::this_thread::get_id();
// cache functor for signal emission to avoid recreating it on each event
const slot_t cached_fn_ = make_slot();
+9
View File
@@ -14,6 +14,11 @@
namespace waybar::util {
enum class PulseaudioTarget {
Sink,
Source,
};
class AudioBackend {
private:
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
@@ -92,6 +97,10 @@ class AudioBackend {
void toggleSourceMute();
void toggleSourceMute(bool);
uint16_t getVolume(PulseaudioTarget) const;
bool getMuted(PulseaudioTarget) const;
void unmute(PulseaudioTarget);
bool isBluetooth();
};
+16 -4
View File
@@ -20,6 +20,8 @@ extern std::list<pid_t> reap;
namespace waybar::util::command {
constexpr int kExecFailureExitCode = 127;
struct res {
int exit_code;
std::string out;
@@ -59,6 +61,7 @@ inline int close(FILE* fp, pid_t pid) {
spdlog::debug("Cmd continued");
} else if (ret == -1) {
spdlog::debug("waitpid failed: {}", strerror(errno));
break;
} else {
break;
}
@@ -109,11 +112,13 @@ 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);
exit(0);
const int saved_errno = errno;
spdlog::error("execlp(/bin/sh) failed in open: {}", strerror(saved_errno));
_exit(kExecFailureExitCode);
} else {
::close(fd[1]);
}
@@ -138,7 +143,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,8 +162,13 @@ 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);
const int saved_errno = errno;
spdlog::error("execl(/bin/sh) failed in forkExec: {}", strerror(saved_errno));
_exit(kExecFailureExitCode);
} else {
reap_mtx.lock();
reap.push_back(pid);
@@ -169,4 +179,6 @@ inline int32_t forkExec(const std::string& cmd) {
return pid;
}
inline int32_t forkExec(const std::string& cmd) { return forkExec(cmd, ""); }
} // namespace waybar::util::command
+4 -2
View File
@@ -14,12 +14,14 @@ struct pollfd;
namespace waybar {
class CssReloadHelper {
public:
CssReloadHelper(std::string cssFile, std::function<void()> callback);
CssReloadHelper(std::string cssFile, std::function<void(const std::string&)> callback);
virtual ~CssReloadHelper() = default;
virtual void monitorChanges();
virtual void changeCssFile(const std::string& newCssFile);
protected:
std::vector<std::string> parseImports(const std::string& cssFile);
@@ -42,7 +44,7 @@ class CssReloadHelper {
private:
std::string m_cssFile;
std::function<void()> m_callback;
std::function<void(const std::string&)> m_callback;
std::vector<std::tuple<Glib::RefPtr<Gio::FileMonitor>>> m_fileMonitors;
};
+1 -3
View File
@@ -15,7 +15,7 @@
namespace date {
#if HAVE_CHRONO_TIMEZONES
using namespace std::chrono;
using namespace std;
using std::format;
#else
using system_clock = std::chrono::system_clock;
@@ -73,5 +73,3 @@ struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> {
}
};
#endif
using namespace date;
+3 -1
View File
@@ -10,5 +10,7 @@ class DefaultGtkIconThemeWrapper {
public:
static bool has_icon(const std::string&);
static Glib::RefPtr<Gdk::Pixbuf> load_icon(const char*, int, Gtk::IconLookupFlags);
static Glib::RefPtr<Gdk::Pixbuf> load_icon(
const char*, int, Gtk::IconLookupFlags,
Glib::RefPtr<Gtk::StyleContext> style = Glib::RefPtr<Gtk::StyleContext>());
};
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <string>
/**
* Result of transforming 8-bit hex codes to rgba().
*/
struct TransformResult {
std::string css;
bool was_transformed;
};
/**
* Reads a CSS file, searches for 8-bit hex codes (#RRGGBBAA),
* and transforms them into GTK-compatible rgba() syntax.
*/
TransformResult transform_8bit_to_hex(const std::string& file_path);
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <gdkmm/general.h>
#include <gio/gdesktopappinfo.h>
#include <giomm/desktopappinfo.h>
#include <glibmm/fileutils.h>
#include <gtkmm/image.h>
#include <spdlog/spdlog.h>
#include <string>
#include <vector>
#include "util/gtk_icon.hpp"
class IconLoader {
private:
std::vector<Glib::RefPtr<Gtk::IconTheme>> custom_icon_themes_;
Glib::RefPtr<Gtk::IconTheme> default_icon_theme_ = Gtk::IconTheme::get_default();
static std::vector<std::string> search_prefix();
static Glib::RefPtr<Gio::DesktopAppInfo> get_app_info_by_name(const std::string& app_id);
static Glib::RefPtr<Gio::DesktopAppInfo> get_desktop_app_info(const std::string& app_id);
static Glib::RefPtr<Gdk::Pixbuf> load_icon_from_file(std::string const& icon_path, int size);
static std::string get_icon_name_from_icon_theme(const Glib::RefPtr<Gtk::IconTheme>& icon_theme,
const std::string& app_id);
static bool image_load_icon(Gtk::Image& image, const Glib::RefPtr<Gtk::IconTheme>& icon_theme,
Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size);
public:
void add_custom_icon_theme(const std::string& theme_name);
bool image_load_icon(Gtk::Image& image, Glib::RefPtr<Gio::DesktopAppInfo> app_info,
int size) const;
static Glib::RefPtr<Gio::DesktopAppInfo> get_app_info_from_app_id_list(
const std::string& app_id_list);
};
+12 -5
View File
@@ -7,6 +7,7 @@
#include <codecvt>
#include <iostream>
#include <locale>
#include <memory>
#include <regex>
#if (FMT_VERSION >= 90000)
@@ -26,19 +27,25 @@ class JsonParser {
Json::Value root;
// replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences
std::string modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
std::string modifiedJsonStr;
const std::string* json = &jsonStr;
if (jsonStr.find("\\x") != std::string::npos) {
modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
json = &modifiedJsonStr;
}
std::istringstream jsonStream(modifiedJsonStr);
std::string errs;
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;
auto reader = std::unique_ptr<Json::CharReader>(readerBuilder.newCharReader());
if (!reader->parse(json->data(), json->data() + json->size(), &root, &errs)) {
throw std::runtime_error("Error parsing JSON: " + errs);
}
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");
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <json/value.h>
#include <cstdint>
namespace waybar::util {
enum class KillSignalAction : std::uint8_t {
TOGGLE,
RELOAD,
SHOW,
HIDE,
NOOP,
};
const std::map<std::string, KillSignalAction> userKillSignalActions = {
{"TOGGLE", KillSignalAction::TOGGLE},
{"RELOAD", KillSignalAction::RELOAD},
{"SHOW", KillSignalAction::SHOW},
{"HIDE", KillSignalAction::HIDE},
{"NOOP", KillSignalAction::NOOP}};
const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR1 = KillSignalAction::TOGGLE;
const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR2 = KillSignalAction::RELOAD;
}; // namespace waybar::util
@@ -25,6 +25,7 @@ class PrivacyNodeInfo {
std::string media_name;
std::string node_name;
std::string application_name;
bool is_monitor = false;
std::string pipewire_access_portal_app_id;
std::string application_icon_name;
+1 -3
View File
@@ -6,14 +6,12 @@
namespace waybar {
using namespace Gio;
enum class Appearance {
UNKNOWN = 0,
DARK = 1,
LIGHT = 2,
};
class Portal : private DBus::Proxy {
class Portal : private Gio::DBus::Proxy {
public:
Portal();
void refreshAppearance();
+1 -1
View File
@@ -4,6 +4,6 @@
namespace waybar::util {
// Get a signal emited with value true when entering sleep, and false when exiting
// Get a signal emitted with value true when entering sleep, and false when exiting
SafeSignal<bool>& prepare_for_sleep();
} // namespace waybar::util
+3 -1
View File
@@ -5,6 +5,8 @@
#include <sigc++/signal.h>
#include <sigc++/trackable.h>
#include <atomic>
namespace waybar::util {
class Rfkill : public sigc::trackable {
@@ -17,7 +19,7 @@ class Rfkill : public sigc::trackable {
private:
enum rfkill_type rfkill_type_;
bool state_ = false;
std::atomic_bool state_ = false;
int fd_ = -1;
bool on_event(Glib::IOCondition cond);
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <unistd.h>
namespace waybar::util {
class ScopedFd {
public:
explicit ScopedFd(int fd = -1) : fd_(fd) {}
~ScopedFd() {
if (fd_ != -1) {
close(fd_);
}
}
// ScopedFd is non-copyable
ScopedFd(const ScopedFd&) = delete;
ScopedFd& operator=(const ScopedFd&) = delete;
// ScopedFd is moveable
ScopedFd(ScopedFd&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
ScopedFd& operator=(ScopedFd&& other) noexcept {
if (this != &other) {
if (fd_ != -1) {
close(fd_);
}
fd_ = other.fd_;
other.fd_ = -1;
}
return *this;
}
int get() const { return fd_; }
operator int() const { return fd_; }
void reset(int fd = -1) {
if (fd_ != -1) {
close(fd_);
}
fd_ = fd;
}
int release() {
int fd = fd_;
fd_ = -1;
return fd;
}
private:
int fd_;
};
} // namespace waybar::util
+54 -14
View File
@@ -1,5 +1,6 @@
#pragma once
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <ctime>
@@ -31,8 +32,8 @@ class SleeperThread {
SleeperThread(std::function<void()> func)
: thread_{[this, func] {
while (do_run_) {
signal_ = false;
while (do_run_.load(std::memory_order_relaxed)) {
signal_.store(false, std::memory_order_relaxed);
func();
}
}} {
@@ -42,9 +43,18 @@ class SleeperThread {
}
SleeperThread& operator=(std::function<void()> func) {
if (thread_.joinable()) {
stop();
thread_.join();
}
{
std::lock_guard<std::mutex> lck(mutex_);
do_run_.store(true, std::memory_order_relaxed);
signal_.store(false, std::memory_order_relaxed);
}
thread_ = std::thread([this, func] {
while (do_run_) {
signal_ = false;
while (do_run_.load(std::memory_order_relaxed)) {
signal_.store(false, std::memory_order_relaxed);
func();
}
});
@@ -56,24 +66,34 @@ class SleeperThread {
return *this;
}
bool isRunning() const { return do_run_; }
bool isRunning() const { return do_run_.load(std::memory_order_relaxed); }
auto sleep() {
std::unique_lock lk(mutex_);
CancellationGuard cancel_lock;
return condvar_.wait(lk, [this] { return signal_ || !do_run_; });
return condvar_.wait(lk, [this] {
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
});
}
auto sleep_for(std::chrono::system_clock::duration dur) {
std::unique_lock lk(mutex_);
CancellationGuard cancel_lock;
condvar_.wait(lk, [this] {
return !is_paused_ || signal_.load(std::memory_order_relaxed) ||
!do_run_.load(std::memory_order_relaxed);
});
constexpr auto max_time_point = std::chrono::steady_clock::time_point::max();
auto wait_end = max_time_point;
auto now = std::chrono::steady_clock::now();
if (now < max_time_point - dur) {
wait_end = now + dur;
}
return condvar_.wait_until(lk, wait_end, [this] { return signal_ || !do_run_; });
return condvar_.wait_until(lk, wait_end, [this] {
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
});
}
auto sleep_until(
@@ -81,22 +101,30 @@ class SleeperThread {
time_point) {
std::unique_lock lk(mutex_);
CancellationGuard cancel_lock;
return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
condvar_.wait(lk, [this] {
return !is_paused_ || signal_.load(std::memory_order_relaxed) ||
!do_run_.load(std::memory_order_relaxed);
});
return condvar_.wait_until(lk, time_point, [this] {
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
});
}
void wake_up() {
{
std::lock_guard<std::mutex> lck(mutex_);
signal_ = true;
signal_.store(true, std::memory_order_relaxed);
}
condvar_.notify_all();
}
auto stop() {
void stop() {
{
std::lock_guard<std::mutex> lck(mutex_);
signal_ = true;
do_run_ = false;
signal_.store(true, std::memory_order_relaxed);
do_run_.store(false, std::memory_order_relaxed);
}
condvar_.notify_all();
auto handle = thread_.native_handle();
@@ -106,6 +134,17 @@ class SleeperThread {
}
}
void pause() {
std::lock_guard<std::mutex> lock(mutex_);
is_paused_ = true;
}
void resume() {
std::lock_guard<std::mutex> lock(mutex_);
is_paused_ = false;
condvar_.notify_all();
}
~SleeperThread() {
connection_.disconnect();
stop();
@@ -118,9 +157,10 @@ class SleeperThread {
std::thread thread_;
std::condition_variable condvar_;
std::mutex mutex_;
bool do_run_ = true;
bool signal_ = false;
std::atomic<bool> do_run_ = true;
std::atomic<bool> signal_ = false;
sigc::connection connection_;
bool is_paused_{false};
};
} // namespace waybar::util
+23
View File
@@ -23,3 +23,26 @@ inline std::string capitalize(const std::string& str) {
[](unsigned char c) { return std::toupper(c); });
return result;
}
inline std::string toLower(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::tolower(c); });
return result;
}
inline std::vector<std::string> split(std::string_view s, std::string_view delimiter,
int max_splits = -1) {
std::vector<std::string> result;
size_t pos = 0;
size_t next_pos = 0;
while ((next_pos = s.find(delimiter, pos)) != std::string::npos) {
result.push_back(std::string(s.substr(pos, next_pos - pos)));
pos = next_pos + delimiter.size();
if (max_splits > 0 && result.size() == static_cast<size_t>(max_splits)) {
break;
}
}
result.push_back(std::string(s.substr(pos)));
return result;
}
+21
View 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
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <string>
namespace waybar::util {
size_t utf8_width(const std::string& str);
void utf8_truncate(std::string& s, const std::string& ellipsis, size_t max_len);
} // namespace waybar::util
+36 -1
View File
@@ -27,6 +27,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
default: false ++
Option to use the battery design capacity instead of its current maximal capacity.
*full-at-plugged*: ++
typeof: bool ++
default: false ++
When enabled, a battery that is *Full* while the adapter is online is reported with the *Plugged* status instead of *Full* (so you can style/format it separately). Disabled by default to preserve the existing *Full* behaviour.
*interval*: ++
typeof: integer ++
default: 60 ++
@@ -91,6 +96,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.
@@ -116,7 +126,7 @@ The *battery* module displays the current capacity and state (eg. charging) of y
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
GtkMenu with id *menu*.
*menu-actions*: ++
typeof: array ++
@@ -127,6 +137,10 @@ The *battery* module displays the current capacity and state (eg. charging) of y
default: false ++
Enables this module to consume all left over space dynamically.
*events*: ++
typeof: object ++
Specifies commands to be executed on specific battery states. See *EVENTS* section below.
# FORMAT REPLACEMENTS
*{capacity}*: Capacity in percentage
@@ -166,6 +180,20 @@ The *battery* module allows one to define custom formats based on up to two fact
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. Each class gets activated when the current capacity is equal to or below the configured *<value>*.
- Also each state can have its own *format*. Those can be configured via *format-<name>*. Or if you want to differentiate a bit more even as *format-<status>-<state>*. For more information see *custom-formats*.
# EVENTS
Every entry in the *events* object consists of a *<event-name>* (typeof: *string*) and a *<command>* (typeof: *string*). ++
*<event-name>* can be in one of the following formats:
- *on-<status>-<state>*
- *on-<status>-<capacity>*
- *on-<status>*
Where:
- *<status>* is either *charging* or *discharging*,
- *<state>* is the name of one of the states specified in the *states* object,
- *<capacity>* is a battery level value (between *0-100*).
# EXAMPLES
@@ -178,6 +206,13 @@ The *battery* module allows one to define custom formats based on up to two fact
"warning": 30,
"critical": 15
},
"events": {
"on-discharging-warning": "notify-send -u normal 'Low Battery'",
"on-discharging-critical": "notify-send -u critical 'Very Low Battery'",
"on-charging-100": "notify-send -u normal 'Battery Full!'",
"on-discharging": "notify-send -u normal 'Power Switch' Discharging",
"on-charging": "notify-send -u normal 'Power Switch' Charging'"
},
"format": "{capacity}% {icon}",
"format-icons": ["", "", "", "", ""],
"max-length": 25
+508 -7
View File
@@ -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)
+45 -2
View File
@@ -39,6 +39,12 @@ $XDG_CONFIG_HOME/waybar/config ++
:[ A list of timezones (as in *timezone*) to use for time display, changed using
the scroll wheel. Do not specify *timezone* option when *timezones* is specified.
"" represents the system's local timezone
|[ *timezone-tooltip-format*
:[ string
:[
:[ Format to use for displaying timezones in the tooltip. When set, this allows showing
timezone information (like timezone abbreviations) in the tooltip while keeping the
main display clean. Uses the same format options as *format*
|[ *locale*
:[ string
:[
@@ -126,6 +132,12 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
:[ 1
:[ Value to scroll months/years forward/backward. Can be negative. Is
configured under *on-scroll* option
|[ *iso8601*
:[ bool
:[ false
:[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on
Monday, and the first week of the year is numbered 1. The default week format is
'{:%V}'.
3. Addressed by *clock: calendar: format*
[- *Option*
@@ -192,7 +204,7 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
```
"clock": {
"format": "{:%H:%M}  ",
"format-alt": "{:%A, %B %d, %Y (%R)} ",
"format-alt": "{:%A, %B %d, %Y (%R)} 󰃰 ",
"tooltip-format": "<tt><small>{calendar}</small></tt>",
"calendar": {
"mode" : "year",
@@ -229,6 +241,37 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
}
```
4. Show timezone in tooltip only
```
"clock": {
"interval": 60,
"format": "{:%H:%M}",
"timezone-tooltip-format": "{:%H:%M %Z}",
"timezones": [
"",
"America/Chicago",
"America/Los_Angeles",
"Europe/Paris",
"UTC"
],
"tooltip": true,
"tooltip-format": "{tz_list}"
}
```
5. Simple calendar tooltip
```
"clock": {
"format": "{:%H:%M}",
"tooltip-format": "<tt>{calendar}</tt>",
"calendar": {
"format": {
"today": "<span color='#ffcc66'><b>{}</b></span>"
}
}
}
```
# STYLE
- *#clock*
@@ -256,7 +299,7 @@ Example of working config
```
"clock": {
"format": "{:%H:%M}  ",
"format-alt": "{:%A, %B %d, %Y (%R)} ",
"format-alt": "{:%A, %B %d, %Y (%R)} 󰃰 ",
"tooltip-format": "\n<span size='9pt' font='WenQuanYi Zen Hei Mono'>{calendar}</span>",
"calendar": {
"mode" : "year",
+3 -2
View File
@@ -11,9 +11,10 @@ The *cpu* module displays the current CPU utilization.
# CONFIGURATION
*interval*: ++
typeof: integer ++
typeof: integer or float ++
default: 10 ++
The interval in which the information gets polled.
The interval in which the information gets polled. ++
Minimum value is 0.001 (1ms). Values smaller than 1ms will be set to 1ms.
*format*: ++
typeof: string ++
+5 -4
View File
@@ -35,15 +35,17 @@ Addressed by *custom/<name>*
See *return-type*
*interval*: ++
typeof: integer ++
typeof: integer or float ++
The interval (in seconds) in which the information gets polled. ++
Minimum value is 0.001 (1ms). Values smaller than 1ms will be set to 1ms. ++
Use *once* if you want to execute the module only on startup. ++
You can update it manually with a signal. If no *interval* or *signal* is defined, it is assumed that the out script loops itself. ++
If a *signal* is defined then the script will run once on startup and will only update with a signal.
*restart-interval*: ++
typeof: integer ++
typeof: integer or float ++
The restart interval (in seconds). ++
Minimum value is 0.001 (1ms). Values smaller than 1ms will be set to 1ms. ++
Can't be used with the *interval* option, so only with continuous scripts. ++
Once the script exits, it'll be re-executed after the *restart-interval*.
@@ -232,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
@@ -240,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
+1
View File
@@ -43,6 +43,7 @@ Addressed by *dwl/tags*
- *#tags button*
- *#tags button.occupied*
- *#tags button.empty*
- *#tags button.focused*
- *#tags button.urgent*
@@ -10,7 +10,7 @@ The *workspaces* module displays the currently used workspaces in wayland compos
# CONFIGURATION
Addressed by *wlr/workspaces*
Addressed by *ext/workspaces*
*format*: ++
typeof: string ++
@@ -24,18 +24,18 @@ Addressed by *wlr/workspaces*
*sort-by-name*: ++
typeof: bool ++
default: true ++
Should workspaces be sorted by name.
Should workspaces be sorted by name. Workspace names will be sorted numerically when all names are numbers.
*sort-by-coordinates*: ++
typeof: bool ++
default: true ++
default: false ++
Should workspaces be sorted by coordinates. ++
Note that if both *sort-by-name* and *sort-by-coordinates* are true sort-by name will be first. If both are false - sort by id will be performed.
*sort-by-number*: ++
*sort-by-id*: ++
typeof: bool ++
default: false ++
If set to true, workspace names will be sorted numerically. Takes precedence over any other sort-by option.
Should workspaces be sorted by ID. Workspace ID will be sorted numerically when all ID are numbers. Takes precedence over any other sort-by option.
*all-outputs*: ++
typeof: bool ++
@@ -47,9 +47,16 @@ Addressed by *wlr/workspaces*
default: false ++
If set to true only active or urgent workspaces will be shown.
*ignore-hidden*: ++
typeof: bool ++
default: true ++
If set to false hidden workspaces will be shown.
# FORMAT REPLACEMENTS
*{name}*: Name of workspace assigned by compositor
*{name}*: Name of workspace assigned by compositor.
*{id}*: ID of workspace assigned by compositor.
*{icon}*: Icon, as defined in *format-icons*.
@@ -57,6 +64,8 @@ Addressed by *wlr/workspaces*
*activate*: Switch to workspace.
*deactivate*: Deactivate the workspace.
*close*: Close the workspace.
# ICONS
@@ -69,18 +78,18 @@ In addition to workspace name matching, the following *format-icons* can be set.
# EXAMPLES
```
"wlr/workspaces": {
"ext/workspaces": {
"format": "{name}: {icon}",
"on-click": "activate",
"format-icons": {
"1": "",
"2": "",
"3": "",
"4": "",
"5": "",
"Workspace 1": "",
"Workspace 2": "",
"Workspace 3": "",
"Workspace 4": "",
"active": "",
"default": ""
},
"sort-by-number": true
"sort-by-id": true
}
```
+2 -2
View File
@@ -43,7 +43,7 @@ Feral Gamemode optimizations.
*glyph*: ++
typeof: string ++
default: ++
default: 󰊴 ++
The string icon to display. Only visible if *use-icon* is set to false.
*icon-name*: ++
@@ -82,7 +82,7 @@ Feral Gamemode optimizations.
"gamemode": {
"format": "{glyph}",
"format-alt": "{glyph} {count}",
"glyph": "",
"glyph": "󰊴",
"hide-not-running": true,
"use-icon": true,
"icon-name": "input-gaming-symbolic",

Some files were not shown because too many files have changed in this diff Show More