Merge branch 'master' into master

This commit is contained in:
Marc Radau 2020-02-23 23:00:09 +01:00 committed by GitHub
commit 9abe1e2790
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 225 additions and 105 deletions

View File

@ -12,6 +12,11 @@
namespace waybar::modules {
struct waybar_time {
std::locale locale;
date::zoned_seconds ztime;
};
class Clock : public ALabel {
public:
Clock(const std::string&, const Json::Value&);
@ -23,6 +28,12 @@ class Clock : public ALabel {
std::locale locale_;
const date::time_zone* time_zone_;
bool fixed_time_zone_;
date::year_month_day cached_calendar_ymd_;
std::string cached_calendar_text_;
auto calendar_text(const waybar_time& wtime) -> std::string;
auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void;
auto first_day_of_week() -> date::weekday;
};
} // namespace waybar::modules

View File

@ -21,7 +21,7 @@ class Tray : public AModule {
static inline std::size_t nb_hosts_ = 0;
Gtk::Box box_;
SNI::Watcher watcher_;
SNI::Watcher::singleton watcher_;
SNI::Host host_;
};

View File

@ -7,10 +7,24 @@
namespace waybar::modules::SNI {
class Watcher {
private:
Watcher();
public:
Watcher(std::size_t id);
~Watcher();
using singleton = std::shared_ptr<Watcher>;
static singleton getInstance() {
static std::weak_ptr<Watcher> weak;
std::shared_ptr<Watcher> strong = weak.lock();
if (!strong) {
strong = std::shared_ptr<Watcher>(new Watcher());
weak = strong;
}
return strong;
}
private:
typedef enum { GF_WATCH_TYPE_HOST, GF_WATCH_TYPE_ITEM } GfWatchType;
@ -34,7 +48,6 @@ class Watcher {
void updateRegisteredItems(SnWatcher *obj);
uint32_t bus_name_id_;
uint32_t watcher_id_;
GSList * hosts_ = nullptr;
GSList * items_ = nullptr;
SnWatcher *watcher_ = nullptr;

View File

@ -8,6 +8,7 @@
#include <memory>
#include <mutex>
#include "ipc.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@ -28,6 +29,7 @@ class Ipc {
void sendCmd(uint32_t type, const std::string &payload = "");
void subscribe(const std::string &payload);
void handleEvent();
void setWorker(std::function<void()> &&func);
protected:
static inline const std::string ipc_magic_ = "i3-ipc";
@ -41,6 +43,7 @@ class Ipc {
int fd_;
int fd_event_;
std::mutex mutex_;
util::SleeperThread thread_;
};
} // namespace waybar::modules::sway

View File

@ -6,7 +6,6 @@
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@ -18,13 +17,10 @@ class Mode : public ALabel, public sigc::trackable {
private:
void onEvent(const struct Ipc::ipc_response&);
void worker();
std::string mode_;
util::JsonParser parser_;
std::mutex mutex_;
util::SleeperThread thread_;
Ipc ipc_;
};

View File

@ -7,7 +7,6 @@
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@ -20,7 +19,6 @@ class Window : public ALabel, public sigc::trackable {
private:
void onEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&);
void worker();
std::tuple<std::size_t, int, std::string, std::string> getFocusedNode(const Json::Value& nodes,
std::string& output);
void getTree();
@ -33,8 +31,6 @@ class Window : public ALabel, public sigc::trackable {
std::size_t app_nb_;
util::JsonParser parser_;
std::mutex mutex_;
util::SleeperThread thread_;
Ipc ipc_;
};

View File

@ -1,5 +1,6 @@
#pragma once
#include <unordered_map>
#include <fmt/format.h>
#include <gtkmm/button.h>
#include <gtkmm/label.h>
@ -8,7 +9,6 @@
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@ -21,7 +21,6 @@ class Workspaces : public AModule, public sigc::trackable {
private:
void onCmd(const struct Ipc::ipc_response&);
void onEvent(const struct Ipc::ipc_response&);
void worker();
bool filterButtons();
Gtk::Button& addButton(const Json::Value&);
void onButtonReady(const Json::Value&, Gtk::Button&);
@ -38,8 +37,6 @@ class Workspaces : public AModule, public sigc::trackable {
util::JsonParser parser_;
std::unordered_map<std::string, Gtk::Button> buttons_;
std::mutex mutex_;
util::SleeperThread thread_;
Ipc ipc_;
};

View File

@ -65,6 +65,10 @@ The *clock* module displays the current date and time.
View all valid format options in *strftime(3)*.
# FORMAT REPLACEMENTS
*{calendar}*: Current month calendar
# EXAMPLES
```

View File

@ -100,16 +100,17 @@ The following strings for *format-icons* are supported.
If they are found in the current PulseAudio port name, the corresponding icons will be selected.
- *default* (Shown, when no other port is found)
- *headphones*
- *headphone*
- *speaker*
- *hdmi*
- *headset*
- *handsfree*
- *hands-free*
- *portable*
- *car*
- *hifi*
- *phone*
# EXAMPLES
```

View File

@ -22,7 +22,7 @@ Addressed by *temperature*
*critical-threshold*: ++
typeof: integer ++
The threshold before it is considered critical (Celcius).
The threshold before it is considered critical (Celsius).
*interval*: ++
typeof: integer ++
@ -36,11 +36,11 @@ Addressed by *temperature*
*format*: ++
typeof: string ++
default: {temperatureC}°C ++
The format (Celcius/Farenheit) in which the temperature should be displayed.
The format (Celsius/Fahrenheit) in which the temperature should be displayed.
*format-icons*: ++
typeof: array ++
Based on the current temperature (Celcius) and *critical-threshold* if available, the corresponding icon gets selected. The order is *low* to *high*.
Based on the current temperature (Celsius) and *critical-threshold* if available, the corresponding icon gets selected. The order is *low* to *high*.
*rotate*: ++
typeof: integer ++
@ -81,7 +81,7 @@ Addressed by *temperature*
# FORMAT REPLACEMENTS
*{temperatureC}*: Temperature in Celcius.
*{temperatureC}*: Temperature in Celsius.
*{temperatureF}*: Temperature in Fahrenheit.

View File

@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
version: '0.9.0',
version: '0.9.1',
license: 'MIT',
default_options : [
'cpp_std=c++17',
@ -9,6 +9,8 @@ project(
],
)
compiler = meson.get_compiler('cpp')
cpp_args = []
cpp_link_args = []
@ -16,12 +18,13 @@ if get_option('libcxx')
cpp_args += ['-stdlib=libc++']
cpp_link_args += ['-stdlib=libc++', '-lc++abi']
if compiler.has_link_argument('-lc++fs')
cpp_link_args += ['-lc++fs']
endif
else
cpp_link_args += ['-lstdc++fs']
endif
compiler = meson.get_compiler('cpp')
git = find_program('git', required: false)
if not git.found()
@ -42,6 +45,22 @@ if not compiler.has_header('filesystem')
endif
endif
code = '''
#include <langinfo.h>
#include <locale.h>
int main(int argc, char** argv) {
locale_t locale = newlocale(LC_ALL, "en_US.UTF-8", nullptr);
char* str;
str = nl_langinfo_l(_NL_TIME_WEEK_1STDAY, locale);
str = nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, locale);
freelocale(locale);
return 0;
}
'''
if compiler.links(code, name : 'nl_langinfo with _NL_TIME_WEEK_1STDAY, _NL_TIME_FIRST_WEEKDAY')
add_project_arguments('-DHAVE_LANGINFO_1STDAY', language: 'cpp')
endif
add_global_arguments(cpp_args, language : 'cpp')
add_global_link_arguments(cpp_link_args, language : 'cpp')

View File

@ -65,7 +65,7 @@
},
"clock": {
// "timezone": "America/New_York",
"tooltip-format": "{:%Y-%m-%d | %H:%M}",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
"format-alt": "{:%Y-%m-%d}"
},
"cpu": {
@ -122,8 +122,8 @@
"format-source": "{volume}% ",
"format-source-muted": "",
"format-icons": {
"headphones": "",
"handsfree": "",
"headphone": "",
"hands-free": "",
"headset": "",
"phone": "",
"portable": "",

View File

@ -79,7 +79,7 @@ def signal_handler(sig, frame):
def parse_arguments():
parser = argparse.ArgumentParser()
# Increase verbosity with every occurance of -v
# Increase verbosity with every occurence of -v
parser.add_argument('-v', '--verbose', action='count', default=0)
# Define for which player we're listening

View File

@ -1,4 +1,12 @@
#include "modules/clock.hpp"
#include <sstream>
#include <type_traits>
#ifdef HAVE_LANGINFO_1STDAY
#include <langinfo.h>
#include <locale.h>
#endif
using waybar::modules::waybar_time;
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: ALabel(config, "clock", id, "{:%H:%M}", 60)
@ -24,35 +32,110 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
};
}
using zoned_time = date::zoned_time<std::chrono::system_clock::duration>;
struct waybar_time {
std::locale locale;
zoned_time ztime;
};
auto waybar::modules::Clock::update() -> void {
if (!fixed_time_zone_) {
// Time zone can change. Be sure to pick that.
time_zone_ = date::current_zone();
}
auto now = std::chrono::system_clock::now();
waybar_time wtime = {locale_, date::make_zoned(time_zone_, now)};
waybar_time wtime = {locale_,
date::make_zoned(time_zone_, date::floor<std::chrono::seconds>(now))};
auto text = fmt::format(format_, wtime);
label_.set_markup(text);
if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) {
const auto calendar = calendar_text(wtime);
auto tooltip_format = config_["tooltip-format"].asString();
auto tooltip_text = fmt::format(tooltip_format, wtime);
label_.set_tooltip_text(tooltip_text);
auto tooltip_text = fmt::format(tooltip_format, wtime, fmt::arg("calendar", calendar));
label_.set_tooltip_markup(tooltip_text);
} else {
label_.set_tooltip_text(text);
label_.set_tooltip_markup(text);
}
}
}
auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::string {
const auto daypoint = date::floor<date::days>(wtime.ztime.get_local_time());
const auto ymd = date::year_month_day(daypoint);
if (cached_calendar_ymd_ == ymd) {
return cached_calendar_text_;
}
const date::year_month ym(ymd.year(), ymd.month());
const auto curr_day = ymd.day();
std::stringstream os;
const auto first_dow = first_day_of_week();
weekdays_header(first_dow, os);
// First week prefixed with spaces if needed.
auto wd = date::weekday(ym/1);
auto empty_days = (wd - first_dow).count();
if (empty_days > 0) {
os << std::string(empty_days * 3 - 1, ' ');
}
auto last_day = (ym/date::literals::last).day();
for (auto d = date::day(1); d <= last_day; ++d, ++wd) {
if (wd != first_dow) {
os << ' ';
} else if (unsigned(d) != 1) {
os << '\n';
}
if (d == curr_day) {
os << "<b><u>" << date::format("%e", d) << "</u></b>";
} else {
os << date::format("%e", d);
}
}
auto result = os.str();
cached_calendar_ymd_ = ymd;
cached_calendar_text_ = result;
return result;
}
auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void {
auto wd = first_dow;
do {
if (wd != first_dow) os << ' ';
Glib::ustring wd_ustring(date::format(locale_, "%a", wd));
auto wd_len = wd_ustring.length();
if (wd_len > 2) {
wd_ustring = wd_ustring.substr(0, 2);
wd_len = 2;
}
const std::string pad(2 - wd_len, ' ');
os << pad << wd_ustring;
} while (++wd != first_dow);
os << "\n";
}
#ifdef HAVE_LANGINFO_1STDAY
template <auto fn>
using deleter_from_fn = std::integral_constant<decltype(fn), fn>;
template <typename T, auto fn>
using deleting_unique_ptr = std::unique_ptr<T, deleter_from_fn<fn>>;
#endif
// Computations done similarly to Linux cal utility.
auto waybar::modules::Clock::first_day_of_week() -> date::weekday {
#ifdef HAVE_LANGINFO_1STDAY
deleting_unique_ptr<std::remove_pointer<locale_t>::type, freelocale>
posix_locale{newlocale(LC_ALL, locale_.name().c_str(), nullptr)};
if (posix_locale) {
const int i = (std::intptr_t) nl_langinfo_l(_NL_TIME_WEEK_1STDAY, posix_locale.get());
auto ymd = date::year(i / 10000)/(i / 100 % 100)/(i % 100);
auto wd = date::weekday(ymd);
uint8_t j = *nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, posix_locale.get());
return wd + date::days(j - 1);
}
#endif
return date::Sunday;
}
template <>
struct fmt::formatter<waybar_time> : fmt::formatter<std::tm> {
template <typename FormatContext>

View File

@ -296,7 +296,7 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthDownOctets", pow_format(bandwidth_down / interval_.count(), "o/s")),
fmt::arg("bandwidthUpOctets", pow_format(bandwidth_up / interval_.count(), "o/s")));
if (text != label_.get_label()) {
if (text.compare(label_.get_label()) != 0) {
label_.set_markup(text);
if (text.empty()) {
event_box_.hide();

View File

@ -52,7 +52,8 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data) {
pa_context_set_subscribe_callback(c, subscribeCb, data);
pa_context_subscribe(
c,
static_cast<enum pa_subscription_mask>(static_cast<int>(PA_SUBSCRIPTION_MASK_SINK) |
static_cast<enum pa_subscription_mask>(static_cast<int>(PA_SUBSCRIPTION_MASK_SERVER) |
static_cast<int>(PA_SUBSCRIPTION_MASK_SINK) |
static_cast<int>(PA_SUBSCRIPTION_MASK_SOURCE)),
nullptr,
nullptr);
@ -109,7 +110,9 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context * conte
if (operation != PA_SUBSCRIPTION_EVENT_CHANGE) {
return;
}
if (facility == PA_SUBSCRIPTION_EVENT_SINK) {
if (facility == PA_SUBSCRIPTION_EVENT_SERVER) {
pa_context_get_server_info(context, serverInfoCb, data);
} else if (facility == PA_SUBSCRIPTION_EVENT_SINK) {
pa_context_get_sink_info_by_index(context, idx, sinkInfoCb, data);
} else if (facility == PA_SUBSCRIPTION_EVENT_SOURCE) {
pa_context_get_source_info_by_index(context, idx, sourceInfoCb, data);
@ -176,11 +179,11 @@ void waybar::modules::Pulseaudio::serverInfoCb(pa_context *context, const pa_ser
}
static const std::array<std::string, 9> ports = {
"headphones",
"headphone",
"speaker",
"hdmi",
"headset",
"handsfree",
"hands-free",
"portable",
"car",
"hifi",
@ -200,6 +203,7 @@ const std::string waybar::modules::Pulseaudio::getPortIcon() const {
auto waybar::modules::Pulseaudio::update() -> void {
auto format = format_;
if (!alt_) {
std::string format_name = "format";
if (monitor_.find("a2dp_sink") != std::string::npos) {
format_name = format_name + "-bluetooth";
@ -215,6 +219,7 @@ auto waybar::modules::Pulseaudio::update() -> void {
}
format =
config_[format_name].isString() ? config_[format_name].asString() : format;
}
// TODO: find a better way to split source/sink
std::string format_source = "{volume}%";
if (source_muted_ && config_["format-source-muted"].isString()) {

View File

@ -6,7 +6,7 @@ namespace waybar::modules::SNI {
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
: AModule(config, "tray", id),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
watcher_(nb_hosts_),
watcher_(SNI::Watcher::getInstance()),
host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1)) {
spdlog::warn(

View File

@ -3,14 +3,13 @@
using namespace waybar::modules::SNI;
Watcher::Watcher(std::size_t id)
Watcher::Watcher()
: bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION,
"org.kde.StatusNotifierWatcher",
sigc::mem_fun(*this, &Watcher::busAcquired),
Gio::DBus::SlotNameAcquired(), Gio::DBus::SlotNameLost(),
Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE)),
watcher_id_(id),
watcher_(sn_watcher_skeleton_new()) {}
Watcher::~Watcher() {
@ -23,6 +22,7 @@ Watcher::~Watcher() {
g_slist_free_full(items_, gfWatchFree);
items_ = nullptr;
}
Gio::DBus::unown_name(bus_name_id_);
auto iface = G_DBUS_INTERFACE_SKELETON(watcher_);
g_dbus_interface_skeleton_unexport(iface);
}
@ -34,7 +34,7 @@ void Watcher::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib:
if (error != nullptr) {
// Don't print an error when a watcher is already present
if (error->code != 2) {
spdlog::error("Watcher {}: {}", watcher_id_, error->message);
spdlog::error("Watcher: {}", error->message);
}
g_error_free(error);
return;

View File

@ -10,19 +10,23 @@ Ipc::Ipc() {
}
Ipc::~Ipc() {
thread_.stop();
if (fd_ > 0) {
// To fail the IPC header
write(fd_, "close-sway-ipc", 14);
write(fd_event_, "close-sway-ipc", 14);
if (fd_ > 0) {
close(fd_);
fd_ = -1;
}
if (fd_event_ > 0) {
write(fd_event_, "close-sway-ipc", 14);
close(fd_event_);
fd_event_ = -1;
}
}
void Ipc::setWorker(std::function<void()>&& func) { thread_ = func; }
const std::string Ipc::getSocketPath() const {
const char* env = getenv("SWAYSOCK");
if (env != nullptr) {

View File

@ -8,7 +8,13 @@ Mode::Mode(const std::string& id, const Json::Value& config)
ipc_.subscribe(R"(["mode"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Mode::onEvent));
// Launch worker
worker();
ipc_.setWorker([this] {
try {
ipc_.handleEvent();
} catch (const std::exception& e) {
spdlog::error("Mode: {}", e.what());
}
});
dp.emit();
}
@ -31,16 +37,6 @@ void Mode::onEvent(const struct Ipc::ipc_response& res) {
}
}
void Mode::worker() {
thread_ = [this] {
try {
ipc_.handleEvent();
} catch (const std::exception& e) {
spdlog::error("Mode: {}", e.what());
}
};
}
auto Mode::update() -> void {
if (mode_.empty()) {
event_box_.hide();

View File

@ -11,7 +11,13 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
// Get Initial focused window
getTree();
// Launch worker
worker();
ipc_.setWorker([this] {
try {
ipc_.handleEvent();
} catch (const std::exception& e) {
spdlog::error("Window: {}", e.what());
}
});
}
void Window::onEvent(const struct Ipc::ipc_response& res) { getTree(); }
@ -28,16 +34,6 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
}
}
void Window::worker() {
thread_ = [this] {
try {
ipc_.handleEvent();
} catch (const std::exception& e) {
spdlog::error("Window: {}", e.what());
}
};
}
auto Window::update() -> void {
if (!old_app_id_.empty()) {
bar_.window.get_style_context()->remove_class(old_app_id_);

View File

@ -22,7 +22,13 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
window.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
}
// Launch worker
worker();
ipc_.setWorker([this] {
try {
ipc_.handleEvent();
} catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what());
}
});
}
void Workspaces::onEvent(const struct Ipc::ipc_response &res) {
@ -102,16 +108,6 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
}
}
void Workspaces::worker() {
thread_ = [this] {
try {
ipc_.handleEvent();
} catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what());
}
};
}
bool Workspaces::filterButtons() {
bool needReorder = false;
for (auto it = buttons_.begin(); it != buttons_.end();) {