Merge branch 'master' into amd_fix

This commit is contained in:
Ilia Sheshukov 2019-05-17 22:33:02 +03:00
commit f743882baa
31 changed files with 440 additions and 255 deletions

View File

@ -8,6 +8,7 @@ env:
- distro: archlinux - distro: archlinux
- distro: opensuse - distro: opensuse
- distro: fedora - distro: fedora
- distro: alpine
before_install: before_install:
- docker pull alexays/waybar:${distro} - docker pull alexays/waybar:${distro}

3
Dockerfiles/alpine Normal file
View File

@ -0,0 +1,3 @@
FROM alpine:latest
RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev libnl3-dev pulseaudio-dev libmpdclient-dev

View File

@ -13,7 +13,7 @@ class ALabel : public IModule {
ALabel(const Json::Value &, const std::string &format, uint16_t interval = 0); ALabel(const Json::Value &, const std::string &format, uint16_t interval = 0);
virtual ~ALabel(); virtual ~ALabel();
virtual auto update() -> void; virtual auto update() -> void;
virtual std::string getIcon(uint16_t, const std::string &alt = ""); virtual std::string getIcon(uint16_t, const std::string &alt = "", uint16_t max = 0);
virtual operator Gtk::Widget &(); virtual operator Gtk::Widget &();
protected: protected:
@ -31,7 +31,7 @@ class ALabel : public IModule {
virtual bool handleToggle(GdkEventButton *const &ev); virtual bool handleToggle(GdkEventButton *const &ev);
virtual bool handleScroll(GdkEventScroll *); virtual bool handleScroll(GdkEventScroll *);
virtual std::string getState(uint8_t value); virtual std::string getState(uint8_t value, bool lesser = false);
private: private:
std::vector<int> pid_; std::vector<int> pid_;

View File

@ -7,11 +7,13 @@
#include "modules/sway/window.hpp" #include "modules/sway/window.hpp"
#include "modules/sway/workspaces.hpp" #include "modules/sway/workspaces.hpp"
#endif #endif
#ifndef NO_FILESYSTEM
#include "modules/battery.hpp" #include "modules/battery.hpp"
#endif
#include "modules/cpu.hpp" #include "modules/cpu.hpp"
#include "modules/idle_inhibitor.hpp" #include "modules/idle_inhibitor.hpp"
#include "modules/memory.hpp" #include "modules/memory.hpp"
#ifdef HAVE_DBUSMENU #if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
#include "modules/sni/tray.hpp" #include "modules/sni/tray.hpp"
#endif #endif
#ifdef HAVE_LIBNL #ifdef HAVE_LIBNL

View File

@ -32,8 +32,8 @@ class Battery : public ALabel {
void getBatteries(); void getBatteries();
void worker(); void worker();
const std::string getAdapterStatus(uint8_t capacity) const; const std::string getAdapterStatus(uint8_t capacity, uint32_t current_now) const;
const std::tuple<uint8_t, std::string> getInfos() const; const std::tuple<uint8_t, uint32_t, std::string> getInfos() const;
util::SleeperThread thread_; util::SleeperThread thread_;
util::SleeperThread thread_timer_; util::SleeperThread thread_timer_;

View File

@ -28,7 +28,6 @@ class Network : public ALabel {
static int handleScan(struct nl_msg*, void*); static int handleScan(struct nl_msg*, void*);
void worker(); void worker();
void disconnected();
void createInfoSocket(); void createInfoSocket();
void createEventSocket(); void createEventSocket();
int getExternalInterface(); int getExternalInterface();
@ -37,27 +36,35 @@ class Network : public ALabel {
int netlinkResponse(void*, uint32_t, uint32_t groups = 0); int netlinkResponse(void*, uint32_t, uint32_t groups = 0);
void parseEssid(struct nlattr**); void parseEssid(struct nlattr**);
void parseSignal(struct nlattr**); void parseSignal(struct nlattr**);
void parseFreq(struct nlattr**);
bool associatedOrJoined(struct nlattr**); bool associatedOrJoined(struct nlattr**);
bool checkInterface(int if_index, std::string name);
int getPreferredIface();
auto getInfo() -> void; auto getInfo() -> void;
bool wildcardMatch(const std::string& pattern, const std::string& text);
waybar::util::SleeperThread thread_; waybar::util::SleeperThread thread_;
waybar::util::SleeperThread thread_timer_; waybar::util::SleeperThread thread_timer_;
int ifid_; int ifid_;
int last_ext_iface_;
sa_family_t family_; sa_family_t family_;
struct sockaddr_nl nladdr_ = {0}; struct sockaddr_nl nladdr_ = {0};
struct nl_sock* sk_ = nullptr; struct nl_sock* sock_ = nullptr;
struct nl_sock* info_sock_ = nullptr; struct nl_sock* ev_sock_ = nullptr;
int efd_; int efd_;
int ev_fd_; int ev_fd_;
int nl80211_id_; int nl80211_id_;
std::mutex mutex_;
std::string essid_; std::string essid_;
std::string ifname_; std::string ifname_;
std::string ipaddr_; std::string ipaddr_;
std::string netmask_; std::string netmask_;
int cidr_; int cidr_;
bool linked_;
int32_t signal_strength_dbm_; int32_t signal_strength_dbm_;
uint8_t signal_strength_; uint8_t signal_strength_;
uint32_t frequency_;
}; };
} // namespace waybar::modules } // namespace waybar::modules

View File

@ -20,7 +20,7 @@ class Pulseaudio : public ALabel {
static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*); static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*);
static void serverInfoCb(pa_context*, const pa_server_info*, void*); static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*); static void volumeModifyCb(pa_context*, int, void*);
bool handleScroll(GdkEventScroll* e); bool handleVolume(GdkEventScroll* e);
const std::string getPortIcon() const; const std::string getPortIcon() const;
@ -33,6 +33,7 @@ class Pulseaudio : public ALabel {
bool muted_; bool muted_;
std::string port_name_; std::string port_name_;
std::string desc_; std::string desc_;
std::string monitor_;
bool scrolling_; bool scrolling_;
}; };

View File

@ -46,7 +46,7 @@ class Item : public sigc::trackable {
std::string menu; std::string menu;
DbusmenuGtkMenu* dbus_menu = nullptr; DbusmenuGtkMenu* dbus_menu = nullptr;
Gtk::Menu* gtk_menu = nullptr; Gtk::Menu* gtk_menu = nullptr;
bool item_is_menu; bool item_is_menu = false;
private: private:
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result); void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
@ -59,12 +59,12 @@ class Item : public sigc::trackable {
void updateImage(); void updateImage();
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant); Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size); Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
static void onMenuDestroyed(Item* self); static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
bool makeMenu(GdkEventButton* const& ev); void makeMenu(GdkEventButton* const& ev);
bool handleClick(GdkEventButton* const& /*ev*/); bool handleClick(GdkEventButton* const& /*ev*/);
Glib::RefPtr<Gio::Cancellable> cancellable_;
Glib::RefPtr<Gio::DBus::Proxy> proxy_; Glib::RefPtr<Gio::DBus::Proxy> proxy_;
Glib::RefPtr<Gio::Cancellable> cancellable_;
bool update_pending_; bool update_pending_;
}; };

View File

