Compare commits

...

45 Commits
0.6.5 ... 0.6.6

Author SHA1 Message Date
bf5c00ff2a chore: 0.6.6 2019-05-22 10:16:14 +02:00
14ace24a26 style(battery): format 2019-05-22 10:09:05 +02:00
2fa581c7ea fix(battery): multiple paths 2019-05-22 10:06:54 +02:00
6ff013e25b Estimate of time remaining until empty|full on tooltip (#331)
Estimate of time remaining until empty|full on tooltip
2019-05-22 09:44:55 +02:00
cf3cb4c61f feat(Battery) Format argument for time to full|empty 2019-05-21 13:44:05 -04:00
00ada46dfc feat(Battery) Time remaining on tooltip 2019-05-21 13:36:14 -04:00
2db81a6107 fix(Battery) "current" unused and removed 2019-05-21 13:35:39 -04:00
3e76984ce7 chore: update network config 2019-05-21 17:44:46 +02:00
48a58cd979 fix(network): switch between ifaces upon disconnection 2019-05-21 17:38:47 +02:00
296b448d06 chore: update pulseaudio config 2019-05-21 14:58:03 +02:00
7a3febf6a7 fix(pulseaudio): default source format 2019-05-21 14:55:17 +02:00
bb4af295bc feat(pulseaudio): source info 2019-05-21 14:53:31 +02:00
cf7663153d fix(pulseaudio): allow to scroll to 0 2019-05-21 09:29:39 +02:00
12a251c3a4 fix(mode): escape text 2019-05-20 20:51:19 +02:00
4accdd4524 fix(Workspace): ordering 2019-05-20 20:46:59 +02:00
032ad925af Merge pull request #339 from alebastr/master
Tray error handling and logging improvements
2019-05-20 20:34:29 +02:00
50bfe78aed refactor(tray): improve error handling and add debug logs 2019-05-20 08:00:07 -07:00
afd291a566 fix(tray): Fix glib assertion when old property value is missing
xembedsniproxy sets WindowId as 'i' instead of 'u' and DBus::Proxy
ignores incorrectly typed value.
2019-05-20 07:16:08 -07:00
316a9be656 refactor(tray): Use spdlog for SNI::Item error messages 2019-05-20 07:16:08 -07:00
cdb347aaca Add --log-level command line option 2019-05-20 06:48:44 -07:00
ed240ac105 feat: add warning about tray requirements 2019-05-20 15:21:13 +02:00
232073ca17 Fix clock is always a second off (#333)
Fix clock is always a second off
2019-05-20 14:45:34 +02:00
5314b74dae fix: remove workaround 2019-05-20 14:39:49 +02:00
e3879559a2 Merge pull request #330 from Organic-Code/master
Adding sway/workspaces:persistant_workspaces
2019-05-20 14:33:31 +02:00
0ec8774a08 Fixing: missing argument for fmt, workspace order
Persistant workspaces would reorder upon their first creation
2019-05-20 08:23:42 -04:00
071b4928dc fix(workspaces): order 2019-05-20 13:31:02 +02:00
7c4d75d428 feat: create new workspace on the wanted output 2019-05-20 13:21:22 +02:00
67593b8c0f Merge pull request #332 from Organic-Code/enhancement/spdlog
Adding spdlog
2019-05-20 12:07:58 +02:00
cff39bc7cf fix: remove watcher_id fixme comment as fixed on master 2019-05-20 11:56:55 +02:00
f2edc8f965 feat(Watcher): define watcher_id 2019-05-20 11:47:52 +02:00
7b11283b73 Allow formatting memory with used and available memory (#334)
Allow formatting memory with used and available memory
2019-05-20 11:30:19 +02:00
03e43fb31d refactor: remove wlroots dependency 2019-05-20 09:49:54 +02:00
913d0f7ad0 backlight: fix for percentage output for amdgpu_bl0 device (#336)
backlight: fix for percentage output for amdgpu_bl0 device
2019-05-20 09:40:03 +02:00
5feb478611 Merge branch 'master' into amd_fix 2019-05-19 22:40:47 +03:00
6bf64cd04d Allow formatting memory with used and available memory 2019-05-19 16:34:42 +01:00
5e43b4f587 Fix clock is always a second off 2019-05-19 13:30:19 +01:00
e8dd1e2d2c Adding missing ; and _
I'll admit I don't have libmpd on my computer
2019-05-18 20:10:42 -04:00
51be97f9aa Adding spdlog 2019-05-18 19:44:45 -04:00
a00f812cd1 Typo 2019-05-18 18:21:01 -04:00
863e0babd8 Adding break when sorted_workspaces is filled 2019-05-18 12:09:30 -04:00
8ba3052dd1 Adding comments & fixing code style 2019-05-18 12:04:09 -04:00
1a76aa0c8c Improving ordering 2019-05-18 11:58:01 -04:00
85f177a213 Adding sway/workspaces:persistant_workspaces in config file
c.f. https://github.com/Alexays/Waybar/issues/210
2019-05-18 10:58:55 -04:00
f743882baa Merge branch 'master' into amd_fix 2019-05-17 22:33:02 +03:00
9fa0eb7068 more elegant amd fix 2019-05-17 22:30:45 +03:00
31 changed files with 503 additions and 278 deletions

View File

@ -17,4 +17,4 @@ script:
- echo FROM alexays/waybar:${distro} > Dockerfile
- echo ADD . /root >> Dockerfile
- docker build -t waybar .
- docker run waybar /bin/sh -c "cd /root && git clone --depth=1 https://github.com/swaywm/wlroots subprojects/wlroots && meson build && ninja -C build"
- docker run waybar /bin/sh -c "cd /root && meson build && ninja -C build"

View File

@ -38,13 +38,13 @@ class Bar {
bool vertical = false;
private:
static inline const std::string MIN_HEIGHT_MSG =
static constexpr const char* MIN_HEIGHT_MSG =
"Requested height: {} exceeds the minimum height: {} required by the modules";
static inline const std::string MIN_WIDTH_MSG =
static constexpr const char* MIN_WIDTH_MSG =
"Requested width: {} exceeds the minimum width: {} required by the modules";
static inline const std::string BAR_SIZE_MSG =
static constexpr const char* BAR_SIZE_MSG =
"Bar configured (width: {}, height: {}) for output: {}";
static inline const std::string SIZE_DEFINED =
static constexpr const char* SIZE_DEFINED =
"{} size is defined in the config file so it will stay like that";
static void layerSurfaceHandleConfigure(void *, struct zwlr_layer_surface_v1 *, uint32_t,
uint32_t, uint32_t);

View File

@ -9,7 +9,8 @@
#include <sys/inotify.h>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
@ -32,8 +33,9 @@ class Battery : public ALabel {
void getBatteries();
void worker();
const std::string getAdapterStatus(uint8_t capacity, uint32_t current_now) const;
const std::tuple<uint8_t, uint32_t, std::string> getInfos() const;
const std::string getAdapterStatus(uint8_t capacity) const;
const std::tuple<uint8_t, float, std::string> getInfos() const;
const std::string formatTimeRemaining(float hoursRemaining);
util::SleeperThread thread_;
util::SleeperThread thread_timer_;

View File

@ -3,9 +3,11 @@
#include <fmt/format.h>
#include <sys/sysinfo.h>
#include <fstream>
#include <iostream>
#include <cstdint>
#include <numeric>
#include <vector>
#include <string>
#include <utility>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"

View File

@ -2,7 +2,7 @@
#include <fmt/format.h>
#include <csignal>
#include <iostream>
#include <string>
#include "ALabel.hpp"
#include "util/command.hpp"
#include "util/json.hpp"

View File

@ -30,7 +30,7 @@ class Network : public ALabel {
void worker();
void createInfoSocket();
void createEventSocket();
int getExternalInterface();
int getExternalInterface(int skip_idx = -1);
void getInterfaceAddress();
int netlinkRequest(void*, uint32_t, uint32_t groups = 0);
int netlinkResponse(void*, uint32_t, uint32_t groups = 0);
@ -39,8 +39,9 @@ class Network : public ALabel {
void parseFreq(struct nlattr**);
bool associatedOrJoined(struct nlattr**);
bool checkInterface(struct ifinfomsg *rtif, std::string name);
int getPreferredIface();
int getPreferredIface(int skip_idx = -1);
auto getInfo() -> void;
void clearIface();
bool wildcardMatch(const std::string& pattern, const std::string& text);
waybar::util::SleeperThread thread_;

View File

@ -18,6 +18,7 @@ class Pulseaudio : public ALabel {
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
static void contextStateCb(pa_context*, void*);
static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*);
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*);
bool handleVolume(GdkEventScroll* e);
@ -27,14 +28,21 @@ class Pulseaudio : public ALabel {
pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_;
pa_context* context_;
uint32_t sink_idx_{0};
uint16_t volume_;
pa_cvolume pa_volume_;
bool muted_;
std::string port_name_;
std::string desc_;
std::string monitor_;
bool scrolling_;
// SINK
uint32_t sink_idx_{0};
uint16_t volume_;
pa_cvolume pa_volume_;
bool muted_;
std::string port_name_;
std::string desc_;
std::string monitor_;
// SOURCE
uint32_t source_idx_{0};
uint16_t source_volume_;
bool source_muted_;
std::string source_port_name_;
std::string source_desc_;
};
} // namespace waybar::modules

View File

@ -8,7 +8,7 @@ namespace waybar::modules::SNI {
class Watcher {
public:
Watcher();
Watcher(std::size_t id);
~Watcher();
private:

View File

@ -35,6 +35,7 @@ class Workspaces : public IModule, public sigc::trackable {
const Bar& bar_;
const Json::Value& config_;
std::vector<Json::Value> workspaces_;
std::vector<std::string> workspaces_order_;
waybar::util::SleeperThread thread_;
std::mutex mutex_;
Gtk::Box box_;

View File

@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
version: '0.6.5',
version: '0.6.6',
license: 'MIT',
default_options : [
'cpp_std=c++17',
@ -48,10 +48,10 @@ add_global_link_arguments(cpp_link_args, language : 'cpp')
thread_dep = dependency('threads')
libinput = dependency('libinput')
fmt = dependency('fmt', version : ['>=5.3.0'], fallback : ['fmt', 'fmt_dep'])
spdlog = dependency('spdlog', version : ['>=1.3.1'], fallback : ['spdlog', 'spdlog_dep'])
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
wayland_protos = dependency('wayland-protocols')
wlroots = dependency('wlroots', fallback: ['wlroots', 'wlroots'])
gtkmm = dependency('gtkmm-3.0')
dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
giounix = dependency('gio-unix-2.0', required: get_option('dbusmenu-gtk'))
@ -125,10 +125,10 @@ executable(
src_files,
dependencies: [
thread_dep,
wlroots,
client_protos,
wayland_client,
fmt,
spdlog,
sigcpp,
jsoncpp,
libinput,

View File

@ -96,6 +96,7 @@
"format": "{capacity}% {icon}",
"format-charging": "{capacity}% ",
"format-plugged": "{capacity}% ",
"format-alt": "{time} {icon}",
// "format-good": "", // An empty format will hide the module
// "format-full": "",
"format-icons": ["", "", "", "", ""]
@ -108,13 +109,16 @@
"format-wifi": "{essid} ({signalStrength}%) ",
"format-ethernet": "{ifname}: {ipaddr}/{cidr} ",
"format-linked": "{ifname} (No IP) ",
"format-disconnected": "Disconnected ⚠"
"format-disconnected": "Disconnected ⚠",
"format-alt": "{ifname}: {ipaddr}/{cidr}"
},
"pulseaudio": {
// "scroll-step": 1, // %, can be a float
"format": "{volume}% {icon}",
"format-bluetooth": "{volume}% {icon}",
"format-muted": "",
"format": "{volume}% {icon} {format_source}",
"format-bluetooth": "{volume}% {icon} {format_source}",
"format-muted": " {format_source}",
"format-source": "{volume}% ",
"format-source-muted": "",
"format-icons": {
"headphones": "",
"handsfree": "",

View File

@ -1,4 +1,5 @@
#include "bar.hpp"
#include <spdlog/spdlog.h>
#include "client.hpp"
#include "factory.hpp"
@ -114,7 +115,7 @@ void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) {
.left = std::stoi(margins[3], nullptr, 10)};
}
} catch (...) {
std::cerr << "Invalid margins: " + config["margin"].asString() << std::endl;
spdlog::warn("Invalid margins: {}", config["margin"].asString());
}
} else if (config["margin"].isInt()) {
auto gaps = config["margin"].asInt();
@ -132,10 +133,10 @@ void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
if (ev->height > static_cast<int>(height_)) {
// Default minimal value
if (height_ != 1) {
std::cout << fmt::format(MIN_HEIGHT_MSG, height_, ev->height) << std::endl;
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
if (config["height"].isUInt()) {
std::cout << fmt::format(SIZE_DEFINED, "Height") << std::endl;
spdlog::info(SIZE_DEFINED, "Height");
} else {
tmp_height = ev->height;
}
@ -143,10 +144,10 @@ void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
if (ev->width > static_cast<int>(width_)) {
// Default minimal value
if (width_ != 1) {
std::cout << fmt::format(MIN_WIDTH_MSG, width_, ev->width) << std::endl;
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
if (config["width"].isUInt()) {
std::cout << fmt::format(SIZE_DEFINED, "Width") << std::endl;
spdlog::info(SIZE_DEFINED, "Width");
} else {
tmp_width = ev->width;
}
@ -227,11 +228,10 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surf
o->window.resize(o->width_, o->height_);
auto zone = o->vertical ? width + o->margins_.right : height + o->margins_.bottom;
zwlr_layer_surface_v1_set_exclusive_zone(o->layer_surface, zone);
std::cout << fmt::format(BAR_SIZE_MSG,
spdlog::info(BAR_SIZE_MSG,
o->width_ == 1 ? "auto" : std::to_string(o->width_),
o->height_ == 1 ? "auto" : std::to_string(o->height_),
o->output->name)
<< std::endl;
o->output->name);
wl_surface_commit(o->surface);
}
zwlr_layer_surface_v1_ack_configure(surface, serial);
@ -277,12 +277,12 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
try {
module->update();
} catch (const std::exception& e) {
std::cerr << name.asString() + ": " + e.what() << std::endl;
spdlog::error("{}: {}", name.asString(), e.what());
}
});
});
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
spdlog::warn("module {}: {}", name.asString(), e.what());
}
}
}

View File

@ -1,6 +1,7 @@
#include "client.hpp"
#include <fstream>
#include <iostream>
#include <spdlog/spdlog.h>
#include "util/clara.hpp"
#include "util/json.hpp"
@ -55,7 +56,7 @@ void waybar::Client::handleGlobalRemove(void * data, struct wl_registry * /*re
auto output_name = (*it)->output->name;
(*it)->window.close();
it = client->bars.erase(it);
std::cout << "Bar removed from output: " + output_name << std::endl;
spdlog::info("Bar removed from output: {}", output_name);
} else {
++it;
}
@ -191,7 +192,7 @@ void waybar::Client::setupConfigs(const std::string &config, const std::string &
if (css_file_.empty() || config_file_.empty()) {
throw std::runtime_error("Missing required resources files");
}
std::cout << "Resources files: " + config_file_ + ", " + css_file_ << std::endl;
spdlog::info("Resources files: {}, {}", config_file_, css_file_);
}
auto waybar::Client::setupConfig() -> void {
@ -242,14 +243,18 @@ int waybar::Client::main(int argc, char *argv[]) {
std::string config;
std::string style;
std::string bar_id;
std::string log_level;
auto cli = clara::detail::Help(show_help) |
clara::detail::Opt(show_version)["-v"]["--version"]("Show version") |
clara::detail::Opt(config, "config")["-c"]["--config"]("Config path") |
clara::detail::Opt(style, "style")["-s"]["--style"]("Style path") |
clara::detail::Opt(
log_level,
"trace|debug|info|warning|error|critical|off")["-l"]["--log-level"]("Log level") |
clara::detail::Opt(bar_id, "id")["-b"]["--bar"]("Bar id");
auto res = cli.parse(clara::detail::Args(argc, argv));
if (!res) {
std::cerr << "Error in command line: " << res.errorMessage() << std::endl;
spdlog::error("Error in command line: {}", res.errorMessage());
return 1;
}
if (show_help) {
@ -260,6 +265,9 @@ int waybar::Client::main(int argc, char *argv[]) {
std::cout << "Waybar v" << VERSION << std::endl;
return 0;
}
if (!log_level.empty()) {
spdlog::set_level(spdlog::level::from_str(log_level));
}
setupConfigs(config, style);
setupConfig();
setupCss();

View File

@ -1,5 +1,5 @@
#include <csignal>
#include <iostream>
#include <spdlog/spdlog.h>
#include "client.hpp"
int main(int argc, char* argv[]) {
@ -23,10 +23,10 @@ int main(int argc, char* argv[]) {
delete client;
return ret;
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
spdlog::error("{}", e.what());
return 1;
} catch (const Glib::Exception& e) {
std::cerr << e.what().c_str() << std::endl;
spdlog::error("{}", static_cast<std::string>(e.what()));
return 1;
}
}

View File

@ -213,7 +213,9 @@ void waybar::modules::Backlight::upsert_device(ForwardIt first, ForwardIt last,
const char *name = udev_device_get_sysname(dev);
check_nn(name);
const char *actual = udev_device_get_sysattr_value(dev, "actual_brightness");
const char *actual_brightness_attr = strcmp(name, "amdgpu_bl0") == 0 ? "brightness" : "actual_brightness";
const char *actual = udev_device_get_sysattr_value(dev, actual_brightness_attr);
check_nn(actual);
const int actual_int = std::stoi(actual);

View File

@ -1,4 +1,5 @@
#include "modules/battery.hpp"
#include <spdlog/spdlog.h>
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
: ALabel(config, "{capacity}%", 60) {
@ -75,23 +76,34 @@ void waybar::modules::Battery::getBatteries() {
}
}
const std::tuple<uint8_t, uint32_t, std::string> waybar::modules::Battery::getInfos() const {
const std::tuple<uint8_t, float, std::string> waybar::modules::Battery::getInfos() const {
try {
uint16_t total = 0;
uint32_t total_current = 0;
uint32_t total_power = 0; // μW
uint32_t total_energy = 0; // μWh
uint32_t total_energy_full = 0;
std::string status = "Unknown";
for (auto const& bat : batteries_) {
uint16_t capacity;
uint32_t current_now;
uint32_t power_now;
uint32_t energy_full;
uint32_t energy_now;
std::string _status;
std::ifstream(bat / "capacity") >> capacity;
std::ifstream(bat / "status") >> _status;
std::ifstream(bat / "current_now") >> current_now;
auto rate_path = fs::exists(bat / "current_now") ? "current_now" : "power_now";
std::ifstream(bat / rate_path) >> power_now;
auto now_path = fs::exists(bat / "charge_now") ? "charge_now" : "energy_now";
std::ifstream(bat / now_path) >> energy_now;
auto full_path = fs::exists(bat / "charge_full") ? "charge_full" : "energy_full";
std::ifstream(bat / full_path) >> energy_full;
if (_status != "Unknown") {
status = _status;
}
total += capacity;
total_current += current_now;
total_power += power_now;
total_energy += energy_now;
total_energy_full += energy_full;
}
if (!adapter_.empty() && status == "Discharging") {
bool online;
@ -100,16 +112,21 @@ const std::tuple<uint8_t, uint32_t, std::string> waybar::modules::Battery::getIn
status = "Plugged";
}
}
float time_remaining = 0;
if (status == "Discharging" && total_power != 0) {
time_remaining = (float)total_energy / total_power;
} else if (status == "Charging" && total_power != 0) {
time_remaining = -(float)(total_energy_full - total_energy) / total_power;
}
uint16_t capacity = total / batteries_.size();
return {capacity, total_current, status};
return {capacity, time_remaining, status};
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
spdlog::error("Battery: {}", e.what());
return {0, 0, "Unknown"};
}
}
const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity,
uint32_t current_now) const {
const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const {
if (!adapter_.empty()) {
bool online;
std::ifstream(adapter_ / "online") >> online;
@ -124,13 +141,27 @@ const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity,
return "Unknown";
}
const std::string waybar::modules::Battery::formatTimeRemaining(float hoursRemaining) {
hoursRemaining = std::fabs(hoursRemaining);
uint16_t full_hours = static_cast<uint16_t>(hoursRemaining);
uint16_t minutes = static_cast<uint16_t>(60 * (hoursRemaining - full_hours));
return std::to_string(full_hours) + " h " + std::to_string(minutes) + " min";
}
auto waybar::modules::Battery::update() -> void {
auto [capacity, current_now, status] = getInfos();
auto [capacity, time_remaining, status] = getInfos();
if (status == "Unknown") {
status = getAdapterStatus(capacity, current_now);
status = getAdapterStatus(capacity);
}
if (tooltipEnabled()) {
label_.set_tooltip_text(status);
std::string tooltip_text;
if (time_remaining != 0) {
std::string time_to = std::string("Time to ") + ((time_remaining > 0) ? "empty" : "full");
tooltip_text = time_to + ": " + formatTimeRemaining(time_remaining);
} else {
tooltip_text = status;
}
label_.set_tooltip_text(tooltip_text);
}
std::transform(status.begin(), status.end(), status.begin(), ::tolower);
auto format = format_;
@ -151,7 +182,9 @@ auto waybar::modules::Battery::update() -> void {
event_box_.hide();
} else {
event_box_.show();
label_.set_markup(fmt::format(
format, fmt::arg("capacity", capacity), fmt::arg("icon", getIcon(capacity, state))));
label_.set_markup(fmt::format(format,
fmt::arg("capacity", capacity),
fmt::arg("icon", getIcon(capacity, state)),
fmt::arg("time", formatTimeRemaining(time_remaining))));
}
}

View File

@ -14,16 +14,13 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
auto sub_m =
std::chrono::duration_cast<std::chrono::seconds>(time_s.time_since_epoch()).count() %
interval_.count();
if (sub_m > 0) {
thread_.sleep_until(timeout - std::chrono::seconds(sub_m - 1));
} else {
thread_.sleep_until(timeout - std::chrono::seconds(sub_m));
}
thread_.sleep_until(timeout - std::chrono::seconds(sub_m));
};
}
auto waybar::modules::Clock::update() -> void {
auto localtime = fmt::localtime(std::time(nullptr));
auto now = std::chrono::system_clock::now();
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
auto text = fmt::format(format_, localtime);
label_.set_markup(text);

View File

@ -1,4 +1,5 @@
#include "modules/cpu.hpp"
#include <numeric>
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: ALabel(config, "{usage}%", 10) {

View File

@ -1,4 +1,5 @@
#include "modules/custom.hpp"
#include <spdlog/spdlog.h>
waybar::modules::Custom::Custom(const std::string& name, const Json::Value& config)
: ALabel(config, "{}"), name_(name), fp_(nullptr), pid_(-1) {
@ -58,7 +59,7 @@ void waybar::modules::Custom::continuousWorker() {
if (exit_code != 0) {
output_ = {exit_code, ""};
dp.emit();
std::cerr << name_ + " just stopped unexpectedly, is it endless?" << std::endl;
spdlog::error("{} stopped unexpectedly, is it endless?", name_);
}
return;
}

View File

@ -16,9 +16,14 @@ auto waybar::modules::Memory::update() -> void {
parseMeminfo();
if (memtotal_ > 0 && memfree_ >= 0) {
int used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_;
getState(used_ram_percentage);
label_.set_markup(fmt::format(format_, used_ram_percentage));
auto used_ram_gigabytes = (memtotal_ - memfree_) / std::pow(1024, 2);
auto available_ram_gigabytes = memfree_ / std::pow(1024, 2);
getState(used_ram_percentage);
label_.set_markup(fmt::format(format_, used_ram_percentage,
fmt::arg("percentage", used_ram_percentage),
fmt::arg("used", used_ram_gigabytes),
fmt::arg("avail", available_ram_gigabytes)));
if (tooltipEnabled()) {
label_.set_tooltip_text(fmt::format("{:.{}f}Gb used", used_ram_gigabytes, 1));
}

View File

@ -1,7 +1,7 @@
#include "modules/mpd.hpp"
#include <fmt/chrono.h>
#include <iostream>
#include <spdlog/spdlog.h>
waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
: ALabel(config, "{album} - {artist} - {title}", 5),
@ -14,11 +14,11 @@ waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
status_(nullptr, &mpd_status_free),
song_(nullptr, &mpd_song_free) {
if (!config_["port"].isNull() && !config_["port"].isUInt()) {
std::cerr << module_name_ << ": `port` configuration should be an unsigned int" << std::endl;
spdlog::warn("{}: `port` configuration should be an unsigned int", module_name_);
}
if (!config_["timeout"].isNull() && !config_["timeout"].isUInt()) {
std::cerr << module_name_ << ": `timeout` configuration should be an unsigned int" << std::endl;
spdlog::warn("{}: `timeout` configuration should be an unsigned int", module_name_);
}
label_.set_name("mpd");
@ -28,7 +28,7 @@ waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
if (!config["server"].isNull()) {
if (!config_["server"].isString()) {
std::cerr << module_name_ << "`server` configuration should be a string" << std::endl;
spdlog::warn("{}:`server` configuration should be a string", module_name_);
}
server_ = config["server"].asCString();
}
@ -51,7 +51,7 @@ auto waybar::modules::MPD::update() -> void {
periodic_updater().detach();
}
} catch (const std::exception& e) {
std::cerr << module_name_ + ": " + e.what() << std::endl;
spdlog::error("{}: {}", module_name_, e.what());
state_ = MPD_STATE_UNKNOWN;
}
}
@ -72,7 +72,7 @@ std::thread waybar::modules::MPD::event_listener() {
dp.emit();
}
} catch (const std::exception& e) {
std::cerr << module_name_ + ": " + e.what() << std::endl;
spdlog::warn("{}: {}", module_name_, e.what());
}
}
});
@ -206,12 +206,12 @@ std::string waybar::modules::MPD::getStateIcon() {
}
if (connection_ == nullptr) {
std::cerr << module_name_ << ": Trying to fetch state icon while disconnected" << std::endl;
spdlog::warn("{}: Trying to fetch state icon while disconnected", module_name_);
return "";
}
if (stopped()) {
std::cerr << module_name_ << ": Trying to fetch state icon while stopped" << std::endl;
spdlog::warn("{}: Trying to fetch state icon while stopped", module_name_);
return "";
}
@ -228,7 +228,7 @@ std::string waybar::modules::MPD::getOptionIcon(std::string optionName, bool act
}
if (connection_ == nullptr) {
std::cerr << module_name_ << ": Trying to fetch option icon while disconnected" << std::endl;
spdlog::warn("{}: Trying to fetch option icon while disconnected", module_name_);
return "";
}
@ -251,7 +251,7 @@ void waybar::modules::MPD::tryConnect() {
unique_connection(mpd_connection_new(server_, port_, timeout_), &mpd_connection_free);
if (connection_ == nullptr || alternate_connection_ == nullptr) {
std::cerr << module_name_ << ": Failed to connect to MPD" << std::endl;
spdlog::error("{}: Failed to connect to MPD", module_name_);
connection_.reset();
alternate_connection_.reset();
return;
@ -259,9 +259,9 @@ void waybar::modules::MPD::tryConnect() {
try {
checkErrors(connection_.get());
std::cerr << module_name_ << ": Connected to MPD" << std::endl;
spdlog::info("{}: Connected to MPD", module_name_);
} catch (std::runtime_error& e) {
std::cerr << module_name_ << ": Failed to connect to MPD: " << e.what() << std::endl;
spdlog::error("{}: Failed to connect to MPD: {}", module_name_, e.what());
connection_.reset();
alternate_connection_.reset();
}

View File

@ -1,74 +1,76 @@
#include "modules/network.hpp"
#include <spdlog/spdlog.h>
#include <sys/eventfd.h>
#include <fstream>
#include <iostream>
namespace {
constexpr const char * NETSTAT_FILE = "/proc/net/netstat"; // std::ifstream does not take std::string_view as param
constexpr std::string_view BANDWIDTH_CATEGORY = "IpExt";
constexpr std::string_view BANDWIDTH_DOWN_TOTAL_KEY = "InOctets";
constexpr std::string_view BANDWIDTH_UP_TOTAL_KEY = "OutOctets";
constexpr const char *NETSTAT_FILE =
"/proc/net/netstat"; // std::ifstream does not take std::string_view as param
constexpr std::string_view BANDWIDTH_CATEGORY = "IpExt";
constexpr std::string_view BANDWIDTH_DOWN_TOTAL_KEY = "InOctets";
constexpr std::string_view BANDWIDTH_UP_TOTAL_KEY = "OutOctets";
std::ifstream netstat(NETSTAT_FILE);
std::optional<unsigned long long> read_netstat(std::string_view category, std::string_view key) {
if (!netstat) {
std::cerr << "Failed to open netstat file " << NETSTAT_FILE << '\n' << std::flush;
return {};
}
netstat.seekg(std::ios_base::beg);
// finding corresponding line (category)
// looks into the file for the first line starting by the 'category' string
auto starts_with = [](const std::string& str, std::string_view start) {
return start == std::string_view{str.data(), std::min(str.size(), start.size())};
};
std::string read;
while (std::getline(netstat, read) && !starts_with(read, category));
if (!starts_with(read, category)) {
std::cerr << "Category '" << category << "' not found in netstat file " << NETSTAT_FILE << '\n' << std::flush;
return {};
}
// finding corresponding column (key)
// looks into the fetched line for the first word (space separated) equal to 'key'
int index = 0;
auto r_it = read.begin();
auto k_it = key.begin();
while (k_it != key.end() && r_it != read.end()) {
if (*r_it != *k_it) {
r_it = std::find(r_it, read.end(), ' ');
if (r_it != read.end()) {
++r_it;
}
k_it = key.begin();
++index;
} else {
++r_it;
++k_it;
}
}
if (r_it == read.end() && k_it != key.end()) {
std::cerr << "Key '" << key << "' not found in category '" << category << "' of netstat file " << NETSTAT_FILE << '\n' << std::flush;
return {};
}
// finally accessing value
// accesses the line right under the fetched one
std::getline(netstat, read);
assert(starts_with(read, category));
std::istringstream iss(read);
while (index--) {
std::getline(iss, read, ' ');
}
unsigned long long value;
iss >> value;
return value;
std::ifstream netstat(NETSTAT_FILE);
std::optional<unsigned long long> read_netstat(std::string_view category, std::string_view key) {
if (!netstat) {
spdlog::warn("Failed to open netstat file {}", NETSTAT_FILE);
return {};
}
netstat.seekg(std::ios_base::beg);
// finding corresponding line (category)
// looks into the file for the first line starting by the 'category' string
auto starts_with = [](const std::string &str, std::string_view start) {
return start == std::string_view{str.data(), std::min(str.size(), start.size())};
};
std::string read;
while (std::getline(netstat, read) && !starts_with(read, category))
;
if (!starts_with(read, category)) {
spdlog::warn("Category '{}' not found in netstat file {}", category, NETSTAT_FILE);
return {};
}
// finding corresponding column (key)
// looks into the fetched line for the first word (space separated) equal to 'key'
int index = 0;
auto r_it = read.begin();
auto k_it = key.begin();
while (k_it != key.end() && r_it != read.end()) {
if (*r_it != *k_it) {
r_it = std::find(r_it, read.end(), ' ');
if (r_it != read.end()) {
++r_it;
}
k_it = key.begin();
++index;
} else {
++r_it;
++k_it;
}
}
if (r_it == read.end() && k_it != key.end()) {
spdlog::warn(
"Key '{}' not found in category '{}' of netstat file {}", key, category, NETSTAT_FILE);
return {};
}
// finally accessing value
// accesses the line right under the fetched one
std::getline(netstat, read);
assert(starts_with(read, category));
std::istringstream iss(read);
while (index--) {
std::getline(iss, read, ' ');
}
unsigned long long value;
iss >> value;
return value;
}
} // namespace
waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
: ALabel(config, "{ifname}", 60),
@ -272,39 +274,42 @@ auto waybar::modules::Network::update() -> void {
format_ = default_format_;
}
getState(signal_strength_);
auto pow_format = [](unsigned long long value, const std::string& unit) {
if (value > 2000ull * 1000ull * 1000ull) { // > 2G
auto pow_format = [](unsigned long long value, const std::string &unit) {
if (value > 2000ull * 1000ull * 1000ull) { // > 2G
auto go = value / (1000 * 1000 * 1000);
return std::to_string(go) + "." + std::to_string((value - go * 1000 * 1000 * 1000) / (100 * 1000 * 1000)) + "G" + unit;
return std::to_string(go) + "." +
std::to_string((value - go * 1000 * 1000 * 1000) / (100 * 1000 * 1000)) + "G" + unit;
} else if (value > 2000ull * 1000ull) { // > 2M
} else if (value > 2000ull * 1000ull) { // > 2M
auto mo = value / (1000 * 1000);
return std::to_string(mo) + "." + std::to_string((value - mo * 1000 * 1000) / (100 * 1000)) + "M" + unit;
return std::to_string(mo) + "." + std::to_string((value - mo * 1000 * 1000) / (100 * 1000)) +
"M" + unit;
} else if (value > 2000ull) { // > 2k
} else if (value > 2000ull) { // > 2k
auto ko = value / 1000;
return std::to_string(ko) + "." + std::to_string((value - ko * 1000) / 100) + "k" + unit;
} else {
return std::to_string(value) + unit;
}
};
auto text = fmt::format(format_,
fmt::arg("essid", essid_),
fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_),
fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype)),
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
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")));
auto text = fmt::format(
format_,
fmt::arg("essid", essid_),
fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_),
fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype)),
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
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()) {
label_.set_markup(text);
}
@ -313,20 +318,22 @@ auto waybar::modules::Network::update() -> void {
tooltip_format = config_["tooltip-format"].asString();
}
if (!tooltip_format.empty()) {
auto tooltip_text = fmt::format(tooltip_format,
fmt::arg("essid", essid_),
fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_),
fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype)),
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
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")));
auto tooltip_text = fmt::format(
tooltip_format,
fmt::arg("essid", essid_),
fmt::arg("signaldBm", signal_strength_dbm_),
fmt::arg("signalStrength", signal_strength_),
fmt::arg("ifname", ifname_),
fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype)),
fmt::arg("bandwidthDownBits",
pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
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 (label_.get_tooltip_text() != text) {
label_.set_tooltip_text(tooltip_text);
}
@ -337,7 +344,7 @@ auto waybar::modules::Network::update() -> void {
}
// Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698
int waybar::modules::Network::getExternalInterface() {
int waybar::modules::Network::getExternalInterface(int skip_idx) {
static const uint32_t route_buffer_size = 8192;
struct nlmsghdr * hdr = nullptr;
struct rtmsg * rt = nullptr;
@ -447,7 +454,7 @@ int waybar::modules::Network::getExternalInterface() {
/* If this is the default route, and we know the interface index,
* we can stop parsing this message.
*/
if (has_gateway && !has_destination && temp_idx != -1) {
if (has_gateway && !has_destination && temp_idx != -1 && temp_idx != skip_idx) {
ifidx = temp_idx;
break;
}
@ -540,7 +547,7 @@ bool waybar::modules::Network::checkInterface(struct ifinfomsg *rtif, std::strin
return external_iface == rtif->ifi_index;
}
int waybar::modules::Network::getPreferredIface() {
int waybar::modules::Network::getPreferredIface(int skip_idx) {
if (config_["interface"].isString()) {
ifid_ = if_nametoindex(config_["interface"].asCString());
if (ifid_ > 0) {
@ -566,7 +573,7 @@ int waybar::modules::Network::getPreferredIface() {
return ifid_;
}
}
ifid_ = getExternalInterface();
ifid_ = getExternalInterface(skip_idx);
if (ifid_ > 0) {
char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname);
@ -576,6 +583,17 @@ int waybar::modules::Network::getPreferredIface() {
return -1;
}
void waybar::modules::Network::clearIface() {
essid_.clear();
ipaddr_.clear();
netmask_.clear();
cidr_ = 0;
signal_strength_dbm_ = 0;
signal_strength_ = 0;
frequency_ = 0;
linked_ = false;
}
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
auto net = static_cast<waybar::modules::Network *>(data);
auto nh = nlmsg_hdr(msg);
@ -586,13 +604,18 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
char ifname[IF_NAMESIZE];
if_indextoname(rtif->ifi_index, ifname);
// Auto detected network can also be assigned here
if (net->ifid_ == -1 && net->checkInterface(rtif, ifname)) {
if ((net->ifid_ == -1 || rtif->ifi_index != net->ifid_) && net->checkInterface(rtif, ifname)) {
// If iface is different, clear data
if (rtif->ifi_index != net->ifid_) {
net->clearIface();
}
net->linked_ = true;
net->ifname_ = ifname;
net->ifid_ = rtif->ifi_index;
}
// Check for valid interface
if (rtif->ifi_index == net->ifid_) {
net->linked_ = true;
// Get Iface and WIFI info
net->getInterfaceAddress();
net->thread_timer_.wake_up();
@ -617,15 +640,9 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
net->ifid_ = rtif->ifi_index;
net->dp.emit();
} else if (rtif->ifi_index == net->ifid_) {
net->linked_ = false;
net->ifname_.clear();
net->ifid_ = -1;
net->essid_.clear();
net->signal_strength_dbm_ = 0;
net->signal_strength_ = 0;
net->frequency_ = 0;
net->clearIface();
// Check for a new interface and get info
auto new_iface = net->getPreferredIface();
auto new_iface = net->getPreferredIface(rtif->ifi_index);
if (new_iface != -1) {
net->getInterfaceAddress();
net->thread_timer_.wake_up();

View File

@ -1,15 +1,17 @@
#include "modules/pulseaudio.hpp"
#include <array>
waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value &config)
: ALabel(config, "{volume}%"),
mainloop_(nullptr),
mainloop_api_(nullptr),
context_(nullptr),
scrolling_(false),
sink_idx_(0),
volume_(0),
muted_(false),
scrolling_(false) {
source_idx_(0),
source_volume_(0),
source_muted_(false) {
label_.set_name("pulseaudio");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
@ -58,7 +60,12 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data) {
case PA_CONTEXT_READY:
pa_context_get_server_info(c, serverInfoCb, data);
pa_context_set_subscribe_callback(c, subscribeCb, data);
pa_context_subscribe(c, PA_SUBSCRIPTION_MASK_SINK, nullptr, nullptr);
pa_context_subscribe(
c,
static_cast<enum pa_subscription_mask>(static_cast<int>(PA_SUBSCRIPTION_MASK_SINK) |
static_cast<int>(PA_SUBSCRIPTION_MASK_SOURCE)),
nullptr,
nullptr);
break;
case PA_CONTEXT_FAILED:
pa->mainloop_api_->quit(pa->mainloop_api_, 1);
@ -76,10 +83,10 @@ bool waybar::modules::Pulseaudio::handleVolume(GdkEventScroll *e) {
if (scrolling_) {
return false;
}
bool direction_up = false;
double volume_tick = (double)PA_VOLUME_NORM / 100;
bool direction_up = false;
double volume_tick = (double)PA_VOLUME_NORM / 100;
pa_volume_t change = volume_tick;
pa_cvolume pa_volume = pa_volume_;
pa_cvolume pa_volume = pa_volume_;
scrolling_ = true;
if (e->direction == GDK_SCROLL_UP) {
direction_up = true;
@ -108,7 +115,7 @@ bool waybar::modules::Pulseaudio::handleVolume(GdkEventScroll *e) {
pa_cvolume_inc(&pa_volume, change);
}
} else {
if (volume_ - 1 > 0) {
if (volume_ - 1 >= 0) {
pa_cvolume_dec(&pa_volume, change);
}
}
@ -127,6 +134,8 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context * conte
unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
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);
}
}
@ -140,6 +149,23 @@ void waybar::modules::Pulseaudio::volumeModifyCb(pa_context *c, int success, voi
}
}
/*
* Called when the requested source information is ready.
*/
void waybar::modules::Pulseaudio::sourceInfoCb(pa_context * /*context*/, const pa_source_info *i,
int /*eol*/, void *data) {
if (i != nullptr) {
auto self = static_cast<waybar::modules::Pulseaudio *>(data);
auto source_volume = static_cast<float>(pa_cvolume_avg(&(i->volume))) / float{PA_VOLUME_NORM};
self->source_volume_ = std::round(source_volume * 100.0F);
self->source_idx_ = i->index;
self->source_muted_ = i->mute != 0;
self->source_desc_ = i->description;
self->source_port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown";
self->dp.emit();
}
}
/*
* Called when the requested sink information is ready.
*/
@ -166,6 +192,7 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_
void waybar::modules::Pulseaudio::serverInfoCb(pa_context *context, const pa_server_info *i,
void *data) {
pa_context_get_sink_info_by_name(context, i->default_sink_name, sinkInfoCb, data);
pa_context_get_source_info_by_name(context, i->default_source_name, sourceInfoCb, data);
}
static const std::array<std::string, 9> ports = {
@ -206,8 +233,18 @@ auto waybar::modules::Pulseaudio::update() -> void {
label_.get_style_context()->remove_class("bluetooth");
}
}
label_.set_markup(fmt::format(
format, fmt::arg("volume", volume_), fmt::arg("icon", getIcon(volume_, getPortIcon()))));
// TODO: find a better way to split source/sink
std::string format_source = "{volume}%";
if (source_muted_ && config_["format-source-muted"].isString()) {
format_source = config_["format-source-muted"].asString();
} else if (!source_muted_ && config_["format-source"].isString()) {
format_source = config_["format-source"].asString();
}
format_source = fmt::format(format_source, fmt::arg("volume", source_volume_));
label_.set_markup(fmt::format(format,
fmt::arg("volume", volume_),
fmt::arg("format_source", format_source),
fmt::arg("icon", getIcon(volume_, getPortIcon()))));
getState(volume_);
if (tooltipEnabled()) {
label_.set_tooltip_text(desc_);

View File

@ -1,5 +1,6 @@
#include "modules/sni/host.hpp"
#include <iostream>
#include <spdlog/spdlog.h>
#include <fmt/ostream.h>
namespace waybar::modules::SNI {
@ -63,14 +64,14 @@ void Host::proxyReady(GObject* src, GAsyncResult* res, gpointer data) {
GError* error = nullptr;
SnWatcher* watcher = sn_watcher_proxy_new_finish(res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
std::cerr << error->message << std::endl;
spdlog::error("Host: {}", error->message);
g_error_free(error);
return;
}
auto host = static_cast<SNI::Host*>(data);
host->watcher_ = watcher;
if (error != nullptr) {
std::cerr << error->message << std::endl;
spdlog::error("Host: {}", error->message);
g_error_free(error);
return;
}
@ -82,13 +83,13 @@ void Host::registerHost(GObject* src, GAsyncResult* res, gpointer data) {
GError* error = nullptr;
sn_watcher_call_register_host_finish(SN_WATCHER(src), res, &error);
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
std::cerr << error->message << std::endl;
spdlog::error("Host: {}", error->message);
g_error_free(error);
return;
}
auto host = static_cast<SNI::Host*>(data);
if (error != nullptr) {
std::cerr << error->message << std::endl;
spdlog::error("Host: {}", error->message);
g_error_free(error);
return;
}
@ -139,4 +140,4 @@ void Host::addRegisteredItem(std::string service) {
}
}
} // namespace waybar::modules::SNI
} // namespace waybar::modules::SNI

View File

@ -1,6 +1,32 @@
#include "modules/sni/item.hpp"
#include <glibmm/main.h>
#include <iostream>
#include <spdlog/spdlog.h>
#include "modules/sni/item.hpp"
template <>
struct fmt::formatter<Glib::ustring> : formatter<std::string> {
template <typename FormatContext>
auto format(const Glib::ustring& value, FormatContext& ctx) {
return formatter<std::string>::format(value, ctx);
}
};
template <>
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
bool is_printable(const Glib::VariantBase& value) {
auto type = value.get_type_string();
/* Print only primitive (single character excluding 'v') and short complex types */
return (type.length() == 1 && islower(type[0]) && type[0] != 'v') || value.get_size() <= 32;
}
template <typename FormatContext>
auto format(const Glib::VariantBase& value, FormatContext& ctx) {
if (is_printable(value)) {
return formatter<std::string>::format(value.print(), ctx);
} else {
return formatter<std::string>::format(value.get_type_string(), ctx);
}
}
};
namespace waybar::modules::SNI {
@ -47,23 +73,16 @@ void Item::proxyReady(Glib::RefPtr<Gio::AsyncResult>& result) {
this->proxy_->signal_signal().connect(sigc::mem_fun(*this, &Item::onSignal));
if (this->id.empty() || this->category.empty() || this->status.empty()) {
std::cerr << "Invalid Status Notifier Item: " + this->bus_name + "," + this->object_path
<< std::endl;
spdlog::error("Invalid Status Notifier Item: {}, {}", bus_name, object_path);
return;
}
this->updateImage();
// this->event_box.set_tooltip_text(this->title);
} catch (const Glib::Error& err) {
g_error("Failed to create DBus Proxy for %s %s: %s",
bus_name.c_str(),
object_path.c_str(),
err.what().c_str());
spdlog::error("Failed to create DBus Proxy for {} {}: {}", bus_name, object_path, err.what());
} catch (const std::exception& err) {
g_error("Failed to create DBus Proxy for %s %s: %s",
bus_name.c_str(),
object_path.c_str(),
err.what());
spdlog::error("Failed to create DBus Proxy for {} {}: {}", bus_name, object_path, err.what());
}
}
@ -73,41 +92,57 @@ T get_variant(Glib::VariantBase& value) {
}
void Item::setProperty(const Glib::ustring& name, Glib::VariantBase& value) {
if (name == "Category") {
category = get_variant<std::string>(value);
} else if (name == "Id") {
id = get_variant<std::string>(value);
} else if (name == "Title") {
title = get_variant<std::string>(value);
} else if (name == "Status") {
status = get_variant<std::string>(value);
} else if (name == "WindowId") {
window_id = get_variant<int32_t>(value);
} else if (name == "IconName") {
icon_name = get_variant<std::string>(value);
} else if (name == "IconPixmap") {
icon_pixmap = this->extractPixBuf(value.gobj());
} else if (name == "OverlayIconName") {
overlay_icon_name = get_variant<std::string>(value);
} else if (name == "OverlayIconPixmap") {
// TODO: overlay_icon_pixmap
} else if (name == "AttentionIconName") {
attention_icon_name = get_variant<std::string>(value);
} else if (name == "AttentionIconPixmap") {
// TODO: attention_icon_pixmap
} else if (name == "AttentionMovieName") {
attention_movie_name = get_variant<std::string>(value);
} else if (name == "ToolTip") {
// TODO: tooltip
} else if (name == "IconThemePath") {
icon_theme_path = get_variant<std::string>(value);
if (!icon_theme_path.empty()) {
icon_theme->set_search_path({icon_theme_path});
try {
spdlog::trace("Set tray item property: {}.{} = {}", id.empty() ? bus_name : id, name, value);
if (name == "Category") {
category = get_variant<std::string>(value);
} else if (name == "Id") {
id = get_variant<std::string>(value);
} else if (name == "Title") {
title = get_variant<std::string>(value);
} else if (name == "Status") {
status = get_variant<std::string>(value);
} else if (name == "WindowId") {
window_id = get_variant<int32_t>(value);
} else if (name == "IconName") {
icon_name = get_variant<std::string>(value);
} else if (name == "IconPixmap") {
icon_pixmap = this->extractPixBuf(value.gobj());
} else if (name == "OverlayIconName") {
overlay_icon_name = get_variant<std::string>(value);
} else if (name == "OverlayIconPixmap") {
// TODO: overlay_icon_pixmap
} else if (name == "AttentionIconName") {
attention_icon_name = get_variant<std::string>(value);
} else if (name == "AttentionIconPixmap") {
// TODO: attention_icon_pixmap
} else if (name == "AttentionMovieName") {
attention_movie_name = get_variant<std::string>(value);
} else if (name == "ToolTip") {
// TODO: tooltip
} else if (name == "IconThemePath") {
icon_theme_path = get_variant<std::string>(value);
if (!icon_theme_path.empty()) {
icon_theme->set_search_path({icon_theme_path});
}
} else if (name == "Menu") {
menu = get_variant<std::string>(value);
} else if (name == "ItemIsMenu") {
item_is_menu = get_variant<bool>(value);
}
} else if (name == "Menu") {
menu = get_variant<std::string>(value);
} else if (name == "ItemIsMenu") {
item_is_menu = get_variant<bool>(value);
} catch (const Glib::Error& err) {
spdlog::warn("Failed to set tray item property: {}.{}, value = {}, err = {}",
id.empty() ? bus_name : id,
name,
value,
err.what());
} catch (const std::exception& err) {
spdlog::warn("Failed to set tray item property: {}.{}, value = {}, err = {}",
id.empty() ? bus_name : id,
name,
value,
err.what());
}
}
@ -132,7 +167,7 @@ void Item::processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& _result) {
for (const auto& [name, value] : properties) {
Glib::VariantBase old_value;
proxy_->get_cached_property(old_value, name);
if (!value.equal(old_value)) {
if (!old_value || !value.equal(old_value)) {
proxy_->set_cached_property(name, value);
setProperty(name, const_cast<Glib::VariantBase&>(value));
}
@ -141,14 +176,15 @@ void Item::processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& _result) {
this->updateImage();
// this->event_box.set_tooltip_text(this->title);
} catch (const Glib::Error& err) {
g_warning("Failed to update properties: %s", err.what().c_str());
spdlog::warn("Failed to update properties: {}", err.what());
} catch (const std::exception& err) {
g_warning("Failed to update properties: %s", err.what());
spdlog::warn("Failed to update properties: {}", err.what());
}
}
void Item::onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
const Glib::VariantContainerBase& arguments) {
spdlog::trace("Tray item '{}' got signal {}", id, signal_name);
if (!update_pending_ && signal_name.compare(0, 3, "New") == 0) {
/* Debounce signals and schedule update of all properties.
* Based on behavior of Plasma dataengine for StatusNotifierItem.
@ -235,7 +271,7 @@ void Item::updateImage() {
image.set(getIconByName(icon_name, icon_size));
}
} catch (Glib::Error& e) {
std::cerr << "Exception: " << e.what() << std::endl;
spdlog::error("Item '{}': {}", id, static_cast<std::string>(e.what()));
}
} else if (icon_pixmap) {
// An icon extracted may be the wrong size for the tray
@ -321,4 +357,4 @@ bool Item::handleClick(GdkEventButton* const& ev) {
return false;
}
} // namespace waybar::modules::SNI
} // namespace waybar::modules::SNI

View File

@ -1,14 +1,18 @@
#include "modules/sni/tray.hpp"
#include <iostream>
#include <spdlog/spdlog.h>
namespace waybar::modules::SNI {
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
: config_(config),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
watcher_(nb_hosts_),
host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1)) {
box_.set_name("tray");
spdlog::warn(
"For a functionnal tray you must have libappindicator-* installed and export "
"XDG_CURRENT_DESKTOP=Unity");
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
@ -39,4 +43,4 @@ auto Tray::update() -> void {
Tray::operator Gtk::Widget&() { return box_; }
}
} // namespace waybar::modules::SNI

View File

@ -1,16 +1,16 @@
#include "modules/sni/watcher.hpp"
#include <iostream>
#include <spdlog/spdlog.h>
using namespace waybar::modules::SNI;
Watcher::Watcher()
Watcher::Watcher(std::size_t id)
: 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() {
@ -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) {
std::cerr << error->message << std::endl;
spdlog::error("Watcher {}: {}", watcher_id_, error->message);
}
g_error_free(error);
return;
@ -193,4 +193,4 @@ void Watcher::updateRegisteredItems(SnWatcher* obj) {
sn_watcher_set_registered_items(obj, items);
g_variant_unref(variant);
g_free(items);
}
}

View File

@ -1,4 +1,5 @@
#include "modules/sway/mode.hpp"
#include <spdlog/spdlog.h>
namespace waybar::modules::sway {
@ -18,13 +19,13 @@ void Mode::onEvent(const struct Ipc::ipc_response& res) {
try {
auto payload = parser_.parse(res.payload);
if (payload["change"] != "default") {
mode_ = payload["change"].asString();
mode_ = Glib::Markup::escape_text(payload["change"].asString());
} else {
mode_.clear();
}
dp.emit();
} catch (const std::exception& e) {
std::cerr << "Mode: " << e.what() << std::endl;
spdlog::error("Mode: {}", e.what());
}
}
@ -33,7 +34,7 @@ void Mode::worker() {
try {
ipc_.handleEvent();
} catch (const std::exception& e) {
std::cerr << "Mode: " << e.what() << std::endl;
spdlog::error("Mode: {}", e.what());
}
};
}
@ -50,4 +51,4 @@ auto Mode::update() -> void {
}
}
} // namespace waybar::modules::sway
} // namespace waybar::modules::sway

View File

@ -1,4 +1,5 @@
#include "modules/sway/window.hpp"
#include <spdlog/spdlog.h>
namespace waybar::modules::sway {
@ -55,7 +56,7 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
dp.emit();
}
} catch (const std::exception& e) {
std::cerr << "Window: " << e.what() << std::endl;
spdlog::error("Window: {}", e.what());
}
}
@ -64,7 +65,7 @@ void Window::worker() {
try {
ipc_.handleEvent();
} catch (const std::exception& e) {
std::cerr << "Window: " << e.what() << std::endl;
spdlog::error("Window: {}", e.what());
}
};
}
@ -102,7 +103,7 @@ void Window::getTree() {
try {
ipc_.sendCmd(IPC_GET_TREE);
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
spdlog::error("Window: {}", e.what());
}
}

View File

@ -1,4 +1,5 @@
#include "modules/sway/workspaces.hpp"
#include <spdlog/spdlog.h>
namespace waybar::modules::sway {
@ -16,7 +17,7 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Workspaces::onCmd));
ipc_.sendCmd(IPC_GET_WORKSPACES);
if (!config["disable-bar-scroll"].asBool()) {
auto &window = const_cast<Bar&>(bar_).window;
auto &window = const_cast<Bar &>(bar_).window;
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
window.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
}
@ -28,7 +29,7 @@ void Workspaces::onEvent(const struct Ipc::ipc_response &res) {
try {
ipc_.sendCmd(IPC_GET_WORKSPACES);
} catch (const std::exception &e) {
std::cerr << "Workspaces: " << e.what() << std::endl;
spdlog::error("Workspaces: {}", e.what());
}
}
@ -47,10 +48,53 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
? workspace["output"].asString() == bar_.output->name
: true;
});
// adding persistant workspaces (as per the config file)
if (config_["persistant_workspaces"].isObject()) {
const Json::Value & p_workspaces = config_["persistant_workspaces"];
const std::vector<std::string> p_workspaces_names = p_workspaces.getMemberNames();
for (const std::string &p_w_name : p_workspaces_names) {
const Json::Value &p_w = p_workspaces[p_w_name];
auto it =
std::find_if(payload.begin(), payload.end(), [&p_w_name](const Json::Value &node) {
return node["name"].asString() == p_w_name;
});
if (it != payload.end()) {
continue; // already displayed by some bar
}
if (p_w.isArray() && !p_w.empty()) {
// Adding to target outputs
for (const Json::Value &output : p_w) {
if (output.asString() == bar_.output->name) {
Json::Value v;
v["name"] = p_w_name;
v["target_output"] = bar_.output->name;
workspaces_.emplace_back(std::move(v));
break;
}
}
} else {
// Adding to all outputs
Json::Value v;
v["name"] = p_w_name;
workspaces_.emplace_back(std::move(v));
}
}
std::sort(workspaces_.begin(),
workspaces_.end(),
[](const Json::Value &lhs, const Json::Value &rhs) {
return lhs["name"].asString() < rhs["name"].asString();
});
}
dp.emit();
}
} catch (const std::exception &e) {
std::cerr << "Workspaces: " << e.what() << std::endl;
spdlog::error("Workspaces: {}", e.what());
}
} else {
if (scrolling_) {
@ -64,7 +108,7 @@ void Workspaces::worker() {
try {
ipc_.handleEvent();
} catch (const std::exception &e) {
std::cerr << "Workspaces: " << e.what() << std::endl;
spdlog::error("Workspaces: {}", e.what());
}
};
}
@ -135,11 +179,20 @@ Gtk::Button &Workspaces::addButton(const Json::Value &node) {
auto &button = pair.first->second;
box_.pack_start(button, false, false, 0);
button.set_relief(Gtk::RELIEF_NONE);
button.signal_clicked().connect([this, pair] {
button.signal_clicked().connect([this, node] {
try {
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", pair.first->first));
if (node["target_output"].isString()) {
ipc_.sendCmd(
IPC_COMMAND,
fmt::format("workspace \"{}\"; move workspace to output \"{}\"; workspace \"{}\"",
node["name"].asString(),
node["target_output"].asString(),
node["name"].asString()));
} else {
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", node["name"].asString()));
}
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
spdlog::error("Workspaces: {}", e.what());
}
});
if (!config_["disable-scroll"].asBool()) {
@ -208,7 +261,7 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
try {
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name));
} catch (const std::exception &e) {
std::cerr << "Workspaces: " << e.what() << std::endl;
spdlog::error("Workspaces: {}", e.what());
}
return true;
}

10
subprojects/spdlog.wrap Normal file
View File

@ -0,0 +1,10 @@
[wrap-file]
directory = spdlog-1.3.1
source_url = https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz
source_filename = v1.3.1.tar.gz
source_hash = 160845266e94db1d4922ef755637f6901266731c4cb3b30b45bf41efa0e6ab70
patch_url = https://wrapdb.mesonbuild.com/v1/projects/spdlog/1.3.1/1/get_zip
patch_filename = spdlog-1.3.1-1-wrap.zip
patch_hash = 715a0229781019b853d409cc0bf891ee4b9d3a17bec0cf87f4ad30b28bbecc87