Merge remote-tracking branch 'origin/master' into fix/sni-host-proxy-retry
This commit is contained in:
@@ -25,6 +25,10 @@ class AModule : public IModule {
|
|||||||
|
|
||||||
bool expandEnabled() const;
|
bool expandEnabled() const;
|
||||||
|
|
||||||
|
virtual void suspend() {};
|
||||||
|
virtual void resume() {};
|
||||||
|
bool shouldSuspend() const { return disable_on_sleep_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Don't need to make an object directly
|
// Don't need to make an object directly
|
||||||
// Derived classes are able to use it
|
// Derived classes are able to use it
|
||||||
@@ -48,6 +52,8 @@ class AModule : public IModule {
|
|||||||
virtual bool handleMouseLeave(GdkEventCrossing* const& ev);
|
virtual bool handleMouseLeave(GdkEventCrossing* const& ev);
|
||||||
virtual bool handleScroll(GdkEventScroll*);
|
virtual bool handleScroll(GdkEventScroll*);
|
||||||
virtual bool handleRelease(GdkEventButton* const& ev);
|
virtual bool handleRelease(GdkEventButton* const& ev);
|
||||||
|
|
||||||
|
bool disable_on_sleep_{false};
|
||||||
GObject* menu_ = nullptr;
|
GObject* menu_ = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -57,6 +63,7 @@ class AModule : public IModule {
|
|||||||
bool hasUserEvents_;
|
bool hasUserEvents_;
|
||||||
gdouble distance_scrolled_y_;
|
gdouble distance_scrolled_y_;
|
||||||
gdouble distance_scrolled_x_;
|
gdouble distance_scrolled_x_;
|
||||||
|
sigc::connection cursor_timeout_conn_;
|
||||||
std::map<std::string, std::string> eventActionMap_;
|
std::map<std::string, std::string> eventActionMap_;
|
||||||
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
|
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
|
||||||
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
|
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ class Bar : public sigc::trackable {
|
|||||||
util::KillSignalAction getOnSigusr1Action();
|
util::KillSignalAction getOnSigusr1Action();
|
||||||
util::KillSignalAction getOnSigusr2Action();
|
util::KillSignalAction getOnSigusr2Action();
|
||||||
|
|
||||||
|
void toggleSuspend(bool suspend);
|
||||||
|
|
||||||
struct waybar_output* output;
|
struct waybar_output* output;
|
||||||
Json::Value config;
|
Json::Value config;
|
||||||
struct wl_surface* surface;
|
struct wl_surface* surface;
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ class Memory : public ALabel {
|
|||||||
private:
|
private:
|
||||||
void parseMeminfo();
|
void parseMeminfo();
|
||||||
|
|
||||||
static float calc_divisor(const std::string& divisor);
|
|
||||||
|
|
||||||
std::unordered_map<std::string, unsigned long> meminfo_;
|
std::unordered_map<std::string, unsigned long> meminfo_;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class MPD : public ALabel {
|
|||||||
detail::unique_status status_;
|
detail::unique_status status_;
|
||||||
mpd_state state_;
|
mpd_state state_;
|
||||||
detail::unique_song song_;
|
detail::unique_song song_;
|
||||||
|
std::string ellipsis_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MPD(const std::string&, const Json::Value&);
|
MPD(const std::string&, const Json::Value&);
|
||||||
@@ -45,6 +46,10 @@ class MPD : public ALabel {
|
|||||||
void setLabel();
|
void setLabel();
|
||||||
std::string getStateIcon() const;
|
std::string getStateIcon() const;
|
||||||
std::string getOptionIcon(const 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
|
// GUI-side methods
|
||||||
bool handlePlayPause(GdkEventButton* const&);
|
bool handlePlayPause(GdkEventButton* const&);
|
||||||
@@ -54,7 +59,6 @@ class MPD : public ALabel {
|
|||||||
void tryConnect();
|
void tryConnect();
|
||||||
void checkErrors(mpd_connection* conn);
|
void checkErrors(mpd_connection* conn);
|
||||||
void fetchState();
|
void fetchState();
|
||||||
void queryMPD();
|
|
||||||
|
|
||||||
inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; }
|
inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; }
|
||||||
inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; }
|
inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; }
|
||||||
|
|||||||
@@ -197,7 +197,6 @@ class Context {
|
|||||||
void tryConnect() const;
|
void tryConnect() const;
|
||||||
void checkErrors(mpd_connection*) const;
|
void checkErrors(mpd_connection*) const;
|
||||||
void do_update();
|
void do_update();
|
||||||
void queryMPD() const;
|
|
||||||
void fetchState() const;
|
void fetchState() const;
|
||||||
constexpr mpd_state state() const;
|
constexpr mpd_state state() const;
|
||||||
void emit() const;
|
void emit() const;
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
inline bool Context::is_connected() const { return mpd_module_->connection_ != nullptr; }
|
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_playing() const { return mpd_module_->playing(); }
|
||||||
inline bool Context::is_paused() const { return mpd_module_->paused(); }
|
inline bool Context::is_paused() const { return mpd_module_->paused(); }
|
||||||
inline bool Context::is_stopped() const { return mpd_module_->stopped(); }
|
inline bool Context::is_stopped() const { return mpd_module_->stopped(); }
|
||||||
|
|
||||||
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_.count(); }
|
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_ / 1s; }
|
||||||
inline void Context::tryConnect() const { mpd_module_->tryConnect(); }
|
inline void Context::tryConnect() const { mpd_module_->tryConnect(); }
|
||||||
inline unique_connection& Context::connection() { return mpd_module_->connection_; }
|
inline unique_connection& Context::connection() { return mpd_module_->connection_; }
|
||||||
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
|
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
|
||||||
@@ -15,7 +16,6 @@ constexpr inline mpd_state Context::state() const { return mpd_module_->state_;
|
|||||||
inline void Context::do_update() { mpd_module_->setLabel(); }
|
inline void Context::do_update() { mpd_module_->setLabel(); }
|
||||||
|
|
||||||
inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); }
|
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::fetchState() const { mpd_module_->fetchState(); }
|
||||||
inline void Context::emit() const { mpd_module_->emit(); }
|
inline void Context::emit() const { mpd_module_->emit(); }
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class Privacy : public AModule {
|
|||||||
|
|
||||||
// Config
|
// Config
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
|
std::vector<PrivacyItem*> modules_;
|
||||||
uint iconSpacing = 4;
|
uint iconSpacing = 4;
|
||||||
uint iconSize = 20;
|
uint iconSize = 20;
|
||||||
uint transition_duration = 250;
|
uint transition_duration = 250;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class Item : public sigc::trackable {
|
|||||||
std::string title;
|
std::string title;
|
||||||
std::string icon_name;
|
std::string icon_name;
|
||||||
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
|
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
|
||||||
|
bool has_custom_icon_ = false;
|
||||||
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
||||||
std::string overlay_icon_name;
|
std::string overlay_icon_name;
|
||||||
Glib::RefPtr<Gdk::Pixbuf> overlay_icon_pixmap;
|
Glib::RefPtr<Gdk::Pixbuf> overlay_icon_pixmap;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class Tray : public AModule {
|
|||||||
void queueUpdate();
|
void queueUpdate();
|
||||||
|
|
||||||
static inline std::size_t nb_hosts_ = 0;
|
static inline std::size_t nb_hosts_ = 0;
|
||||||
bool show_passive_ = false;
|
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
SNI::Watcher::singleton watcher_;
|
SNI::Watcher::singleton watcher_;
|
||||||
SNI::Host host_;
|
SNI::Host host_;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::string_view workspace_switch_cmd_ = "workspace {} \"{}\"";
|
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_ =
|
static constexpr std::string_view persistent_workspace_switch_cmd_ =
|
||||||
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
|
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ class Temperature : public ALabel {
|
|||||||
Temperature(const std::string&, const Json::Value&);
|
Temperature(const std::string&, const Json::Value&);
|
||||||
virtual ~Temperature() = default;
|
virtual ~Temperature() = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
void suspend() override;
|
||||||
|
void resume() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float getTemperature();
|
float getTemperature();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
#include <memory>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#if (FMT_VERSION >= 90000)
|
#if (FMT_VERSION >= 90000)
|
||||||
@@ -26,14 +27,19 @@ class JsonParser {
|
|||||||
Json::Value root;
|
Json::Value root;
|
||||||
|
|
||||||
// replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences
|
// 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;
|
std::string errs;
|
||||||
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
||||||
// parser can be called concurrently from multiple module threads
|
// parser can be called concurrently from multiple module threads
|
||||||
Json::CharReaderBuilder readerBuilder;
|
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);
|
throw std::runtime_error("Error parsing JSON: " + errs);
|
||||||
}
|
}
|
||||||
return root;
|
return root;
|
||||||
|
|||||||
@@ -79,6 +79,12 @@ class SleeperThread {
|
|||||||
auto sleep_for(std::chrono::system_clock::duration dur) {
|
auto sleep_for(std::chrono::system_clock::duration dur) {
|
||||||
std::unique_lock lk(mutex_);
|
std::unique_lock lk(mutex_);
|
||||||
CancellationGuard cancel_lock;
|
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();
|
constexpr auto max_time_point = std::chrono::steady_clock::time_point::max();
|
||||||
auto wait_end = max_time_point;
|
auto wait_end = max_time_point;
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
@@ -95,6 +101,12 @@ class SleeperThread {
|
|||||||
time_point) {
|
time_point) {
|
||||||
std::unique_lock lk(mutex_);
|
std::unique_lock lk(mutex_);
|
||||||
CancellationGuard cancel_lock;
|
CancellationGuard cancel_lock;
|
||||||
|
|
||||||
|
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 condvar_.wait_until(lk, time_point, [this] {
|
||||||
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
|
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
|
||||||
});
|
});
|
||||||
@@ -122,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() {
|
~SleeperThread() {
|
||||||
connection_.disconnect();
|
connection_.disconnect();
|
||||||
stop();
|
stop();
|
||||||
@@ -137,6 +160,7 @@ class SleeperThread {
|
|||||||
std::atomic<bool> do_run_ = true;
|
std::atomic<bool> do_run_ = true;
|
||||||
std::atomic<bool> signal_ = false;
|
std::atomic<bool> signal_ = false;
|
||||||
sigc::connection connection_;
|
sigc::connection connection_;
|
||||||
|
bool is_paused_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::util
|
} // 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
|
||||||
@@ -38,6 +38,20 @@ Addressed by *hyprland/language*
|
|||||||
typeof: array ++
|
typeof: array ++
|
||||||
The actions corresponding to the buttons of the menu.
|
The actions corresponding to the buttons of the menu.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: boolean ++
|
||||||
|
default: true ++
|
||||||
|
Enables or disables the tooltip for the language module. By default, the tooltip is enabled. Set to *false* to disable.
|
||||||
|
|
||||||
|
*tooltip-format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {long} ++
|
||||||
|
Specifies the format of the tooltip when it is enabled. It follows the same format replacement rules as the *format* key.
|
||||||
|
|
||||||
|
*tooltip-format-<lang>*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Allows specifying a different tooltip format for each language. The *<lang>* should be replaced with the language code. This can be used to provide a custom tooltip for each language.
|
||||||
|
|
||||||
*expand*: ++
|
*expand*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
@@ -66,6 +80,28 @@ Addressed by *hyprland/language*
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"hyprland/language": {
|
||||||
|
"format": "{}",
|
||||||
|
"format-en": "US",
|
||||||
|
"format-es": "ES",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-format": "{long}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
"hyprland/language": {
|
||||||
|
"format": "{}",
|
||||||
|
"format-en": "US",
|
||||||
|
"format-es": "ES",
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-format": "{}",
|
||||||
|
"tooltip-format-es": "{Español}",
|
||||||
|
"tooltip-format-en": "{English (american)}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
- *#language*
|
- *#language*
|
||||||
|
|||||||
@@ -135,6 +135,14 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
|
|||||||
default: false ++
|
default: false ++
|
||||||
If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
|
If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
|
||||||
|
|
||||||
|
*on-scroll-up*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling up on the module. This replaces the default behaviour of workspace cycling.
|
||||||
|
|
||||||
|
*on-scroll-down*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling down on the module. This replaces the default behaviour of workspace cycling.
|
||||||
|
|
||||||
*ignore-workspaces*: ++
|
*ignore-workspaces*: ++
|
||||||
typeof: array ++
|
typeof: array ++
|
||||||
default: [] ++
|
default: [] ++
|
||||||
|
|||||||
+2
-1
@@ -186,7 +186,8 @@ src_files = files(
|
|||||||
'src/util/icon_loader.cpp',
|
'src/util/icon_loader.cpp',
|
||||||
'src/util/regex_collection.cpp',
|
'src/util/regex_collection.cpp',
|
||||||
'src/util/css_reload_helper.cpp',
|
'src/util/css_reload_helper.cpp',
|
||||||
'src/util/transform_8bit_to_rgba.cpp'
|
'src/util/transform_8bit_to_rgba.cpp',
|
||||||
|
'src/util/utf8_string.cpp'
|
||||||
)
|
)
|
||||||
|
|
||||||
man_files = files(
|
man_files = files(
|
||||||
|
|||||||
+15
-4
@@ -17,10 +17,14 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
|
|||||||
isTooltip{config_["tooltip"].isBool() ? config_["tooltip"].asBool() : true},
|
isTooltip{config_["tooltip"].isBool() ? config_["tooltip"].asBool() : true},
|
||||||
isExpand{config_["expand"].isBool() ? config_["expand"].asBool() : false},
|
isExpand{config_["expand"].isBool() ? config_["expand"].asBool() : false},
|
||||||
distance_scrolled_y_(0.0),
|
distance_scrolled_y_(0.0),
|
||||||
distance_scrolled_x_(0.0) {
|
distance_scrolled_x_(0.0),
|
||||||
|
cursor_timeout_conn_() {
|
||||||
// Configure module action Map
|
// Configure module action Map
|
||||||
const Json::Value actions{config_["actions"]};
|
const Json::Value actions{config_["actions"]};
|
||||||
|
|
||||||
|
disable_on_sleep_ =
|
||||||
|
config_["disable-on-sleep"].isBool() ? config_["disable-on-sleep"].asBool() : false;
|
||||||
|
|
||||||
for (Json::Value::const_iterator it = actions.begin(); it != actions.end(); ++it) {
|
for (Json::Value::const_iterator it = actions.begin(); it != actions.end(); ++it) {
|
||||||
if (it.key().isString() && it->isString())
|
if (it.key().isString() && it->isString())
|
||||||
if (!eventActionMap_.contains(it.key().asString())) {
|
if (!eventActionMap_.contains(it.key().asString())) {
|
||||||
@@ -72,8 +76,12 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
|
|||||||
|
|
||||||
// Respect user configuration of cursor
|
// Respect user configuration of cursor
|
||||||
if (config_.isMember("cursor")) {
|
if (config_.isMember("cursor")) {
|
||||||
if (config_["cursor"].isBool() && config_["cursor"].asBool()) {
|
if (config_["cursor"].isBool()) {
|
||||||
setCursor(Gdk::HAND2);
|
if (config_["cursor"].asBool()) {
|
||||||
|
setCursor(Gdk::HAND2);
|
||||||
|
} else {
|
||||||
|
setCursor(Gdk::ARROW);
|
||||||
|
}
|
||||||
} else if (config_["cursor"].isInt()) {
|
} else if (config_["cursor"].isInt()) {
|
||||||
setCursor(Gdk::CursorType(config_["cursor"].asInt()));
|
setCursor(Gdk::CursorType(config_["cursor"].asInt()));
|
||||||
} else {
|
} else {
|
||||||
@@ -83,6 +91,9 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
AModule::~AModule() {
|
AModule::~AModule() {
|
||||||
|
if (cursor_timeout_conn_.connected()) {
|
||||||
|
cursor_timeout_conn_.disconnect();
|
||||||
|
}
|
||||||
for (const auto& pid : pid_children_) {
|
for (const auto& pid : pid_children_) {
|
||||||
if (pid != -1) {
|
if (pid != -1) {
|
||||||
killpg(pid, SIGTERM);
|
killpg(pid, SIGTERM);
|
||||||
@@ -118,7 +129,7 @@ void AModule::setCursor(Gdk::CursorType const& c) {
|
|||||||
} else {
|
} else {
|
||||||
// window may not be accessible yet, in this case,
|
// window may not be accessible yet, in this case,
|
||||||
// schedule another call for setting the cursor in 1 sec
|
// schedule another call for setting the cursor in 1 sec
|
||||||
Glib::signal_timeout().connect_seconds(
|
cursor_timeout_conn_ = Glib::signal_timeout().connect_seconds(
|
||||||
[this, c]() {
|
[this, c]() {
|
||||||
setCursor(c);
|
setCursor(c);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+31
-2
@@ -263,6 +263,16 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
|||||||
|
|
||||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
||||||
|
|
||||||
|
window.signal_unmap().connect([this]() {
|
||||||
|
spdlog::debug("Output {} unmapped (DPMS off), suspending modules", output->name);
|
||||||
|
toggleSuspend(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.signal_map().connect([this]() {
|
||||||
|
spdlog::debug("Output {} mapped (DPMS on), resuming modules", output->name);
|
||||||
|
toggleSuspend(false);
|
||||||
|
});
|
||||||
|
|
||||||
#if HAVE_SWAY
|
#if HAVE_SWAY
|
||||||
if (auto ipc = config["ipc"]; ipc.isBool() && ipc.asBool()) {
|
if (auto ipc = config["ipc"]; ipc.isBool() && ipc.asBool()) {
|
||||||
bar_id = Client::inst()->bar_id;
|
bar_id = Client::inst()->bar_id;
|
||||||
@@ -545,8 +555,8 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
|
|||||||
if (group_config["modules"].isNull()) {
|
if (group_config["modules"].isNull()) {
|
||||||
spdlog::warn("Group definition '{}' has not been found, group will be hidden", ref);
|
spdlog::warn("Group definition '{}' has not been found, group will be hidden", ref);
|
||||||
}
|
}
|
||||||
auto group_module = std::make_unique<waybar::Group>(
|
auto group_module =
|
||||||
id_name, class_name, group_config, vertical);
|
std::make_unique<waybar::Group>(id_name, class_name, group_config, vertical);
|
||||||
|
|
||||||
getModules(factory, ref, group_module.get());
|
getModules(factory, ref, group_module.get());
|
||||||
module = group_module.release();
|
module = group_module.release();
|
||||||
@@ -696,3 +706,22 @@ void waybar::Bar::configureGlobalOffset(int width, int height) {
|
|||||||
void waybar::Bar::onOutputGeometryChanged() {
|
void waybar::Bar::onOutputGeometryChanged() {
|
||||||
configureGlobalOffset(window.get_width(), window.get_height());
|
configureGlobalOffset(window.get_width(), window.get_height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waybar::Bar::toggleSuspend(bool suspend) {
|
||||||
|
auto process_modules = [suspend](Gtk::Box& module_box) {
|
||||||
|
for (auto* widget : module_box.get_children()) {
|
||||||
|
auto* module = dynamic_cast<waybar::AModule*>(widget);
|
||||||
|
if (module && module->shouldSuspend()) {
|
||||||
|
if (suspend) {
|
||||||
|
module->suspend();
|
||||||
|
} else {
|
||||||
|
module->resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
process_modules(left_);
|
||||||
|
process_modules(center_);
|
||||||
|
process_modules(right_);
|
||||||
|
}
|
||||||
|
|||||||
+47
-32
@@ -153,7 +153,7 @@ void waybar::modules::Battery::refreshBatteries() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (fs::filesystem_error& e) {
|
} catch (fs::filesystem_error& e) {
|
||||||
throw std::runtime_error(e.what());
|
spdlog::warn("Battery directory tracking failed: {}", e.what());
|
||||||
}
|
}
|
||||||
if (warnFirstTime_ && batteries_.empty()) {
|
if (warnFirstTime_ && batteries_.empty()) {
|
||||||
if (config_["bat"].isString()) {
|
if (config_["bat"].isString()) {
|
||||||
@@ -288,63 +288,73 @@ waybar::modules::Battery::getInfos() {
|
|||||||
int32_t _current_now_int = 0;
|
int32_t _current_now_int = 0;
|
||||||
bool current_now_exists = false;
|
bool current_now_exists = false;
|
||||||
if (std::ifstream current_now_f{bat / "current_now"}) {
|
if (std::ifstream current_now_f{bat / "current_now"}) {
|
||||||
current_now_exists = true;
|
if (current_now_f >> _current_now_int) {
|
||||||
current_now_f >> _current_now_int;
|
current_now_exists = true;
|
||||||
|
}
|
||||||
} else if (std::ifstream current_avg_f{bat / "current_avg"}) {
|
} else if (std::ifstream current_avg_f{bat / "current_avg"}) {
|
||||||
current_now_exists = true;
|
if (current_avg_f >> _current_now_int) {
|
||||||
current_avg_f >> _current_now_int;
|
current_now_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Documentation ABI allows a negative value when discharging, positive
|
// Documentation ABI allows a negative value when discharging, positive
|
||||||
// value when charging.
|
// value when charging.
|
||||||
current_now = std::abs(_current_now_int);
|
current_now = std::abs(_current_now_int);
|
||||||
|
|
||||||
if (std::ifstream f{bat / "time_to_empty_now"}) {
|
if (std::ifstream f{bat / "time_to_empty_now"}) {
|
||||||
time_to_empty_now_exists = true;
|
if (f >> time_to_empty_now) {
|
||||||
f >> time_to_empty_now;
|
time_to_empty_now_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::ifstream f{bat / "time_to_full_now"}) {
|
if (std::ifstream f{bat / "time_to_full_now"}) {
|
||||||
time_to_full_now_exists = true;
|
if (f >> time_to_full_now) {
|
||||||
f >> time_to_full_now;
|
time_to_full_now_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t voltage_now = 0;
|
uint32_t voltage_now = 0;
|
||||||
bool voltage_now_exists = false;
|
bool voltage_now_exists = false;
|
||||||
if (std::ifstream voltage_now_f{bat / "voltage_now"}) {
|
if (std::ifstream voltage_now_f{bat / "voltage_now"}) {
|
||||||
voltage_now_exists = true;
|
if (voltage_now_f >> voltage_now) {
|
||||||
voltage_now_f >> voltage_now;
|
voltage_now_exists = true;
|
||||||
|
}
|
||||||
} else if (std::ifstream voltage_avg_f{bat / "voltage_avg"}) {
|
} else if (std::ifstream voltage_avg_f{bat / "voltage_avg"}) {
|
||||||
voltage_now_exists = true;
|
if (voltage_avg_f >> voltage_now) {
|
||||||
voltage_avg_f >> voltage_now;
|
voltage_now_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t charge_full = 0;
|
uint32_t charge_full = 0;
|
||||||
bool charge_full_exists = false;
|
bool charge_full_exists = false;
|
||||||
if (std::ifstream f{bat / "charge_full"}) {
|
if (std::ifstream f{bat / "charge_full"}) {
|
||||||
charge_full_exists = true;
|
if (f >> charge_full) {
|
||||||
f >> charge_full;
|
charge_full_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t charge_full_design = 0;
|
uint32_t charge_full_design = 0;
|
||||||
bool charge_full_design_exists = false;
|
bool charge_full_design_exists = false;
|
||||||
if (std::ifstream f{bat / "charge_full_design"}) {
|
if (std::ifstream f{bat / "charge_full_design"}) {
|
||||||
charge_full_design_exists = true;
|
if (f >> charge_full_design) {
|
||||||
f >> charge_full_design;
|
charge_full_design_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t charge_now = 0;
|
uint32_t charge_now = 0;
|
||||||
bool charge_now_exists = false;
|
bool charge_now_exists = false;
|
||||||
if (std::ifstream f{bat / "charge_now"}) {
|
if (std::ifstream f{bat / "charge_now"}) {
|
||||||
charge_now_exists = true;
|
if (f >> charge_now) {
|
||||||
f >> charge_now;
|
charge_now_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t power_now = 0;
|
uint32_t power_now = 0;
|
||||||
int32_t _power_now_int = 0;
|
int32_t _power_now_int = 0;
|
||||||
bool power_now_exists = false;
|
bool power_now_exists = false;
|
||||||
if (std::ifstream f{bat / "power_now"}) {
|
if (std::ifstream f{bat / "power_now"}) {
|
||||||
power_now_exists = true;
|
if (f >> _power_now_int) {
|
||||||
f >> _power_now_int;
|
power_now_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Some drivers (example: Qualcomm) exposes use a negative value when
|
// Some drivers (example: Qualcomm) exposes use a negative value when
|
||||||
// discharging, positive value when charging.
|
// discharging, positive value when charging.
|
||||||
@@ -353,22 +363,25 @@ waybar::modules::Battery::getInfos() {
|
|||||||
uint32_t energy_now = 0;
|
uint32_t energy_now = 0;
|
||||||
bool energy_now_exists = false;
|
bool energy_now_exists = false;
|
||||||
if (std::ifstream f{bat / "energy_now"}) {
|
if (std::ifstream f{bat / "energy_now"}) {
|
||||||
energy_now_exists = true;
|
if (f >> energy_now) {
|
||||||
f >> energy_now;
|
energy_now_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t energy_full = 0;
|
uint32_t energy_full = 0;
|
||||||
bool energy_full_exists = false;
|
bool energy_full_exists = false;
|
||||||
if (std::ifstream f{bat / "energy_full"}) {
|
if (std::ifstream f{bat / "energy_full"}) {
|
||||||
energy_full_exists = true;
|
if (f >> energy_full) {
|
||||||
f >> energy_full;
|
energy_full_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t energy_full_design = 0;
|
uint32_t energy_full_design = 0;
|
||||||
bool energy_full_design_exists = false;
|
bool energy_full_design_exists = false;
|
||||||
if (std::ifstream f{bat / "energy_full_design"}) {
|
if (std::ifstream f{bat / "energy_full_design"}) {
|
||||||
energy_full_design_exists = true;
|
if (f >> energy_full_design) {
|
||||||
f >> energy_full_design;
|
energy_full_design_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t cycleCount = 0;
|
uint16_t cycleCount = 0;
|
||||||
@@ -404,8 +417,9 @@ waybar::modules::Battery::getInfos() {
|
|||||||
capacity_exists = true;
|
capacity_exists = true;
|
||||||
capacity = 100 * (uint64_t)energy_now / (uint64_t)energy_full;
|
capacity = 100 * (uint64_t)energy_now / (uint64_t)energy_full;
|
||||||
} else if (std::ifstream f{bat / "capacity"}) {
|
} else if (std::ifstream f{bat / "capacity"}) {
|
||||||
capacity_exists = true;
|
if (f >> capacity) {
|
||||||
f >> capacity;
|
capacity_exists = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!voltage_now_exists) {
|
if (!voltage_now_exists) {
|
||||||
@@ -585,11 +599,12 @@ waybar::modules::Battery::getInfos() {
|
|||||||
|
|
||||||
float calculated_capacity{0.0f};
|
float calculated_capacity{0.0f};
|
||||||
if (total_capacity_exists) {
|
if (total_capacity_exists) {
|
||||||
if (total_capacity > 0.0f)
|
if (total_capacity > 0.0f) {
|
||||||
calculated_capacity = (float)total_capacity / batteries_.size();
|
calculated_capacity = (float)total_capacity / batteries_.size();
|
||||||
else if (total_energy_full_exists && total_energy_exists) {
|
} else if (total_energy_full_exists && total_energy_exists) {
|
||||||
if (total_energy_full > 0.0f)
|
if (total_energy_full > 0.0f) {
|
||||||
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
|
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ waybar::modules::Custom::~Custom() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Custom::delayWorker() {
|
void waybar::modules::Custom::delayWorker() {
|
||||||
|
if (!config_["exec"].isString() && !config_["exec-if"].isString()) {
|
||||||
|
dp.emit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
thread_ = [this] {
|
thread_ = [this] {
|
||||||
for (int i : this->pid_children_) {
|
for (int i : this->pid_children_) {
|
||||||
int status;
|
int status;
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ std::string IPC::buildLuaDispatch(const std::string& dispatcher, const std::stri
|
|||||||
// New format: /dispatch hl.dsp.focus({ workspace = "1" })
|
// New format: /dispatch hl.dsp.focus({ workspace = "1" })
|
||||||
//
|
//
|
||||||
// Old format: dispatch focusworkspaceoncurrentmonitor 2
|
// Old format: dispatch focusworkspaceoncurrentmonitor 2
|
||||||
// New format: /dispatch hl.dsp.focus({ workspace = "2", monitor = "current" })
|
// New format: /dispatch hl.dsp.focus({ workspace = "2", on_current_monitor = true })
|
||||||
//
|
//
|
||||||
// Old format: dispatch togglespecialworkspace name
|
// Old format: dispatch togglespecialworkspace name
|
||||||
// New format: /dispatch hl.dsp.workspace.toggle_special("name")
|
// New format: /dispatch hl.dsp.workspace.toggle_special("name")
|
||||||
@@ -329,7 +329,7 @@ std::string IPC::buildLuaDispatch(const std::string& dispatcher, const std::stri
|
|||||||
return "/dispatch hl.dsp.focus({ workspace = \"" + arg + "\" })";
|
return "/dispatch hl.dsp.focus({ workspace = \"" + arg + "\" })";
|
||||||
}
|
}
|
||||||
if (dispatcher == "focusworkspaceoncurrentmonitor") {
|
if (dispatcher == "focusworkspaceoncurrentmonitor") {
|
||||||
return "/dispatch hl.dsp.focus({ workspace = \"" + arg + "\", monitor = \"current\" })";
|
return "/dispatch hl.dsp.focus({ workspace = \"" + arg + "\", on_current_monitor = true })";
|
||||||
}
|
}
|
||||||
if (dispatcher == "togglespecialworkspace") {
|
if (dispatcher == "togglespecialworkspace") {
|
||||||
if (arg.empty()) {
|
if (arg.empty()) {
|
||||||
|
|||||||
@@ -48,12 +48,39 @@ auto Language::update() -> void {
|
|||||||
fmt::arg("shortDescription", layout_.short_description),
|
fmt::arg("shortDescription", layout_.short_description),
|
||||||
fmt::arg("variant", layout_.variant)));
|
fmt::arg("variant", layout_.variant)));
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::debug("hyprland language formatted layout name {}", layoutName);
|
spdlog::debug("hyprland language formatted layout name {}", layoutName);
|
||||||
|
|
||||||
|
std::string tooltipContent = std::string{};
|
||||||
|
bool tooltip_enabled = tooltipEnabled();
|
||||||
|
if (tooltip_enabled) {
|
||||||
|
if (config_.isMember("tooltip-format")) {
|
||||||
|
auto tooltip_format = config_["tooltip-format"].asString();
|
||||||
|
if (config_.isMember("tooltip-format-" + layout_.short_description + "-" + layout_.variant)) {
|
||||||
|
const auto propName = "tooltip-format-" + layout_.short_description + "-" + layout_.variant;
|
||||||
|
tooltipContent = fmt::format(fmt::runtime(tooltip_format), config_[propName].asString());
|
||||||
|
} else if (config_.isMember("tooltip-format-" + layout_.short_description)) {
|
||||||
|
const auto propName = "tooltip-format-" + layout_.short_description;
|
||||||
|
tooltipContent = fmt::format(fmt::runtime(tooltip_format), config_[propName].asString());
|
||||||
|
} else {
|
||||||
|
tooltipContent =
|
||||||
|
trim(fmt::format(fmt::runtime(tooltip_format), fmt::arg("long", layout_.full_name),
|
||||||
|
fmt::arg("short", layout_.short_name),
|
||||||
|
fmt::arg("shortDescription", layout_.short_description),
|
||||||
|
fmt::arg("variant", layout_.variant)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if no tooltip format is provided, use the same text as the module
|
||||||
|
tooltipContent = layoutName;
|
||||||
|
}
|
||||||
|
spdlog::debug("hyprland language formatted tooltip content {}", tooltipContent);
|
||||||
|
}
|
||||||
|
|
||||||
if (!format_.empty()) {
|
if (!format_.empty()) {
|
||||||
label_.show();
|
label_.show();
|
||||||
label_.set_markup(layoutName);
|
label_.set_markup(layoutName);
|
||||||
|
if (tooltip_enabled) {
|
||||||
|
label_.set_tooltip_markup(tooltipContent);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
label_.hide();
|
label_.hide();
|
||||||
}
|
}
|
||||||
@@ -74,8 +101,6 @@ void Language::onEvent(const std::string& ev) {
|
|||||||
spdlog::warn("hyprland language received malformed event payload: {}", ev);
|
spdlog::warn("hyprland language received malformed event payload: {}", ev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string kbName = payload.substr(0, kbSeparator);
|
|
||||||
|
|
||||||
// Last comma before variants parenthesis, eg:
|
// Last comma before variants parenthesis, eg:
|
||||||
// activelayout>>micro-star-int'l-co.,-ltd.-msi-gk50-elite-gaming-keyboard,English (US, intl.,
|
// activelayout>>micro-star-int'l-co.,-ltd.-msi-gk50-elite-gaming-keyboard,English (US, intl.,
|
||||||
// with dead keys)
|
// with dead keys)
|
||||||
@@ -93,8 +118,15 @@ void Language::onEvent(const std::string& ev) {
|
|||||||
}
|
}
|
||||||
auto layoutName = payload.substr(layoutSeparator + 1);
|
auto layoutName = payload.substr(layoutSeparator + 1);
|
||||||
|
|
||||||
if (config_.isMember("keyboard-name") && kbName != config_["keyboard-name"].asString())
|
if (config_.isMember("keyboard-name")) {
|
||||||
return; // ignore
|
const auto keyboardName = config_["keyboard-name"].asString();
|
||||||
|
// The keyboard name itself can contain commas, so match it as a full prefix
|
||||||
|
// (followed by the ',' separator) rather than comparing against the substring
|
||||||
|
// before the first comma, which would truncate such names and drop the event.
|
||||||
|
if (payload.size() <= keyboardName.size() || payload[keyboardName.size()] != ',' ||
|
||||||
|
payload.compare(0, keyboardName.size(), keyboardName) != 0)
|
||||||
|
return; // ignore
|
||||||
|
}
|
||||||
|
|
||||||
layoutName = waybar::util::sanitize_string(layoutName);
|
layoutName = waybar::util::sanitize_string(layoutName);
|
||||||
|
|
||||||
|
|||||||
@@ -108,21 +108,14 @@ auto Window::update() -> void {
|
|||||||
AAppIconLabel::update();
|
AAppIconLabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Window::getActiveWorkspace() -> Workspace {
|
auto Window::getActiveWorkspace() -> Workspace { return getActiveWorkspace(""); }
|
||||||
const auto workspace = IPC::inst().getSocket1JsonReply("activeworkspace");
|
|
||||||
|
|
||||||
if (workspace.isObject()) {
|
|
||||||
return Workspace::parse(workspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
||||||
const auto monitors = IPC::inst().getSocket1JsonReply("monitors");
|
const auto monitors = IPC::inst().getSocket1JsonReply("monitors");
|
||||||
if (monitors.isArray()) {
|
if (monitors.isArray()) {
|
||||||
auto monitor = std::ranges::find_if(
|
auto monitor = std::ranges::find_if(monitors, [&](const Json::Value& monitor) {
|
||||||
monitors, [&](const Json::Value& monitor) { return monitor["name"] == monitorName; });
|
return monitorName.empty() ? monitor["focused"].asBool() : monitor["name"] == monitorName;
|
||||||
|
});
|
||||||
if (monitor == std::end(monitors)) {
|
if (monitor == std::end(monitors)) {
|
||||||
spdlog::warn("Monitor not found: {}", monitorName);
|
spdlog::warn("Monitor not found: {}", monitorName);
|
||||||
return Workspace{
|
return Workspace{
|
||||||
@@ -132,7 +125,8 @@ auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
|||||||
.last_window_title = "",
|
.last_window_title = "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
|
const int special_id = (*monitor)["specialWorkspace"]["id"].asInt();
|
||||||
|
const int id = special_id != 0 ? special_id : (*monitor)["activeWorkspace"]["id"].asInt();
|
||||||
|
|
||||||
const auto workspaces = IPC::inst().getSocket1JsonReply("workspaces");
|
const auto workspaces = IPC::inst().getSocket1JsonReply("workspaces");
|
||||||
if (workspaces.isArray()) {
|
if (workspaces.isArray()) {
|
||||||
|
|||||||
@@ -301,15 +301,18 @@ void Workspace::updateTaskbar(const std::string& workspace_icon) {
|
|||||||
|
|
||||||
auto window_box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL);
|
auto window_box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL);
|
||||||
window_box->set_tooltip_markup(window_repr.window_title);
|
window_box->set_tooltip_markup(window_repr.window_title);
|
||||||
window_box->get_style_context()->add_class("taskbar-window");
|
|
||||||
|
auto button = Gtk::manage(new Gtk::Button());
|
||||||
|
button->set_relief(Gtk::RELIEF_NONE);
|
||||||
|
button->add(*window_box);
|
||||||
|
button->get_style_context()->add_class("taskbar-window");
|
||||||
if (window_repr.isActive) {
|
if (window_repr.isActive) {
|
||||||
window_box->get_style_context()->add_class("active");
|
button->get_style_context()->add_class("active");
|
||||||
}
|
}
|
||||||
auto event_box = Gtk::manage(new Gtk::EventBox());
|
|
||||||
event_box->add(*window_box);
|
|
||||||
if (m_workspaceManager.onClickWindow() != "") {
|
if (m_workspaceManager.onClickWindow() != "") {
|
||||||
event_box->signal_button_press_event().connect(
|
button->signal_button_press_event().connect(
|
||||||
sigc::bind(sigc::mem_fun(*this, &Workspace::handleClick), window_repr.address));
|
sigc::bind(sigc::mem_fun(*this, &Workspace::handleClick), window_repr.address),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto text_before = fmt::format(fmt::runtime(m_workspaceManager.taskbarFormatBefore()),
|
auto text_before = fmt::format(fmt::runtime(m_workspaceManager.taskbarFormatBefore()),
|
||||||
@@ -334,8 +337,8 @@ void Workspace::updateTaskbar(const std::string& workspace_icon) {
|
|||||||
window_box->pack_start(*window_label_after, true, true);
|
window_box->pack_start(*window_label_after, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_content.pack_start(*event_box, true, false);
|
m_content.pack_start(*button, true, false);
|
||||||
event_box->show_all();
|
button->show_all();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (m_workspaceManager.taskbarReverseDirection()) {
|
if (m_workspaceManager.taskbarReverseDirection()) {
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ void Workspaces::init() {
|
|||||||
if (m_scrollEventConnection_.connected()) {
|
if (m_scrollEventConnection_.connected()) {
|
||||||
m_scrollEventConnection_.disconnect();
|
m_scrollEventConnection_.disconnect();
|
||||||
}
|
}
|
||||||
if (barScroll()) {
|
bool hasScrollConfig = config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString();
|
||||||
|
if (barScroll() || hasScrollConfig) {
|
||||||
auto& window = const_cast<Bar&>(m_bar).window;
|
auto& window = const_cast<Bar&>(m_bar).window;
|
||||||
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||||
m_scrollEventConnection_ =
|
m_scrollEventConnection_ =
|
||||||
@@ -326,6 +327,10 @@ void Workspaces::loadPersistentWorkspacesFromWorkspaceRules(const Json::Value& c
|
|||||||
// 2. the rule's monitor is the current monitor
|
// 2. the rule's monitor is the current monitor
|
||||||
// 3. no monitor is specified in the rule => assume it needs to be persistent on every monitor
|
// 3. no monitor is specified in the rule => assume it needs to be persistent on every monitor
|
||||||
if (allOutputs() || m_bar.output->name == monitor || monitor.empty()) {
|
if (allOutputs() || m_bar.output->name == monitor || monitor.empty()) {
|
||||||
|
// => skip ignore-workspaces even if its a persistent
|
||||||
|
if(isWorkspaceIgnored(workspace)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// => persistent workspace should be shown on this monitor
|
// => persistent workspace should be shown on this monitor
|
||||||
auto workspaceData = createMonitorWorkspaceData(workspace, m_bar.output->name);
|
auto workspaceData = createMonitorWorkspaceData(workspace, m_bar.output->name);
|
||||||
workspaceData["persistent-rule"] = true;
|
workspaceData["persistent-rule"] = true;
|
||||||
@@ -1188,6 +1193,12 @@ bool Workspaces::handleScroll(GdkEventScroll* e) {
|
|||||||
if (gdk_event_get_pointer_emulated((GdkEvent*)e)) {
|
if (gdk_event_get_pointer_emulated((GdkEvent*)e)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for custom scroll commands first; delegate to base class
|
||||||
|
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) {
|
||||||
|
return AModule::handleScroll(e);
|
||||||
|
}
|
||||||
|
|
||||||
auto dir = AModule::getScrollDir(e);
|
auto dir = AModule::getScrollDir(e);
|
||||||
if (dir == SCROLL_DIR::NONE) {
|
if (dir == SCROLL_DIR::NONE) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
#include "modules/memory.hpp"
|
#include "modules/memory.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const std::unordered_map<std::string, float> kUnits = {
|
||||||
|
{"kB", 1.000},
|
||||||
|
{"kiB", 1.024},
|
||||||
|
{"MB", 1.000 * 1000.0},
|
||||||
|
{"MiB", 1.024 * 1024.0},
|
||||||
|
{"GB", 1.000 * 1000.0 * 1000.0},
|
||||||
|
{"GiB", 1.024 * 1024.0 * 1024.0},
|
||||||
|
{"TB", 1.000 * 1000.0 * 1000.0 * 1000.0},
|
||||||
|
{"TiB", 1.024 * 1024.0 * 1024.0 * 1024.0}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config)
|
waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config)
|
||||||
: ALabel(config, "memory", id, "{}%", 30) {
|
: ALabel(config, "memory", id, "{}%", 30) {
|
||||||
thread_ = [this] {
|
thread_ = [this] {
|
||||||
@@ -8,6 +21,11 @@ waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config
|
|||||||
};
|
};
|
||||||
if (config["unit"].isString()) {
|
if (config["unit"].isString()) {
|
||||||
unit_ = config["unit"].asString();
|
unit_ = config["unit"].asString();
|
||||||
|
if (!kUnits.contains(unit_)) {
|
||||||
|
unit_ = "GiB";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unit_ = "GiB";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +58,7 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal;
|
used_swap_percentage = 100 * (swaptotal - swapfree) / swaptotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
float divisor = calc_divisor(unit_);
|
float divisor = kUnits.at(unit_);
|
||||||
float total_ram = memtotal / divisor;
|
float total_ram = memtotal / divisor;
|
||||||
float total_swap = swaptotal / divisor;
|
float total_swap = swaptotal / divisor;
|
||||||
float used_ram = (memtotal - memfree) / divisor;
|
float used_ram = (memtotal - memfree) / divisor;
|
||||||
@@ -82,7 +100,7 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
fmt::arg("swapUsed", used_swap), fmt::arg("avail", available_ram),
|
fmt::arg("swapUsed", used_swap), fmt::arg("avail", available_ram),
|
||||||
fmt::arg("swapAvail", available_swap)));
|
fmt::arg("swapAvail", available_swap)));
|
||||||
} else {
|
} else {
|
||||||
label_.set_tooltip_markup(fmt::format("{:.{}f}GiB used", used_ram, 1));
|
label_.set_tooltip_markup(fmt::format("{:.{}f}{} used", used_ram, 1, unit_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -91,25 +109,3 @@ auto waybar::modules::Memory::update() -> void {
|
|||||||
// Call parent update
|
// Call parent update
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
float waybar::modules::Memory::calc_divisor(const std::string& divisor) {
|
|
||||||
if (divisor == "kB") {
|
|
||||||
return 1.0;
|
|
||||||
} else if (divisor == "kiB") {
|
|
||||||
return 1.024;
|
|
||||||
} else if (divisor == "MB") {
|
|
||||||
return 1.000 * 1000.0;
|
|
||||||
} else if (divisor == "MiB") {
|
|
||||||
return 1.024 * 1024.0;
|
|
||||||
} else if (divisor == "GB") {
|
|
||||||
return 1.000 * 1000.0 * 1000.0;
|
|
||||||
} else if (divisor == "GiB") {
|
|
||||||
return 1.024 * 1024.0 * 1024.0;
|
|
||||||
} else if (divisor == "TB") {
|
|
||||||
return 1.000 * 1000.0 * 1000.0 * 1000.0;
|
|
||||||
} else if (divisor == "TiB") {
|
|
||||||
return 1.024 * 1024.0 * 1024.0 * 1024.0;
|
|
||||||
} else { // default to GiB if it is anything that we don't recongnise
|
|
||||||
return 1.024 * 1024.0 * 1024.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+44
-34
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <util/sanitize_str.hpp>
|
#include <util/sanitize_str.hpp>
|
||||||
|
#include <util/utf8_string.hpp>
|
||||||
using namespace waybar::util;
|
using namespace waybar::util;
|
||||||
|
|
||||||
#include "modules/mpd/state.hpp"
|
#include "modules/mpd/state.hpp"
|
||||||
@@ -24,7 +25,8 @@ waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
|
|||||||
timeout_(config_["timeout"].isUInt() ? config_["timeout"].asUInt() * 1'000 : 30'000),
|
timeout_(config_["timeout"].isUInt() ? config_["timeout"].asUInt() * 1'000 : 30'000),
|
||||||
connection_(nullptr, &mpd_connection_free),
|
connection_(nullptr, &mpd_connection_free),
|
||||||
status_(nullptr, &mpd_status_free),
|
status_(nullptr, &mpd_status_free),
|
||||||
song_(nullptr, &mpd_song_free) {
|
song_(nullptr, &mpd_song_free),
|
||||||
|
ellipsis_(config_["ellipsis"].isString() ? config_["ellipsis"].asString() : "\u2026") {
|
||||||
if (!config_["port"].isNull() && !config_["port"].isUInt()) {
|
if (!config_["port"].isNull() && !config_["port"].isUInt()) {
|
||||||
spdlog::warn("{}: `port` configuration should be an unsigned int", module_name_);
|
spdlog::warn("{}: `port` configuration should be an unsigned int", module_name_);
|
||||||
}
|
}
|
||||||
@@ -51,21 +53,6 @@ auto waybar::modules::MPD::update() -> void {
|
|||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::MPD::queryMPD() {
|
|
||||||
if (connection_ != nullptr) {
|
|
||||||
spdlog::trace("{}: fetching state information", module_name_);
|
|
||||||
try {
|
|
||||||
fetchState();
|
|
||||||
spdlog::trace("{}: fetch complete", module_name_);
|
|
||||||
} catch (std::exception const& e) {
|
|
||||||
spdlog::error("{}: {}", module_name_, e.what());
|
|
||||||
state_ = MPD_STATE_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
dp.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string waybar::modules::MPD::getTag(mpd_tag_type type, unsigned idx) const {
|
std::string waybar::modules::MPD::getTag(mpd_tag_type type, unsigned idx) const {
|
||||||
std::string result =
|
std::string result =
|
||||||
config_["unknown-tag"].isString() ? config_["unknown-tag"].asString() : "N/A";
|
config_["unknown-tag"].isString() ? config_["unknown-tag"].asString() : "N/A";
|
||||||
@@ -117,15 +104,15 @@ void waybar::modules::MPD::setLabel() {
|
|||||||
label_.get_style_context()->remove_class("disconnected");
|
label_.get_style_context()->remove_class("disconnected");
|
||||||
|
|
||||||
auto format = format_;
|
auto format = format_;
|
||||||
Glib::ustring artist, album_artist, album, title;
|
|
||||||
std::string date, filename, uri;
|
std::string date, filename, uri;
|
||||||
int song_pos = 0, queue_length = 0, volume = 0;
|
int song_pos = 0, queue_length = 0, volume = 0;
|
||||||
std::chrono::seconds elapsedTime, totalTime;
|
std::chrono::seconds elapsedTime, totalTime;
|
||||||
|
|
||||||
std::string stateIcon = "";
|
std::string stateIcon = "";
|
||||||
bool no_song = song_.get() == nullptr;
|
bool no_song = song_.get() == nullptr;
|
||||||
if (stopped() || no_song) {
|
bool is_stopped = stopped();
|
||||||
if (no_song) spdlog::warn("Bug in mpd: no current song but state is not stopped.");
|
if (is_stopped || no_song) {
|
||||||
|
if (no_song && !is_stopped) spdlog::warn("mpd: no current song while state is not stopped");
|
||||||
format =
|
format =
|
||||||
config_["format-stopped"].isString() ? config_["format-stopped"].asString() : "stopped";
|
config_["format-stopped"].isString() ? config_["format-stopped"].asString() : "stopped";
|
||||||
label_.get_style_context()->add_class("stopped");
|
label_.get_style_context()->add_class("stopped");
|
||||||
@@ -145,10 +132,6 @@ void waybar::modules::MPD::setLabel() {
|
|||||||
|
|
||||||
stateIcon = getStateIcon();
|
stateIcon = getStateIcon();
|
||||||
|
|
||||||
artist = sanitize_string(getTag(MPD_TAG_ARTIST));
|
|
||||||
album_artist = sanitize_string(getTag(MPD_TAG_ALBUM_ARTIST));
|
|
||||||
album = sanitize_string(getTag(MPD_TAG_ALBUM));
|
|
||||||
title = sanitize_string(getTag(MPD_TAG_TITLE));
|
|
||||||
date = sanitize_string(getTag(MPD_TAG_DATE));
|
date = sanitize_string(getTag(MPD_TAG_DATE));
|
||||||
filename = sanitize_string(getFilename());
|
filename = sanitize_string(getFilename());
|
||||||
uri = mpd_song_get_uri(song_.get());
|
uri = mpd_song_get_uri(song_.get());
|
||||||
@@ -170,17 +153,12 @@ void waybar::modules::MPD::setLabel() {
|
|||||||
std::string repeatIcon = getOptionIcon("repeat", repeatActivated);
|
std::string repeatIcon = getOptionIcon("repeat", repeatActivated);
|
||||||
bool singleActivated = mpd_status_get_single(status_.get());
|
bool singleActivated = mpd_status_get_single(status_.get());
|
||||||
std::string singleIcon = getOptionIcon("single", singleActivated);
|
std::string singleIcon = getOptionIcon("single", singleActivated);
|
||||||
if (config_["artist-len"].isInt()) artist = artist.substr(0, config_["artist-len"].asInt());
|
|
||||||
if (config_["album-artist-len"].isInt())
|
|
||||||
album_artist = album_artist.substr(0, config_["album-artist-len"].asInt());
|
|
||||||
if (config_["album-len"].isInt()) album = album.substr(0, config_["album-len"].asInt());
|
|
||||||
if (config_["title-len"].isInt()) title = title.substr(0, config_["title-len"].asInt());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto text = fmt::format(
|
auto text = fmt::format(
|
||||||
fmt::runtime(format), fmt::arg("artist", artist.raw()),
|
fmt::runtime(format), fmt::arg("artist", getArtistStr(true)),
|
||||||
fmt::arg("albumArtist", album_artist.raw()), fmt::arg("album", album.raw()),
|
fmt::arg("albumArtist", getAlbumArtistStr(true)), fmt::arg("album", getAlbumStr(true)),
|
||||||
fmt::arg("title", title.raw()), fmt::arg("date", date), fmt::arg("volume", volume),
|
fmt::arg("title", getTitleStr(true)), fmt::arg("date", date), fmt::arg("volume", volume),
|
||||||
fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime),
|
fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime),
|
||||||
fmt::arg("songPosition", song_pos), fmt::arg("queueLength", queue_length),
|
fmt::arg("songPosition", song_pos), fmt::arg("queueLength", queue_length),
|
||||||
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon),
|
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon),
|
||||||
@@ -202,9 +180,9 @@ void waybar::modules::MPD::setLabel() {
|
|||||||
: "MPD (connected)";
|
: "MPD (connected)";
|
||||||
try {
|
try {
|
||||||
auto tooltip_text = fmt::format(
|
auto tooltip_text = fmt::format(
|
||||||
fmt::runtime(tooltip_format), fmt::arg("artist", artist.raw()),
|
fmt::runtime(tooltip_format), fmt::arg("artist", getArtistStr(false)),
|
||||||
fmt::arg("albumArtist", album_artist.raw()), fmt::arg("album", album.raw()),
|
fmt::arg("albumArtist", getAlbumArtistStr(false)), fmt::arg("album", getAlbumStr(false)),
|
||||||
fmt::arg("title", title.raw()), fmt::arg("date", date), fmt::arg("volume", volume),
|
fmt::arg("title", getTitleStr(false)), fmt::arg("date", date), fmt::arg("volume", volume),
|
||||||
fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime),
|
fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime),
|
||||||
fmt::arg("songPosition", song_pos), fmt::arg("queueLength", queue_length),
|
fmt::arg("songPosition", song_pos), fmt::arg("queueLength", queue_length),
|
||||||
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon),
|
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon),
|
||||||
@@ -257,6 +235,38 @@ std::string waybar::modules::MPD::getOptionIcon(const std::string& optionName,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string waybar::modules::MPD::getArtistStr(bool truncated) const {
|
||||||
|
std::string artist = getTag(MPD_TAG_ARTIST);
|
||||||
|
if (truncated && config_["artist-len"].isInt()) {
|
||||||
|
waybar::util::utf8_truncate(artist, ellipsis_, config_["artist-len"].asInt());
|
||||||
|
}
|
||||||
|
return sanitize_string(artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string waybar::modules::MPD::getAlbumArtistStr(bool truncated) const {
|
||||||
|
std::string album_artist = getTag(MPD_TAG_ALBUM_ARTIST);
|
||||||
|
if (truncated && config_["album-artist-len"].isInt()) {
|
||||||
|
waybar::util::utf8_truncate(album_artist, ellipsis_, config_["album-artist-len"].asInt());
|
||||||
|
}
|
||||||
|
return sanitize_string(album_artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string waybar::modules::MPD::getAlbumStr(bool truncated) const {
|
||||||
|
std::string album = getTag(MPD_TAG_ALBUM);
|
||||||
|
if (truncated && config_["album-len"].isInt()) {
|
||||||
|
waybar::util::utf8_truncate(album, ellipsis_, config_["album-len"].asInt());
|
||||||
|
}
|
||||||
|
return sanitize_string(album);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string waybar::modules::MPD::getTitleStr(bool truncated) const {
|
||||||
|
std::string title = getTag(MPD_TAG_TITLE);
|
||||||
|
if (truncated && config_["title-len"].isInt()) {
|
||||||
|
waybar::util::utf8_truncate(title, ellipsis_, config_["title-len"].asInt());
|
||||||
|
}
|
||||||
|
return sanitize_string(title);
|
||||||
|
}
|
||||||
|
|
||||||
static bool isServerUnavailable(const std::error_code& ec) {
|
static bool isServerUnavailable(const std::error_code& ec) {
|
||||||
if (ec.category() == std::system_category()) {
|
if (ec.category() == std::system_category()) {
|
||||||
switch (ec.value()) {
|
switch (ec.value()) {
|
||||||
|
|||||||
@@ -152,7 +152,6 @@ bool Playing::on_timer() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_->queryMPD();
|
|
||||||
ctx_->emit();
|
ctx_->emit();
|
||||||
} catch (std::exception const& e) {
|
} catch (std::exception const& e) {
|
||||||
spdlog::warn("mpd: Playing: error: {}", e.what());
|
spdlog::warn("mpd: Playing: error: {}", e.what());
|
||||||
|
|||||||
+14
-57
@@ -7,6 +7,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/scope_guard.hpp"
|
#include "util/scope_guard.hpp"
|
||||||
|
#include "util/utf8_string.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <playerctl/playerctl.h>
|
#include <playerctl/playerctl.h>
|
||||||
@@ -202,69 +203,22 @@ auto Mpris::getIconFromJson(const Json::Value& icons, const std::string& key) ->
|
|||||||
// Wide characters count as two, zero-width characters count as zero
|
// Wide characters count as two, zero-width characters count as zero
|
||||||
// Modifies str in-place (unless width = std::string::npos)
|
// Modifies str in-place (unless width = std::string::npos)
|
||||||
// Returns the total width of the string pre-truncating
|
// Returns the total width of the string pre-truncating
|
||||||
size_t utf8_truncate(std::string& str, size_t width = std::string::npos) {
|
|
||||||
if (str.length() == 0) return 0;
|
|
||||||
|
|
||||||
const gchar* trunc_end = nullptr;
|
|
||||||
|
|
||||||
size_t total_width = 0;
|
|
||||||
|
|
||||||
for (gchar *data = str.data(), *end = data + str.size(); data != nullptr;) {
|
|
||||||
gunichar c = g_utf8_get_char_validated(data, end - data);
|
|
||||||
if (c == -1U || c == -2U) {
|
|
||||||
// invalid unicode, treat string as ascii
|
|
||||||
if (width != std::string::npos && str.length() > width) str.resize(width);
|
|
||||||
return str.length();
|
|
||||||
} else if (g_unichar_iswide(c)) {
|
|
||||||
total_width += 2;
|
|
||||||
} else if (!g_unichar_iszerowidth(c) && c != 0xAD) { // neither zero-width nor soft hyphen
|
|
||||||
total_width += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_utf8_find_next_char(data, end);
|
|
||||||
if (width != std::string::npos && total_width <= width && !g_unichar_isspace(c))
|
|
||||||
trunc_end = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trunc_end) str.resize(trunc_end - str.data());
|
|
||||||
|
|
||||||
return total_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t utf8_width(const std::string& str) { return utf8_truncate(const_cast<std::string&>(str)); }
|
|
||||||
|
|
||||||
void truncate(std::string& s, const std::string& ellipsis, size_t max_len) {
|
|
||||||
if (max_len == 0) {
|
|
||||||
s.resize(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
size_t len = utf8_truncate(s, max_len);
|
|
||||||
if (len > max_len) {
|
|
||||||
size_t ellipsis_len = utf8_width(ellipsis);
|
|
||||||
if (max_len >= ellipsis_len) {
|
|
||||||
if (ellipsis_len) utf8_truncate(s, max_len - ellipsis_len);
|
|
||||||
s += ellipsis;
|
|
||||||
} else {
|
|
||||||
s.resize(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Mpris::getArtistStr(const PlayerInfo& info, bool truncated) -> std::string {
|
auto Mpris::getArtistStr(const PlayerInfo& info, bool truncated) -> std::string {
|
||||||
auto artist = info.artist.value_or(std::string());
|
auto artist = info.artist.value_or(std::string());
|
||||||
if (truncated && artist_len_ >= 0) truncate(artist, ellipsis_, artist_len_);
|
if (truncated && artist_len_ >= 0) waybar::util::utf8_truncate(artist, ellipsis_, artist_len_);
|
||||||
return artist;
|
return artist;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mpris::getAlbumStr(const PlayerInfo& info, bool truncated) -> std::string {
|
auto Mpris::getAlbumStr(const PlayerInfo& info, bool truncated) -> std::string {
|
||||||
auto album = info.album.value_or(std::string());
|
auto album = info.album.value_or(std::string());
|
||||||
if (truncated && album_len_ >= 0) truncate(album, ellipsis_, album_len_);
|
if (truncated && album_len_ >= 0) waybar::util::utf8_truncate(album, ellipsis_, album_len_);
|
||||||
return album;
|
return album;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mpris::getTitleStr(const PlayerInfo& info, bool truncated) -> std::string {
|
auto Mpris::getTitleStr(const PlayerInfo& info, bool truncated) -> std::string {
|
||||||
auto title = info.title.value_or(std::string());
|
auto title = info.title.value_or(std::string());
|
||||||
if (truncated && title_len_ >= 0) truncate(title, ellipsis_, title_len_);
|
if (truncated && title_len_ >= 0) waybar::util::utf8_truncate(title, ellipsis_, title_len_);
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,9 +246,9 @@ auto Mpris::getDynamicStr(const PlayerInfo& info, bool truncated, bool html) ->
|
|||||||
// keep position format same as length format
|
// keep position format same as length format
|
||||||
auto position = getPositionStr(info, truncated && truncate_hours_ && length.length() < 6);
|
auto position = getPositionStr(info, truncated && truncate_hours_ && length.length() < 6);
|
||||||
|
|
||||||
size_t artistLen = utf8_width(artist);
|
size_t artistLen = waybar::util::utf8_width(artist);
|
||||||
size_t albumLen = utf8_width(album);
|
size_t albumLen = waybar::util::utf8_width(album);
|
||||||
size_t titleLen = utf8_width(title);
|
size_t titleLen = waybar::util::utf8_width(title);
|
||||||
size_t lengthLen = length.length();
|
size_t lengthLen = length.length();
|
||||||
size_t posLen = position.length();
|
size_t posLen = position.length();
|
||||||
|
|
||||||
@@ -313,7 +267,7 @@ auto Mpris::getDynamicStr(const PlayerInfo& info, bool truncated, bool html) ->
|
|||||||
// Since the first element doesn't present a separator and we don't know a priori which one
|
// Since the first element doesn't present a separator and we don't know a priori which one
|
||||||
// it will be, we add a "virtual separatorLen" to the dynamicLen, since we are adding the
|
// it will be, we add a "virtual separatorLen" to the dynamicLen, since we are adding the
|
||||||
// separatorLen to all the other lengths.
|
// separatorLen to all the other lengths.
|
||||||
size_t separatorLen = utf8_width(dynamic_separator_);
|
size_t separatorLen = waybar::util::utf8_width(dynamic_separator_);
|
||||||
size_t dynamicLen = dynamic_len_ + separatorLen;
|
size_t dynamicLen = dynamic_len_ + separatorLen;
|
||||||
if (showArtist) artistLen += separatorLen;
|
if (showArtist) artistLen += separatorLen;
|
||||||
if (showAlbum) albumLen += separatorLen;
|
if (showAlbum) albumLen += separatorLen;
|
||||||
@@ -775,9 +729,12 @@ auto Mpris::update() -> void {
|
|||||||
auto tooltip_text = fmt::format(
|
auto tooltip_text = fmt::format(
|
||||||
fmt::runtime(tooltipstr), fmt::arg("player", info.name),
|
fmt::runtime(tooltipstr), fmt::arg("player", info.name),
|
||||||
fmt::arg("status", info.status_string),
|
fmt::arg("status", info.status_string),
|
||||||
fmt::arg("artist", getArtistStr(info, tooltip_len_limits_)),
|
fmt::arg("artist",
|
||||||
fmt::arg("title", getTitleStr(info, tooltip_len_limits_)),
|
std::string(Glib::Markup::escape_text(getArtistStr(info, tooltip_len_limits_)))),
|
||||||
fmt::arg("album", getAlbumStr(info, tooltip_len_limits_)),
|
fmt::arg("title",
|
||||||
|
std::string(Glib::Markup::escape_text(getTitleStr(info, tooltip_len_limits_)))),
|
||||||
|
fmt::arg("album",
|
||||||
|
std::string(Glib::Markup::escape_text(getAlbumStr(info, tooltip_len_limits_)))),
|
||||||
fmt::arg("length", tooltipLength), fmt::arg("position", tooltipPosition),
|
fmt::arg("length", tooltipLength), fmt::arg("position", tooltipPosition),
|
||||||
fmt::arg("dynamic", getDynamicStr(info, tooltip_len_limits_, false)),
|
fmt::arg("dynamic", getDynamicStr(info, tooltip_len_limits_, false)),
|
||||||
fmt::arg("player_icon", getIconFromJson(config_["player-icons"], info.name)),
|
fmt::arg("player_icon", getIconFromJson(config_["player-icons"], info.name)),
|
||||||
|
|||||||
@@ -103,7 +103,9 @@ void Workspaces::doUpdate() {
|
|||||||
fmt::arg("output", ws["output"].asString()));
|
fmt::arg("output", ws["output"].asString()));
|
||||||
}
|
}
|
||||||
if (!config_["disable-markup"].asBool()) {
|
if (!config_["disable-markup"].asBool()) {
|
||||||
static_cast<Gtk::Label*>(button.get_children()[0])->set_markup(name);
|
auto* child = gtk_bin_get_child(GTK_BIN(button.gobj()));
|
||||||
|
if (child != nullptr && GTK_IS_LABEL(child))
|
||||||
|
gtk_label_set_markup(GTK_LABEL(child), name.c_str());
|
||||||
} else {
|
} else {
|
||||||
button.set_label(name);
|
button.set_label(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientat
|
|||||||
auto* item = Gtk::make_managed<PrivacyItem>(module, nodeType, nodePtr, orientation, pos,
|
auto* item = Gtk::make_managed<PrivacyItem>(module, nodeType, nodePtr, orientation, pos,
|
||||||
iconSize, transition_duration);
|
iconSize, transition_duration);
|
||||||
box_.add(*item);
|
box_.add(*item);
|
||||||
|
modules_.push_back(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +149,7 @@ auto Privacy::update() -> void {
|
|||||||
bool useAudioOut = false;
|
bool useAudioOut = false;
|
||||||
|
|
||||||
mutex_.lock();
|
mutex_.lock();
|
||||||
for (Gtk::Widget* widget : box_.get_children()) {
|
for (PrivacyItem* module : modules_) {
|
||||||
auto* module = dynamic_cast<PrivacyItem*>(widget);
|
|
||||||
if (module == nullptr) continue;
|
|
||||||
switch (module->privacy_type) {
|
switch (module->privacy_type) {
|
||||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT:
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT:
|
||||||
setScreenshare = true;
|
setScreenshare = true;
|
||||||
|
|||||||
@@ -190,9 +190,17 @@ void Item::setProperty(const Glib::ustring& name, Glib::VariantBase& value) {
|
|||||||
} else if (name == "Status") {
|
} else if (name == "Status") {
|
||||||
setStatus(get_variant<Glib::ustring>(value));
|
setStatus(get_variant<Glib::ustring>(value));
|
||||||
} else if (name == "IconName") {
|
} else if (name == "IconName") {
|
||||||
icon_name = get_variant<std::string>(value);
|
if (has_custom_icon_) {
|
||||||
|
spdlog::trace("Item '{}': ignoring IconName update, custom icon is set", id);
|
||||||
|
} else {
|
||||||
|
icon_name = get_variant<std::string>(value);
|
||||||
|
}
|
||||||
} else if (name == "IconPixmap") {
|
} else if (name == "IconPixmap") {
|
||||||
icon_pixmap = this->extractPixBuf(value.gobj());
|
if (has_custom_icon_) {
|
||||||
|
spdlog::trace("Item '{}': ignoring IconPixmap update, custom icon is set", id);
|
||||||
|
} else {
|
||||||
|
icon_pixmap = this->extractPixBuf(value.gobj());
|
||||||
|
}
|
||||||
} else if (name == "OverlayIconName") {
|
} else if (name == "OverlayIconName") {
|
||||||
overlay_icon_name = get_variant<std::string>(value);
|
overlay_icon_name = get_variant<std::string>(value);
|
||||||
} else if (name == "OverlayIconPixmap") {
|
} else if (name == "OverlayIconPixmap") {
|
||||||
@@ -270,11 +278,13 @@ void Item::setCustomIcon(const std::string& id) {
|
|||||||
Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
|
Glib::RefPtr<Gdk::Pixbuf> custom_pixbuf = Gdk::Pixbuf::create_from_file(custom_icon);
|
||||||
icon_name = ""; // icon_name has priority over pixmap
|
icon_name = ""; // icon_name has priority over pixmap
|
||||||
icon_pixmap = custom_pixbuf;
|
icon_pixmap = custom_pixbuf;
|
||||||
|
has_custom_icon_ = true;
|
||||||
} catch (const Glib::Error& e) {
|
} catch (const Glib::Error& e) {
|
||||||
spdlog::error("Failed to load custom icon {}: {}", custom_icon, e.what());
|
spdlog::error("Failed to load custom icon {}: {}", custom_icon, e.what());
|
||||||
}
|
}
|
||||||
} else { // if file doesn't exist it's most likely an icon_name
|
} else { // if file doesn't exist it's most likely an icon_name
|
||||||
icon_name = custom_icon;
|
icon_name = custom_icon;
|
||||||
|
has_custom_icon_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
|
|||||||
if (config_["spacing"].isUInt()) {
|
if (config_["spacing"].isUInt()) {
|
||||||
box_.set_spacing(config_["spacing"].asUInt());
|
box_.set_spacing(config_["spacing"].asUInt());
|
||||||
}
|
}
|
||||||
if (config["show-passive-items"].isBool()) {
|
|
||||||
show_passive_ = config["show-passive-items"].asBool();
|
|
||||||
}
|
|
||||||
nb_hosts_ += 1;
|
nb_hosts_ += 1;
|
||||||
if (config_["icons"].isObject()) {
|
if (config_["icons"].isObject()) {
|
||||||
IconManager::instance().setIconsConfig(config_["icons"]);
|
IconManager::instance().setIconsConfig(config_["icons"]);
|
||||||
@@ -42,6 +39,8 @@ void Tray::onAdd(std::unique_ptr<Item>& item) {
|
|||||||
} else {
|
} else {
|
||||||
box_.pack_start(item->event_box);
|
box_.pack_start(item->event_box);
|
||||||
}
|
}
|
||||||
|
item->event_box.signal_show().connect([this] { dp.emit(); });
|
||||||
|
item->event_box.signal_hide().connect([this] { dp.emit(); });
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,17 +50,9 @@ void Tray::onRemove(std::unique_ptr<Item>& item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Tray::update() -> void {
|
auto Tray::update() -> void {
|
||||||
// Show tray only when items are available
|
|
||||||
std::vector<Gtk::Widget*> children = box_.get_children();
|
std::vector<Gtk::Widget*> children = box_.get_children();
|
||||||
if (show_passive_) {
|
event_box_.set_visible(std::any_of(children.begin(), children.end(),
|
||||||
event_box_.set_visible(!children.empty());
|
[](Gtk::Widget* child) { return child->get_visible(); }));
|
||||||
} else {
|
|
||||||
event_box_.set_visible(!std::all_of(children.begin(), children.end(), [](Gtk::Widget* child) {
|
|
||||||
return child->get_style_context()->has_class("passive");
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call parent update
|
|
||||||
AModule::update();
|
AModule::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,21 +54,28 @@ void Language::onCmd(const struct Ipc::ipc_response& res) {
|
|||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
auto payload = parser_.parse(res.payload);
|
auto payload = parser_.parse(res.payload);
|
||||||
std::vector<std::string> used_layouts;
|
std::vector<std::string> used_layouts;
|
||||||
// Display current layout of a device with a maximum count of layouts, expecting that all will
|
// Union layout names across every keyboard input so hot-plugged devices contribute their
|
||||||
// be OK
|
// layouts to the map. Track the device with the most layouts to seed the initially displayed
|
||||||
|
// layout, matching the previous behaviour at startup.
|
||||||
Json::ArrayIndex max_id = 0, max = 0;
|
Json::ArrayIndex max_id = 0, max = 0;
|
||||||
for (Json::ArrayIndex i = 0; i < payload.size(); i++) {
|
for (Json::ArrayIndex i = 0; i < payload.size(); i++) {
|
||||||
auto size = payload[i][XKB_LAYOUT_NAMES_KEY].size();
|
if (payload[i]["type"].asString() != "keyboard") continue;
|
||||||
if (size > max) {
|
const auto& names = payload[i][XKB_LAYOUT_NAMES_KEY];
|
||||||
max = size;
|
if (names.size() > max) {
|
||||||
|
max = names.size();
|
||||||
max_id = i;
|
max_id = i;
|
||||||
}
|
}
|
||||||
|
for (const auto& layout : names) {
|
||||||
|
const auto name = layout.asString();
|
||||||
|
if (std::find(used_layouts.begin(), used_layouts.end(), name) == used_layouts.end()) {
|
||||||
|
used_layouts.push_back(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& layout : payload[max_id][XKB_LAYOUT_NAMES_KEY]) {
|
// Rebuild from scratch so init_layouts_map's duplicate-suffix pass doesn't compound across
|
||||||
used_layouts.push_back(layout.asString());
|
// refreshes (e.g. "us" -> "us1" -> "us11").
|
||||||
}
|
layouts_map_.clear();
|
||||||
|
|
||||||
init_layouts_map(used_layouts);
|
init_layouts_map(used_layouts);
|
||||||
set_current_layout(payload[max_id][XKB_ACTIVE_LAYOUT_NAME_KEY].asString());
|
set_current_layout(payload[max_id][XKB_ACTIVE_LAYOUT_NAME_KEY].asString());
|
||||||
dp.emit();
|
dp.emit();
|
||||||
@@ -82,13 +89,26 @@ void Language::onEvent(const struct Ipc::ipc_response& res) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool refresh_inputs = false;
|
||||||
try {
|
try {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
{
|
||||||
auto payload = parser_.parse(res.payload)["input"];
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
if (payload["type"].asString() == "keyboard") {
|
auto root = parser_.parse(res.payload);
|
||||||
set_current_layout(payload[XKB_ACTIVE_LAYOUT_NAME_KEY].asString());
|
auto change = root["change"].asString();
|
||||||
|
auto payload = root["input"];
|
||||||
|
if (payload["type"].asString() == "keyboard") {
|
||||||
|
// A device was added or its keymap changed - the layout set may have grown, so refresh
|
||||||
|
// layouts_map_ via IPC_GET_INPUTS once we've released mutex_.
|
||||||
|
refresh_inputs = (change == "added" || change == "xkb_keymap");
|
||||||
|
set_current_layout(payload[XKB_ACTIVE_LAYOUT_NAME_KEY].asString());
|
||||||
|
}
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
// sendCmd is synchronous: it blocks on the IPC reply and then emits signal_cmd on this same
|
||||||
|
// thread, which lands in onCmd and re-locks mutex_. Must call it with mutex_ released.
|
||||||
|
if (refresh_inputs) {
|
||||||
|
ipc_.sendCmd(IPC_GET_INPUTS);
|
||||||
}
|
}
|
||||||
dp.emit();
|
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::error("Language: {}", e.what());
|
spdlog::error("Language: {}", e.what());
|
||||||
}
|
}
|
||||||
@@ -125,8 +145,15 @@ auto Language::update() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Language::set_current_layout(const std::string& current_layout) -> void {
|
auto Language::set_current_layout(const std::string& current_layout) -> void {
|
||||||
|
// Guard against unknown / empty layout names: transient virtual keyboards (e.g. wtype) and
|
||||||
|
// hot-plugged devices whose layouts haven't made it into the map yet would otherwise blank out
|
||||||
|
// layout_ via map::operator[]'s default-construct-on-miss.
|
||||||
|
auto it = layouts_map_.find(current_layout);
|
||||||
|
if (it == layouts_map_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
label_.get_style_context()->remove_class(layout_.short_name);
|
label_.get_style_context()->remove_class(layout_.short_name);
|
||||||
layout_ = layouts_map_[current_layout];
|
layout_ = it->second;
|
||||||
label_.get_style_context()->add_class(layout_.short_name);
|
label_.get_style_context()->add_class(layout_.short_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -229,7 +229,10 @@ bool Workspaces::filterButtons() {
|
|||||||
auto ws = std::find_if(workspaces_.begin(), workspaces_.end(),
|
auto ws = std::find_if(workspaces_.begin(), workspaces_.end(),
|
||||||
[it](const auto& node) { return node["name"].asString() == it->first; });
|
[it](const auto& node) { return node["name"].asString() == it->first; });
|
||||||
if (ws == workspaces_.end() ||
|
if (ws == workspaces_.end() ||
|
||||||
(!config_["all-outputs"].asBool() && (*ws)["output"].asString() != bar_.output->name)) {
|
((*ws).isMember("target_output") ? (*ws)["target_output"].asString() != bar_.output->name &&
|
||||||
|
(*ws)["target_output"].asString() != ""
|
||||||
|
: !config_["all-outputs"].asBool() &&
|
||||||
|
(*ws)["output"].asString() != bar_.output->name)) {
|
||||||
it = buttons_.erase(it);
|
it = buttons_.erase(it);
|
||||||
needReorder = true;
|
needReorder = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -369,11 +372,14 @@ Gtk::Button& Workspaces::addButton(const Json::Value& node) {
|
|||||||
node["name"].asString(), node["target_output"].asString(),
|
node["name"].asString(), node["target_output"].asString(),
|
||||||
"--no-auto-back-and-forth", node["name"].asString()));
|
"--no-auto-back-and-forth", node["name"].asString()));
|
||||||
} else {
|
} else {
|
||||||
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace {} \"{}\"",
|
std::string flag = config_["disable-auto-back-and-forth"].asBool()
|
||||||
config_["disable-auto-back-and-forth"].asBool()
|
? "--no-auto-back-and-forth"
|
||||||
? "--no-auto-back-and-forth"
|
: "";
|
||||||
: "",
|
if (node["num"].asInt() >= 0) {
|
||||||
node["name"].asString()));
|
ipc_.sendCmd(IPC_COMMAND, fmt::format(workspace_switch_number_cmd_, flag, node["num"].asInt()));
|
||||||
|
} else {
|
||||||
|
ipc_.sendCmd(IPC_COMMAND, fmt::format(workspace_switch_cmd_, flag, node["name"].asString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::error("Workspaces: {}", e.what());
|
spdlog::error("Workspaces: {}", e.what());
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ SystemdFailedUnits::SystemdFailedUnits(const std::string& id, const Json::Value&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!user_props_proxy_ && !system_props_proxy_)
|
||||||
|
throw std::runtime_error("Neither system nor user status is requested.");
|
||||||
|
|
||||||
updateData();
|
updateData();
|
||||||
/* Always update for the first time. */
|
/* Always update for the first time. */
|
||||||
dp.emit();
|
dp.emit();
|
||||||
@@ -103,7 +106,7 @@ auto SystemdFailedUnits::notify_cb(const Glib::ustring& sender_name,
|
|||||||
void SystemdFailedUnits::RequestSystemState() {
|
void SystemdFailedUnits::RequestSystemState() {
|
||||||
auto load = [](const char* kind, Glib::RefPtr<Gio::DBus::Proxy>& proxy) -> std::string {
|
auto load = [](const char* kind, Glib::RefPtr<Gio::DBus::Proxy>& proxy) -> std::string {
|
||||||
try {
|
try {
|
||||||
if (!proxy) return "unknown";
|
if (!proxy) return "ignored";
|
||||||
auto parameters = Glib::VariantContainerBase(
|
auto parameters = Glib::VariantContainerBase(
|
||||||
g_variant_new("(ss)", "org.freedesktop.systemd1.Manager", "SystemState"));
|
g_variant_new("(ss)", "org.freedesktop.systemd1.Manager", "SystemState"));
|
||||||
Glib::VariantContainerBase data = proxy->call_sync("Get", parameters);
|
Glib::VariantContainerBase data = proxy->call_sync("Get", parameters);
|
||||||
@@ -122,7 +125,9 @@ void SystemdFailedUnits::RequestSystemState() {
|
|||||||
|
|
||||||
system_state_ = load("systemwide", system_props_proxy_);
|
system_state_ = load("systemwide", system_props_proxy_);
|
||||||
user_state_ = load("user", user_props_proxy_);
|
user_state_ = load("user", user_props_proxy_);
|
||||||
if (system_state_ == "running" && user_state_ == "running")
|
|
||||||
|
if ((system_state_ == "running" || system_state_ == "ignored") &&
|
||||||
|
(user_state_ == "running" || user_state_ == "ignored"))
|
||||||
overall_state_ = "ok";
|
overall_state_ = "ok";
|
||||||
else
|
else
|
||||||
overall_state_ = "degraded";
|
overall_state_ = "degraded";
|
||||||
|
|||||||
@@ -155,3 +155,7 @@ bool waybar::modules::Temperature::isCritical(uint16_t temperature_c) {
|
|||||||
return config_["critical-threshold"].isInt() &&
|
return config_["critical-threshold"].isInt() &&
|
||||||
temperature_c >= config_["critical-threshold"].asInt();
|
temperature_c >= config_["critical-threshold"].asInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waybar::modules::Temperature::suspend() { thread_.pause(); }
|
||||||
|
|
||||||
|
void waybar::modules::Temperature::resume() { thread_.resume(); }
|
||||||
|
|||||||
@@ -347,10 +347,13 @@ auto IPC::update_state_handler(const std::string& event, const Json::Value& data
|
|||||||
|
|
||||||
if (event == "output-wset-changed") {
|
if (event == "output-wset-changed") {
|
||||||
// data: { event, new-wset: wset.name, output: id, new-wset-data: wset, output-data: output }
|
// data: { event, new-wset: wset.name, output: id, new-wset-data: wset, output-data: output }
|
||||||
auto& output = state.outputs.at(data["output-data"]["name"].asString());
|
try {
|
||||||
auto wset_idx = data["new-wset-data"]["index"].asUInt();
|
auto& output = state.outputs.at(data["output-data"]["name"].asString());
|
||||||
state.wsets.at(wset_idx).output = output;
|
auto wset_idx = data["new-wset-data"]["index"].asUInt();
|
||||||
output.wset_idx = wset_idx;
|
state.wsets.at(wset_idx).output = output;
|
||||||
|
output.wset_idx = wset_idx;
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,15 +99,17 @@ void AudioBackend::contextStateCb(pa_context* c, void* data) {
|
|||||||
nullptr, nullptr);
|
nullptr, nullptr);
|
||||||
break;
|
break;
|
||||||
case PA_CONTEXT_FAILED:
|
case PA_CONTEXT_FAILED:
|
||||||
// When pulseaudio server restarts, the connection is "failed". Try to reconnect.
|
if (pa_context_errno(c) != PA_ERR_CONNECTIONREFUSED) {
|
||||||
// pa_threaded_mainloop_lock is already acquired in callback threads.
|
// When pulseaudio server restarts, the connection is "failed". Try to reconnect.
|
||||||
// So there is no need to lock it again.
|
// pa_threaded_mainloop_lock is already acquired in callback threads.
|
||||||
if (backend->context_ != nullptr) {
|
// So there is no need to lock it again.
|
||||||
pa_context_disconnect(backend->context_);
|
if (backend->context_ != nullptr) {
|
||||||
pa_context_unref(backend->context_);
|
pa_context_disconnect(backend->context_);
|
||||||
backend->context_ = nullptr;
|
pa_context_unref(backend->context_);
|
||||||
|
backend->context_ = nullptr;
|
||||||
|
}
|
||||||
|
backend->connectContext();
|
||||||
}
|
}
|
||||||
backend->connectContext();
|
|
||||||
break;
|
break;
|
||||||
case PA_CONTEXT_CONNECTING:
|
case PA_CONTEXT_CONNECTING:
|
||||||
case PA_CONTEXT_AUTHORIZING:
|
case PA_CONTEXT_AUTHORIZING:
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <util/utf8_string.hpp>
|
||||||
|
|
||||||
|
namespace waybar::util {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Wide characters count as two, zero-width characters count as zero
|
||||||
|
// Modifies str in-place (unless width = std::string::npos)
|
||||||
|
// Returns the total width of the string pre-truncating
|
||||||
|
size_t measure_and_truncate(std::string& str, size_t width = std::string::npos) {
|
||||||
|
if (str.length() == 0) return 0;
|
||||||
|
|
||||||
|
const gchar* trunc_end = nullptr;
|
||||||
|
|
||||||
|
size_t total_width = 0;
|
||||||
|
|
||||||
|
for (gchar *data = str.data(), *end = data + str.size(); data != nullptr;) {
|
||||||
|
gunichar c = g_utf8_get_char_validated(data, end - data);
|
||||||
|
if (c == -1U || c == -2U) {
|
||||||
|
// invalid unicode, treat string as ascii
|
||||||
|
if (width != std::string::npos && str.length() > width) str.resize(width);
|
||||||
|
return str.length();
|
||||||
|
} else if (g_unichar_iswide(c)) {
|
||||||
|
total_width += 2;
|
||||||
|
} else if (!g_unichar_iszerowidth(c) && c != 0xAD) { // neither zero-width nor soft hyphen
|
||||||
|
total_width += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = g_utf8_find_next_char(data, end);
|
||||||
|
if (width != std::string::npos && total_width <= width && !g_unichar_isspace(c))
|
||||||
|
trunc_end = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trunc_end) str.resize(trunc_end - str.data());
|
||||||
|
|
||||||
|
return total_width;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
size_t utf8_width(const std::string& str) {
|
||||||
|
return measure_and_truncate(const_cast<std::string&>(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
void utf8_truncate(std::string& s, const std::string& ellipsis, size_t max_len) {
|
||||||
|
if (max_len == 0) {
|
||||||
|
s.resize(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t len = measure_and_truncate(s, max_len);
|
||||||
|
if (len > max_len) {
|
||||||
|
size_t ellipsis_len = utf8_width(ellipsis);
|
||||||
|
if (max_len >= ellipsis_len) {
|
||||||
|
if (ellipsis_len) measure_and_truncate(s, max_len - ellipsis_len);
|
||||||
|
s += ellipsis;
|
||||||
|
} else {
|
||||||
|
s.resize(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace waybar::util
|
||||||
@@ -160,7 +160,7 @@ TEST_CASE("buildLuaDispatch focusworkspaceoncurrentmonitor", "[buildLuaDispatch]
|
|||||||
IPCTestHelper::buildLuaDispatch("focusworkspaceoncurrentmonitor", "3");
|
IPCTestHelper::buildLuaDispatch("focusworkspaceoncurrentmonitor", "3");
|
||||||
REQUIRE(
|
REQUIRE(
|
||||||
result ==
|
result ==
|
||||||
"/dispatch hl.dsp.focus({ workspace = \"3\", monitor = \"current\" })");
|
"/dispatch hl.dsp.focus({ workspace = \"3\", on_current_monitor = true })");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("buildLuaDispatch togglespecialworkspace", "[buildLuaDispatch]") {
|
TEST_CASE("buildLuaDispatch togglespecialworkspace", "[buildLuaDispatch]") {
|
||||||
|
|||||||
Reference in New Issue
Block a user