This commit is contained in:
2026-08-15 13:07:50 -07:00
275 changed files with 15644 additions and 2751 deletions
+6
View File
@@ -9,6 +9,7 @@
#include <poll.h>
#include <algorithm>
#include <chrono>
#include <fstream>
#include <string>
#include <vector>
@@ -51,6 +52,11 @@ class Battery : public ALabel {
bool warnFirstTime_{true};
bool weightedAverage_{true};
const Bar& bar_;
bool smoothPowerEnable_{false};
double time_constant_s_{260.0};
double smooth_power_{0.0}; // µW
std::chrono::steady_clock::time_point last_t_{std::chrono::steady_clock::now()};
std::string old_status_raw_{""};
util::SleeperThread thread_;
util::SleeperThread thread_battery_update_;
+7
View File
@@ -41,6 +41,7 @@ class Bluetooth : public ALabel {
bool services_resolved;
// NOTE: experimental feature in bluez
std::optional<unsigned char> battery_percentage;
std::optional<unsigned char> battery_percentage_peripheral;
};
public:
@@ -59,6 +60,12 @@ class Bluetooth : public ALabel {
gpointer) -> void;
auto getDeviceBatteryPercentage(GDBusObject*) -> std::optional<unsigned char>;
auto getDeviceGattBatteryLevels(GDBusObject*, std::optional<unsigned char>&,
std::optional<unsigned char>&) -> void;
static auto processBatteryServiceCharacteristics(GList*, const std::string&, const std::string&,
const std::string&,
std::optional<unsigned char>&,
std::optional<unsigned char>&) -> void;
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
+46 -10
View File
@@ -1,36 +1,64 @@
#pragma once
#include <epoxy/gl.h>
#include <gtkmm/glarea.h>
#include <map>
#include <string>
#include <array>
#include <sigc++/connection.h>
#include "AModule.hpp"
#include "cava_backend.hpp"
namespace waybar::modules::cava {
class CavaGLSL final : public AModule, public Gtk::GLArea {
class CavaGLSL final : public AModule {
public:
CavaGLSL(const std::string&, const Json::Value&);
~CavaGLSL() = default;
~CavaGLSL();
auto doAction(const std::string& name) -> void override;
private:
using Action = void (CavaGLSL::*)();
Gtk::GLArea gl_area_;
std::shared_ptr<CavaBackend> backend_;
struct ::cava::config_params prm_;
int frame_counter{0};
// Cached config params (deep-copied strings to avoid dangling char* on backend reload)
int sdl_width_{0};
int sdl_height_{0};
int bar_width_{0};
int bar_spacing_{0};
int gradient_count_{0};
std::string vertex_shader_;
std::string fragment_shader_;
std::string bcolor_;
std::string color_;
std::array<std::string, 8> gradient_colors_;
int frame_counter_{0};
bool silence_{false};
bool hide_on_silence_{false};
bool mapped_{false};
// Cava method
auto onUpdate(const ::cava::audio_raw& input) -> void;
void pauseResume();
auto onUpdate(const CavaBackend::AudioRaw& input) -> void;
auto onSilence() -> void;
// Member variable to store the shared pointer
std::shared_ptr<::cava::audio_raw> m_data_;
GLuint shaderProgram_;
auto onBackendConfigChanged() -> void;
void cacheConfigParams(const ::cava::config_params& src);
// Member variable to store audio data
CavaBackend::AudioRaw m_data_;
GLuint shaderProgram_{0};
// OpenGL variables
GLuint fbo_;
GLuint texture_;
GLuint fbo_{0};
GLuint texture_{0};
GLuint vbo_{0};
GLuint ibo_{0};
GLuint vao_{0};
GLint uniform_bars_;
GLint uniform_previous_bars_;
GLint uniform_bars_count_;
GLint uniform_time_;
GLint uniform_input_texture_;
// Methods
void onRealize();
bool onRender(const Glib::RefPtr<Gdk::GLContext>& context);
@@ -39,5 +67,13 @@ class CavaGLSL final : public AModule, public Gtk::GLArea {
void initSurface();
void initGLSL();
GLuint loadShader(const std::string& fileName, GLenum type);
void cleanupGL();
// ModuleActionMap
static const std::map<std::string, Action> actionMap_;
sigc::connection audio_raw_update_conn_;
sigc::connection silence_conn_;
sigc::connection config_changed_conn_;
};
} // namespace waybar::modules::cava
+17 -9
View File
@@ -1,30 +1,38 @@
#pragma once
#include <map>
#include <string>
#include <sigc++/connection.h>
#include "ALabel.hpp"
#include "cava_backend.hpp"
namespace waybar::modules::cava {
class Cava final : public ALabel, public sigc::trackable {
class CavaRaw final : public ALabel {
public:
Cava(const std::string&, const Json::Value&);
~Cava() = default;
CavaRaw(const std::string&, const Json::Value&);
~CavaRaw();
auto doAction(const std::string& name) -> void override;
private:
using Action = void (CavaRaw::*)();
std::shared_ptr<CavaBackend> backend_;
// Text to display
Glib::ustring label_text_{""};
Glib::ustring label_text_;
bool silence_{false};
bool hide_on_silence_{false};
std::string format_silent_{""};
int ascii_range_{0};
std::string format_silent_;
// Cava method
void pause_resume();
void pauseResume();
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}};
static const std::map<std::string, Action> actionMap_;
sigc::connection update_conn_;
sigc::connection silence_conn_;
};
} // namespace waybar::modules::cava
+90 -21
View File
@@ -1,8 +1,17 @@
#pragma once
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include <json/json.h>
#include <sigc++/sigc++.h>
#include "util/SafeSignal.hpp"
#include "util/sleeper_thread.hpp"
namespace cava {
@@ -21,7 +30,6 @@ extern "C" {
} // namespace cava
namespace waybar::modules::cava {
using namespace std::literals::chrono_literals;
class CavaBackend final {
public:
@@ -29,19 +37,38 @@ class CavaBackend final {
virtual ~CavaBackend();
// Methods
int getAsciiRange();
int getAsciiRange() const;
void doPauseResume();
void Update();
const struct ::cava::config_params* getPrm();
std::chrono::milliseconds getFrameTimeMilsec();
void update();
const ::cava::config_params& getPrm() const;
std::chrono::milliseconds getFrameTimeMilsec() const;
struct AudioRaw {
std::vector<float> bars_raw;
std::vector<float> previous_bars_raw;
int number_of_bars = 0;
AudioRaw() = default;
explicit AudioRaw(const ::cava::audio_raw& raw) {
number_of_bars = raw.number_of_bars;
if (raw.bars_raw != nullptr && number_of_bars > 0) {
bars_raw.assign(raw.bars_raw, raw.bars_raw + number_of_bars);
}
if (raw.previous_bars_raw != nullptr && number_of_bars > 0) {
previous_bars_raw.assign(raw.previous_bars_raw, raw.previous_bars_raw + number_of_bars);
}
}
};
// Signal accessor
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();
using SignalUpdate = SafeSignal<const std::string&>;
SignalUpdate& signalUpdate();
using SignalAudioRawUpdate = SafeSignal<AudioRaw>;
SignalAudioRawUpdate& signalAudioRawUpdate();
using SignalSilence = SafeSignal<>;
SignalSilence& signalSilence();
using SignalConfigChanged = SafeSignal<>;
SignalConfigChanged& signalConfigChanged();
private:
CavaBackend(const Json::Value& config);
@@ -49,36 +76,78 @@ class CavaBackend final {
util::SleeperThread out_thread_;
// Cava API to read audio source
::cava::ptr input_source_{NULL};
::cava::ptr input_source_{nullptr};
struct ::cava::error_s error_{}; // cava errors
struct ::cava::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{}};
struct ::cava::cava_plan* plan_{nullptr}; //{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_;
struct AdaptiveDelay {
std::chrono::milliseconds delay;
std::chrono::seconds delta{0};
explicit AdaptiveDelay(std::chrono::milliseconds initial = std::chrono::seconds(1))
: delay(initial) {}
bool increase() {
if (delta == std::chrono::seconds{0}) {
delta += std::chrono::seconds{1};
delay += delta;
return true;
}
return false;
}
bool decrease() {
if (delta > std::chrono::seconds{0}) {
delay -= delta;
delta -= std::chrono::seconds{1};
return true;
}
return false;
}
std::chrono::milliseconds current() const { return delay; }
void reset(std::chrono::milliseconds new_delay) {
delay = new_delay;
delta = std::chrono::seconds{0};
}
};
AdaptiveDelay adaptive_delay_;
Json::Value config_;
int re_paint_{0};
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();
bool isSilent();
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_;
SignalUpdate m_signal_update_;
SignalAudioRawUpdate m_signal_audio_raw_;
SignalSilence m_signal_silence_;
SignalConfigChanged m_signal_config_changed_;
std::atomic<bool> shutdown_{false};
bool audio_raw_initialized_{false};
mutable std::recursive_mutex state_mutex_;
// Synchronization for joining read_thread_ during destruction
bool read_thread_exited_{false};
mutable std::mutex read_thread_exit_mutex_;
std::condition_variable read_thread_exit_cv_;
};
} // namespace waybar::modules::cava
+6 -4
View File
@@ -1,5 +1,7 @@
#pragma once
#include <memory>
#ifdef HAVE_LIBCAVA
#include "cavaRaw.hpp"
#include "cava_backend.hpp"
@@ -9,16 +11,16 @@
#endif
namespace waybar::modules::cava {
AModule* getModule(const std::string& id, const Json::Value& config) {
inline std::unique_ptr<AModule> getModule(const std::string& id, const Json::Value& config) {
#ifdef HAVE_LIBCAVA
const std::shared_ptr<CavaBackend> backend_{waybar::modules::cava::CavaBackend::inst(config)};
switch (backend_->getPrm()->output) {
switch (backend_->getPrm().output) {
#ifdef HAVE_LIBCAVAGLSL
case ::cava::output_method::OUTPUT_SDL_GLSL:
return new waybar::modules::cava::CavaGLSL(id, config);
return std::make_unique<waybar::modules::cava::CavaGLSL>(id, config);
#endif
default:
return new waybar::modules::cava::Cava(id, config);
return std::make_unique<waybar::modules::cava::CavaRaw>(id, config);
}
#else
throw std::runtime_error("Unknown module");
+6
View File
@@ -12,6 +12,7 @@ const std::string kOrdPlaceholder{"ordinal_date"};
enum class CldMode { MONTH, YEAR };
enum class WS { LEFT, RIGHT, HIDDEN };
enum class WeekNumbering { LOCALE, ISO, MONDAY, SUNDAY };
class Clock final : public ALabel {
public:
@@ -51,6 +52,7 @@ class Clock final : public ALabel {
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
WeekNumbering weekNumbering_{WeekNumbering::LOCALE}; // week number calculation method
CldMode cldMode_{CldMode::MONTH};
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd,
const date::time_zone* tz) -> const std::string;
@@ -80,6 +82,7 @@ class Clock final : public ALabel {
void cldShift_reset();
void tz_up();
void tz_down();
void action_exec(const std::string& action);
// Module Action Map
static inline std::map<const std::string, void (waybar::modules::Clock::* const)()> actionMap_{
{"mode", &waybar::modules::Clock::cldModeSwitch},
@@ -88,6 +91,9 @@ class Clock final : public ALabel {
{"shift_reset", &waybar::modules::Clock::cldShift_reset},
{"tz_up", &waybar::modules::Clock::tz_up},
{"tz_down", &waybar::modules::Clock::tz_down}};
static inline std::map<const std::string,
void (waybar::modules::Clock::* const)(const std::string& action)>
actionWithArgsMap_{{"exec", &waybar::modules::Clock::action_exec}};
};
} // namespace waybar::modules
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <fmt/format.h>
#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>
#include "AGraph.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class CpuGraph : public AGraph {
public:
CpuGraph(const std::string&, const Json::Value&);
virtual ~CpuGraph() = default;
auto update() -> void override;
private:
static constexpr const char* MODERATE_CLASS = "cpu-moderate";
static constexpr const char* HIGH_CLASS = "cpu-high";
static constexpr const char* INTENSIVE_CLASS = "cpu-intensive";
std::vector<std::tuple<size_t, size_t>> prev_times_;
util::SleeperThread thread_;
};
} // namespace waybar::modules
+12 -4
View File
@@ -3,16 +3,18 @@
#include <fmt/format.h>
#include <csignal>
#include <memory>
#include <string>
#include "ALabel.hpp"
#include "AIconLabel.hpp"
#include "util/command.hpp"
#include "util/command_line_stream.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class Custom : public ALabel {
class Custom : public AIconLabel {
public:
Custom(const std::string&, const std::string&, const Json::Value&, const std::string&);
virtual ~Custom();
@@ -22,6 +24,9 @@ class Custom : public ALabel {
private:
void delayWorker();
void continuousWorker();
void startContinuousProcess(bool throw_on_failure);
void handleContinuousProcessExit(int exit_code);
void scheduleContinuousRestart();
void waitingWorker();
void parseOutputRaw();
void parseOutputJson();
@@ -36,13 +41,16 @@ class Custom : public ALabel {
std::string alt_;
std::string tooltip_;
std::string last_tooltip_markup_;
std::string image_path_;
std::string image_name_;
unsigned app_icon_size_{24};
const bool tooltip_format_enabled_;
std::vector<std::string> class_;
int percentage_;
FILE* fp_;
int pid_;
util::command::res output_;
util::JsonParser parser_;
std::unique_ptr<util::command::LineStream> continuous_stream_;
sigc::connection restart_connection_;
util::SleeperThread thread_;
};
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include <fmt/format.h>
#include <csignal>
#include <string>
#include "AGraph.hpp"
#include "util/command.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class CustomGraph : public AGraph {
public:
CustomGraph(const std::string&, const std::string&, const Json::Value&, const std::string&);
virtual ~CustomGraph();
auto update() -> void override;
void refresh(int /*signal*/) override;
private:
void delayWorker();
void continuousWorker();
void waitingWorker();
void parseOutputRaw();
void parseOutputJson();
void handleEvent();
bool handleScroll(GdkEventScroll* e) override;
bool handleToggle(GdkEventButton* const& e) override;
const std::string name_;
const std::string output_name_;
std::string text_;
std::string id_;
std::string alt_;
std::string tooltip_;
const bool tooltip_format_enabled_;
std::vector<std::string> class_;
int percentage_;
FILE* fp_;
int pid_;
util::command::res output_;
util::JsonParser parser_;
util::SleeperThread thread_;
};
} // namespace waybar::modules
+4 -1
View File
@@ -4,6 +4,7 @@
#include <sys/statvfs.h>
#include <fstream>
#include <vector>
#include "ALabel.hpp"
#include "util/format.hpp"
@@ -19,7 +20,9 @@ class Disk : public ALabel {
private:
util::SleeperThread thread_;
std::string path_;
std::string header_;
std::vector<std::string> paths_;
std::string separator_;
std::string unit_;
float calc_specific_divisor(const std::string& divisor);
+3
View File
@@ -21,6 +21,8 @@ class Tags : public waybar::AModule {
void handle_primary_clicked(uint32_t tag);
bool handle_button_press(GdkEventButton* event_button, uint32_t tag);
void handle_active_output(zdwl_ipc_output_v2* zdwl_output_v2, uint32_t active);
struct zdwl_ipc_manager_v2* status_manager_;
struct wl_seat* seat_;
@@ -28,6 +30,7 @@ class Tags : public waybar::AModule {
const waybar::Bar& bar_;
Gtk::Box box_;
std::vector<Gtk::Button> buttons_;
bool hide_vacant_;
struct zdwl_ipc_output_v2* output_status_;
};
+4
View File
@@ -19,6 +19,7 @@ class Window : public AAppIconLabel, public sigc::trackable {
void handle_layout(const uint32_t layout);
void handle_title(const char* title);
void handle_appid(const char* ppid);
void handle_active(const uint32_t active);
void handle_layout_symbol(const char* layout_symbol);
void handle_frame();
@@ -30,6 +31,9 @@ class Window : public AAppIconLabel, public sigc::trackable {
std::string title_;
std::string appid_;
std::string layout_symbol_;
bool active_;
bool hide_inactive_;
bool hide_empty_;
uint32_t layout_;
struct zdwl_ipc_output_v2* output_status_;
+1
View File
@@ -37,6 +37,7 @@ class Language : public waybar::ALabel, public EventHandler {
util::JsonParser parser_;
Layout layout_;
std::string prev_short_name_; // applied CSS class; touched only in update() (#4665)
IPC& m_ipc;
};
+2
View File
@@ -26,9 +26,11 @@ class Submap : public waybar::ALabel, public EventHandler {
const Bar& bar_;
util::JsonParser parser_;
std::string submap_;
std::string icon_;
std::string prev_submap_;
bool always_on_ = false;
std::string default_submap_ = "Default";
std::unordered_map<std::string, std::string> icons_;
IPC& m_ipc;
};
+16 -2
View File
@@ -30,7 +30,8 @@ class Workspace {
public:
explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
const Json::Value& clients_data = Json::Value::nullRef);
std::string& selectIcon(std::map<std::string, std::string>& icons_map);
~Workspace();
std::string& selectString(std::map<std::string, std::string>& string_map);
Gtk::Button& button() { return m_button; };
int id() const { return m_id; };
@@ -45,12 +46,22 @@ class Workspace {
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; };
void setUrgent(bool value = true) { m_isUrgent = value; };
void setVisible(bool value = true) { m_isVisible = value; };
void setWindows(uint value) { m_windows = value; };
void setId(int value) { m_id = value; };
void setName(std::string const& value) { m_name = value; };
void setOutput(std::string const& value) { m_output = value; };
bool containsWindow(WindowAddress const& addr) const {
@@ -64,13 +75,14 @@ class Workspace {
bool onWindowOpened(WindowCreationPayload const& create_window_payload);
std::optional<WindowRepr> closeWindow(WindowAddress const& addr);
void update(const std::string& workspace_icon);
void update(const std::string& workspace_icon, const std::string& workspace_tooltip);
private:
Workspaces& m_workspaceManager;
int m_id;
std::string m_name;
std::string m_prevNameClass;
std::string m_output;
uint m_windows;
bool m_isActive = false;
@@ -80,6 +92,8 @@ class Workspace {
bool m_isUrgent = false;
bool m_isVisible = false;
sigc::connection m_hoverCheckConnection;
std::vector<WindowRepr> m_windowMap;
Gtk::Button m_button;
+27 -8
View File
@@ -39,9 +39,11 @@ class Workspaces : public AModule, public EventHandler {
auto allOutputs() const -> bool { return m_allOutputs; }
auto showSpecial() const -> bool { return m_showSpecial; }
auto activeOnly() const -> bool { return m_activeOnly; }
auto hideActive() const -> bool { return m_hideActive; }
auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; }
auto persistentOnly() const -> bool { return m_persistentOnly; }
auto moveToMonitor() const -> bool { return m_moveToMonitor; }
auto uniqueIcons() const -> bool { return m_uniqueIcons; }
auto enableTaskbar() const -> bool { return m_enableTaskbar; }
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
auto barScroll() const -> bool { return m_barScroll; }
@@ -52,16 +54,20 @@ class Workspaces : public AModule, public EventHandler {
auto taskbarFormatBefore() const -> std::string { return m_taskbarFormatBefore; }
auto taskbarFormatAfter() const -> std::string { return m_taskbarFormatAfter; }
auto taskbarIconSize() const -> int { return m_taskbarIconSize; }
auto taskbarMaxIcons() const -> int { return m_taskbarMaxIcons; }
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; }
auto maxWindows() const -> int { return m_maxWindows; }
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; }
auto windowRewriteGroupThreshold() const -> int { return m_windowRewriteGroupThreshold; }
auto const& getWindowRewriteGroupFormat() const { return m_windowRewriteGroupFormat; }
bool isWorkspaceIgnored(std::string const& workspace_name);
bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; }
@@ -89,6 +95,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 populateMaxWindowsConfig(const Json::Value& config) -> void;
auto populateWorkspaceTaskbarConfig(const Json::Value& config) -> void;
void registerIpc();
@@ -101,6 +108,7 @@ class Workspaces : public AModule, public EventHandler {
Json::Value const& clientsData = Json::Value::nullRef);
void onWorkspaceMoved(std::string const& payload);
void onWorkspaceRenamed(std::string const& payload);
void onWorkspaceIdChanged(std::string const& payload);
static std::optional<int> parseWorkspaceId(std::string const& workspaceIdStr);
// monitor events
@@ -146,9 +154,11 @@ class Workspaces : public AModule, public EventHandler {
bool m_allOutputs = false;
bool m_showSpecial = false;
bool m_activeOnly = false;
bool m_hideActive = false;
bool m_specialVisibleOnly = false;
bool m_persistentOnly = false;
bool m_moveToMonitor = false;
bool m_uniqueIcons = false;
bool m_barScroll = false;
Json::Value m_persistentWorkspaceConfig;
@@ -158,21 +168,25 @@ class Workspaces : public AModule, public EventHandler {
std::map<WindowAddress, WindowRepr, std::less<>> m_orphanWindowMap;
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}};
static inline const 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_formatBefore;
std::string m_formatAfter;
std::map<std::string, std::string> m_iconsMap;
std::map<std::string, std::string> m_tooltipMap;
bool m_withTooltip = false;
util::RegexCollection m_windowRewriteRules;
bool m_anyWindowRewriteRuleUsesTitle = false;
std::string m_formatWindowSeparator;
int m_windowRewriteGroupThreshold = 0;
std::string m_windowRewriteGroupFormat = "{icon}×{count}";
bool m_withIcon;
uint64_t m_monitorId;
@@ -191,17 +205,18 @@ class Workspaces : public AModule, public EventHandler {
std::string m_taskbarFormatBefore;
std::string m_taskbarFormatAfter;
int m_taskbarIconSize = 16;
int m_taskbarMaxIcons = 0; // 0 means unlimited
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 = {
static inline std::map<std::string, ActiveWindowPosition> m_activeWindowPositionMap = {
{"NONE", ActiveWindowPosition::NONE},
{"FIRST", ActiveWindowPosition::FIRST},
{"LAST", ActiveWindowPosition::LAST},
};
std::string m_onClickWindow;
std::string m_currentActiveWindowAddress;
int m_maxWindows = 0;
std::vector<std::regex> m_ignoreWorkspaces;
std::vector<std::regex> m_ignoreWindows;
@@ -211,6 +226,10 @@ class Workspaces : public AModule, public EventHandler {
Gtk::Box m_box;
sigc::connection m_scrollEventConnection_;
IPC& m_ipc;
// Coalesces bursts of Hyprland events into a single UI refresh. Armed and
// disconnected only on the GTK main thread (see Workspaces::update).
sigc::connection m_debounceTimer;
};
} // namespace waybar::modules::hyprland
+18 -1
View File
@@ -6,25 +6,42 @@
#include "bar.hpp"
#include "client.hpp"
struct ext_idle_notification_v1;
namespace waybar::modules {
class IdleInhibitor : public ALabel {
sigc::connection timeout_;
ext_idle_notification_v1* idle_notification_;
uint32_t idle_timeout_ms_;
public:
IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~IdleInhibitor();
auto update() -> void override;
auto refresh(int) -> void override;
static std::list<waybar::AModule*> modules;
static bool status;
static long deactivationTime;
private:
bool handleToggle(GdkEventButton* const& e) override;
void toggleStatus();
bool handleScroll(GdkEventScroll* e) override;
void toggleStatus(int force_status = -1);
void setupIdleNotification();
void teardownIdleNotification();
static void handleIdled(void* data, ext_idle_notification_v1* notification);
static void handleResumed(void* data, ext_idle_notification_v1* notification);
const Bar& bar_;
struct zwp_idle_inhibitor_v1* idle_inhibitor_;
int pid_;
bool dynamicTimeout = false;
double timeout;
double timeout_step;
bool wait_for_activity_;
};
} // namespace waybar::modules
+66 -8
View File
@@ -14,6 +14,69 @@
namespace waybar::modules {
namespace image {
class IStrategy {
public:
virtual ~IStrategy() = default;
// Runs on the worker thread before update(). Use it for blocking work (e.g.
// spawning a user script) so the GTK main loop isn't stalled. Default no-op.
virtual void fetch() {}
virtual void update() = 0;
};
class SingleImageStrategy : public IStrategy {
public:
SingleImageStrategy(const std::string&, const Json::Value&, const std::string&, Gtk::EventBox&,
bool);
~SingleImageStrategy() override = default;
void update() override;
private:
void parseOutputRaw();
util::command::res output_;
Json::Value config_;
Gtk::Image image_;
std::string path_;
std::string tooltip_;
int size_;
Gtk::Box box_;
bool hasTooltip_;
};
class MultipleImageStrategy : public IStrategy {
public:
MultipleImageStrategy(const std::string&, const Json::Value&, const std::string&, Gtk::EventBox&);
~MultipleImageStrategy() override = default;
void fetch() override;
void update() override;
private:
struct ImageData {
std::string path;
std::string marker;
std::string tooltip;
std::string on_click;
std::shared_ptr<Gtk::Image> img;
std::shared_ptr<Gtk::Button> btn;
};
void setImagesData(const Json::Value&);
void setupAndDraw();
void resetBoxAndMemory();
void handleClick(const Glib::ustring& data);
Json::Value config_;
int size_;
Gtk::Box box_;
std::vector<ImageData> images_data_;
// stdout captured by fetch() on the worker thread and consumed by update()
std::string exec_output_;
};
} // namespace image
class Image : public AModule {
public:
Image(const std::string&, const Json::Value&);
@@ -24,16 +87,11 @@ class Image : public AModule {
private:
void delayWorker();
void handleEvent();
void parseOutputRaw();
static std::unique_ptr<image::IStrategy> getStrategy(const std::string&, const Json::Value&,
const std::string&, Gtk::EventBox&, bool);
Gtk::Box box_;
Gtk::Image image_;
std::string path_;
std::string tooltip_;
int size_;
std::chrono::milliseconds interval_;
util::command::res output_;
std::unique_ptr<image::IStrategy> strategy_;
util::SleeperThread thread_;
};
+1 -2
View File
@@ -36,8 +36,7 @@ class KeyboardState : public AModule {
std::string capslock_format_;
std::string scrolllock_format_;
const std::chrono::seconds interval_;
std::string icon_locked_;
std::string icon_unlocked_;
std::unordered_map<std::string, std::vector<std::string>> key_icon_states_;
std::string devices_path_;
struct libinput* libinput_;
+69
View File
@@ -0,0 +1,69 @@
// include/modules/mango/backend.hpp
#pragma once
#include <atomic>
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
#include "util/json.hpp"
namespace waybar::modules::mango {
class EventHandler {
public:
virtual void onEvent(const Json::Value& ev) = 0;
virtual ~EventHandler() = default;
};
class IPC {
public:
static IPC& getInstance();
IPC(const IPC&) = delete;
IPC& operator=(const IPC&) = delete;
void registerForIPC(const std::string& ev, EventHandler* handler);
void unregisterForIPC(EventHandler* handler);
static Json::Value send(const Json::Value& request);
static void sendAsync(const Json::Value& request);
std::unique_lock<std::mutex> lockData() { return std::unique_lock<std::mutex>(data_mutex_); }
std::unordered_map<std::string, Json::Value> getMonitors() const;
Json::Value getMonitor(const std::string& name);
Json::Value getActiveClientForMonitor(const std::string& name) const;
std::string getKeyboardLayout() const;
std::string getKeymode() const;
std::string getLayoutSymbolForMonitor(const std::string& name) const;
private:
IPC();
~IPC();
void startIPC();
static int connectToSocket();
void parseIPC(const std::string& line);
void handleMonitorUpdate(const Json::Value& mon);
void updateFocusingClient(const Json::Value& client);
void updateKeyboardLayout(const std::string& layout);
static Json::Value sendCommand(const std::string& cmd);
std::atomic<bool> running_ = true;
int sockfd_ = -1;
std::thread ipc_thread_;
mutable std::mutex data_mutex_;
std::unordered_map<std::string, Json::Value> monitors_;
std::unordered_map<uint64_t, Json::Value> clients_;
uint64_t focusing_client_id_ = 0;
std::string keyboard_layout_;
std::string keymode_;
Json::Value active_client_;
std::mutex callback_mutex_;
std::list<std::pair<std::string, EventHandler*>> callbacks_;
};
} // namespace waybar::modules::mango
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <mutex>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Keymode : public ALabel, public EventHandler {
public:
Keymode(const std::string&, const Bar&, const Json::Value&);
~Keymode() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
std::mutex mutex_;
const Bar& bar_;
std::string last_keymode_;
};
} // namespace waybar::modules::mango
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <xkbcommon/xkbregistry.h>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Language : public ALabel, public EventHandler {
public:
Language(const std::string&, const Bar&, const Json::Value&);
~Language() override;
void update() override;
private:
void updateFromIPC();
void onEvent(const Json::Value& ev) override;
void doUpdate();
struct Layout {
std::string full_name;
std::string short_name;
std::string variant;
std::string short_description;
};
Layout getLayout(const std::string& fullName);
std::mutex mutex_;
const Bar& bar_;
std::vector<Layout> layouts_;
unsigned current_idx_;
std::string last_short_name_;
struct rxkb_context* rxkb_ctx_ = nullptr;
};
} // namespace waybar::modules::mango
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <mutex>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Layout : public ALabel, public EventHandler {
public:
Layout(const std::string&, const Bar&, const Json::Value&);
~Layout() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
std::mutex mutex_;
const Bar& bar_;
std::string last_symbol_;
};
} // namespace waybar::modules::mango
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <gtkmm/button.h>
#include <json/value.h>
#include <mutex>
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Window : public AAppIconLabel, public EventHandler {
public:
Window(const std::string&, const Bar&, const Json::Value&);
~Window() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
void setClass(const std::string& className, bool enable);
const Bar& bar_;
std::string oldAppId_;
std::mutex mutex_;
};
} // namespace waybar::modules::mango
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <gtkmm/button.h>
#include <json/value.h>
#include <unordered_map>
#include "AModule.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Workspaces : public AModule, public EventHandler {
public:
Workspaces(const std::string&, const Bar&, const Json::Value&);
~Workspaces() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
Gtk::Button& addButton(uint64_t idx);
void updateButtonState(Gtk::Button& button, const Json::Value& tag, const Json::Value& monitor);
std::string getIcon(const std::string& value, const Json::Value& tag);
bool handleButtonClick(GdkEventButton* event, uint64_t idx, bool isOverview);
const Bar& bar_;
Gtk::Box box_;
std::unordered_map<uint64_t, Gtk::Button> buttons_;
Gtk::Button* overview_button_ = nullptr;
std::string on_click_left_;
std::string on_click_middle_;
std::string on_click_right_;
};
} // namespace waybar::modules::mango
-2
View File
@@ -19,8 +19,6 @@ class Memory : public ALabel {
private:
void parseMeminfo();
static float calc_divisor(const std::string& divisor);
std::unordered_map<std::string, unsigned long> meminfo_;
util::SleeperThread thread_;
+8 -1
View File
@@ -28,11 +28,14 @@ class MPD : public ALabel {
unsigned timeout_;
unsigned playing_interval_;
detail::unique_connection connection_;
detail::unique_status status_;
mpd_state state_;
detail::unique_song song_;
std::string ellipsis_;
public:
MPD(const std::string&, const Json::Value&);
@@ -45,6 +48,10 @@ class MPD : public ALabel {
void setLabel();
std::string getStateIcon() 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,11 +61,11 @@ 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; }
inline bool paused() const { return connection_ && state_ == MPD_STATE_PAUSE; }
inline unsigned playing_interval() const { return playing_interval_; }
};
#if !defined(MPD_NOINLINE)
+5 -1
View File
@@ -82,6 +82,7 @@ class Idle : public State {
class Playing : public State {
Context* const ctx_;
sigc::connection timer_connection_;
sigc::connection idle_connection_;
public:
Playing(Context* const ctx) : ctx_{ctx} {}
@@ -98,7 +99,10 @@ class Playing : public State {
Playing(Playing const&) = delete;
Playing& operator=(Playing const&) = delete;
void timer() noexcept;
void idle() noexcept;
bool on_timer();
bool on_io(Glib::IOCondition const&);
};
class Paused : public State {
@@ -194,10 +198,10 @@ class Context {
bool is_paused() const;
bool is_stopped() const;
constexpr std::size_t interval() const;
unsigned playing_interval() const;
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;
+3 -2
View File
@@ -1,13 +1,15 @@
#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 unsigned Context::playing_interval() const { return mpd_module_->playing_interval(); }
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 +17,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(); }
+3
View File
@@ -38,6 +38,7 @@ class Mpris : public ALabel {
std::optional<std::string> artist;
std::optional<std::string> album;
std::optional<std::string> album_artist;
std::optional<std::string> title;
std::optional<std::string> length; // as HH:MM:SS
std::optional<std::string> position; // same format
@@ -76,6 +77,8 @@ class Mpris : public ALabel {
std::string player_;
std::vector<std::string> ignored_players_;
bool prefer_album_artist_;
PlayerctlPlayerManager* manager;
PlayerctlPlayer* player;
PlayerctlPlayer* last_active_player_ = nullptr;
+9
View File
@@ -17,6 +17,8 @@
#include "util/rfkill.hpp"
#endif
#define ETH_ALEN 6
enum ip_addr_pref : uint8_t { IPV4, IPV6, IPV4_6 };
namespace waybar::modules {
@@ -34,6 +36,7 @@ class Network : public ALabel {
static int handleEvents(struct nl_msg*, void*);
static int handleEventsDone(struct nl_msg*, void*);
static int handleScan(struct nl_msg*, void*);
static int handleStationGet(struct nl_msg *msg, void *data);
void askForStateDump(void);
@@ -48,15 +51,18 @@ class Network : public ALabel {
bool matchInterface(const std::string& ifname, const std::vector<std::string>& altnames,
std::string& matched) const;
auto getInfo() -> void;
bool isWireless() const;
const std::string getNetworkState() const;
void clearIface();
std::optional<std::pair<unsigned long long, unsigned long long>> readBandwidthUsage();
uint32_t readLinkSpeed() const;
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};
struct nl_sock* station_sock_{nullptr};
int efd_{-1};
int ev_fd_{-1};
int nl80211_id_{-1};
@@ -90,6 +96,7 @@ class Network : public ALabel {
uint8_t signal_strength_;
std::string signal_strength_app_;
uint32_t route_priority;
uint32_t link_speed_{0};
util::SleeperThread thread_;
util::SleeperThread thread_timer_;
@@ -97,6 +104,8 @@ class Network : public ALabel {
util::Rfkill rfkill_{RFKILL_TYPE_WLAN};
#endif
float frequency_{0};
uint32_t tx_bitrate_{0};
uint32_t rx_bitrate_{0};
};
} // namespace waybar::modules
+5 -1
View File
@@ -1,5 +1,6 @@
#pragma once
#include <atomic>
#include <list>
#include <mutex>
#include <string>
@@ -18,6 +19,7 @@ class EventHandler {
class IPC {
public:
IPC();
~IPC();
void registerForIPC(const std::string& ev, EventHandler* ev_handler);
void unregisterForIPC(EventHandler* handler);
@@ -32,7 +34,7 @@ class IPC {
unsigned keyboardLayoutCurrent() const { return keyboardLayoutCurrent_; }
private:
void startIPC();
void startIPC(int initial_socketfd);
static int connectToSocket();
void parseIPC(const std::string&);
@@ -45,6 +47,8 @@ class IPC {
util::JsonParser parser_;
std::mutex callbackMutex_;
std::list<std::pair<std::string, EventHandler*>> callbacks_;
std::atomic<bool> running_{true};
};
inline std::unique_ptr<IPC> gIPC;
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#include <gtkmm/box.h>
#include <gtkmm/button.h>
#include <gtkmm/image.h>
#include <gtkmm/label.h>
#include <json/value.h>
#include <string>
namespace waybar::modules::niri {
class Workspaces;
class Workspace {
public:
Workspace(const Json::Value& workspace_data, Workspaces& manager);
~Workspace() = default;
Workspace(const Workspace&) = delete;
Workspace& operator=(const Workspace&) = delete;
Gtk::Button& button() { return button_; }
uint64_t id() const { return id_; }
void update(const Json::Value& workspace_data, const std::vector<Json::Value>& all_windows,
const std::string& windows_str, std::size_t total);
private:
void rebuildTaskbar(const std::vector<Json::Value>& my_windows);
Glib::RefPtr<Gdk::Pixbuf> loadIcon(const std::string& app_id, int size);
Workspaces& manager_;
uint64_t id_;
// Layout: button_
// └─ box_ (horizontal)
// ├─ label_ workspace label / icon
// └─ taskbar_box_ app icon buttons (shown only when taskbar enabled)
Gtk::Button button_;
Gtk::Box box_;
Gtk::Label label_;
Gtk::Box taskbar_box_;
};
} // namespace waybar::modules::niri
+38 -6
View File
@@ -1,30 +1,62 @@
#pragma once
#include <gtkmm/button.h>
#include <gtkmm/box.h>
#include <json/value.h>
#include <memory>
#include <regex>
#include <vector>
#include "AModule.hpp"
#include "bar.hpp"
#include "modules/niri/backend.hpp"
#include "modules/niri/workspace.hpp"
#include "util/regex_collection.hpp" // Added for rewrite rules
namespace waybar::modules::niri {
class Workspaces : public AModule, public EventHandler {
public:
Workspaces(const std::string&, const Bar&, const Json::Value&);
Workspaces(const std::string& id, const Bar& bar, const Json::Value& config);
~Workspaces() override;
void update() override;
const Json::Value& config() const { return config_; }
const Bar& bar() const { return bar_; }
std::string getIcon(const std::string& value, const Json::Value& ws) const;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
Gtk::Button& addButton(const Json::Value& ws);
std::string getIcon(const std::string& value, const Json::Value& ws);
void createWorkspace(const Json::Value& workspace_data);
void sortWorkspaces(std::vector<const Json::Value*>& workspaces) const;
bool isWorkspaceIgnored(const std::string& name);
bool handleScroll(GdkEventScroll* /*unused*/) override;
// Added for window rewrite
void populateWindowRewriteConfig();
void populateFormatWindowSeparatorConfig();
std::string getRewrite(const std::string& app_id, const std::string& title);
std::string getWindowsRepresentation(const Json::Value& ws);
const Bar& bar_;
Gtk::Box box_;
// Map from niri workspace id to button.
std::unordered_map<uint64_t, Gtk::Button> buttons_;
std::vector<std::unique_ptr<Workspace>> workspaces_;
// Vec of regex rules to ignore workspaces.
std::vector<std::regex> ignoreWorkspaces_;
bool sort_by_id_ = false;
bool sort_by_name_ = false;
bool sort_by_coordinates_ = false;
// Added for window rewrite
util::RegexCollection m_windowRewriteRules;
std::string m_windowRewriteDefault;
std::string m_formatWindowSeparator;
};
} // namespace waybar::modules::niri
+10 -1
View File
@@ -9,9 +9,18 @@ namespace waybar::modules {
struct Profile {
std::string name;
// Legacy driver field, kept for backward compatibility with the
// `{driver}` format placeholder and with older power-profiles-daemon
// versions that only expose a single `Driver` DBus property.
std::string driver;
std::string cpuDriver;
std::string platformDriver;
Profile(std::string n, std::string d) : name(std::move(n)), driver(std::move(d)) {}
Profile(std::string n, std::string d, std::string cd, std::string pd)
: name(std::move(n)),
driver(std::move(d)),
cpuDriver(std::move(cd)),
platformDriver(std::move(pd)) {}
};
class PowerProfilesDaemon : public ALabel {
+17 -7
View File
@@ -1,40 +1,50 @@
#pragma once
#include <atomic>
#include <string>
#include "gtkmm/box.h"
#include "modules/privacy/privacy_item.hpp"
#include "util/geoclue_backend.hpp"
#include "util/pipewire/pipewire_backend.hpp"
#include "util/pipewire/privacy_node_info.hpp"
using waybar::util::PipewireBackend::PrivacyNodeInfo;
using waybar::util::PipewireBackend::PrivacyNodeType;
using waybar::util::PipewireBackend::PWPrivacyNodeInfo;
namespace waybar::modules::privacy {
class Privacy : public AModule {
public:
Privacy(const std::string&, const Json::Value&, Gtk::Orientation, const std::string& pos);
~Privacy() override;
auto update() -> void override;
void onPrivacyNodesChanged();
private:
std::list<PrivacyNodeInfo*> nodes_screenshare; // Screen is being shared
std::list<PrivacyNodeInfo*> nodes_audio_in; // Application is using the microphone
std::list<PrivacyNodeInfo*> nodes_audio_out; // Application is outputting audio
std::list<PWPrivacyNodeInfo*> nodes_screenshare; // Screen is being shared
std::list<PWPrivacyNodeInfo*> nodes_audio_in; // Application is using the microphone
std::list<PWPrivacyNodeInfo*> nodes_audio_out; // Application is outputting audio
std::atomic<bool> location_in_use; // GeoClue is being used
std::mutex mutex_;
sigc::connection visibility_conn;
sigc::connection geoclue_timeout_conn;
// 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;
std::shared_ptr<util::PipewireBackend::PipewireBackend> pw_backend = nullptr;
std::shared_ptr<util::GeoClueBackend::GeoClueBackend> geoclue_backend = nullptr;
void onPWPrivacyNodesChanged();
bool locationTimeout(bool in_use);
void onGeoCluePrivacyNodesChanged();
};
} // namespace waybar::modules::privacy
+35 -10
View File
@@ -9,35 +9,36 @@
#include "gtkmm/revealer.h"
#include "util/pipewire/privacy_node_info.hpp"
using waybar::util::PipewireBackend::PrivacyNodeInfo;
using waybar::util::PipewireBackend::PrivacyNodeType;
using waybar::util::PipewireBackend::PWPrivacyNodeInfo;
namespace waybar::modules::privacy {
class PrivacyItem : public Gtk::Revealer {
public:
protected:
PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
std::list<PrivacyNodeInfo*>* nodes, Gtk::Orientation orientation,
const std::string& pos, const uint icon_size, const uint transition_duration);
Gtk::Orientation orientation, const std::string& pos, const uint icon_size,
const uint transition_duration);
public:
virtual void set_tooltip() = 0;
enum PrivacyNodeType privacy_type;
void set_in_use(bool in_use);
private:
std::list<PrivacyNodeInfo*>* nodes;
sigc::connection signal_conn;
uint tooltipIconSize = 24;
Gtk::Box tooltip_window;
private:
sigc::connection signal_conn;
bool init = false;
bool in_use = false;
// Config
std::string iconName = "image-missing-symbolic";
bool tooltip = true;
uint tooltipIconSize = 24;
Gtk::Box box_;
Gtk::Image icon_;
@@ -45,4 +46,28 @@ class PrivacyItem : public Gtk::Revealer {
void update_tooltip();
};
class GeoCluePrivacyItem : public PrivacyItem {
public:
GeoCluePrivacyItem(const Json::Value& config_, Gtk::Orientation orientation,
const std::string& pos, const uint icon_size, const uint transition_duration)
: PrivacyItem(config_, util::PipewireBackend::PRIVACY_NODE_TYPE_LOCATION, orientation, pos,
icon_size, transition_duration) {}
void set_tooltip() override;
};
class PWPrivacyItem : public PrivacyItem {
public:
PWPrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
std::list<PWPrivacyNodeInfo*>* nodes_, Gtk::Orientation orientation,
const std::string& pos, const uint icon_size, const uint transition_duration)
: PrivacyItem(config_, privacy_type_, orientation, pos, icon_size, transition_duration),
nodes(nodes_) {}
void set_tooltip() override;
private:
std::list<PWPrivacyNodeInfo*>* nodes;
};
} // namespace waybar::modules::privacy
+1
View File
@@ -22,6 +22,7 @@ class Pulseaudio : public ALabel {
const std::vector<std::string> getPulseIcon() const;
std::shared_ptr<util::AudioBackend> backend = nullptr;
util::PulseaudioTarget target = util::PulseaudioTarget::Sink;
};
} // namespace waybar::modules
+10 -7
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
} // namespace waybar::modules
+6 -4
View File
@@ -21,6 +21,8 @@ class Tags : public waybar::AModule {
void handle_view_tags(struct wl_array* tags);
void handle_urgent_tags(uint32_t tags);
void handle_focused_view(const char *title, uint32_t tags);
void handle_focused_output(struct wl_output* output);
void handle_unfocused_output(struct wl_output* output);
void handle_show();
void handle_primary_clicked(uint32_t tag);
@@ -28,17 +30,17 @@ class Tags : public waybar::AModule {
struct zriver_status_manager_v1* status_manager_;
struct zriver_control_v1* control_;
struct zriver_seat_status_v1 *seat_status_;
struct wl_seat* seat_;
// used to make sure the focused view tags are on the correct output
const wl_output* output_;
const wl_output* focused_output_;
private:
const waybar::Bar& bar_;
struct wl_output* focused_output_; // stores the focused output
struct wl_output* output_; // stores the output this module belongs to
Gtk::Box box_;
std::vector<Gtk::Button> buttons_;
struct zriver_output_status_v1* output_status_;
struct zriver_seat_status_v1* seat_status_;
bool hide_vacant_ = false; // parsed once; asBool() in a wl callback would throw (#4078)
};
} /* namespace waybar::modules::river */
+21 -6
View File
@@ -14,16 +14,22 @@ namespace waybar::modules::SNI {
class Host {
public:
Host(const std::size_t id, const Json::Value&, const Bar&,
Host(std::size_t id, const Json::Value&, const Bar&, const std::vector<std::string>&,
const std::function<void(std::unique_ptr<Item>&)>&,
const std::function<void(std::unique_ptr<Item>&)>&, const std::function<void()>&);
const std::function<void(std::unique_ptr<Item>&)>&, const std::function<void()>&,
const std::function<void()>&);
~Host();
void checkIgnoreList(const std::vector<std::string>& ignore_list,
const std::function<void(std::unique_ptr<Item>&)>& on_remove);
void reorderItems();
private:
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring,
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&);
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&,
const Glib::ustring&);
void nameVanished(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
void nameVanished(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&);
static void proxyReady(GObject*, GAsyncResult*, gpointer);
static void registerHost(GObject*, GAsyncResult*, gpointer);
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
@@ -33,7 +39,7 @@ class Host {
void removeItem(std::vector<std::unique_ptr<Item>>::iterator);
void clearItems();
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
static std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string&);
void addRegisteredItem(const std::string& service);
std::vector<std::unique_ptr<Item>> items_;
@@ -43,10 +49,19 @@ 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::vector<std::string> ignore_list_;
const std::function<void(std::unique_ptr<Item>&)> on_add_;
const std::function<void(std::unique_ptr<Item>&)> on_remove_;
// Re-applies the configured ordering to the already-added tray widgets. This
// must NOT re-run the add path (which would re-parent widgets and reconnect
// signals); it only reorders existing children.
const std::function<void()> on_reorder_;
ItemOrderMap orders_;
const std::function<void()> on_update_;
};
+10 -1
View File
@@ -5,6 +5,7 @@
#include <string>
#include <unordered_map>
#include <unordered_set>
class IconManager {
public:
@@ -19,7 +20,10 @@ class IconManager {
std::string app_name = key;
const Json::Value& icon_value = icons_config[key];
if (icon_value.isString()) {
if (icon_value.isBool() && !icon_value.asBool()) {
// false value means hide this app
hidden_apps_.insert(app_name);
} else if (icon_value.isString()) {
std::string icon_path = icon_value.asString();
icons_map_[app_name] = icon_path;
}
@@ -37,7 +41,12 @@ class IconManager {
return "";
}
bool isHidden(const std::string& app_name) const {
return hidden_apps_.find(app_name) != hidden_apps_.end();
}
private:
IconManager() = default;
std::unordered_map<std::string, std::string> icons_map_;
std::unordered_set<std::string> hidden_apps_;
};
+12 -1
View File
@@ -24,11 +24,15 @@ struct ToolTip {
Glib::ustring text;
};
class Host;
using ItemOrderMap = std::unordered_map<std::string, int>;
class Item : public sigc::trackable {
public:
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()>&);
const std::function<void()>&, Host&, const ItemOrderMap&);
~Item();
bool isReady() const;
@@ -46,6 +50,7 @@ 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;
@@ -63,6 +68,7 @@ class Item : public sigc::trackable {
* while compliant SNI implementation would always reset the flag to desired value.
*/
bool item_is_menu = true;
int order_ = -1; // -1 means not set
private:
void onConfigure(GdkEventConfigure* ev);
@@ -100,6 +106,8 @@ class Item : public sigc::trackable {
gdouble distance_scrolled_y_ = 0;
// visibility of items with Status == Passive
bool show_passive_ = false;
// hidden via config
bool is_hidden_ = false;
bool ready_ = false;
Glib::ustring status_ = "active";
@@ -111,6 +119,9 @@ class Item : public sigc::trackable {
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
Glib::RefPtr<Gio::Cancellable> cancellable_;
std::set<std::string_view> update_pending_;
Host& host_;
const ItemOrderMap& orders_;
};
} // namespace waybar::modules::SNI
+15 -2
View File
@@ -1,6 +1,10 @@
#pragma once
#include <fmt/format.h>
#include <sigc++/connection.h>
#include <unordered_map>
#include <utility>
#include "AModule.hpp"
#include "bar.hpp"
@@ -13,19 +17,28 @@ namespace waybar::modules::SNI {
class Tray : public AModule {
public:
Tray(const std::string&, const Bar&, const Json::Value&);
virtual ~Tray() = default;
~Tray() override = default;
auto update() -> void override;
private:
void onAdd(std::unique_ptr<Item>& item);
void onRemove(std::unique_ptr<Item>& item);
// Reorders the already-added tray widgets by their configured order. Does not
// add or remove any widget.
void reorderBox();
void checkIgnoreList(std::unique_ptr<Item>* item);
std::vector<std::string> parseIgnoreList(const Json::Value& config);
void queueUpdate();
static inline std::size_t nb_hosts_ = 0;
bool show_passive_ = false;
Gtk::Box box_;
SNI::Watcher::singleton watcher_;
std::vector<std::string> ignore_list_;
SNI::Host host_;
std::vector<Item*> items_;
// signal_show/signal_hide connections owned per added item, so they can be
// disconnected on removal instead of leaking and accumulating.
std::unordered_map<Item*, std::pair<sigc::connection, sigc::connection>> item_connections_;
};
} // namespace waybar::modules::SNI
+15 -8
View File
@@ -1,15 +1,13 @@
#pragma once
#include <sigc++/sigc++.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <cstring>
#include <memory>
#include <atomic>
#include <cstdint>
#include <functional>
#include <mutex>
#include <stdexcept>
#include <string>
#include <vector>
#include "ipc.hpp"
#include "util/SafeSignal.hpp"
@@ -41,11 +39,20 @@ class Ipc {
static inline const std::string ipc_magic_ = "i3-ipc";
static inline const size_t ipc_header_size_ = ipc_magic_.size() + 8;
const std::string getSocketPath() const;
int open(const std::string&) const;
static std::string getSocketPath();
static int open(const std::string&);
struct ipc_response send(int fd, uint32_t type, const std::string& payload = "");
struct ipc_response recv(int fd);
// Re-establish the event socket and re-subscribe after sway drops us, backing
// off between attempts so we don't busy-loop while sway is unavailable.
void reconnectEvent();
std::string socketPath_;
std::vector<std::string> subscribed_events_;
std::atomic<bool> running_{true};
util::ScopedFd fd_;
util::ScopedFd fd_event_;
std::mutex mutex_;
+3
View File
@@ -54,6 +54,9 @@ class Language : public ALabel, public sigc::trackable {
const static std::string XKB_ACTIVE_LAYOUT_NAME_KEY;
Layout layout_;
// CSS class currently applied to label_. Tracked so update() (main thread) can swap classes
// instead of set_current_layout() mutating the widget from the IPC worker thread (#3702).
std::string applied_class_;
std::string tooltip_format_ = "";
std::map<std::string, Layout> layouts_map_;
bool hide_single_;
+7
View File
@@ -4,6 +4,7 @@
#include <gtkmm/button.h>
#include <gtkmm/label.h>
#include <optional>
#include <string_view>
#include <unordered_map>
@@ -24,12 +25,15 @@ 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(const std::string& name);
static int windowRewritePriorityFunction(std::string const& window_rule);
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
bool isWorkspaceIgnored(std::string const& name);
void onCmd(const struct Ipc::ipc_response&);
void onEvent(const struct Ipc::ipc_response&);
bool filterButtons();
@@ -41,6 +45,7 @@ class Workspaces : public AModule, public sigc::trackable {
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
uint16_t getWorkspaceIndex(const std::string& name) const;
static std::string trimWorkspaceName(const std::string&);
std::optional<uint16_t> getCustomSortIndex(const std::string& name) const;
bool handleScroll(GdkEventScroll* /*unused*/) override;
const Bar& bar_;
@@ -49,9 +54,11 @@ class Workspaces : public AModule, public sigc::trackable {
std::vector<std::string> workspaces_order_;
Gtk::Box box_;
std::string m_formatWindowSeparator;
std::vector<std::regex> m_ignoreWorkspaces;
util::RegexCollection m_windowRewriteRules;
util::JsonParser parser_;
std::unordered_map<std::string, Gtk::Button> buttons_;
std::unordered_map<std::string, uint16_t> custom_sort_priorities_;
std::mutex mutex_;
Ipc ipc_;
};
+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();
+27 -4
View File
@@ -17,6 +17,11 @@ class Wireplumber : public ALabel {
auto update() -> void override;
private:
bool setupConnection();
void teardownConnection();
void scheduleReconnect();
bool onReconnectTimeout();
static void onCoreDisconnected(waybar::modules::Wireplumber* self);
void asyncLoadRequiredApiModules();
void prepare(waybar::modules::Wireplumber* self);
void activatePlugins();
@@ -24,17 +29,25 @@ class Wireplumber : public ALabel {
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);
static void onMixerApiLoaded(WpObject* p, GAsyncResult* res, waybar::modules::Wireplumber* self);
static void onPluginActivated(WpObject* p, GAsyncResult* res, gpointer data);
static void onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res, gpointer data);
static void onMixerApiLoaded(WpObject* p, GAsyncResult* res, gpointer data);
static void onObjectManagerInstalled(waybar::modules::Wireplumber* self);
static void onMixerChanged(waybar::modules::Wireplumber* self, uint32_t id);
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
bool handleScroll(GdkEventScroll* e) override;
std::vector<std::string> getWPIcon();
static std::list<waybar::modules::Wireplumber*> modules;
// Returns true while `self` is still a live module. Async load/activation callbacks use this to
// avoid dereferencing a `self` that was destroyed before the callback fired (see #3974).
static bool isModuleAlive(waybar::modules::Wireplumber* self);
uint32_t resolvePhysicalSink(uint32_t start_id);
uint32_t findPlaybackNodeId(const gchar* description);
uint32_t get_linked_sink_id(WpObjectManager* om, uint32_t from_node_id);
uint32_t get_linked_node_from_output_ports(WpObjectManager* om, uint32_t from_node_id);
WpCore* wp_core_;
GPtrArray* apis_;
@@ -43,6 +56,10 @@ class Wireplumber : public ALabel {
WpPlugin* def_nodes_api_;
gchar* default_node_name_;
uint32_t pending_plugins_;
// Bumped on every (re)connection. The async load/activate callbacks capture the generation they
// were scheduled under (via their user_data) and no-op if it no longer matches, so a completion
// from a connection that was already torn down cannot corrupt the new generation's state (#2882).
uint32_t connection_generation_{0};
bool muted_;
double volume_;
double min_step_;
@@ -54,6 +71,12 @@ class Wireplumber : public ALabel {
bool source_muted_;
double source_volume_;
gchar* default_source_name_;
bool only_physical_;
bool resolved_physical_;
std::string form_factor_;
// Timer used to retry connecting to PipeWire after it goes away; disconnected in the destructor
// so a pending attempt can't outlive the module. See #2882.
sigc::connection reconnect_timer_;
};
} // namespace waybar::modules
+44
View File
@@ -11,6 +11,7 @@
#include <map>
#include <memory>
#include <ranges>
#include <string>
#include <unordered_set>
#include <vector>
@@ -18,6 +19,7 @@
#include "AModule.hpp"
#include "bar.hpp"
#include "client.hpp"
#include "ext-workspace-v1-client-protocol.h"
#include "giomm/desktopappinfo.h"
#include "util/icon_loader.hpp"
#include "util/json.hpp"
@@ -68,6 +70,11 @@ class Task {
Glib::RefPtr<Gio::DesktopAppInfo> app_info_;
bool button_visible_ = false;
bool ignored_ = false;
bool squashed_ = false;
/* Whether the toplevel is on this bar's output, per the protocol's
* output_enter/output_leave events */
bool on_bar_output_ = false;
bool size_allocate_connected_ = false;
bool with_icon_ = false;
bool with_name_ = false;
@@ -80,6 +87,7 @@ class Task {
std::string title_;
std::string app_id_;
uint32_t state_ = 0;
struct ext_workspace_handle_v1* workspace_ = nullptr;
int32_t drag_start_x;
int32_t drag_start_y;
@@ -91,6 +99,9 @@ class Task {
void set_minimize_hint();
void on_button_size_allocated(Gtk::Allocation& alloc);
void hide_if_ignored();
void hide_if_duplicate();
void show_button();
void hide_button();
public:
/* Getter functions */
@@ -102,6 +113,9 @@ class Task {
bool minimized() const { return state_ & MINIMIZED; }
bool active() const { return state_ & ACTIVE; }
bool fullscreen() const { return state_ & FULLSCREEN; }
bool visible() const { return button_visible_; }
struct ext_workspace_handle_v1* workspace() const { return workspace_; }
void set_workspace(struct ext_workspace_handle_v1* workspace) { workspace_ = workspace; }
public:
/* Callbacks for the wlr protocol */
@@ -142,6 +156,12 @@ using TaskPtr = std::unique_ptr<Task>;
class Taskbar : public waybar::AModule {
public:
struct WorkspaceState {
Taskbar* taskbar;
struct ext_workspace_handle_v1* handle;
uint32_t state = 0;
};
Taskbar(const std::string&, const waybar::Bar&, const Json::Value&);
~Taskbar();
void update();
@@ -153,32 +173,56 @@ class Taskbar : public waybar::AModule {
IconLoader icon_loader_;
std::unordered_set<std::string> ignore_list_;
std::unordered_set<std::string> squash_list_;
std::map<std::string, std::string> app_ids_replace_map_;
struct zwlr_foreign_toplevel_manager_v1* manager_;
struct ext_workspace_manager_v1* workspace_manager_;
struct wl_seat* seat_;
std::vector<struct ext_workspace_group_handle_v1*> workspace_groups_;
std::vector<std::unique_ptr<WorkspaceState>> workspaces_;
struct ext_workspace_handle_v1* current_workspace_ = nullptr;
public:
/* Callbacks for global registration */
void register_manager(struct wl_registry*, uint32_t name, uint32_t version);
void register_workspace_manager(struct wl_registry*, uint32_t name, uint32_t version);
void register_seat(struct wl_registry*, uint32_t name, uint32_t version);
/* Callbacks for the wlr protocol */
void handle_toplevel_create(struct zwlr_foreign_toplevel_handle_v1*);
void handle_finished();
void handle_workspace_group_create(struct ext_workspace_group_handle_v1*);
void handle_workspace_group_removed(struct ext_workspace_group_handle_v1*);
void handle_workspace_create(struct ext_workspace_handle_v1*);
void handle_workspace_done();
void handle_workspace_finished();
void handle_workspace_removed(struct ext_workspace_handle_v1*);
public:
void add_button(Gtk::Button&);
void move_button(Gtk::Button&, int);
void remove_button(Gtk::Button&);
void remove_task(uint32_t);
void assign_current_workspace(Task&);
void update_bar_css_classes();
bool show_output(struct wl_output*) const;
bool all_outputs() const;
const IconLoader& icon_loader() const;
const std::unordered_set<std::string>& ignore_list() const;
const std::unordered_set<std::string>& squash_list() const;
const std::map<std::string, std::string>& app_ids_replace_map() const;
std::size_t task_id_count(std::string_view id) const;
std::size_t task_title_count(std::string_view title) const;
auto tasks() {
return tasks_ | std::views::transform([](auto& task) -> Task& { return *task; });
}
private:
void set_bar_css_class(const std::string&, bool);
};
} /* namespace waybar::modules::wlr */
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include <fmt/format.h>
#include <libmm-glib/libmm-glib.h>
#include <sys/statvfs.h>
#include <fstream>
#include "ALabel.hpp"
#include "util/format.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class Wwan : public ALabel {
public:
Wwan(const std::string&, const Json::Value&);
virtual ~Wwan();
auto update() -> void override;
private:
void updateCurrentModem();
util::SleeperThread thread_;
std::string state_;
GDBusConnection* connection = nullptr;
MMManager* manager = nullptr;
MMModem* current_modem = nullptr;
bool hideDisconnected = true;
const std::string dbus_name = "org.freedesktop.ModemManager1";
const std::string dbus_obj_path = "/org/freedesktop/ModemManager1/";
const std::string dbus_modems_path = "/org/freedesktop/ModemManager1/Modems/";
};
} // namespace waybar::modules