@ -10,7 +10,7 @@
namespace waybar::modules::sway { namespace waybar::modules::sway {
class Mode : public ALabel { class Mode : public ALabel, public sigc::trackable {
public: public:
Mode(const std::string&, const Json::Value&); Mode(const std::string&, const Json::Value&);
~Mode() = default; ~Mode() = default;

View File

@ -6,12 +6,12 @@
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
#include "util/sleeper_thread.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway { namespace waybar::modules::sway {
class Window : public ALabel { class Window : public ALabel, public sigc::trackable {
public: public:
Window(const std::string&, const waybar::Bar&, const Json::Value&); Window(const std::string&, const waybar::Bar&, const Json::Value&);
~Window() = default; ~Window() = default;
@ -27,6 +27,7 @@ class Window : public ALabel {
const Bar& bar_; const Bar& bar_;
waybar::util::SleeperThread thread_; waybar::util::SleeperThread thread_;
Ipc ipc_; Ipc ipc_;
std::mutex mutex_;
std::string window_; std::string window_;
int windowId_; int windowId_;
std::string app_id_; std::string app_id_;

View File

@ -7,12 +7,12 @@
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
#include "util/sleeper_thread.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway { namespace waybar::modules::sway {
class Workspaces : public IModule { class Workspaces : public IModule, public sigc::trackable {
public: public:
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&); Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
~Workspaces() = default; ~Workspaces() = default;
@ -27,10 +27,10 @@ class Workspaces : public IModule {
Gtk::Button& addButton(const Json::Value&); Gtk::Button& addButton(const Json::Value&);
void onButtonReady(const Json::Value&, Gtk::Button&); void onButtonReady(const Json::Value&, Gtk::Button&);
std::string getIcon(const std::string&, const Json::Value&); std::string getIcon(const std::string&, const Json::Value&);
bool handleScroll(GdkEventScroll*);
const std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const; const std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
uint16_t getWorkspaceIndex(const std::string& name) const; uint16_t getWorkspaceIndex(const std::string& name) const;
std::string trimWorkspaceName(std::string); std::string trimWorkspaceName(std::string);
bool handleScroll(GdkEventScroll*);
const Bar& bar_; const Bar& bar_;
const Json::Value& config_; const Json::Value& config_;

View File

@ -4,11 +4,6 @@
#include <fstream> #include <fstream>
#include "ALabel.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
#ifdef FILESYSTEM_EXPERIMENTAL
#include <experimental/filesystem>
#else
#include <filesystem>
#endif
namespace waybar::modules { namespace waybar::modules {

View File

@ -5,15 +5,16 @@
namespace waybar::util { namespace waybar::util {
struct JsonParser { struct JsonParser {
JsonParser() : reader_(builder_.newCharReader()) {} JsonParser() {}
const Json::Value parse(const std::string& data) const { const Json::Value parse(const std::string& data) const {
Json::Value root(Json::objectValue); Json::Value root(Json::objectValue);
if (data.empty()) { if (data.empty()) {
return root; return root;
} }
std::unique_ptr<Json::CharReader> const reader(builder_.newCharReader());
std::string err; std::string err;
bool res = reader_->parse(data.c_str(), data.c_str() + data.size(), &root, &err); bool res = reader->parse(data.c_str(), data.c_str() + data.size(), &root, &err);
if (!res) throw std::runtime_error(err); if (!res) throw std::runtime_error(err);
return root; return root;
} }
@ -22,7 +23,6 @@ struct JsonParser {
private: private:
Json::CharReaderBuilder builder_; Json::CharReaderBuilder builder_;
std::unique_ptr<Json::CharReader> const reader_;
}; };
} // namespace waybar::util } // namespace waybar::util

View File

@ -1,6 +1,6 @@
project( project(
'waybar', 'cpp', 'c', 'waybar', 'cpp', 'c',
version: '0.6.2', version: '0.6.4',
license: 'MIT', license: 'MIT',
default_options : [ default_options : [
'cpp_std=c++17', 'cpp_std=c++17',
@ -12,7 +12,7 @@ project(
cpp_args = [] cpp_args = []
cpp_link_args = [] cpp_link_args = []
if false # libc++ if get_option('libcxx')
cpp_args += ['-stdlib=libc++'] cpp_args += ['-stdlib=libc++']
cpp_link_args += ['-stdlib=libc++', '-lc++abi'] cpp_link_args += ['-stdlib=libc++', '-lc++abi']
@ -34,7 +34,12 @@ else
endif endif
if not compiler.has_header('filesystem') if not compiler.has_header('filesystem')
if compiler.has_header('experimental/filesystem')
add_project_arguments('-DFILESYSTEM_EXPERIMENTAL', language: 'cpp') add_project_arguments('-DFILESYSTEM_EXPERIMENTAL', language: 'cpp')
else
add_project_arguments('-DNO_FILESYSTEM', language: 'cpp')
warning('No filesystem header found, some modules may not work')
endif
endif endif
add_global_arguments(cpp_args, language : 'cpp') add_global_arguments(cpp_args, language : 'cpp')

View File

@ -1,3 +1,4 @@
option('libcxx', type : 'boolean', value : false, description : 'Build with Clang\'s libc++ instead of libstdc++ on Linux.')
option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl support for network related features') option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl support for network related features')
option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev support for udev related features') option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev support for udev related features')
option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio') option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio')

View File

@ -78,8 +78,9 @@
// "thermal-zone": 2, // "thermal-zone": 2,
// "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input", // "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
"critical-threshold": 80, "critical-threshold": 80,
// "format-critical": "{temperatureC}°C ", // "format-critical": "{temperatureC}°C {icon}",
"format": "{temperatureC}°C " "format": "{temperatureC}°C {icon}",
"format-icons": ["", "", ""]
}, },
"backlight": { "backlight": {
// "device": "acpi_video1", // "device": "acpi_video1",
@ -93,6 +94,8 @@
"critical": 15 "critical": 15
}, },
"format": "{capacity}% {icon}", "format": "{capacity}% {icon}",
"format-charging": "{capacity}% ",
"format-plugged": "{capacity}% ",
// "format-good": "", // An empty format will hide the module // "format-good": "", // An empty format will hide the module
// "format-full": "", // "format-full": "",
"format-icons": ["", "", "", "", ""] "format-icons": ["", "", "", "", ""]
@ -101,16 +104,17 @@
"bat": "BAT2" "bat": "BAT2"
}, },
"network": { "network": {
// "interface": "wlp2s0", // (Optional) To force the use of this interface // "interface": "wlp2*", // (Optional) To force the use of this interface
"format-wifi": "{essid} ({signalStrength}%) ", "format-wifi": "{essid} ({signalStrength}%) ",
"format-ethernet": "{ifname}: {ipaddr}/{cidr} ", "format-ethernet": "{ifname}: {ipaddr}/{cidr} ",
"format-linked": "{ifname} (No IP) ",
"format-disconnected": "Disconnected ⚠" "format-disconnected": "Disconnected ⚠"
}, },
"pulseaudio": { "pulseaudio": {
//"scroll-step": 1, // "scroll-step": 1, // %, can be a float
"format": "{volume}% {icon}", "format": "{volume}% {icon}",
"format-bluetooth": "{volume}% {icon}", "format-bluetooth": "{volume}% {icon}",
"format-muted": "", "format-muted": "",
"format-icons": { "format-icons": {
"headphones": "", "headphones": "",
"handsfree": "", "handsfree": "",
@ -118,7 +122,7 @@
"phone": "", "phone": "",
"portable": "", "portable": "",
"car": "", "car": "",
"default": ["", ""] "default": ["", "", ""]
}, },
"on-click": "pavucontrol" "on-click": "pavucontrol"
}, },

View File

@ -32,8 +32,7 @@ window#waybar.termite {
} }
window#waybar.chromium { window#waybar.chromium {
background-color: #DEE1E6; background-color: #000000;
color: #000000;
border: none; border: none;
} }
@ -45,19 +44,11 @@ window#waybar.chromium {
border-bottom: 3px solid transparent; border-bottom: 3px solid transparent;
} }
window#waybar.chromium #workspaces button {
color: #3F3F3F;
}
#workspaces button.focused { #workspaces button.focused {
background: #64727D; background: #64727D;
border-bottom: 3px solid #ffffff; border-bottom: 3px solid #ffffff;
} }
window#waybar.chromium #workspaces button.focused {
color: #ffffff;
}
#workspaces button.urgent { #workspaces button.urgent {
background-color: #eb4d4b; background-color: #eb4d4b;
} }
@ -142,6 +133,7 @@ label:focus {
#custom-media { #custom-media {
background: #66cc99; background: #66cc99;
color: #2a5c45; color: #2a5c45;
min-width: 100px;
} }
.custom-spotify { .custom-spotify {

View File

@ -109,7 +109,7 @@ bool waybar::ALabel::handleScroll(GdkEventScroll* e) {
return true; return true;
} }
std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt) { std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) {
auto format_icons = config_["format-icons"]; auto format_icons = config_["format-icons"];
if (format_icons.isObject()) { if (format_icons.isObject()) {
if (!alt.empty() && (format_icons[alt].isString() || format_icons[alt].isArray())) { if (!alt.empty() && (format_icons[alt].isString() || format_icons[alt].isArray())) {
@ -120,7 +120,7 @@ std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt)
} }
if (format_icons.isArray()) { if (format_icons.isArray()) {
auto size = format_icons.size(); auto size = format_icons.size();
auto idx = std::clamp(percentage / (100 / size), 0U, size - 1); auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1);
format_icons = format_icons[idx]; format_icons = format_icons[idx];
} }
if (format_icons.isString()) { if (format_icons.isString()) {
@ -129,7 +129,10 @@ std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt)
return ""; return "";
} }
std::string waybar::ALabel::getState(uint8_t value) { std::string waybar::ALabel::getState(uint8_t value, bool lesser) {
if (!config_["states"].isObject()) {
return "";
}
// Get current state // Get current state
std::vector<std::pair<std::string, uint8_t>> states; std::vector<std::pair<std::string, uint8_t>> states;
if (config_["states"].isObject()) { if (config_["states"].isObject()) {
@ -140,10 +143,12 @@ std::string waybar::ALabel::getState(uint8_t value) {
} }
} }
// Sort states // Sort states
std::sort(states.begin(), states.end(), [](auto& a, auto& b) { return a.second < b.second; }); std::sort(states.begin(), states.end(), [&lesser](auto& a, auto& b) {
return lesser ? a.second < b.second : a.second > b.second;
});
std::string valid_state; std::string valid_state;
for (auto const& state : states) { for (auto const& state : states) {
if (value <= state.second && valid_state.empty()) { if ((lesser ? value <= state.second : value >= state.second) && valid_state.empty()) {
label_.get_style_context()->add_class(state.first); label_.get_style_context()->add_class(state.first);
valid_state = state.first; valid_state = state.first;
} else { } else {

View File

@ -20,7 +20,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
height_ = 0; height_ = 0;
width_ = 1; width_ = 1;
} }
window.set_size_request(width_, height_);
auto gtk_window = window.gobj(); auto gtk_window = window.gobj();
auto gtk_widget = GTK_WIDGET(gtk_window); auto gtk_widget = GTK_WIDGET(gtk_window);
@ -43,8 +42,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
auto height = config["height"].isUInt() ? config["height"].asUInt() : height_; auto height = config["height"].isUInt() ? config["height"].asUInt() : height_;
auto width = config["width"].isUInt() ? config["width"].asUInt() : width_; auto width = config["width"].isUInt() ? config["width"].asUInt() : width_;
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
if (config["position"] == "bottom") { if (config["position"] == "bottom") {
anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
@ -73,6 +70,9 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
wl_display_roundtrip(client->wl_display); wl_display_roundtrip(client->wl_display);
setupWidgets(); setupWidgets();
window.set_size_request(width_, height_);
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
} }
void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) { void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) {

View File

@ -153,6 +153,7 @@ void waybar::Client::handleName(void * data, struct zxdg_output_v1 * /*xdg_
wl_output_destroy(output->output); wl_output_destroy(output->output);
zxdg_output_v1_destroy(output->xdg_output); zxdg_output_v1_destroy(output->xdg_output);
} else { } else {
wl_display_roundtrip(client->wl_display);
for (const auto &config : configs) { for (const auto &config : configs) {
client->bars.emplace_back(std::make_unique<Bar>(output.get(), config)); client->bars.emplace_back(std::make_unique<Bar>(output.get(), config));
Glib::RefPtr<Gdk::Screen> screen = client->bars.back()->window.get_screen(); Glib::RefPtr<Gdk::Screen> screen = client->bars.back()->window.get_screen();

View File

@ -7,9 +7,11 @@ waybar::IModule* waybar::Factory::makeModule(const std::string& name) const {
auto hash_pos = name.find('#'); auto hash_pos = name.find('#');
auto ref = name.substr(0, hash_pos); auto ref = name.substr(0, hash_pos);
auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : ""; auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : "";
#ifndef NO_FILESYSTEM
if (ref == "battery") { if (ref == "battery") {
return new waybar::modules::Battery(id, config_[name]); return new waybar::modules::Battery(id, config_[name]);
} }
#endif
#ifdef HAVE_SWAY #ifdef HAVE_SWAY
if (ref == "sway/mode") { if (ref == "sway/mode") {
return new waybar::modules::sway::Mode(id, config_[name]); return new waybar::modules::sway::Mode(id, config_[name]);
@ -33,7 +35,7 @@ waybar::IModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "clock") { if (ref == "clock") {
return new waybar::modules::Clock(id, config_[name]); return new waybar::modules::Clock(id, config_[name]);
} }
#ifdef HAVE_DBUSMENU #if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
if (ref == "tray") { if (ref == "tray") {
return new waybar::modules::SNI::Tray(id, bar_, config_[name]); return new waybar::modules::SNI::Tray(id, bar_, config_[name]);
} }

View File

@ -47,21 +47,21 @@ void waybar::modules::Battery::worker() {
void waybar::modules::Battery::getBatteries() { void waybar::modules::Battery::getBatteries() {
try { try {
for (auto const& node : fs::directory_iterator(data_dir_)) { for (auto& node : fs::directory_iterator(data_dir_)) {
if (!fs::is_directory(node)) { if (!fs::is_directory(node)) {
continue; continue;
} }
auto dir_name = node.path().filename(); auto dir_name = node.path().filename();
auto bat_defined = config_["bat"].isString(); auto bat_defined = config_["bat"].isString();
if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) && if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) &&
fs::exists(node / "capacity") && fs::exists(node / "uevent") && fs::exists(node.path() / "capacity") && fs::exists(node.path() / "uevent") &&
fs::exists(node / "status")) { fs::exists(node.path() / "status")) {
batteries_.push_back(node); batteries_.push_back(node.path());
} }
auto adap_defined = config_["adapter"].isString(); auto adap_defined = config_["adapter"].isString();
if (((adap_defined && dir_name == config_["adapter"].asString()) || !adap_defined) && if (((adap_defined && dir_name == config_["adapter"].asString()) || !adap_defined) &&
fs::exists(node / "online")) { fs::exists(node.path() / "online")) {
adapter_ = node; adapter_ = node.path();
} }
} }
} catch (fs::filesystem_error& e) { } catch (fs::filesystem_error& e) {
@ -75,52 +75,69 @@ void waybar::modules::Battery::getBatteries() {
} }
} }
const std::tuple<uint8_t, std::string> waybar::modules::Battery::getInfos() const { const std::tuple<uint8_t, uint32_t, std::string> waybar::modules::Battery::getInfos() const {
try { try {
uint16_t total = 0; uint16_t total = 0;
uint32_t total_current = 0;
std::string status = "Unknown"; std::string status = "Unknown";
for (auto const& bat : batteries_) { for (auto const& bat : batteries_) {
uint16_t capacity; uint16_t capacity;
uint32_t current_now;
std::string _status; std::string _status;
std::ifstream(bat / "capacity") >> capacity; std::ifstream(bat / "capacity") >> capacity;
std::ifstream(bat / "status") >> _status; std::ifstream(bat / "status") >> _status;
std::ifstream(bat / "current_now") >> current_now;
if (_status != "Unknown") { if (_status != "Unknown") {
status = _status; status = _status;
} }
total += capacity; total += capacity;
total_current += current_now;
}
if (!adapter_.empty() && status == "Discharging") {
bool online;
std::ifstream(adapter_ / "online") >> online;
if (online) {
status = "Plugged";
}
} }
uint16_t capacity = total / batteries_.size(); uint16_t capacity = total / batteries_.size();
return {capacity, status}; return {capacity, total_current, status};
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
return {0, "Unknown"}; return {0, 0, "Unknown"};
} }
} }
const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const { const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity,
uint32_t current_now) const {
if (!adapter_.empty()) { if (!adapter_.empty()) {
bool online; bool online;
std::ifstream(adapter_ / "online") >> online; std::ifstream(adapter_ / "online") >> online;
if (capacity == 100) { if (capacity == 100) {
return "Full"; return "Full";
} }
return online ? "Charging" : "Discharging"; if (online) {
return "Charging";
}
return "Discharging";
} }
return "Unknown"; return "Unknown";
} }
auto waybar::modules::Battery::update() -> void { auto waybar::modules::Battery::update() -> void {
auto [capacity, status] = getInfos(); auto [capacity, current_now, status] = getInfos();
if (status == "Unknown") { if (status == "Unknown") {
status = getAdapterStatus(capacity); status = getAdapterStatus(capacity, current_now);
} }
if (tooltipEnabled()) { if (tooltipEnabled()) {
label_.set_tooltip_text(status); label_.set_tooltip_text(status);
} }
std::transform(status.begin(), status.end(), status.begin(), ::tolower); std::transform(status.begin(), status.end(), status.begin(), ::tolower);
auto format = format_; auto format = format_;
auto state = getState(capacity); auto state = getState(capacity, true);
if (!old_status_.empty()) {
label_.get_style_context()->remove_class(old_status_); label_.get_style_context()->remove_class(old_status_);
}
label_.get_style_context()->add_class(status); label_.get_style_context()->add_class(status);
old_status_ = status; old_status_ = status;
if (!state.empty() && config_["format-" + status + "-" + state].isString()) { if (!state.empty() && config_["format-" + status + "-" + state].isString()) {
@ -134,7 +151,7 @@ auto waybar::modules::Battery::update() -> void {
event_box_.hide(); event_box_.hide();
} else { } else {
event_box_.show(); event_box_.show();
label_.set_markup( label_.set_markup(fmt::format(
fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("icon", getIcon(capacity)))); format, fmt::arg("capacity", capacity), fmt::arg("icon", getIcon(capacity, state))));
} }
} }

View File

@ -65,7 +65,7 @@ std::thread waybar::modules::MPD::event_listener() {
try { try {
if (connection_ == nullptr) { if (connection_ == nullptr) {
// Retry periodically if no connection // Retry periodically if no connection
update(); dp.emit();
std::this_thread::sleep_for(interval_); std::this_thread::sleep_for(interval_);
} else { } else {
waitForEvent(); waitForEvent();

View File

@ -3,31 +3,27 @@
waybar::modules::Network::Network(const std::string &id, const Json::Value &config) waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
: ALabel(config, "{ifname}", 60), : ALabel(config, "{ifname}", 60),
family_(AF_INET), ifid_(-1),
last_ext_iface_(-1),
family_(config["family"] == "ipv6" ? AF_INET6 : AF_INET),
efd_(-1), efd_(-1),
ev_fd_(-1), ev_fd_(-1),
cidr_(-1), cidr_(-1),
signal_strength_dbm_(0), signal_strength_dbm_(0),
signal_strength_(0) { signal_strength_(0),
frequency_(0) {
label_.set_name("network"); label_.set_name("network");
if (!id.empty()) { if (!id.empty()) {
label_.get_style_context()->add_class(id); label_.get_style_context()->add_class(id);
} }
createInfoSocket(); createInfoSocket();
createEventSocket(); createEventSocket();
if (config_["interface"].isString()) { auto default_iface = getPreferredIface();
ifid_ = if_nametoindex(config_["interface"].asCString()); if (default_iface != -1) {
ifname_ = config_["interface"].asString();
if (ifid_ <= 0) {
throw std::runtime_error("Can't found network interface");
}
} else {
ifid_ = getExternalInterface();
if (ifid_ > 0) {
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname); if_indextoname(default_iface, ifname);
ifname_ = ifname; ifname_ = ifname;
} getInterfaceAddress();
} }
dp.emit(); dp.emit();
worker(); worker();
@ -42,39 +38,42 @@ waybar::modules::Network::~Network() {
if (efd_ > -1) { if (efd_ > -1) {
close(efd_); close(efd_);
} }
if (info_sock_ != nullptr) { if (ev_sock_ != nullptr) {
nl_socket_drop_membership(info_sock_, RTMGRP_LINK); nl_socket_drop_membership(ev_sock_, RTNLGRP_LINK);
nl_socket_drop_membership(info_sock_, RTMGRP_IPV4_IFADDR); nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
nl_close(info_sock_); nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
nl_socket_free(info_sock_); nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV4_ROUTE);
nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV6_ROUTE);
nl_close(ev_sock_);
nl_socket_free(ev_sock_);
} }
if (sk_ != nullptr) { if (sock_ != nullptr) {
nl_close(sk_); nl_close(sock_);
nl_socket_free(sk_); nl_socket_free(sock_);
} }
} }
void waybar::modules::Network::createInfoSocket() { void waybar::modules::Network::createInfoSocket() {
info_sock_ = nl_socket_alloc(); ev_sock_ = nl_socket_alloc();
if (nl_connect(info_sock_, NETLINK_ROUTE) != 0) { nl_socket_disable_seq_check(ev_sock_);
nl_socket_modify_cb(ev_sock_, NL_CB_VALID, NL_CB_CUSTOM, handleEvents, this);
nl_join_groups(ev_sock_, RTMGRP_LINK);
if (nl_connect(ev_sock_, NETLINK_ROUTE) != 0) {
throw std::runtime_error("Can't connect network socket"); throw std::runtime_error("Can't connect network socket");
} }
if (nl_socket_add_membership(info_sock_, RTMGRP_LINK) != 0) { nl_socket_add_membership(ev_sock_, RTNLGRP_LINK);
throw std::runtime_error("Can't add membership"); nl_socket_add_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
} nl_socket_add_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
if (nl_socket_add_membership(info_sock_, RTMGRP_IPV4_IFADDR) != 0) { nl_socket_add_membership(ev_sock_, RTNLGRP_IPV4_ROUTE);
throw std::runtime_error("Can't add membership"); nl_socket_add_membership(ev_sock_, RTNLGRP_IPV6_ROUTE);
}
nl_socket_disable_seq_check(info_sock_);
nl_socket_set_nonblocking(info_sock_);
nl_socket_modify_cb(info_sock_, NL_CB_VALID, NL_CB_CUSTOM, handleEvents, this);
efd_ = epoll_create1(EPOLL_CLOEXEC); efd_ = epoll_create1(EPOLL_CLOEXEC);
if (efd_ < 0) { if (efd_ < 0) {
throw std::runtime_error("Can't create epoll"); throw std::runtime_error("Can't create epoll");
} }
{ {
ev_fd_ = eventfd(0, EFD_NONBLOCK); ev_fd_ = eventfd(0, EFD_NONBLOCK);
struct epoll_event event = {0}; struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN | EPOLLET; event.events = EPOLLIN | EPOLLET;
event.data.fd = ev_fd_; event.data.fd = ev_fd_;
if (epoll_ctl(efd_, EPOLL_CTL_ADD, ev_fd_, &event) == -1) { if (epoll_ctl(efd_, EPOLL_CTL_ADD, ev_fd_, &event) == -1) {
@ -82,8 +81,9 @@ void waybar::modules::Network::createInfoSocket() {
} }
} }
{ {
auto fd = nl_socket_get_fd(info_sock_); auto fd = nl_socket_get_fd(ev_sock_);
struct epoll_event event = {0}; struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
event.data.fd = fd; event.data.fd = fd;
if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) { if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) {
@ -93,14 +93,14 @@ void waybar::modules::Network::createInfoSocket() {
} }
void waybar::modules::Network::createEventSocket() { void waybar::modules::Network::createEventSocket() {
sk_ = nl_socket_alloc(); sock_ = nl_socket_alloc();
if (genl_connect(sk_) != 0) { if (genl_connect(sock_) != 0) {
throw std::runtime_error("Can't connect to netlink socket"); throw std::runtime_error("Can't connect to netlink socket");
} }
if (nl_socket_modify_cb(sk_, NL_CB_VALID, NL_CB_CUSTOM, handleScan, this) < 0) { if (nl_socket_modify_cb(sock_, NL_CB_VALID, NL_CB_CUSTOM, handleScan, this) < 0) {
throw std::runtime_error("Can't set callback"); throw std::runtime_error("Can't set callback");
} }
nl80211_id_ = genl_ctrl_resolve(sk_, "nl80211"); nl80211_id_ = genl_ctrl_resolve(sock_, "nl80211");
if (nl80211_id_ < 0) { if (nl80211_id_ < 0) {
throw std::runtime_error("Can't resolve nl80211 interface"); throw std::runtime_error("Can't resolve nl80211 interface");
} }
@ -119,15 +119,13 @@ void waybar::modules::Network::worker() {
int ec = epoll_wait(efd_, events.data(), EPOLL_MAX, -1); int ec = epoll_wait(efd_, events.data(), EPOLL_MAX, -1);
if (ec > 0) { if (ec > 0) {
for (auto i = 0; i < ec; i++) { for (auto i = 0; i < ec; i++) {
if (events[i].data.fd == nl_socket_get_fd(info_sock_)) { if (events[i].data.fd == nl_socket_get_fd(ev_sock_)) {
nl_recvmsgs_default(info_sock_); nl_recvmsgs_default(ev_sock_);
} else { } else {
thread_.stop(); thread_.stop();
break; break;
} }
} }
} else if (ec == -1) {
thread_.stop();
} }
}; };
} }
@ -138,7 +136,7 @@ auto waybar::modules::Network::update() -> void {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString(); tooltip_format = config_["tooltip-format"].asString();
} }
if (ifid_ <= 0 || ipaddr_.empty()) { if (ifid_ <= 0 || !linked_) {
if (config_["format-disconnected"].isString()) { if (config_["format-disconnected"].isString()) {
default_format_ = config_["format-disconnected"].asString(); default_format_ = config_["format-disconnected"].asString();
} }
@ -156,6 +154,14 @@ auto waybar::modules::Network::update() -> void {
tooltip_format = config_["tooltip-format-ethernet"].asString(); tooltip_format = config_["tooltip-format-ethernet"].asString();
} }
connectiontype = "ethernet"; connectiontype = "ethernet";
} else if (ipaddr_.empty()) {
if (config_["format-linked"].isString()) {
default_format_ = config_["format-linked"].asString();
}
if (config_["tooltip-format-linked"].isString()) {
tooltip_format = config_["tooltip-format-linked"].asString();
}
connectiontype = "linked";
} else { } else {
if (config_["format-wifi"].isString()) { if (config_["format-wifi"].isString()) {
default_format_ = config_["format-wifi"].asString(); default_format_ = config_["format-wifi"].asString();
@ -179,6 +185,7 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("netmask", netmask_), fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_), fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_), fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype))); fmt::arg("icon", getIcon(signal_strength_, connectiontype)));
label_.set_markup(text); label_.set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
@ -191,6 +198,7 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("netmask", netmask_), fmt::arg("netmask", netmask_),
fmt::arg("ipaddr", ipaddr_), fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_), fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype))); fmt::arg("icon", getIcon(signal_strength_, connectiontype)));
label_.set_tooltip_text(tooltip_text); label_.set_tooltip_text(tooltip_text);
} else { } else {
@ -199,21 +207,6 @@ auto waybar::modules::Network::update() -> void {
} }
} }
void waybar::modules::Network::disconnected() {
essid_.clear();
signal_strength_dbm_ = 0;
signal_strength_ = 0;
ipaddr_.clear();
netmask_.clear();
cidr_ = 0;
if (!config_["interface"].isString()) {
ifname_.clear();
ifid_ = -1;
}
// Need to wait otherwise we'll have the same information
thread_.sleep_for(std::chrono::seconds(1));
}
// Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698 // Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698
int waybar::modules::Network::getExternalInterface() { int waybar::modules::Network::getExternalInterface() {
static const uint32_t route_buffer_size = 8192; static const uint32_t route_buffer_size = 8192;
@ -333,6 +326,7 @@ int waybar::modules::Network::getExternalInterface() {
} while (true); } while (true);
out: out:
last_ext_iface_ = ifidx;
return ifidx; return ifidx;
} }
@ -343,14 +337,23 @@ void waybar::modules::Network::getInterfaceAddress() {
netmask_.clear(); netmask_.clear();
cidr_ = 0; cidr_ = 0;
int success = getifaddrs(&ifaddr); int success = getifaddrs(&ifaddr);
if (success == 0) { if (success != 0) {
return;
}
ifa = ifaddr; ifa = ifaddr;
while (ifa != nullptr && ipaddr_.empty() && netmask_.empty()) { while (ifa != nullptr && ipaddr_.empty() && netmask_.empty()) {
if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_) { if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_ &&
if (strcmp(ifa->ifa_name, ifname_.c_str()) == 0) { ifa->ifa_name == ifname_) {
ipaddr_ = inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr); char ipaddr[INET6_ADDRSTRLEN];
netmask_ = inet_ntoa(((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr); ipaddr_ = inet_ntop(family_,
cidrRaw = ((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr; &reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr)->sin_addr,
ipaddr,
INET6_ADDRSTRLEN);
char netmask[INET6_ADDRSTRLEN];
auto net_addr = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask);
netmask_ = inet_ntop(family_, &net_addr->sin_addr, netmask, INET6_ADDRSTRLEN);
cidrRaw = net_addr->sin_addr.s_addr;
linked_ = ifa->ifa_flags & IFF_RUNNING;
unsigned int cidr = 0; unsigned int cidr = 0;
while (cidrRaw) { while (cidrRaw) {
cidr += cidrRaw & 1; cidr += cidrRaw & 1;
@ -358,20 +361,23 @@ void waybar::modules::Network::getInterfaceAddress() {
} }
cidr_ = cidr; cidr_ = cidr;
} }
}
ifa = ifa->ifa_next; ifa = ifa->ifa_next;
} }
freeifaddrs(ifaddr); freeifaddrs(ifaddr);
} }
}
int waybar::modules::Network::netlinkRequest(void *req, uint32_t reqlen, uint32_t groups) { int waybar::modules::Network::netlinkRequest(void *req, uint32_t reqlen, uint32_t groups) {
struct sockaddr_nl sa = {}; struct sockaddr_nl sa = {};
sa.nl_family = AF_NETLINK; sa.nl_family = AF_NETLINK;
sa.nl_groups = groups; sa.nl_groups = groups;
struct iovec iov = {req, reqlen}; struct iovec iov = {req, reqlen};
struct msghdr msg = {&sa, sizeof(sa), &iov, 1, nullptr, 0, 0}; struct msghdr msg = {
return sendmsg(nl_socket_get_fd(info_sock_), &msg, 0); .msg_name = &sa,
.msg_namelen = sizeof(sa),
.msg_iov = &iov,
.msg_iovlen = 1,
};
return sendmsg(nl_socket_get_fd(ev_sock_), &msg, 0);
} }
int waybar::modules::Network::netlinkResponse(void *resp, uint32_t resplen, uint32_t groups) { int waybar::modules::Network::netlinkResponse(void *resp, uint32_t resplen, uint32_t groups) {
@ -379,57 +385,126 @@ int waybar::modules::Network::netlinkResponse(void *resp, uint32_t resplen, uint
sa.nl_family = AF_NETLINK; sa.nl_family = AF_NETLINK;
sa.nl_groups = groups; sa.nl_groups = groups;
struct iovec iov = {resp, resplen}; struct iovec iov = {resp, resplen};
struct msghdr msg = {&sa, sizeof(sa), &iov, 1, nullptr, 0, 0}; struct msghdr msg = {
auto ret = recvmsg(nl_socket_get_fd(info_sock_), &msg, 0); .msg_name = &sa,
.msg_namelen = sizeof(sa),
.msg_iov = &iov,
.msg_iovlen = 1,
};
auto ret = recvmsg(nl_socket_get_fd(ev_sock_), &msg, 0);
if (msg.msg_flags & MSG_TRUNC) { if (msg.msg_flags & MSG_TRUNC) {
return -1; return -1;
} }
return ret; return ret;
} }
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { bool waybar::modules::Network::checkInterface(int if_index, std::string name) {
int ret = 0; if (config_["interface"].isString()) {
auto net = static_cast<waybar::modules::Network *>(data); return config_["interface"].asString() == name ||
bool need_update = false; wildcardMatch(config_["interface"].asString(), name);
for (nlmsghdr *nh = nlmsg_hdr(msg); NLMSG_OK(nh, ret); nh = NLMSG_NEXT(nh, ret)) {
if (nh->nlmsg_type == RTM_NEWADDR) {
need_update = true;
} }
if (nh->nlmsg_type < RTM_NEWADDR) { auto external_iface = getExternalInterface();
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh)); if (external_iface == -1) {
if (rtif->ifi_index == static_cast<int>(net->ifid_)) { // Try with lastest working external iface
need_update = true; return last_ext_iface_ == if_index;
if (!(rtif->ifi_flags & IFF_RUNNING)) {
net->disconnected();
net->dp.emit();
return NL_SKIP;
} }
return external_iface == if_index;
} }
int waybar::modules::Network::getPreferredIface() {
if (config_["interface"].isString()) {
ifid_ = if_nametoindex(config_["interface"].asCString());
if (ifid_ > 0) {
ifname_ = config_["interface"].asString();
return ifid_;
} else {
// Try with wildcard
struct ifaddrs *ifaddr, *ifa;
int success = getifaddrs(&ifaddr);
if (success != 0) {
return -1;
} }
if (need_update) break; ifa = ifaddr;
} ifid_ = -1;
if (net->ifid_ <= 0 && !net->config_["interface"].isString()) { while (ifa != nullptr) {
for (uint8_t i = 0; i < MAX_RETRY; i += 1) { if (wildcardMatch(config_["interface"].asString(), ifa->ifa_name)) {
net->ifid_ = net->getExternalInterface(); ifid_ = if_nametoindex(ifa->ifa_name);
if (net->ifid_ > 0) {
break; break;
} }
// Need to wait before get external interface ifa = ifa->ifa_next;
net->thread_.sleep_for(std::chrono::seconds(1));
} }
if (net->ifid_ > 0) { freeifaddrs(ifaddr);
return ifid_;
}
}
ifid_ = getExternalInterface();
if (ifid_ > 0) {
char ifname[IF_NAMESIZE]; char ifname[IF_NAMESIZE];
if_indextoname(net->ifid_, ifname); if_indextoname(ifid_, ifname);
ifname_ = ifname;
return ifid_;
}
return -1;
}
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
auto net = static_cast<waybar::modules::Network *>(data);
auto nh = nlmsg_hdr(msg);
std::lock_guard<std::mutex> lock(net->mutex_);
if (nh->nlmsg_type == RTM_NEWADDR) {
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
char ifname[IF_NAMESIZE];
if_indextoname(rtif->ifi_index, ifname);
// Auto detected network can also be assigned here
if (net->checkInterface(rtif->ifi_index, ifname) && net->ifid_ == -1) {
net->linked_ = true;
net->ifname_ = ifname; net->ifname_ = ifname;
need_update = true; net->ifid_ = rtif->ifi_index;
net->dp.emit();
} }
// Check for valid interface
if (rtif->ifi_index == static_cast<int>(net->ifid_)) {
// Get Iface and WIFI info
net->thread_timer_.wake_up();
net->getInterfaceAddress();
net->dp.emit();
} }
if (need_update) { } else if (nh->nlmsg_type == RTM_DELADDR) {
if (net->ifid_ > 0) { auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
net->getInfo(); // Check for valid interface
if (rtif->ifi_index == static_cast<int>(net->ifid_)) {
net->ipaddr_.clear();
net->netmask_.clear();
net->cidr_ = 0;
net->dp.emit();
}
} else if (nh->nlmsg_type < RTM_NEWADDR) {
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
char ifname[IF_NAMESIZE];
if_indextoname(rtif->ifi_index, ifname);
// Check for valid interface
if (net->checkInterface(rtif->ifi_index, ifname) && rtif->ifi_flags & IFF_RUNNING) {
net->linked_ = true;
net->ifname_ = ifname;
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;
// Check for a new interface and get info
auto new_iface = net->getPreferredIface();
if (new_iface != -1) {
net->thread_timer_.wake_up();
net->getInterfaceAddress();
} }
net->dp.emit(); net->dp.emit();
} }
}
return NL_SKIP; return NL_SKIP;
} }
@ -464,7 +539,7 @@ int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
} }
net->parseEssid(bss); net->parseEssid(bss);
net->parseSignal(bss); net->parseSignal(bss);
// TODO(someone): parse quality net->parseFreq(bss);
return NL_SKIP; return NL_SKIP;
} }
@ -504,6 +579,13 @@ void waybar::modules::Network::parseSignal(struct nlattr **bss) {
} }
} }
void waybar::modules::Network::parseFreq(struct nlattr **bss) {
if (bss[NL80211_BSS_FREQUENCY] != nullptr) {
// in MHz
frequency_ = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
}
}
bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) { bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
if (bss[NL80211_BSS_STATUS] == nullptr) { if (bss[NL80211_BSS_STATUS] == nullptr) {
return false; return false;
@ -520,7 +602,6 @@ bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
} }
auto waybar::modules::Network::getInfo() -> void { auto waybar::modules::Network::getInfo() -> void {
getInterfaceAddress();
struct nl_msg *nl_msg = nlmsg_alloc(); struct nl_msg *nl_msg = nlmsg_alloc();
if (nl_msg == nullptr) { if (nl_msg == nullptr) {
return; return;
@ -532,5 +613,44 @@ auto waybar::modules::Network::getInfo() -> void {
nlmsg_free(nl_msg); nlmsg_free(nl_msg);
return; return;
} }
nl_send_sync(sk_, nl_msg); nl_send_sync(sock_, nl_msg);
}
// https://gist.github.com/rressi/92af77630faf055934c723ce93ae2495
bool waybar::modules::Network::wildcardMatch(const std::string &pattern, const std::string &text) {
auto P = int(pattern.size());
auto T = int(text.size());
auto p = 0, fallback_p = -1;
auto t = 0, fallback_t = -1;
while (t < T) {
// Wildcard match:
if (p < P && pattern[p] == '*') {
fallback_p = p++; // starting point after failures
fallback_t = t; // starting point after failures
}
// Simple match:
else if (p < P && (pattern[p] == '?' || pattern[p] == text[t])) {
p++;
t++;
}
// Failure, fall back just after last matched '*':
else if (fallback_p >= 0) {
p = fallback_p + 1; // position just after last matched '*"
t = ++fallback_t; // re-try to match text from here
}
// There were no '*' before, so we fail here:
else {
return false;
}
}
// Consume all '*' at the end of pattern:
while (p < P && pattern[p] == '*') p++;
return p == P;
} }

View File

@ -39,7 +39,7 @@ waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value
// events are configured // events are configured
if (!config["on-scroll-up"].isString() && !config["on-scroll-down"].isString()) { if (!config["on-scroll-up"].isString() && !config["on-scroll-down"].isString()) {
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &Pulseaudio::handleScroll)); event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &Pulseaudio::handleVolume));
} }
} }
@ -71,15 +71,15 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data) {
} }
} }
bool waybar::modules::Pulseaudio::handleScroll(GdkEventScroll *e) { bool waybar::modules::Pulseaudio::handleVolume(GdkEventScroll *e) {
// Avoid concurrent scroll event // Avoid concurrent scroll event
bool direction_up = false;
uint16_t change = config_["scroll-step"].isUInt() ? config_["scroll-step"].asUInt() * 100 : 100;
pa_cvolume pa_volume = pa_volume_;
if (scrolling_) { if (scrolling_) {
return false; return false;
} }
bool direction_up = false;
double volume_tick = (double)PA_VOLUME_NORM / 100;
pa_volume_t change = volume_tick;
pa_cvolume pa_volume = pa_volume_;
scrolling_ = true; scrolling_ = true;
if (e->direction == GDK_SCROLL_UP) { if (e->direction == GDK_SCROLL_UP) {
direction_up = true; direction_up = true;
@ -98,6 +98,11 @@ bool waybar::modules::Pulseaudio::handleScroll(GdkEventScroll *e) {
} }
} }
// isDouble returns true for integers as well, just in case
if (config_["scroll-step"].isDouble()) {
change = round(config_["scroll-step"].asDouble() * volume_tick);
}
if (direction_up) { if (direction_up) {
if (volume_ + 1 < 100) { if (volume_ + 1 < 100) {
pa_cvolume_inc(&pa_volume, change); pa_cvolume_inc(&pa_volume, change);
@ -148,6 +153,7 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_
pa->volume_ = std::round(volume * 100.0F); pa->volume_ = std::round(volume * 100.0F);
pa->muted_ = i->mute != 0; pa->muted_ = i->mute != 0;
pa->desc_ = i->description; pa->desc_ = i->description;
pa->monitor_ = i->monitor_source_name;
pa->port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown"; pa->port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown";
pa->dp.emit(); pa->dp.emit();
} }
@ -192,7 +198,7 @@ auto waybar::modules::Pulseaudio::update() -> void {
label_.get_style_context()->add_class("muted"); label_.get_style_context()->add_class("muted");
} else { } else {
label_.get_style_context()->remove_class("muted"); label_.get_style_context()->remove_class("muted");
if (port_name_.find("a2dp_sink") != std::string::npos) { if (monitor_.find("a2dp_sink") != std::string::npos) {
format = format =
config_["format-bluetooth"].isString() ? config_["format-bluetooth"].asString() : format; config_["format-bluetooth"].isString() ? config_["format-bluetooth"].asString() : format;
label_.get_style_context()->add_class("bluetooth"); label_.get_style_context()->add_class("bluetooth");

View File

@ -130,8 +130,13 @@ std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::st
void Host::addRegisteredItem(std::string service) { void Host::addRegisteredItem(std::string service) {
auto [bus_name, object_path] = getBusNameAndObjectPath(service); auto [bus_name, object_path] = getBusNameAndObjectPath(service);
auto it = std::find_if(items_.begin(), items_.end(), [&bus_name, &object_path](const auto& item) {
return bus_name == item->bus_name && object_path == item->object_path;
});
if (it == items_.end()) {
items_.emplace_back(new Item(bus_name, object_path, config_)); items_.emplace_back(new Item(bus_name, object_path, config_));
on_add_(items_.back()); on_add_(items_.back());
} }
} }
} // namespace waybar::modules::SNI

View File

@ -276,14 +276,15 @@ Glib::RefPtr<Gdk::Pixbuf> Item::getIconByName(const std::string& name, int reque
name.c_str(), tmp_size, Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE); name.c_str(), tmp_size, Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
} }
void Item::onMenuDestroyed(Item* self) { void Item::onMenuDestroyed(Item* self, GObject* old_menu_pointer) {
if (old_menu_pointer == reinterpret_cast<GObject*>(self->dbus_menu)) {
self->gtk_menu = nullptr; self->gtk_menu = nullptr;
self->dbus_menu = nullptr; self->dbus_menu = nullptr;
} }
}
bool Item::makeMenu(GdkEventButton* const& ev) { void Item::makeMenu(GdkEventButton* const& ev) {
if (gtk_menu == nullptr) { if (gtk_menu == nullptr && !menu.empty()) {
if (!menu.empty()) {
dbus_menu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data()); dbus_menu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
if (dbus_menu != nullptr) { if (dbus_menu != nullptr) {
g_object_ref_sink(G_OBJECT(dbus_menu)); g_object_ref_sink(G_OBJECT(dbus_menu));
@ -293,6 +294,12 @@ bool Item::makeMenu(GdkEventButton* const& ev) {
} }
} }
} }
bool Item::handleClick(GdkEventButton* const& ev) {
auto parameters = Glib::VariantContainerBase::create_tuple(
{Glib::Variant<int>::create(ev->x), Glib::Variant<int>::create(ev->y)});
if ((ev->button == 1 && item_is_menu) || ev->button == 3) {
makeMenu(ev);
if (gtk_menu != nullptr) { if (gtk_menu != nullptr) {
#if GTK_CHECK_VERSION(3, 22, 0) #if GTK_CHECK_VERSION(3, 22, 0)
gtk_menu->popup_at_pointer(reinterpret_cast<GdkEvent*>(ev)); gtk_menu->popup_at_pointer(reinterpret_cast<GdkEvent*>(ev));
@ -300,15 +307,7 @@ bool Item::makeMenu(GdkEventButton* const& ev) {
gtk_menu->popup(ev->button, ev->time); gtk_menu->popup(ev->button, ev->time);
#endif #endif
return true; return true;
} } else {
return false;
}
bool Item::handleClick(GdkEventButton* const& ev) {
auto parameters = Glib::VariantContainerBase::create_tuple(
{Glib::Variant<int>::create(ev->x), Glib::Variant<int>::create(ev->y)});
if ((ev->button == 1 && item_is_menu) || ev->button == 3) {
if (!makeMenu(ev)) {
proxy_->call("ContextMenu", parameters); proxy_->call("ContextMenu", parameters);
return true; return true;
} }

View File

@ -14,11 +14,6 @@ Watcher::Watcher()
watcher_(sn_watcher_skeleton_new()) {} watcher_(sn_watcher_skeleton_new()) {}
Watcher::~Watcher() { Watcher::~Watcher() {
if (bus_name_id_ != 0) {
Gio::DBus::unown_name(bus_name_id_);
bus_name_id_ = 0;
}
if (hosts_ != nullptr) { if (hosts_ != nullptr) {
g_slist_free_full(hosts_, gfWatchFree); g_slist_free_full(hosts_, gfWatchFree);
hosts_ = nullptr; hosts_ = nullptr;
@ -28,7 +23,8 @@ Watcher::~Watcher() {
g_slist_free_full(items_, gfWatchFree); g_slist_free_full(items_, gfWatchFree);
items_ = nullptr; items_ = nullptr;
} }
g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(watcher_)); auto iface = G_DBUS_INTERFACE_SKELETON(watcher_);
g_dbus_interface_skeleton_unexport(iface);
} }
void Watcher::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name) { void Watcher::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name) {

View File

@ -25,16 +25,23 @@ void Window::onEvent(const struct Ipc::ipc_response& res) { getTree(); }
void Window::onCmd(const struct Ipc::ipc_response& res) { void Window::onCmd(const struct Ipc::ipc_response& res) {
try { try {
std::lock_guard<std::mutex> lock(mutex_);
auto payload = parser_.parse(res.payload); auto payload = parser_.parse(res.payload);
auto [nb, id, name, app_id] = getFocusedNode(payload); auto [nb, id, name, app_id] = getFocusedNode(payload);
if (!app_id_.empty()) { if (!app_id_.empty()) {
bar_.window.get_style_context()->remove_class(app_id_); bar_.window.get_style_context()->remove_class(app_id_);
} }
if (nb == 0) { if (nb == 0) {
bar_.window.get_style_context()->remove_class("solo");
if (!bar_.window.get_style_context()->has_class("empty")) {
bar_.window.get_style_context()->add_class("empty"); bar_.window.get_style_context()->add_class("empty");
}
} else if (nb == 1) { } else if (nb == 1) {
bar_.window.get_style_context()->remove_class("empty");
if (!bar_.window.get_style_context()->has_class("solo")) {
bar_.window.get_style_context()->add_class("solo"); bar_.window.get_style_context()->add_class("solo");
if (!app_id.empty()) { }
if (!app_id.empty() && !bar_.window.get_style_context()->has_class(app_id)) {
bar_.window.get_style_context()->add_class(app_id); bar_.window.get_style_context()->add_class(app_id);
} }
} else { } else {

View File

@ -15,11 +15,22 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent)); ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent));
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Workspaces::onCmd)); ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Workspaces::onCmd));
ipc_.sendCmd(IPC_GET_WORKSPACES); ipc_.sendCmd(IPC_GET_WORKSPACES);
if (!config["disable-bar-scroll"].asBool()) {
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));
}
// Launch worker // Launch worker
worker(); worker();
} }
void Workspaces::onEvent(const struct Ipc::ipc_response &res) { ipc_.sendCmd(IPC_GET_WORKSPACES); } 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;
}
}
void Workspaces::onCmd(const struct Ipc::ipc_response &res) { void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
if (res.type == IPC_GET_WORKSPACES) { if (res.type == IPC_GET_WORKSPACES) {
@ -194,7 +205,11 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
return false; return false;
} }
} }
try {
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name)); ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name));
} catch (const std::exception &e) {
std::cerr << "Workspaces: " << e.what() << std::endl;
}
return true; return true;
} }
@ -208,7 +223,7 @@ const std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterat
else if (!prev && it != workspaces_.end()) else if (!prev && it != workspaces_.end())
++it; ++it;
if (!prev && it == workspaces_.end()) { if (!prev && it == workspaces_.end()) {
return (*(++workspaces_.begin()))["name"].asString(); return (*(workspaces_.begin()))["name"].asString();
} }
return (*it)["name"].asString(); return (*it)["name"].asString();
} }

View File

@ -8,11 +8,8 @@ waybar::modules::Temperature::Temperature(const std::string& id, const Json::Val
auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0; auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0;
file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone); file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);
} }
#ifdef FILESYSTEM_EXPERIMENTAL std::ifstream temp(file_path_);
if (!std::experimental::filesystem::exists(file_path_)) { if (!temp.is_open()) {
#else
if (!std::filesystem::exists(file_path_)) {
#endif
throw std::runtime_error("Can't open " + file_path_); throw std::runtime_error("Can't open " + file_path_);
} }
label_.set_name("temperature"); label_.set_name("temperature");
@ -35,8 +32,11 @@ auto waybar::modules::Temperature::update() -> void {
} else { } else {
label_.get_style_context()->remove_class("critical"); label_.get_style_context()->remove_class("critical");
} }
label_.set_markup(fmt::format( auto max_temp = config_["critical-threshold"].isInt() ? config_["critical-threshold"].asInt() : 0;
format, fmt::arg("temperatureC", temperature_c), fmt::arg("temperatureF", temperature_f))); label_.set_markup(fmt::format(format,
fmt::arg("temperatureC", temperature_c),
fmt::arg("temperatureF", temperature_f),
fmt::arg("icon", getIcon(temperature_c, "", max_temp))));
} }
std::tuple<uint16_t, uint16_t> waybar::modules::Temperature::getTemperature() { std::tuple<uint16_t, uint16_t> waybar::modules::Temperature::getTemperature() {