Merge remote-tracking branch 'origin/master' into pr/pulseaudio_mapping
# Conflicts: # src/util/audio_backend.cpp
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <glibmm/dispatcher.h>
|
||||
#include <sigc++/signal.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
@@ -22,6 +23,12 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
|
||||
public:
|
||||
SafeSignal() { dp_.connect(sigc::mem_fun(*this, &SafeSignal::handle_event)); }
|
||||
|
||||
void set_max_queued_events(std::size_t max_queued_events) {
|
||||
std::unique_lock lock(mutex_);
|
||||
max_queued_events_ = max_queued_events;
|
||||
trim_queue_locked();
|
||||
}
|
||||
|
||||
template <typename... EmitArgs>
|
||||
void emit(EmitArgs&&... args) {
|
||||
if (main_tid_ == std::this_thread::get_id()) {
|
||||
@@ -36,6 +43,9 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
|
||||
} else {
|
||||
{
|
||||
std::unique_lock lock(mutex_);
|
||||
if (max_queued_events_ != 0 && queue_.size() >= max_queued_events_) {
|
||||
queue_.pop();
|
||||
}
|
||||
queue_.emplace(std::forward<EmitArgs>(args)...);
|
||||
}
|
||||
dp_.emit();
|
||||
@@ -55,6 +65,15 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
|
||||
using signal_t::emit_reverse;
|
||||
using signal_t::make_slot;
|
||||
|
||||
void trim_queue_locked() {
|
||||
if (max_queued_events_ == 0) {
|
||||
return;
|
||||
}
|
||||
while (queue_.size() > max_queued_events_) {
|
||||
queue_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_event() {
|
||||
for (std::unique_lock lock(mutex_); !queue_.empty(); lock.lock()) {
|
||||
auto args = queue_.front();
|
||||
@@ -67,6 +86,7 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
|
||||
Glib::Dispatcher dp_;
|
||||
std::mutex mutex_;
|
||||
std::queue<arg_tuple_t> queue_;
|
||||
std::size_t max_queued_events_ = 4096;
|
||||
const std::thread::id main_tid_ = std::this_thread::get_id();
|
||||
// cache functor for signal emission to avoid recreating it on each event
|
||||
const slot_t cached_fn_ = make_slot();
|
||||
|
||||
@@ -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*);
|
||||
@@ -38,6 +43,8 @@ class AudioBackend {
|
||||
std::string desc_;
|
||||
std::string monitor_;
|
||||
std::string current_sink_name_;
|
||||
std::string default_sink_name;
|
||||
bool default_sink_running_;
|
||||
bool current_sink_running_;
|
||||
// SOURCE
|
||||
uint32_t source_idx_{0};
|
||||
@@ -92,6 +99,10 @@ class AudioBackend {
|
||||
void toggleSourceMute();
|
||||
void toggleSourceMute(bool);
|
||||
|
||||
uint16_t getVolume(PulseaudioTarget) const;
|
||||
bool getMuted(PulseaudioTarget) const;
|
||||
void unmute(PulseaudioTarget);
|
||||
|
||||
bool isBluetooth();
|
||||
};
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ class BacklightDevice {
|
||||
void set_max(int max);
|
||||
bool get_powered() const;
|
||||
void set_powered(bool powered);
|
||||
friend inline bool operator==(const BacklightDevice &lhs, const BacklightDevice &rhs) {
|
||||
friend inline bool operator==(const BacklightDevice& lhs, const BacklightDevice& rhs) {
|
||||
return lhs.name_ == rhs.name_ && lhs.actual_ == rhs.actual_ && lhs.max_ == rhs.max_;
|
||||
}
|
||||
|
||||
@@ -52,25 +52,25 @@ class BacklightBackend {
|
||||
BacklightBackend(std::chrono::milliseconds interval, std::function<void()> on_updated_cb = NOOP);
|
||||
|
||||
// const inline BacklightDevice *get_best_device(std::string_view preferred_device);
|
||||
const BacklightDevice *get_previous_best_device();
|
||||
const BacklightDevice* get_previous_best_device();
|
||||
|
||||
void set_previous_best_device(const BacklightDevice *device);
|
||||
void set_previous_best_device(const BacklightDevice* device);
|
||||
|
||||
void set_brightness(const std::string &preferred_device, ChangeType change_type, double step);
|
||||
void set_brightness(const std::string& preferred_device, ChangeType change_type, double step);
|
||||
|
||||
void set_scaled_brightness(const std::string &preferred_device, int brightness);
|
||||
int get_scaled_brightness(const std::string &preferred_device);
|
||||
void set_scaled_brightness(const std::string& preferred_device, int brightness);
|
||||
int get_scaled_brightness(const std::string& preferred_device);
|
||||
|
||||
bool is_login_proxy_initialized() const { return static_cast<bool>(login_proxy_); }
|
||||
|
||||
static const BacklightDevice *best_device(const std::vector<BacklightDevice> &devices,
|
||||
static const BacklightDevice* best_device(const std::vector<BacklightDevice>& devices,
|
||||
std::string_view);
|
||||
|
||||
std::vector<BacklightDevice> devices_;
|
||||
std::mutex udev_thread_mutex_;
|
||||
|
||||
private:
|
||||
void set_brightness_internal(const std::string &device_name, int brightness, int max_brightness);
|
||||
void set_brightness_internal(const std::string& device_name, int brightness, int max_brightness);
|
||||
|
||||
std::function<void()> on_updated_cb_;
|
||||
std::chrono::milliseconds polling_interval_;
|
||||
|
||||
+128
-128
@@ -78,7 +78,7 @@ class Column {
|
||||
class iterator {
|
||||
friend Column;
|
||||
|
||||
Column const &m_column;
|
||||
Column const& m_column;
|
||||
size_t m_stringIndex = 0;
|
||||
size_t m_pos = 0;
|
||||
|
||||
@@ -86,10 +86,10 @@ class Column {
|
||||
size_t m_end = 0;
|
||||
bool m_suffix = false;
|
||||
|
||||
iterator(Column const &column, size_t stringIndex)
|
||||
iterator(Column const& column, size_t stringIndex)
|
||||
: m_column(column), m_stringIndex(stringIndex) {}
|
||||
|
||||
auto line() const -> std::string const & { return m_column.m_strings[m_stringIndex]; }
|
||||
auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
|
||||
|
||||
auto isBoundary(size_t at) const -> bool {
|
||||
assert(at > 0);
|
||||
@@ -129,18 +129,18 @@ class Column {
|
||||
return initial == std::string::npos ? m_column.m_indent : initial;
|
||||
}
|
||||
|
||||
auto addIndentAndSuffix(std::string const &plain) const -> std::string {
|
||||
auto addIndentAndSuffix(std::string const& plain) const -> std::string {
|
||||
return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
|
||||
}
|
||||
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = std::string;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
explicit iterator(Column const &column) : m_column(column) {
|
||||
explicit iterator(Column const& column) : m_column(column) {
|
||||
assert(m_column.m_width > m_column.m_indent);
|
||||
assert(m_column.m_initialIndent == std::string::npos ||
|
||||
m_column.m_width > m_column.m_initialIndent);
|
||||
@@ -154,7 +154,7 @@ class Column {
|
||||
return addIndentAndSuffix(line().substr(m_pos, m_len));
|
||||
}
|
||||
|
||||
auto operator++() -> iterator & {
|
||||
auto operator++() -> iterator& {
|
||||
m_pos += m_len;
|
||||
if (m_pos < line().size() && line()[m_pos] == '\n')
|
||||
m_pos += 1;
|
||||
@@ -174,26 +174,26 @@ class Column {
|
||||
return prev;
|
||||
}
|
||||
|
||||
auto operator==(iterator const &other) const -> bool {
|
||||
auto operator==(iterator const& other) const -> bool {
|
||||
return m_pos == other.m_pos && m_stringIndex == other.m_stringIndex &&
|
||||
&m_column == &other.m_column;
|
||||
}
|
||||
auto operator!=(iterator const &other) const -> bool { return !operator==(other); }
|
||||
auto operator!=(iterator const& other) const -> bool { return !operator==(other); }
|
||||
};
|
||||
using const_iterator = iterator;
|
||||
|
||||
explicit Column(std::string const &text) { m_strings.push_back(text); }
|
||||
explicit Column(std::string const& text) { m_strings.push_back(text); }
|
||||
|
||||
auto width(size_t newWidth) -> Column & {
|
||||
auto width(size_t newWidth) -> Column& {
|
||||
assert(newWidth > 0);
|
||||
m_width = newWidth;
|
||||
return *this;
|
||||
}
|
||||
auto indent(size_t newIndent) -> Column & {
|
||||
auto indent(size_t newIndent) -> Column& {
|
||||
m_indent = newIndent;
|
||||
return *this;
|
||||
}
|
||||
auto initialIndent(size_t newIndent) -> Column & {
|
||||
auto initialIndent(size_t newIndent) -> Column& {
|
||||
m_initialIndent = newIndent;
|
||||
return *this;
|
||||
}
|
||||
@@ -202,7 +202,7 @@ class Column {
|
||||
auto begin() const -> iterator { return iterator(*this); }
|
||||
auto end() const -> iterator { return {*this, m_strings.size()}; }
|
||||
|
||||
inline friend std::ostream &operator<<(std::ostream &os, Column const &col) {
|
||||
inline friend std::ostream& operator<<(std::ostream& os, Column const& col) {
|
||||
bool first = true;
|
||||
for (auto line : col) {
|
||||
if (first)
|
||||
@@ -214,7 +214,7 @@ class Column {
|
||||
return os;
|
||||
}
|
||||
|
||||
auto operator+(Column const &other) -> Columns;
|
||||
auto operator+(Column const& other) -> Columns;
|
||||
|
||||
auto toString() const -> std::string {
|
||||
std::ostringstream oss;
|
||||
@@ -236,34 +236,34 @@ class Columns {
|
||||
friend Columns;
|
||||
struct EndTag {};
|
||||
|
||||
std::vector<Column> const &m_columns;
|
||||
std::vector<Column> const& m_columns;
|
||||
std::vector<Column::iterator> m_iterators;
|
||||
size_t m_activeIterators;
|
||||
|
||||
iterator(Columns const &columns, EndTag) : m_columns(columns.m_columns), m_activeIterators(0) {
|
||||
iterator(Columns const& columns, EndTag) : m_columns(columns.m_columns), m_activeIterators(0) {
|
||||
m_iterators.reserve(m_columns.size());
|
||||
|
||||
for (auto const &col : m_columns) m_iterators.push_back(col.end());
|
||||
for (auto const& col : m_columns) m_iterators.push_back(col.end());
|
||||
}
|
||||
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = std::string;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
explicit iterator(Columns const &columns)
|
||||
explicit iterator(Columns const& columns)
|
||||
: m_columns(columns.m_columns), m_activeIterators(m_columns.size()) {
|
||||
m_iterators.reserve(m_columns.size());
|
||||
|
||||
for (auto const &col : m_columns) m_iterators.push_back(col.begin());
|
||||
for (auto const& col : m_columns) m_iterators.push_back(col.begin());
|
||||
}
|
||||
|
||||
auto operator==(iterator const &other) const -> bool {
|
||||
auto operator==(iterator const& other) const -> bool {
|
||||
return m_iterators == other.m_iterators;
|
||||
}
|
||||
auto operator!=(iterator const &other) const -> bool {
|
||||
auto operator!=(iterator const& other) const -> bool {
|
||||
return m_iterators != other.m_iterators;
|
||||
}
|
||||
auto operator*() const -> std::string {
|
||||
@@ -284,7 +284,7 @@ class Columns {
|
||||
}
|
||||
return row;
|
||||
}
|
||||
auto operator++() -> iterator & {
|
||||
auto operator++() -> iterator& {
|
||||
for (size_t i = 0; i < m_columns.size(); ++i) {
|
||||
if (m_iterators[i] != m_columns[i].end()) ++m_iterators[i];
|
||||
}
|
||||
@@ -301,17 +301,17 @@ class Columns {
|
||||
auto begin() const -> iterator { return iterator(*this); }
|
||||
auto end() const -> iterator { return {*this, iterator::EndTag()}; }
|
||||
|
||||
auto operator+=(Column const &col) -> Columns & {
|
||||
auto operator+=(Column const& col) -> Columns& {
|
||||
m_columns.push_back(col);
|
||||
return *this;
|
||||
}
|
||||
auto operator+(Column const &col) -> Columns {
|
||||
auto operator+(Column const& col) -> Columns {
|
||||
Columns combined = *this;
|
||||
combined += col;
|
||||
return combined;
|
||||
}
|
||||
|
||||
inline friend std::ostream &operator<<(std::ostream &os, Columns const &cols) {
|
||||
inline friend std::ostream& operator<<(std::ostream& os, Columns const& cols) {
|
||||
bool first = true;
|
||||
for (auto line : cols) {
|
||||
if (first)
|
||||
@@ -330,7 +330,7 @@ class Columns {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto Column::operator+(Column const &other) -> Columns {
|
||||
inline auto Column::operator+(Column const& other) -> Columns {
|
||||
Columns cols;
|
||||
cols += *this;
|
||||
cols += other;
|
||||
@@ -381,7 +381,7 @@ class Args {
|
||||
std::vector<std::string> m_args;
|
||||
|
||||
public:
|
||||
Args(int argc, char const *const *argv) : m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
|
||||
Args(int argc, char const* const* argv) : m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
|
||||
|
||||
Args(std::initializer_list<std::string> args)
|
||||
: m_exeName(*args.begin()), m_args(args.begin() + 1, args.end()) {}
|
||||
@@ -419,7 +419,7 @@ class TokenStream {
|
||||
while (it != itEnd && it->empty()) ++it;
|
||||
|
||||
if (it != itEnd) {
|
||||
auto const &next = *it;
|
||||
auto const& next = *it;
|
||||
if (isOptPrefix(next[0])) {
|
||||
auto delimiterPos = next.find_first_of(" :=");
|
||||
if (delimiterPos != std::string::npos) {
|
||||
@@ -443,7 +443,7 @@ class TokenStream {
|
||||
}
|
||||
|
||||
public:
|
||||
explicit TokenStream(Args const &args) : TokenStream(args.m_args.begin(), args.m_args.end()) {}
|
||||
explicit TokenStream(Args const& args) : TokenStream(args.m_args.begin(), args.m_args.end()) {}
|
||||
|
||||
TokenStream(Iterator it, Iterator itEnd) : it(it), itEnd(itEnd) { loadBuffer(); }
|
||||
|
||||
@@ -456,12 +456,12 @@ class TokenStream {
|
||||
return m_tokenBuffer.front();
|
||||
}
|
||||
|
||||
auto operator->() const -> Token const * {
|
||||
auto operator->() const -> Token const* {
|
||||
assert(!m_tokenBuffer.empty());
|
||||
return &m_tokenBuffer.front();
|
||||
}
|
||||
|
||||
auto operator++() -> TokenStream & {
|
||||
auto operator++() -> TokenStream& {
|
||||
if (m_tokenBuffer.size() >= 2) {
|
||||
m_tokenBuffer.erase(m_tokenBuffer.begin());
|
||||
} else {
|
||||
@@ -488,7 +488,7 @@ class ResultBase {
|
||||
template <typename T>
|
||||
class ResultValueBase : public ResultBase {
|
||||
public:
|
||||
auto value() const -> T const & {
|
||||
auto value() const -> T const& {
|
||||
enforceOk();
|
||||
return m_value;
|
||||
}
|
||||
@@ -496,13 +496,13 @@ class ResultValueBase : public ResultBase {
|
||||
protected:
|
||||
ResultValueBase(Type type) : ResultBase(type) {}
|
||||
|
||||
ResultValueBase(ResultValueBase const &other) : ResultBase(other) {
|
||||
ResultValueBase(ResultValueBase const& other) : ResultBase(other) {
|
||||
if (m_type == ResultBase::Ok) new (&m_value) T(other.m_value);
|
||||
}
|
||||
|
||||
ResultValueBase(Type, T const &value) : ResultBase(Ok) { new (&m_value) T(value); }
|
||||
ResultValueBase(Type, T const& value) : ResultBase(Ok) { new (&m_value) T(value); }
|
||||
|
||||
auto operator=(ResultValueBase const &other) -> ResultValueBase & {
|
||||
auto operator=(ResultValueBase const& other) -> ResultValueBase& {
|
||||
if (m_type == ResultBase::Ok) m_value.~T();
|
||||
ResultBase::operator=(other);
|
||||
if (m_type == ResultBase::Ok) new (&m_value) T(other.m_value);
|
||||
@@ -528,20 +528,20 @@ template <typename T = void>
|
||||
class BasicResult : public ResultValueBase<T> {
|
||||
public:
|
||||
template <typename U>
|
||||
explicit BasicResult(BasicResult<U> const &other)
|
||||
explicit BasicResult(BasicResult<U> const& other)
|
||||
: ResultValueBase<T>(other.type()), m_errorMessage(other.errorMessage()) {
|
||||
assert(type() != ResultBase::Ok);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
static auto ok(U const &value) -> BasicResult {
|
||||
static auto ok(U const& value) -> BasicResult {
|
||||
return {ResultBase::Ok, value};
|
||||
}
|
||||
static auto ok() -> BasicResult { return {ResultBase::Ok}; }
|
||||
static auto logicError(std::string const &message) -> BasicResult {
|
||||
static auto logicError(std::string const& message) -> BasicResult {
|
||||
return {ResultBase::LogicError, message};
|
||||
}
|
||||
static auto runtimeError(std::string const &message) -> BasicResult {
|
||||
static auto runtimeError(std::string const& message) -> BasicResult {
|
||||
return {ResultBase::RuntimeError, message};
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ class BasicResult : public ResultValueBase<T> {
|
||||
|
||||
std::string m_errorMessage; // Only populated if resultType is an error
|
||||
|
||||
BasicResult(ResultBase::Type type, std::string const &message)
|
||||
BasicResult(ResultBase::Type type, std::string const& message)
|
||||
: ResultValueBase<T>(type), m_errorMessage(message) {
|
||||
assert(m_type != ResultBase::Ok);
|
||||
}
|
||||
@@ -573,7 +573,7 @@ enum class ParseResultType { Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
|
||||
|
||||
class ParseState {
|
||||
public:
|
||||
ParseState(ParseResultType type, TokenStream const &remainingTokens)
|
||||
ParseState(ParseResultType type, TokenStream const& remainingTokens)
|
||||
: m_type(type), m_remainingTokens(remainingTokens) {}
|
||||
|
||||
auto type() const -> ParseResultType { return m_type; }
|
||||
@@ -594,7 +594,7 @@ struct HelpColumns {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline auto convertInto(std::string const &source, T &target) -> ParserResult {
|
||||
inline auto convertInto(std::string const& source, T& target) -> ParserResult {
|
||||
std::stringstream ss;
|
||||
ss << source;
|
||||
ss >> target;
|
||||
@@ -603,11 +603,11 @@ inline auto convertInto(std::string const &source, T &target) -> ParserResult {
|
||||
else
|
||||
return ParserResult::ok(ParseResultType::Matched);
|
||||
}
|
||||
inline auto convertInto(std::string const &source, std::string &target) -> ParserResult {
|
||||
inline auto convertInto(std::string const& source, std::string& target) -> ParserResult {
|
||||
target = source;
|
||||
return ParserResult::ok(ParseResultType::Matched);
|
||||
}
|
||||
inline auto convertInto(std::string const &source, bool &target) -> ParserResult {
|
||||
inline auto convertInto(std::string const& source, bool& target) -> ParserResult {
|
||||
std::string srcLC = source;
|
||||
std::transform(srcLC.begin(), srcLC.end(), srcLC.begin(),
|
||||
[](char c) { return static_cast<char>(::tolower(c)); });
|
||||
@@ -622,7 +622,7 @@ inline auto convertInto(std::string const &source, bool &target) -> ParserResult
|
||||
}
|
||||
#ifdef CLARA_CONFIG_OPTIONAL_TYPE
|
||||
template <typename T>
|
||||
inline auto convertInto(std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T> &target)
|
||||
inline auto convertInto(std::string const& source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target)
|
||||
-> ParserResult {
|
||||
T temp;
|
||||
auto result = convertInto(source, temp);
|
||||
@@ -633,10 +633,10 @@ inline auto convertInto(std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>
|
||||
|
||||
struct NonCopyable {
|
||||
NonCopyable() = default;
|
||||
NonCopyable(NonCopyable const &) = delete;
|
||||
NonCopyable(NonCopyable &&) = delete;
|
||||
NonCopyable &operator=(NonCopyable const &) = delete;
|
||||
NonCopyable &operator=(NonCopyable &&) = delete;
|
||||
NonCopyable(NonCopyable const&) = delete;
|
||||
NonCopyable(NonCopyable&&) = delete;
|
||||
NonCopyable& operator=(NonCopyable const&) = delete;
|
||||
NonCopyable& operator=(NonCopyable&&) = delete;
|
||||
};
|
||||
|
||||
struct BoundRef : NonCopyable {
|
||||
@@ -645,7 +645,7 @@ struct BoundRef : NonCopyable {
|
||||
virtual auto isFlag() const -> bool { return false; }
|
||||
};
|
||||
struct BoundValueRefBase : BoundRef {
|
||||
virtual auto setValue(std::string const &arg) -> ParserResult = 0;
|
||||
virtual auto setValue(std::string const& arg) -> ParserResult = 0;
|
||||
};
|
||||
struct BoundFlagRefBase : BoundRef {
|
||||
virtual auto setFlag(bool flag) -> ParserResult = 0;
|
||||
@@ -654,22 +654,22 @@ struct BoundFlagRefBase : BoundRef {
|
||||
|
||||
template <typename T>
|
||||
struct BoundValueRef : BoundValueRefBase {
|
||||
T &m_ref;
|
||||
T& m_ref;
|
||||
|
||||
explicit BoundValueRef(T &ref) : m_ref(ref) {}
|
||||
explicit BoundValueRef(T& ref) : m_ref(ref) {}
|
||||
|
||||
auto setValue(std::string const &arg) -> ParserResult override { return convertInto(arg, m_ref); }
|
||||
auto setValue(std::string const& arg) -> ParserResult override { return convertInto(arg, m_ref); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
|
||||
std::vector<T> &m_ref;
|
||||
std::vector<T>& m_ref;
|
||||
|
||||
explicit BoundValueRef(std::vector<T> &ref) : m_ref(ref) {}
|
||||
explicit BoundValueRef(std::vector<T>& ref) : m_ref(ref) {}
|
||||
|
||||
auto isContainer() const -> bool override { return true; }
|
||||
|
||||
auto setValue(std::string const &arg) -> ParserResult override {
|
||||
auto setValue(std::string const& arg) -> ParserResult override {
|
||||
T temp;
|
||||
auto result = convertInto(arg, temp);
|
||||
if (result) m_ref.push_back(temp);
|
||||
@@ -678,9 +678,9 @@ struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
|
||||
};
|
||||
|
||||
struct BoundFlagRef : BoundFlagRefBase {
|
||||
bool &m_ref;
|
||||
bool& m_ref;
|
||||
|
||||
explicit BoundFlagRef(bool &ref) : m_ref(ref) {}
|
||||
explicit BoundFlagRef(bool& ref) : m_ref(ref) {}
|
||||
|
||||
auto setFlag(bool flag) -> ParserResult override {
|
||||
m_ref = flag;
|
||||
@@ -694,7 +694,7 @@ struct LambdaInvoker {
|
||||
"Lambda must return void or clara::ParserResult");
|
||||
|
||||
template <typename L, typename ArgType>
|
||||
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult {
|
||||
static auto invoke(L const& lambda, ArgType const& arg) -> ParserResult {
|
||||
return lambda(arg);
|
||||
}
|
||||
};
|
||||
@@ -702,14 +702,14 @@ struct LambdaInvoker {
|
||||
template <>
|
||||
struct LambdaInvoker<void> {
|
||||
template <typename L, typename ArgType>
|
||||
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult {
|
||||
static auto invoke(L const& lambda, ArgType const& arg) -> ParserResult {
|
||||
lambda(arg);
|
||||
return ParserResult::ok(ParseResultType::Matched);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ArgType, typename L>
|
||||
inline auto invokeLambda(L const &lambda, std::string const &arg) -> ParserResult {
|
||||
inline auto invokeLambda(L const& lambda, std::string const& arg) -> ParserResult {
|
||||
ArgType temp{};
|
||||
auto result = convertInto(arg, temp);
|
||||
return !result ? result
|
||||
@@ -721,9 +721,9 @@ struct BoundLambda : BoundValueRefBase {
|
||||
L m_lambda;
|
||||
|
||||
static_assert(UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument");
|
||||
explicit BoundLambda(L const &lambda) : m_lambda(lambda) {}
|
||||
explicit BoundLambda(L const& lambda) : m_lambda(lambda) {}
|
||||
|
||||
auto setValue(std::string const &arg) -> ParserResult override {
|
||||
auto setValue(std::string const& arg) -> ParserResult override {
|
||||
return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(m_lambda, arg);
|
||||
}
|
||||
};
|
||||
@@ -736,7 +736,7 @@ struct BoundFlagLambda : BoundFlagRefBase {
|
||||
static_assert(std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value,
|
||||
"flags must be boolean");
|
||||
|
||||
explicit BoundFlagLambda(L const &lambda) : m_lambda(lambda) {}
|
||||
explicit BoundFlagLambda(L const& lambda) : m_lambda(lambda) {}
|
||||
|
||||
auto setFlag(bool flag) -> ParserResult override {
|
||||
return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(m_lambda, flag);
|
||||
@@ -751,11 +751,11 @@ class ParserBase {
|
||||
public:
|
||||
virtual ~ParserBase() = default;
|
||||
virtual auto validate() const -> Result { return Result::ok(); }
|
||||
virtual auto parse(std::string const &exeName, TokenStream const &tokens) const
|
||||
virtual auto parse(std::string const& exeName, TokenStream const& tokens) const
|
||||
-> InternalParseResult = 0;
|
||||
virtual auto cardinality() const -> size_t { return 1; }
|
||||
|
||||
auto parse(Args const &args) const -> InternalParseResult {
|
||||
auto parse(Args const& args) const -> InternalParseResult {
|
||||
return parse(args.exeName(), TokenStream(args));
|
||||
}
|
||||
};
|
||||
@@ -764,10 +764,10 @@ template <typename DerivedT>
|
||||
class ComposableParserImpl : public ParserBase {
|
||||
public:
|
||||
template <typename T>
|
||||
auto operator|(T const &other) const -> Parser;
|
||||
auto operator|(T const& other) const -> Parser;
|
||||
|
||||
template <typename T>
|
||||
auto operator+(T const &other) const -> Parser;
|
||||
auto operator+(T const& other) const -> Parser;
|
||||
};
|
||||
|
||||
// Common code and state for Args and Opts
|
||||
@@ -779,30 +779,30 @@ class ParserRefImpl : public ComposableParserImpl<DerivedT> {
|
||||
std::string m_hint;
|
||||
std::string m_description;
|
||||
|
||||
explicit ParserRefImpl(std::shared_ptr<BoundRef> const &ref) : m_ref(ref) {}
|
||||
explicit ParserRefImpl(std::shared_ptr<BoundRef> const& ref) : m_ref(ref) {}
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
ParserRefImpl(T &ref, std::string const &hint)
|
||||
ParserRefImpl(T& ref, std::string const& hint)
|
||||
: m_ref(std::make_shared<BoundValueRef<T>>(ref)), m_hint(hint) {}
|
||||
|
||||
template <typename LambdaT>
|
||||
ParserRefImpl(LambdaT const &ref, std::string const &hint)
|
||||
ParserRefImpl(LambdaT const& ref, std::string const& hint)
|
||||
: m_ref(std::make_shared<BoundLambda<LambdaT>>(ref)), m_hint(hint) {}
|
||||
|
||||
auto operator()(std::string const &description) -> DerivedT & {
|
||||
auto operator()(std::string const& description) -> DerivedT& {
|
||||
m_description = description;
|
||||
return static_cast<DerivedT &>(*this);
|
||||
return static_cast<DerivedT&>(*this);
|
||||
}
|
||||
|
||||
auto optional() -> DerivedT & {
|
||||
auto optional() -> DerivedT& {
|
||||
m_optionality = Optionality::Optional;
|
||||
return static_cast<DerivedT &>(*this);
|
||||
return static_cast<DerivedT&>(*this);
|
||||
};
|
||||
|
||||
auto required() -> DerivedT & {
|
||||
auto required() -> DerivedT& {
|
||||
m_optionality = Optionality::Required;
|
||||
return static_cast<DerivedT &>(*this);
|
||||
return static_cast<DerivedT&>(*this);
|
||||
};
|
||||
|
||||
auto isOptional() const -> bool { return m_optionality == Optionality::Optional; }
|
||||
@@ -822,29 +822,29 @@ class ExeName : public ComposableParserImpl<ExeName> {
|
||||
std::shared_ptr<BoundValueRefBase> m_ref;
|
||||
|
||||
template <typename LambdaT>
|
||||
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
|
||||
static auto makeRef(LambdaT const& lambda) -> std::shared_ptr<BoundValueRefBase> {
|
||||
return std::make_shared<BoundLambda<LambdaT>>(lambda);
|
||||
}
|
||||
|
||||
public:
|
||||
ExeName() : m_name(std::make_shared<std::string>("<executable>")) {}
|
||||
|
||||
explicit ExeName(std::string &ref) : ExeName() {
|
||||
explicit ExeName(std::string& ref) : ExeName() {
|
||||
m_ref = std::make_shared<BoundValueRef<std::string>>(ref);
|
||||
}
|
||||
|
||||
template <typename LambdaT>
|
||||
explicit ExeName(LambdaT const &lambda) : ExeName() {
|
||||
explicit ExeName(LambdaT const& lambda) : ExeName() {
|
||||
m_ref = std::make_shared<BoundLambda<LambdaT>>(lambda);
|
||||
}
|
||||
|
||||
// The exe name is not parsed out of the normal tokens, but is handled specially
|
||||
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override {
|
||||
auto parse(std::string const&, TokenStream const& tokens) const -> InternalParseResult override {
|
||||
return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens));
|
||||
}
|
||||
|
||||
auto name() const -> std::string { return *m_name; }
|
||||
auto set(std::string const &newName) -> ParserResult {
|
||||
auto set(std::string const& newName) -> ParserResult {
|
||||
auto lastSlash = newName.find_last_of("\\/");
|
||||
auto filename = (lastSlash == std::string::npos) ? newName : newName.substr(lastSlash + 1);
|
||||
|
||||
@@ -860,17 +860,17 @@ class Arg : public ParserRefImpl<Arg> {
|
||||
public:
|
||||
using ParserRefImpl::ParserRefImpl;
|
||||
|
||||
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override {
|
||||
auto parse(std::string const&, TokenStream const& tokens) const -> InternalParseResult override {
|
||||
auto validationResult = validate();
|
||||
if (!validationResult) return InternalParseResult(validationResult);
|
||||
|
||||
auto remainingTokens = tokens;
|
||||
auto const &token = *remainingTokens;
|
||||
auto const& token = *remainingTokens;
|
||||
if (token.type != TokenType::Argument)
|
||||
return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens));
|
||||
|
||||
assert(!m_ref->isFlag());
|
||||
auto valueRef = static_cast<detail::BoundValueRefBase *>(m_ref.get());
|
||||
auto valueRef = static_cast<detail::BoundValueRefBase*>(m_ref.get());
|
||||
|
||||
auto result = valueRef->setValue(remainingTokens->token);
|
||||
if (!result)
|
||||
@@ -880,7 +880,7 @@ class Arg : public ParserRefImpl<Arg> {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto normaliseOpt(std::string const &optName) -> std::string {
|
||||
inline auto normaliseOpt(std::string const& optName) -> std::string {
|
||||
#ifdef CLARA_PLATFORM_WINDOWS
|
||||
if (optName[0] == '/')
|
||||
return "-" + optName.substr(1);
|
||||
@@ -895,18 +895,18 @@ class Opt : public ParserRefImpl<Opt> {
|
||||
|
||||
public:
|
||||
template <typename LambdaT>
|
||||
explicit Opt(LambdaT const &ref)
|
||||
explicit Opt(LambdaT const& ref)
|
||||
: ParserRefImpl(std::make_shared<BoundFlagLambda<LambdaT>>(ref)) {}
|
||||
|
||||
explicit Opt(bool &ref) : ParserRefImpl(std::make_shared<BoundFlagRef>(ref)) {}
|
||||
explicit Opt(bool& ref) : ParserRefImpl(std::make_shared<BoundFlagRef>(ref)) {}
|
||||
|
||||
template <typename LambdaT>
|
||||
Opt(LambdaT const &ref, std::string const &hint) : ParserRefImpl(ref, hint) {}
|
||||
Opt(LambdaT const& ref, std::string const& hint) : ParserRefImpl(ref, hint) {}
|
||||
|
||||
template <typename T>
|
||||
Opt(T &ref, std::string const &hint) : ParserRefImpl(ref, hint) {}
|
||||
Opt(T& ref, std::string const& hint) : ParserRefImpl(ref, hint) {}
|
||||
|
||||
auto operator[](std::string const &optName) -> Opt & {
|
||||
auto operator[](std::string const& optName) -> Opt& {
|
||||
m_optNames.push_back(optName);
|
||||
return *this;
|
||||
}
|
||||
@@ -914,7 +914,7 @@ class Opt : public ParserRefImpl<Opt> {
|
||||
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
||||
std::ostringstream oss;
|
||||
bool first = true;
|
||||
for (auto const &opt : m_optNames) {
|
||||
for (auto const& opt : m_optNames) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
@@ -925,9 +925,9 @@ class Opt : public ParserRefImpl<Opt> {
|
||||
return {{oss.str(), m_description}};
|
||||
}
|
||||
|
||||
auto isMatch(std::string const &optToken) const -> bool {
|
||||
auto isMatch(std::string const& optToken) const -> bool {
|
||||
auto normalisedToken = normaliseOpt(optToken);
|
||||
for (auto const &name : m_optNames) {
|
||||
for (auto const& name : m_optNames) {
|
||||
if (normaliseOpt(name) == normalisedToken) return true;
|
||||
}
|
||||
return false;
|
||||
@@ -935,26 +935,26 @@ class Opt : public ParserRefImpl<Opt> {
|
||||
|
||||
using ParserBase::parse;
|
||||
|
||||
auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override {
|
||||
auto parse(std::string const&, TokenStream const& tokens) const -> InternalParseResult override {
|
||||
auto validationResult = validate();
|
||||
if (!validationResult) return InternalParseResult(validationResult);
|
||||
|
||||
auto remainingTokens = tokens;
|
||||
if (remainingTokens && remainingTokens->type == TokenType::Option) {
|
||||
auto const &token = *remainingTokens;
|
||||
auto const& token = *remainingTokens;
|
||||
if (isMatch(token.token)) {
|
||||
if (m_ref->isFlag()) {
|
||||
auto flagRef = static_cast<detail::BoundFlagRefBase *>(m_ref.get());
|
||||
auto flagRef = static_cast<detail::BoundFlagRefBase*>(m_ref.get());
|
||||
auto result = flagRef->setFlag(true);
|
||||
if (!result) return InternalParseResult(result);
|
||||
if (result.value() == ParseResultType::ShortCircuitAll)
|
||||
return InternalParseResult::ok(ParseState(result.value(), remainingTokens));
|
||||
} else {
|
||||
auto valueRef = static_cast<detail::BoundValueRefBase *>(m_ref.get());
|
||||
auto valueRef = static_cast<detail::BoundValueRefBase*>(m_ref.get());
|
||||
++remainingTokens;
|
||||
if (!remainingTokens)
|
||||
return InternalParseResult::runtimeError("Expected argument following " + token.token);
|
||||
auto const &argToken = *remainingTokens;
|
||||
auto const& argToken = *remainingTokens;
|
||||
if (argToken.type != TokenType::Argument)
|
||||
return InternalParseResult::runtimeError("Expected argument following " + token.token);
|
||||
auto result = valueRef->setValue(argToken.token);
|
||||
@@ -970,7 +970,7 @@ class Opt : public ParserRefImpl<Opt> {
|
||||
|
||||
auto validate() const -> Result override {
|
||||
if (m_optNames.empty()) return Result::logicError("No options supplied to Opt");
|
||||
for (auto const &name : m_optNames) {
|
||||
for (auto const& name : m_optNames) {
|
||||
if (name.empty()) return Result::logicError("Option name cannot be empty");
|
||||
#ifdef CLARA_PLATFORM_WINDOWS
|
||||
if (name[0] != '-' && name[0] != '/')
|
||||
@@ -984,12 +984,12 @@ class Opt : public ParserRefImpl<Opt> {
|
||||
};
|
||||
|
||||
struct Help : Opt {
|
||||
Help(bool &showHelpFlag)
|
||||
Help(bool& showHelpFlag)
|
||||
: Opt([&](bool flag) {
|
||||
showHelpFlag = flag;
|
||||
return ParserResult::ok(ParseResultType::ShortCircuitAll);
|
||||
}) {
|
||||
static_cast<Opt &>(*this)("display usage information")["-?"]["-h"]["--help"].optional();
|
||||
static_cast<Opt&>(*this)("display usage information")["-?"]["-h"]["--help"].optional();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -998,57 +998,57 @@ struct Parser : ParserBase {
|
||||
std::vector<Opt> m_options;
|
||||
std::vector<Arg> m_args;
|
||||
|
||||
auto operator|=(ExeName const &exeName) -> Parser & {
|
||||
auto operator|=(ExeName const& exeName) -> Parser& {
|
||||
m_exeName = exeName;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator|=(Arg const &arg) -> Parser & {
|
||||
auto operator|=(Arg const& arg) -> Parser& {
|
||||
m_args.push_back(arg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator|=(Opt const &opt) -> Parser & {
|
||||
auto operator|=(Opt const& opt) -> Parser& {
|
||||
m_options.push_back(opt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto operator|=(Parser const &other) -> Parser & {
|
||||
auto operator|=(Parser const& other) -> Parser& {
|
||||
m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
|
||||
m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto operator|(T const &other) const -> Parser {
|
||||
auto operator|(T const& other) const -> Parser {
|
||||
return Parser(*this) |= other;
|
||||
}
|
||||
|
||||
// Forward deprecated interface with '+' instead of '|'
|
||||
template <typename T>
|
||||
auto operator+=(T const &other) -> Parser & {
|
||||
auto operator+=(T const& other) -> Parser& {
|
||||
return operator|=(other);
|
||||
}
|
||||
template <typename T>
|
||||
auto operator+(T const &other) const -> Parser {
|
||||
auto operator+(T const& other) const -> Parser {
|
||||
return operator|(other);
|
||||
}
|
||||
|
||||
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
||||
std::vector<HelpColumns> cols;
|
||||
for (auto const &o : m_options) {
|
||||
for (auto const& o : m_options) {
|
||||
auto childCols = o.getHelpColumns();
|
||||
cols.insert(cols.end(), childCols.begin(), childCols.end());
|
||||
}
|
||||
return cols;
|
||||
}
|
||||
|
||||
void writeToStream(std::ostream &os) const {
|
||||
void writeToStream(std::ostream& os) const {
|
||||
if (!m_exeName.name().empty()) {
|
||||
os << "usage:\n"
|
||||
<< " " << m_exeName.name() << " ";
|
||||
bool required = true, first = true;
|
||||
for (auto const &arg : m_args) {
|
||||
for (auto const& arg : m_args) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
@@ -1068,28 +1068,28 @@ struct Parser : ParserBase {
|
||||
auto rows = getHelpColumns();
|
||||
size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
|
||||
size_t optWidth = 0;
|
||||
for (auto const &cols : rows) optWidth = (std::max)(optWidth, cols.left.size() + 2);
|
||||
for (auto const& cols : rows) optWidth = (std::max)(optWidth, cols.left.size() + 2);
|
||||
|
||||
optWidth = (std::min)(optWidth, consoleWidth / 2);
|
||||
|
||||
for (auto const &cols : rows) {
|
||||
for (auto const& cols : rows) {
|
||||
auto row = TextFlow::Column(cols.left).width(optWidth).indent(2) + TextFlow::Spacer(4) +
|
||||
TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth);
|
||||
os << row << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
friend auto operator<<(std::ostream &os, Parser const &parser) -> std::ostream & {
|
||||
friend auto operator<<(std::ostream& os, Parser const& parser) -> std::ostream& {
|
||||
parser.writeToStream(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
auto validate() const -> Result override {
|
||||
for (auto const &opt : m_options) {
|
||||
for (auto const& opt : m_options) {
|
||||
auto result = opt.validate();
|
||||
if (!result) return result;
|
||||
}
|
||||
for (auto const &arg : m_args) {
|
||||
for (auto const& arg : m_args) {
|
||||
auto result = arg.validate();
|
||||
if (!result) return result;
|
||||
}
|
||||
@@ -1098,10 +1098,10 @@ struct Parser : ParserBase {
|
||||
|
||||
using ParserBase::parse;
|
||||
|
||||
auto parse(std::string const &exeName, TokenStream const &tokens) const
|
||||
auto parse(std::string const& exeName, TokenStream const& tokens) const
|
||||
-> InternalParseResult override {
|
||||
struct ParserInfo {
|
||||
ParserBase const *parser = nullptr;
|
||||
ParserBase const* parser = nullptr;
|
||||
size_t count = 0;
|
||||
};
|
||||
const size_t totalParsers = m_options.size() + m_args.size();
|
||||
@@ -1111,8 +1111,8 @@ struct Parser : ParserBase {
|
||||
|
||||
{
|
||||
size_t i = 0;
|
||||
for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
|
||||
for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
|
||||
for (auto const& opt : m_options) parseInfos[i++].parser = &opt;
|
||||
for (auto const& arg : m_args) parseInfos[i++].parser = &arg;
|
||||
}
|
||||
|
||||
m_exeName.set(exeName);
|
||||
@@ -1122,7 +1122,7 @@ struct Parser : ParserBase {
|
||||
bool tokenParsed = false;
|
||||
|
||||
for (size_t i = 0; i < totalParsers; ++i) {
|
||||
auto &parseInfo = parseInfos[i];
|
||||
auto& parseInfo = parseInfos[i];
|
||||
if (parseInfo.parser->cardinality() == 0 ||
|
||||
parseInfo.count < parseInfo.parser->cardinality()) {
|
||||
result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
|
||||
@@ -1147,8 +1147,8 @@ struct Parser : ParserBase {
|
||||
|
||||
template <typename DerivedT>
|
||||
template <typename T>
|
||||
auto ComposableParserImpl<DerivedT>::operator|(T const &other) const -> Parser {
|
||||
return Parser() | static_cast<DerivedT const &>(*this) | other;
|
||||
auto ComposableParserImpl<DerivedT>::operator|(T const& other) const -> Parser {
|
||||
return Parser() | static_cast<DerivedT const&>(*this) | other;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ extern std::list<pid_t> reap;
|
||||
|
||||
namespace waybar::util::command {
|
||||
|
||||
constexpr int kExecFailureExitCode = 127;
|
||||
|
||||
struct res {
|
||||
int exit_code;
|
||||
std::string out;
|
||||
@@ -59,6 +61,7 @@ inline int close(FILE* fp, pid_t pid) {
|
||||
spdlog::debug("Cmd continued");
|
||||
} else if (ret == -1) {
|
||||
spdlog::debug("waitpid failed: {}", strerror(errno));
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -109,11 +112,13 @@ inline FILE* open(const std::string& cmd, int& pid, const std::string& output_na
|
||||
::close(fd[0]);
|
||||
dup2(fd[1], 1);
|
||||
setpgid(child_pid, child_pid);
|
||||
if (output_name != "") {
|
||||
if (!output_name.empty()) {
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
const int saved_errno = errno;
|
||||
spdlog::error("execlp(/bin/sh) failed in open: {}", strerror(saved_errno));
|
||||
_exit(kExecFailureExitCode);
|
||||
} else {
|
||||
::close(fd[1]);
|
||||
}
|
||||
@@ -138,7 +143,7 @@ inline struct res execNoRead(const std::string& cmd) {
|
||||
return {WEXITSTATUS(stat), ""};
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) {
|
||||
inline int32_t forkExec(const std::string& cmd, const std::string& output_name) {
|
||||
if (cmd == "") return -1;
|
||||
|
||||
pid_t pid = fork();
|
||||
@@ -157,8 +162,13 @@ inline int32_t forkExec(const std::string& cmd) {
|
||||
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
|
||||
if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err));
|
||||
setpgid(pid, pid);
|
||||
if (!output_name.empty()) {
|
||||
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
|
||||
}
|
||||
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
|
||||
exit(0);
|
||||
const int saved_errno = errno;
|
||||
spdlog::error("execl(/bin/sh) failed in forkExec: {}", strerror(saved_errno));
|
||||
_exit(kExecFailureExitCode);
|
||||
} else {
|
||||
reap_mtx.lock();
|
||||
reap.push_back(pid);
|
||||
@@ -169,4 +179,6 @@ inline int32_t forkExec(const std::string& cmd) {
|
||||
return pid;
|
||||
}
|
||||
|
||||
inline int32_t forkExec(const std::string& cmd) { return forkExec(cmd, ""); }
|
||||
|
||||
} // namespace waybar::util::command
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
namespace date {
|
||||
#if HAVE_CHRONO_TIMEZONES
|
||||
using namespace std::chrono;
|
||||
using namespace std;
|
||||
using std::format;
|
||||
#else
|
||||
|
||||
using system_clock = std::chrono::system_clock;
|
||||
@@ -73,5 +73,3 @@ struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> {
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
using namespace date;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
class pow_format {
|
||||
public:
|
||||
pow_format(long long val, std::string&& unit, bool binary = false)
|
||||
: val_(val), unit_(unit), binary_(binary){};
|
||||
: val_(val), unit_(unit), binary_(binary) {};
|
||||
|
||||
long long val_;
|
||||
std::string unit_;
|
||||
|
||||
@@ -10,5 +10,7 @@ class DefaultGtkIconThemeWrapper {
|
||||
|
||||
public:
|
||||
static bool has_icon(const std::string&);
|
||||
static Glib::RefPtr<Gdk::Pixbuf> load_icon(const char*, int, Gtk::IconLookupFlags);
|
||||
static Glib::RefPtr<Gdk::Pixbuf> load_icon(
|
||||
const char*, int, Gtk::IconLookupFlags,
|
||||
Glib::RefPtr<Gtk::StyleContext> style = Glib::RefPtr<Gtk::StyleContext>());
|
||||
};
|
||||
|
||||
@@ -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,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <gdkmm/general.h>
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
#include <giomm/desktopappinfo.h>
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <gtkmm/image.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "util/gtk_icon.hpp"
|
||||
|
||||
class IconLoader {
|
||||
private:
|
||||
std::vector<Glib::RefPtr<Gtk::IconTheme>> custom_icon_themes_;
|
||||
Glib::RefPtr<Gtk::IconTheme> default_icon_theme_ = Gtk::IconTheme::get_default();
|
||||
static std::vector<std::string> search_prefix();
|
||||
static Glib::RefPtr<Gio::DesktopAppInfo> get_app_info_by_name(const std::string& app_id);
|
||||
static Glib::RefPtr<Gio::DesktopAppInfo> get_desktop_app_info(const std::string& app_id);
|
||||
static Glib::RefPtr<Gdk::Pixbuf> load_icon_from_file(std::string const& icon_path, int size);
|
||||
static std::string get_icon_name_from_icon_theme(const Glib::RefPtr<Gtk::IconTheme>& icon_theme,
|
||||
const std::string& app_id);
|
||||
static bool image_load_icon(Gtk::Image& image, const Glib::RefPtr<Gtk::IconTheme>& icon_theme,
|
||||
Glib::RefPtr<Gio::DesktopAppInfo> app_info, int size);
|
||||
|
||||
public:
|
||||
void add_custom_icon_theme(const std::string& theme_name);
|
||||
bool image_load_icon(Gtk::Image& image, Glib::RefPtr<Gio::DesktopAppInfo> app_info,
|
||||
int size) const;
|
||||
static Glib::RefPtr<Gio::DesktopAppInfo> get_app_info_from_app_id_list(
|
||||
const std::string& app_id_list);
|
||||
};
|
||||
+12
-5
@@ -7,6 +7,7 @@
|
||||
#include <codecvt>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
#if (FMT_VERSION >= 90000)
|
||||
@@ -26,19 +27,25 @@ class JsonParser {
|
||||
Json::Value root;
|
||||
|
||||
// replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences
|
||||
std::string modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
|
||||
std::string modifiedJsonStr;
|
||||
const std::string* json = &jsonStr;
|
||||
if (jsonStr.find("\\x") != std::string::npos) {
|
||||
modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
|
||||
json = &modifiedJsonStr;
|
||||
}
|
||||
|
||||
std::istringstream jsonStream(modifiedJsonStr);
|
||||
std::string errs;
|
||||
if (!Json::parseFromStream(m_readerBuilder, jsonStream, &root, &errs)) {
|
||||
// Use local CharReaderBuilder for thread safety - the IPC singleton's
|
||||
// parser can be called concurrently from multiple module threads
|
||||
Json::CharReaderBuilder readerBuilder;
|
||||
auto reader = std::unique_ptr<Json::CharReader>(readerBuilder.newCharReader());
|
||||
if (!reader->parse(json->data(), json->data() + json->size(), &root, &errs)) {
|
||||
throw std::runtime_error("Error parsing JSON: " + errs);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
private:
|
||||
Json::CharReaderBuilder m_readerBuilder;
|
||||
|
||||
static std::string replaceHexadecimalEscape(const std::string& str) {
|
||||
static std::regex re("\\\\x");
|
||||
return std::regex_replace(str, re, "\\u00");
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <json/value.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
enum class KillSignalAction : std::uint8_t {
|
||||
TOGGLE,
|
||||
RELOAD,
|
||||
SHOW,
|
||||
HIDE,
|
||||
NOOP,
|
||||
};
|
||||
const std::map<std::string, KillSignalAction> userKillSignalActions = {
|
||||
{"TOGGLE", KillSignalAction::TOGGLE},
|
||||
{"RELOAD", KillSignalAction::RELOAD},
|
||||
{"SHOW", KillSignalAction::SHOW},
|
||||
{"HIDE", KillSignalAction::HIDE},
|
||||
{"NOOP", KillSignalAction::NOOP}};
|
||||
|
||||
const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR1 = KillSignalAction::TOGGLE;
|
||||
const KillSignalAction SIGNALACTION_DEFAULT_SIGUSR2 = KillSignalAction::RELOAD;
|
||||
|
||||
}; // namespace waybar::util
|
||||
@@ -25,6 +25,7 @@ class PrivacyNodeInfo {
|
||||
std::string media_name;
|
||||
std::string node_name;
|
||||
std::string application_name;
|
||||
bool is_monitor = false;
|
||||
|
||||
std::string pipewire_access_portal_app_id;
|
||||
std::string application_icon_name;
|
||||
@@ -32,14 +33,14 @@ class PrivacyNodeInfo {
|
||||
struct spa_hook object_listener;
|
||||
struct spa_hook proxy_listener;
|
||||
|
||||
void *data;
|
||||
void* data;
|
||||
|
||||
std::string getName();
|
||||
std::string getIconName();
|
||||
|
||||
// Handlers for PipeWire events
|
||||
void handleProxyEventDestroy();
|
||||
void handleNodeEventInfo(const struct pw_node_info *info);
|
||||
void handleNodeEventInfo(const struct pw_node_info* info);
|
||||
};
|
||||
|
||||
} // namespace waybar::util::PipewireBackend
|
||||
|
||||
@@ -6,14 +6,12 @@
|
||||
|
||||
namespace waybar {
|
||||
|
||||
using namespace Gio;
|
||||
|
||||
enum class Appearance {
|
||||
UNKNOWN = 0,
|
||||
DARK = 1,
|
||||
LIGHT = 2,
|
||||
};
|
||||
class Portal : private DBus::Proxy {
|
||||
class Portal : private Gio::DBus::Proxy {
|
||||
public:
|
||||
Portal();
|
||||
void refreshAppearance();
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
// Get a signal emited with value true when entering sleep, and false when exiting
|
||||
// Get a signal emitted with value true when entering sleep, and false when exiting
|
||||
SafeSignal<bool>& prepare_for_sleep();
|
||||
} // namespace waybar::util
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <sigc++/signal.h>
|
||||
#include <sigc++/trackable.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace waybar::util {
|
||||
|
||||
class Rfkill : public sigc::trackable {
|
||||
@@ -17,7 +19,7 @@ class Rfkill : public sigc::trackable {
|
||||
|
||||
private:
|
||||
enum rfkill_type rfkill_type_;
|
||||
bool state_ = false;
|
||||
std::atomic_bool state_ = false;
|
||||
int fd_ = -1;
|
||||
|
||||
bool on_event(Glib::IOCondition cond);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,3 +23,26 @@ inline std::string capitalize(const std::string& str) {
|
||||
[](unsigned char c) { return std::toupper(c); });
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::string toLower(const std::string& str) {
|
||||
std::string result = str;
|
||||
std::transform(result.begin(), result.end(), result.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::vector<std::string> split(std::string_view s, std::string_view delimiter,
|
||||
int max_splits = -1) {
|
||||
std::vector<std::string> result;
|
||||
size_t pos = 0;
|
||||
size_t next_pos = 0;
|
||||
while ((next_pos = s.find(delimiter, pos)) != std::string::npos) {
|
||||
result.push_back(std::string(s.substr(pos, next_pos - pos)));
|
||||
pos = next_pos + delimiter.size();
|
||||
if (max_splits > 0 && result.size() == static_cast<size_t>(max_splits)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.push_back(std::string(s.substr(pos)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
namespace waybar::util {
|
||||
struct UdevDeleter {
|
||||
void operator()(udev* ptr) const { udev_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevDeviceDeleter {
|
||||
void operator()(udev_device* ptr) const { udev_device_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevEnumerateDeleter {
|
||||
void operator()(udev_enumerate* ptr) const { udev_enumerate_unref(ptr); }
|
||||
};
|
||||
|
||||
struct UdevMonitorDeleter {
|
||||
void operator()(udev_monitor* ptr) const { udev_monitor_unref(ptr); }
|
||||
};
|
||||
} // namespace waybar::util
|
||||
@@ -2,4 +2,4 @@
|
||||
#include <glibmm/ustring.h>
|
||||
|
||||
// calculate column width of ustring
|
||||
int ustring_clen(const Glib::ustring &str);
|
||||
int ustring_clen(const Glib::ustring& str);
|
||||
@@ -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