Merge branch 'master' into feat-hyprland-submap-icon-handling
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <glibmm/markup.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <json/json.h>
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "AModule.hpp"
|
||||
|
||||
namespace waybar {
|
||||
|
||||
enum class GraphType { LINE, BAR, GAUGE };
|
||||
|
||||
class AGraph : public AModule {
|
||||
public:
|
||||
AGraph(const Json::Value&, const std::string&, const std::string&, uint16_t interval = 0,
|
||||
bool enable_click = false, bool enable_scroll = false);
|
||||
virtual ~AGraph() = default;
|
||||
auto update() -> void override;
|
||||
|
||||
protected:
|
||||
Gtk::DrawingArea graph_;
|
||||
std::deque<int> values_;
|
||||
uint16_t datapoints_ = 20;
|
||||
GraphType graph_type_ = GraphType::LINE;
|
||||
|
||||
void addValue(const int n);
|
||||
|
||||
const std::chrono::seconds interval_;
|
||||
|
||||
bool onDraw(const Cairo::RefPtr<Cairo::Context>& cr);
|
||||
|
||||
std::map<std::string, GtkMenuItem*> submenus_;
|
||||
std::map<std::string, std::string> menuActionsMap_;
|
||||
static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
|
||||
|
||||
private:
|
||||
void drawFilledArea(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||
const std::vector<std::pair<double, double>>& points, double height,
|
||||
const Gdk::RGBA& bg_color);
|
||||
|
||||
void drawLine(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||
const std::vector<std::pair<double, double>>& points, const Gdk::RGBA& fg_color);
|
||||
|
||||
void drawPath(const Cairo::RefPtr<Cairo::Context>& cr,
|
||||
const std::vector<std::pair<double, double>>& points);
|
||||
|
||||
void drawBars(const Cairo::RefPtr<Cairo::Context>& cr, double width, double height,
|
||||
int current_value, const Gdk::RGBA& fg_color);
|
||||
|
||||
void drawGauge(const Cairo::RefPtr<Cairo::Context>& cr, double width, double height,
|
||||
int current_value, const Gdk::RGBA& fg_color);
|
||||
};
|
||||
|
||||
} // namespace waybar
|
||||
@@ -14,10 +14,14 @@ class AIconLabel : public ALabel {
|
||||
bool enable_click = false, bool enable_scroll = false);
|
||||
virtual ~AIconLabel() = default;
|
||||
auto update() -> void override;
|
||||
static std::tuple<std::string, std::string> extractIcon(const std::string& input);
|
||||
|
||||
protected:
|
||||
Gtk::Image image_;
|
||||
Gtk::Box box_;
|
||||
unsigned app_icon_size_{24};
|
||||
|
||||
bool label_contains_icon{false};
|
||||
|
||||
bool iconEnabled() const;
|
||||
};
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <gtkmm/label.h>
|
||||
#include <json/json.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "AModule.hpp"
|
||||
|
||||
namespace waybar {
|
||||
@@ -25,12 +27,20 @@ class ALabel : public AModule {
|
||||
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;
|
||||
void copyToClipboard(const std::string&);
|
||||
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
|
||||
|
||||
+11
-3
@@ -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
|
||||
@@ -41,14 +45,16 @@ class AModule : public IModule {
|
||||
const Json::Value& config_;
|
||||
Gtk::EventBox event_box_;
|
||||
|
||||
virtual void setCursor(Gdk::CursorType const& c);
|
||||
virtual void setCursor(std::string const& c);
|
||||
|
||||
virtual bool handleToggle(GdkEventButton* const& ev);
|
||||
virtual bool handleMouseEnter(GdkEventCrossing* const& ev);
|
||||
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);
|
||||
@@ -57,6 +63,7 @@ class AModule : public IModule {
|
||||
bool hasUserEvents_;
|
||||
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"},
|
||||
@@ -78,7 +85,8 @@ class AModule : public IModule {
|
||||
{std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"},
|
||||
{std::make_pair(9, GdkEventType::GDK_BUTTON_RELEASE), "on-click-forward-release"},
|
||||
{std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"},
|
||||
{std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"}};
|
||||
{std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"},
|
||||
{std::make_pair(10, GdkEventType::GDK_BUTTON_PRESS), "on-click-copy"}};
|
||||
};
|
||||
|
||||
} // namespace waybar
|
||||
|
||||
@@ -75,6 +75,8 @@ class Bar : public sigc::trackable {
|
||||
util::KillSignalAction getOnSigusr1Action();
|
||||
util::KillSignalAction getOnSigusr2Action();
|
||||
|
||||
void toggleSuspend(bool suspend);
|
||||
|
||||
struct waybar_output* output;
|
||||
Json::Value config;
|
||||
struct wl_surface* surface;
|
||||
@@ -99,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();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
struct zwp_idle_inhibitor_v1;
|
||||
struct zwp_idle_inhibit_manager_v1;
|
||||
struct ext_idle_notifier_v1;
|
||||
|
||||
namespace waybar {
|
||||
|
||||
@@ -27,6 +28,7 @@ class Client {
|
||||
struct wl_registry* registry = nullptr;
|
||||
struct zxdg_output_manager_v1* xdg_output_manager = nullptr;
|
||||
struct zwp_idle_inhibit_manager_v1* idle_inhibit_manager = nullptr;
|
||||
struct ext_idle_notifier_v1* idle_notifier = nullptr;
|
||||
std::vector<std::unique_ptr<Bar>> bars;
|
||||
Config config;
|
||||
std::string bar_id;
|
||||
@@ -44,6 +46,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);
|
||||
@@ -58,6 +61,8 @@ class Client {
|
||||
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
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
namespace waybar {
|
||||
|
||||
class Group : public AModule {
|
||||
sigc::connection reveal_timeout_;
|
||||
|
||||
public:
|
||||
Group(const std::string&, const std::string&, const Json::Value&, bool);
|
||||
~Group() override = default;
|
||||
@@ -26,10 +28,12 @@ class Group : public AModule {
|
||||
bool is_first_widget = true;
|
||||
bool is_drawer = false;
|
||||
bool click_to_reveal = false;
|
||||
int reveal_delay = 0;
|
||||
std::string add_class_to_drawer_children;
|
||||
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();
|
||||
};
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
#if defined(__linux__)
|
||||
#include <sys/inotify.h>
|
||||
#endif
|
||||
#include <sys/poll.h>
|
||||
#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_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -80,6 +80,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 +89,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
|
||||
|
||||
@@ -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
|
||||
@@ -5,14 +5,14 @@
|
||||
#include <csignal>
|
||||
#include <string>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "AIconLabel.hpp"
|
||||
#include "util/command.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();
|
||||
@@ -35,6 +35,10 @@ class Custom : public ALabel {
|
||||
std::string id_;
|
||||
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_;
|
||||
|
||||
@@ -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,6 +4,7 @@
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "util/format.hpp"
|
||||
@@ -19,10 +20,12 @@ 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);
|
||||
float calc_specific_divisor(const std::string& divisor);
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <filesystem>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
@@ -34,19 +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
|
||||
pid_t socketOwnerPid_;
|
||||
bool running_ = true; // the ipcThread will stop running when this is false
|
||||
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
|
||||
};
|
||||
}; // namespace waybar::modules::hyprland
|
||||
|
||||
@@ -30,6 +30,8 @@ class Language : public waybar::ALabel, public EventHandler {
|
||||
std::string short_description;
|
||||
};
|
||||
|
||||
auto removeXkbLayoutCssClass() -> void;
|
||||
auto addXkbLayoutCssClass() -> void;
|
||||
static auto getLayout(const std::string&) -> Layout;
|
||||
|
||||
std::mutex mutex_;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -40,10 +40,11 @@ struct WindowRepr {
|
||||
|
||||
class WindowCreationPayload {
|
||||
public:
|
||||
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
|
||||
WindowCreationPayload(const std::string& workspace_name, WindowAddress window_address,
|
||||
WindowRepr window_repr);
|
||||
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
|
||||
std::string window_class, std::string window_title, bool is_active);
|
||||
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();
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -45,6 +46,15 @@ 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; };
|
||||
@@ -71,6 +81,7 @@ class Workspace {
|
||||
|
||||
int m_id;
|
||||
std::string m_name;
|
||||
std::string m_prevNameClass;
|
||||
std::string m_output;
|
||||
uint m_windows;
|
||||
bool m_isActive = false;
|
||||
@@ -80,6 +91,8 @@ class Workspace {
|
||||
bool m_isUrgent = false;
|
||||
bool m_isVisible = false;
|
||||
|
||||
sigc::connection m_hoverCheckConnection;
|
||||
|
||||
std::vector<WindowRepr> m_windowMap;
|
||||
|
||||
Gtk::Button m_button;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <gtkmm/enums.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <json/value.h>
|
||||
#include <sigc++/connection.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
@@ -38,11 +39,13 @@ 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 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; }
|
||||
@@ -54,12 +57,15 @@ class Workspaces : public AModule, public EventHandler {
|
||||
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(std::string window_class, std::string window_title);
|
||||
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; }
|
||||
@@ -87,6 +93,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();
|
||||
@@ -122,6 +129,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();
|
||||
@@ -142,9 +151,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_barScroll = false;
|
||||
Json::Value m_persistentWorkspaceConfig;
|
||||
|
||||
// Map for windows stored in workspaces not present in the current bar.
|
||||
@@ -168,6 +179,8 @@ class Workspaces : public AModule, public EventHandler {
|
||||
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;
|
||||
@@ -197,6 +210,7 @@ class Workspaces : public AModule, public EventHandler {
|
||||
};
|
||||
std::string m_onClickWindow;
|
||||
std::string m_currentActiveWindowAddress;
|
||||
int m_maxWindows = 0;
|
||||
|
||||
std::vector<std::regex> m_ignoreWorkspaces;
|
||||
std::vector<std::regex> m_ignoreWindows;
|
||||
@@ -204,6 +218,7 @@ class Workspaces : public AModule, public EventHandler {
|
||||
std::mutex m_mutex;
|
||||
const Bar& m_bar;
|
||||
Gtk::Box m_box;
|
||||
sigc::connection m_scrollEventConnection_;
|
||||
IPC& m_ipc;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,25 +6,35 @@
|
||||
#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;
|
||||
|
||||
private:
|
||||
bool handleToggle(GdkEventButton* const& e) override;
|
||||
void toggleStatus();
|
||||
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 wait_for_activity_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <fmt/chrono.h>
|
||||
#include <gtkmm/label.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -35,12 +36,12 @@ 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_;
|
||||
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_;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// include/modules/mango/backend.hpp
|
||||
#pragma once
|
||||
|
||||
#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);
|
||||
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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&);
|
||||
@@ -44,7 +47,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,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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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,8 +77,11 @@ 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;
|
||||
std::string lastStatus;
|
||||
std::string lastPlayer;
|
||||
|
||||
|
||||
@@ -70,6 +70,9 @@ class Network : public ALabel {
|
||||
|
||||
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_;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <gtkmm/button.h>
|
||||
#include <json/value.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "bar.hpp"
|
||||
#include "modules/niri/backend.hpp"
|
||||
@@ -18,13 +20,19 @@ class Workspaces : public AModule, public EventHandler {
|
||||
private:
|
||||
void onEvent(const Json::Value& ev) override;
|
||||
void doUpdate();
|
||||
void sortWorkspaces(std::vector<Json::Value>& workspaces) const;
|
||||
Gtk::Button& addButton(const Json::Value& ws);
|
||||
std::string getIcon(const std::string& value, const Json::Value& ws);
|
||||
bool handleScroll(GdkEventScroll* /*unused*/) override;
|
||||
|
||||
const Bar& bar_;
|
||||
Gtk::Box box_;
|
||||
// Map from niri workspace id to button.
|
||||
std::unordered_map<uint64_t, Gtk::Button> buttons_;
|
||||
|
||||
bool sort_by_id_ = false;
|
||||
bool sort_by_name_ = false;
|
||||
bool sort_by_coordinates_ = false;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::niri
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -28,6 +28,7 @@ class Privacy : public AModule {
|
||||
|
||||
// Config
|
||||
Gtk::Box box_;
|
||||
std::vector<PrivacyItem*> modules_;
|
||||
uint iconSpacing = 4;
|
||||
uint iconSize = 20;
|
||||
uint transition_duration = 250;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,6 +20,8 @@ class Tags : public waybar::AModule {
|
||||
void handle_focused_tags(uint32_t tags);
|
||||
void handle_view_tags(struct wl_array* tags);
|
||||
void handle_urgent_tags(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);
|
||||
@@ -31,9 +33,11 @@ class Tags : public waybar::AModule {
|
||||
|
||||
private:
|
||||
const waybar::Bar& bar_;
|
||||
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_;
|
||||
};
|
||||
|
||||
} /* namespace waybar::modules::river */
|
||||
|
||||
@@ -14,11 +14,14 @@ namespace waybar::modules::SNI {
|
||||
|
||||
class Host {
|
||||
public:
|
||||
Host(const std::size_t id, const Json::Value&, const Bar&,
|
||||
Host(const 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(std::unique_ptr<Item>&)>&, const std::function<void()>&);
|
||||
~Host();
|
||||
|
||||
void checkIgnoreList(const std::vector<std::string>& ignore_list,
|
||||
const std::function<void(std::unique_ptr<Item>&)>& on_remove);
|
||||
|
||||
private:
|
||||
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
|
||||
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring,
|
||||
@@ -28,9 +31,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 +46,14 @@ 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_;
|
||||
const std::function<void()> on_update_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules::SNI
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <libdbusmenu-gtk/dbusmenu-gtk.h>
|
||||
#include <sigc++/trackable.h>
|
||||
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
|
||||
@@ -25,9 +26,13 @@ struct ToolTip {
|
||||
|
||||
class Item : public sigc::trackable {
|
||||
public:
|
||||
Item(const std::string&, const std::string&, const Json::Value&, const Bar&);
|
||||
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_;
|
||||
|
||||
@@ -19,11 +19,14 @@ class Tray : public AModule {
|
||||
private:
|
||||
void onAdd(std::unique_ptr<Item>& item);
|
||||
void onRemove(std::unique_ptr<Item>& item);
|
||||
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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#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 +25,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);
|
||||
@@ -39,13 +37,14 @@ 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);
|
||||
|
||||
int fd_;
|
||||
int fd_event_;
|
||||
util::ScopedFd fd_;
|
||||
util::ScopedFd fd_event_;
|
||||
std::mutex mutex_;
|
||||
util::SleeperThread thread_;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -24,12 +24,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(std::string name);
|
||||
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();
|
||||
@@ -40,7 +43,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_;
|
||||
@@ -49,6 +52,7 @@ 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_;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <giomm/dbusproxy.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
|
||||
@@ -11,23 +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;
|
||||
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_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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "util/scoped_fd.hpp"
|
||||
|
||||
namespace waybar::modules::wayfire {
|
||||
|
||||
using EventHandler = std::function<void(const std::string& event)>;
|
||||
@@ -71,25 +73,9 @@ struct State {
|
||||
auto update_view(const Json::Value& view) -> void;
|
||||
};
|
||||
|
||||
struct Sock {
|
||||
int fd;
|
||||
using Sock = util::ScopedFd;
|
||||
|
||||
Sock(int fd) : fd{fd} {}
|
||||
~Sock() { close(fd); }
|
||||
Sock(const Sock&) = delete;
|
||||
auto operator=(const Sock&) = delete;
|
||||
Sock(Sock&& rhs) noexcept {
|
||||
fd = rhs.fd;
|
||||
rhs.fd = -1;
|
||||
}
|
||||
auto& operator=(Sock&& rhs) noexcept {
|
||||
fd = rhs.fd;
|
||||
rhs.fd = -1;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class IPC {
|
||||
class IPC : public std::enable_shared_from_this<IPC> {
|
||||
static std::weak_ptr<IPC> instance;
|
||||
Json::CharReaderBuilder reader_builder;
|
||||
Json::StreamWriterBuilder writer_builder;
|
||||
@@ -98,7 +84,7 @@ class IPC {
|
||||
State state;
|
||||
std::mutex state_mutex;
|
||||
|
||||
IPC() { start(); }
|
||||
IPC() = default;
|
||||
|
||||
static auto connect() -> Sock;
|
||||
auto receive(Sock& sock) -> Json::Value;
|
||||
|
||||
@@ -33,6 +33,7 @@ class Wireplumber : public ALabel {
|
||||
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
|
||||
|
||||
bool handleScroll(GdkEventScroll* e) override;
|
||||
std::vector<std::string> getWPIcon();
|
||||
|
||||
static std::list<waybar::modules::Wireplumber*> modules;
|
||||
|
||||
@@ -54,6 +55,7 @@ class Wireplumber : public ALabel {
|
||||
bool source_muted_;
|
||||
double source_volume_;
|
||||
gchar* default_source_name_;
|
||||
std::string form_factor_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
||||
|
||||
@@ -18,6 +18,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"
|
||||
@@ -80,6 +81,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;
|
||||
@@ -102,6 +104,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 +147,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();
|
||||
@@ -156,22 +167,35 @@ class Taskbar : public waybar::AModule {
|
||||
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;
|
||||
@@ -179,6 +203,9 @@ class Taskbar : public waybar::AModule {
|
||||
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;
|
||||
|
||||
private:
|
||||
void set_bar_css_class(const std::string&, bool);
|
||||
};
|
||||
|
||||
} /* namespace waybar::modules::wlr */
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <glibmm/dispatcher.h>
|
||||
#include <sigc++/signal.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
@@ -11,11 +12,6 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
#define SIGRTMIN SIGUSR1 - 1
|
||||
#define SIGRTMAX SIGUSR1 + 1
|
||||
#endif
|
||||
|
||||
namespace waybar {
|
||||
|
||||
/**
|
||||
@@ -27,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()) {
|
||||
@@ -41,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();
|
||||
@@ -60,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();
|
||||
@@ -72,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();
|
||||
|
||||
@@ -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*);
|
||||
@@ -22,12 +27,14 @@ class AudioBackend {
|
||||
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
|
||||
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
|
||||
static void volumeModifyCb(pa_context*, int, void*);
|
||||
static void sourceVolumeModifyCb(pa_context*, int, void*);
|
||||
void connectContext();
|
||||
|
||||
pa_threaded_mainloop* mainloop_;
|
||||
pa_mainloop_api* mainloop_api_;
|
||||
pa_context* context_;
|
||||
pa_cvolume pa_volume_;
|
||||
pa_cvolume pa_source_volume_;
|
||||
|
||||
// SINK
|
||||
uint32_t sink_idx_{0};
|
||||
@@ -50,6 +57,7 @@ class AudioBackend {
|
||||
std::string default_source_name_;
|
||||
|
||||
std::vector<std::string> ignored_sinks_;
|
||||
std::map<std::string, std::string> sink_mapping_;
|
||||
|
||||
std::function<void()> on_updated_cb_ = NOOP;
|
||||
|
||||
@@ -67,10 +75,13 @@ class AudioBackend {
|
||||
AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag);
|
||||
~AudioBackend();
|
||||
|
||||
void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100);
|
||||
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100);
|
||||
void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100,
|
||||
PulseaudioTarget target = PulseaudioTarget::Sink);
|
||||
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100,
|
||||
PulseaudioTarget target = PulseaudioTarget::Sink);
|
||||
|
||||
void setIgnoredSinks(const Json::Value& config);
|
||||
void setSinkMapping(const Json::Value& config);
|
||||
|
||||
std::string getSinkPortName() const { return port_name_; }
|
||||
std::string getFormFactor() const { return form_factor_; }
|
||||
@@ -92,7 +103,11 @@ class AudioBackend {
|
||||
void toggleSourceMute();
|
||||
void toggleSourceMute(bool);
|
||||
|
||||
uint16_t getVolume(PulseaudioTarget) const;
|
||||
bool getMuted(PulseaudioTarget) const;
|
||||
void unmute(PulseaudioTarget);
|
||||
|
||||
bool isBluetooth();
|
||||
};
|
||||
|
||||
} // namespace waybar::util
|
||||
} // namespace waybar::util
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -113,7 +116,9 @@ inline FILE* open(const std::string& cmd, int& pid, const std::string& output_na
|
||||
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]);
|
||||
}
|
||||
@@ -161,7 +166,9 @@ inline int32_t forkExec(const std::string& cmd, const std::string& output_name)
|
||||
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);
|
||||
@@ -172,8 +179,6 @@ inline int32_t forkExec(const std::string& cmd, const std::string& output_name)
|
||||
return pid;
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) {
|
||||
return forkExec(cmd, "");
|
||||
}
|
||||
inline int32_t forkExec(const std::string& cmd) { return forkExec(cmd, ""); }
|
||||
|
||||
} // namespace waybar::util::command
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
|
||||
class pow_format {
|
||||
public:
|
||||
pow_format(long long val, std::string&& unit, bool binary = false)
|
||||
: val_(val), unit_(unit), binary_(binary) {};
|
||||
pow_format(long long val, std::string&& unit, bool binary = false, int min_pow_for_decimal = 0)
|
||||
: val_(val), unit_(unit), binary_(binary), min_pow_for_decimal_(min_pow_for_decimal) {};
|
||||
|
||||
long long val_;
|
||||
std::string unit_;
|
||||
bool binary_;
|
||||
int min_pow_for_decimal_;
|
||||
};
|
||||
|
||||
namespace fmt {
|
||||
@@ -74,7 +75,8 @@ struct formatter<pow_format> {
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
format = "{coefficient:.1f}{prefix}{unit}";
|
||||
format = pow < s.min_pow_for_decimal_ ? "{coefficient:.0f}{prefix}{unit}"
|
||||
: "{coefficient:.1f}{prefix}{unit}";
|
||||
break;
|
||||
}
|
||||
return fmt::format_to(
|
||||
|
||||
@@ -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);
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/value.h>
|
||||
|
||||
namespace waybar::util {
|
||||
bool valid_host(const Json::Value& config);
|
||||
} // namespace waybar::util
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <codecvt>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
#if (FMT_VERSION >= 90000)
|
||||
@@ -26,14 +27,19 @@ 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;
|
||||
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
||||
// parser can be called concurrently from multiple module threads
|
||||
Json::CharReaderBuilder readerBuilder;
|
||||
if (!Json::parseFromStream(readerBuilder, jsonStream, &root, &errs)) {
|
||||
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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user