Merge branch 'master' into amd_fix
commit
f743882baa
|
@ -8,6 +8,7 @@ env:
|
|||
- distro: archlinux
|
||||
- distro: opensuse
|
||||
- distro: fedora
|
||||
- distro: alpine
|
||||
|
||||
before_install:
|
||||
- docker pull alexays/waybar:${distro}
|
||||
|
|
|
@ -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
|
|
@ -13,7 +13,7 @@ class ALabel : public IModule {
|
|||
ALabel(const Json::Value &, const std::string &format, uint16_t interval = 0);
|
||||
virtual ~ALabel();
|
||||
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 &();
|
||||
|
||||
protected:
|
||||
|
@ -31,7 +31,7 @@ class ALabel : public IModule {
|
|||
|
||||
virtual bool handleToggle(GdkEventButton *const &ev);
|
||||
virtual bool handleScroll(GdkEventScroll *);
|
||||
virtual std::string getState(uint8_t value);
|
||||
virtual std::string getState(uint8_t value, bool lesser = false);
|
||||
|
||||
private:
|
||||
std::vector<int> pid_;
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include "modules/sway/window.hpp"
|
||||
#include "modules/sway/workspaces.hpp"
|
||||
#endif
|
||||
#ifndef NO_FILESYSTEM
|
||||
#include "modules/battery.hpp"
|
||||
#endif
|
||||
#include "modules/cpu.hpp"
|
||||
#include "modules/idle_inhibitor.hpp"
|
||||
#include "modules/memory.hpp"
|
||||
#ifdef HAVE_DBUSMENU
|
||||
#if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
|
||||
#include "modules/sni/tray.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_LIBNL
|
||||
|
|
|
@ -32,8 +32,8 @@ class Battery : public ALabel {
|
|||
|
||||
void getBatteries();
|
||||
void worker();
|
||||
const std::string getAdapterStatus(uint8_t capacity) const;
|
||||
const std::tuple<uint8_t, std::string> getInfos() const;
|
||||
const std::string getAdapterStatus(uint8_t capacity, uint32_t current_now) const;
|
||||
const std::tuple<uint8_t, uint32_t, std::string> getInfos() const;
|
||||
|
||||
util::SleeperThread thread_;
|
||||
util::SleeperThread thread_timer_;
|
||||
|
|
|
@ -28,7 +28,6 @@ class Network : public ALabel {
|
|||
static int handleScan(struct nl_msg*, void*);
|
||||
|
||||
void worker();
|
||||
void disconnected();
|
||||
void createInfoSocket();
|
||||
void createEventSocket();
|
||||
int getExternalInterface();
|
||||
|
@ -37,27 +36,35 @@ class Network : public ALabel {
|
|||
int netlinkResponse(void*, uint32_t, uint32_t groups = 0);
|
||||
void parseEssid(struct nlattr**);
|
||||
void parseSignal(struct nlattr**);
|
||||
void parseFreq(struct nlattr**);
|
||||
bool associatedOrJoined(struct nlattr**);
|
||||
bool checkInterface(int if_index, std::string name);
|
||||
int getPreferredIface();
|
||||
auto getInfo() -> void;
|
||||
bool wildcardMatch(const std::string& pattern, const std::string& text);
|
||||
|
||||
waybar::util::SleeperThread thread_;
|
||||
waybar::util::SleeperThread thread_timer_;
|
||||
int ifid_;
|
||||
int last_ext_iface_;
|
||||
sa_family_t family_;
|
||||
struct sockaddr_nl nladdr_ = {0};
|
||||
struct nl_sock* sk_ = nullptr;
|
||||
struct nl_sock* info_sock_ = nullptr;
|
||||
struct nl_sock* sock_ = nullptr;
|
||||
struct nl_sock* ev_sock_ = nullptr;
|
||||
int efd_;
|
||||
int ev_fd_;
|
||||
int nl80211_id_;
|
||||
std::mutex mutex_;
|
||||
|
||||
std::string essid_;
|
||||
std::string ifname_;
|
||||
std::string ipaddr_;
|
||||
std::string netmask_;
|
||||
int cidr_;
|
||||
bool linked_;
|
||||
int32_t signal_strength_dbm_;
|
||||
uint8_t signal_strength_;
|
||||
uint32_t frequency_;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
||||
|
|
|
@ -20,7 +20,7 @@ class Pulseaudio : public ALabel {
|
|||
static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*);
|
||||
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
|
||||
static void volumeModifyCb(pa_context*, int, void*);
|
||||
bool handleScroll(GdkEventScroll* e);
|
||||
bool handleVolume(GdkEventScroll* e);
|
||||
|
||||
const std::string getPortIcon() const;
|
||||
|
||||
|
@ -33,6 +33,7 @@ class Pulseaudio : public ALabel {
|
|||
bool muted_;
|
||||
std::string port_name_;
|
||||
std::string desc_;
|
||||
std::string monitor_;
|
||||
bool scrolling_;
|
||||
};
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class Item : public sigc::trackable {
|
|||
std::string menu;
|
||||
DbusmenuGtkMenu* dbus_menu = nullptr;
|
||||
Gtk::Menu* gtk_menu = nullptr;
|
||||
bool item_is_menu;
|
||||
bool item_is_menu = false;
|
||||
|
||||
private:
|
||||
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
|
||||
|
@ -59,12 +59,12 @@ class Item : public sigc::trackable {
|
|||
void updateImage();
|
||||
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
|
||||
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
|
||||
static void onMenuDestroyed(Item* self);
|
||||
bool makeMenu(GdkEventButton* const& ev);
|
||||
static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
|
||||
void makeMenu(GdkEventButton* const& ev);
|
||||
bool handleClick(GdkEventButton* const& /*ev*/);
|
||||
|
||||
Glib::RefPtr<Gio::Cancellable> cancellable_;
|
||||
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
|
||||
Glib::RefPtr<Gio::Cancellable> cancellable_;
|
||||
bool update_pending_;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
class Mode : public ALabel {
|
||||
class Mode : public ALabel, public sigc::trackable {
|
||||
public:
|
||||
Mode(const std::string&, const Json::Value&);
|
||||
~Mode() = default;
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "modules/sway/ipc/client.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#include "util/json.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
class Window : public ALabel {
|
||||
class Window : public ALabel, public sigc::trackable {
|
||||
public:
|
||||
Window(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||
~Window() = default;
|
||||
|
@ -27,6 +27,7 @@ class Window : public ALabel {
|
|||
const Bar& bar_;
|
||||
waybar::util::SleeperThread thread_;
|
||||
Ipc ipc_;
|
||||
std::mutex mutex_;
|
||||
std::string window_;
|
||||
int windowId_;
|
||||
std::string app_id_;
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
#include "bar.hpp"
|
||||
#include "client.hpp"
|
||||
#include "modules/sway/ipc/client.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#include "util/json.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
|
||||
namespace waybar::modules::sway {
|
||||
|
||||
class Workspaces : public IModule {
|
||||
class Workspaces : public IModule, public sigc::trackable {
|
||||
public:
|
||||
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||
~Workspaces() = default;
|
||||
|
@ -27,10 +27,10 @@ class Workspaces : public IModule {
|
|||
Gtk::Button& addButton(const Json::Value&);
|
||||
void onButtonReady(const Json::Value&, Gtk::Button&);
|
||||
std::string getIcon(const std::string&, const Json::Value&);
|
||||
bool handleScroll(GdkEventScroll*);
|
||||
const std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
|
||||
uint16_t getWorkspaceIndex(const std::string& name) const;
|
||||
std::string trimWorkspaceName(std::string);
|
||||
bool handleScroll(GdkEventScroll*);
|
||||
|
||||
const Bar& bar_;
|
||||
const Json::Value& config_;
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
#include <fstream>
|
||||
#include "ALabel.hpp"
|
||||
#include "util/sleeper_thread.hpp"
|
||||
#ifdef FILESYSTEM_EXPERIMENTAL
|
||||
#include <experimental/filesystem>
|
||||
#else
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
namespace waybar::util {
|
||||
|
||||
struct JsonParser {
|
||||
JsonParser() : reader_(builder_.newCharReader()) {}
|
||||
JsonParser() {}
|
||||
|
||||
const Json::Value parse(const std::string& data) const {
|
||||
Json::Value root(Json::objectValue);
|
||||
if (data.empty()) {
|
||||
return root;
|
||||
}
|
||||
std::unique_ptr<Json::CharReader> const reader(builder_.newCharReader());
|
||||
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);
|
||||
return root;
|
||||
}
|
||||
|
@ -22,7 +23,6 @@ struct JsonParser {
|
|||
|
||||
private:
|
||||
Json::CharReaderBuilder builder_;
|
||||
std::unique_ptr<Json::CharReader> const reader_;
|
||||
};
|
||||
|
||||
} // namespace waybar::util
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
project(
|
||||
'waybar', 'cpp', 'c',
|
||||
version: '0.6.2',
|
||||
version: '0.6.4',
|
||||
license: 'MIT',
|
||||
default_options : [
|
||||
'cpp_std=c++17',
|
||||
|
@ -12,7 +12,7 @@ project(
|
|||
cpp_args = []
|
||||
cpp_link_args = []
|
||||
|
||||
if false # libc++
|
||||
if get_option('libcxx')
|
||||
cpp_args += ['-stdlib=libc++']
|
||||
cpp_link_args += ['-stdlib=libc++', '-lc++abi']
|
||||
|
||||
|
@ -34,7 +34,12 @@ else
|
|||
endif
|
||||
|
||||
if not compiler.has_header('filesystem')
|
||||
if compiler.has_header('experimental/filesystem')
|
||||
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
|
||||
|
||||
add_global_arguments(cpp_args, language : 'cpp')
|
||||
|
|
|
@ -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('libudev', type: 'feature', value: 'auto', description: 'Enable libudev support for udev related features')
|
||||
option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio')
|
||||
|
|
|
@ -78,8 +78,9 @@
|
|||
// "thermal-zone": 2,
|
||||
// "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
|
||||
"critical-threshold": 80,
|
||||
// "format-critical": "{temperatureC}°C ",
|
||||
"format": "{temperatureC}°C "
|
||||
// "format-critical": "{temperatureC}°C {icon}",
|
||||
"format": "{temperatureC}°C {icon}",
|
||||
"format-icons": ["", "", ""]
|
||||
},
|
||||
"backlight": {
|
||||
// "device": "acpi_video1",
|
||||
|
@ -93,6 +94,8 @@
|
|||
"critical": 15
|
||||
},
|
||||
"format": "{capacity}% {icon}",
|
||||
"format-charging": "{capacity}% ",
|
||||
"format-plugged": "{capacity}% ",
|
||||
// "format-good": "", // An empty format will hide the module
|
||||
// "format-full": "",
|
||||
"format-icons": ["", "", "", "", ""]
|
||||
|
@ -101,16 +104,17 @@
|
|||
"bat": "BAT2"
|
||||
},
|
||||
"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-ethernet": "{ifname}: {ipaddr}/{cidr} ",
|
||||
"format-ethernet": "{ifname}: {ipaddr}/{cidr} ",
|
||||
"format-linked": "{ifname} (No IP) ",
|
||||
"format-disconnected": "Disconnected ⚠"
|
||||
},
|
||||
"pulseaudio": {
|
||||
//"scroll-step": 1,
|
||||
// "scroll-step": 1, // %, can be a float
|
||||
"format": "{volume}% {icon}",
|
||||
"format-bluetooth": "{volume}% {icon}",
|
||||
"format-muted": "",
|
||||
"format-muted": "",
|
||||
"format-icons": {
|
||||
"headphones": "",
|
||||
"handsfree": "",
|
||||
|
@ -118,7 +122,7 @@
|
|||
"phone": "",
|
||||
"portable": "",
|
||||
"car": "",
|
||||
"default": ["", ""]
|
||||
"default": ["", "", ""]
|
||||
},
|
||||
"on-click": "pavucontrol"
|
||||
},
|
||||
|
|
|
@ -32,8 +32,7 @@ window#waybar.termite {
|
|||
}
|
||||
|
||||
window#waybar.chromium {
|
||||
background-color: #DEE1E6;
|
||||
color: #000000;
|
||||
background-color: #000000;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
@ -45,19 +44,11 @@ window#waybar.chromium {
|
|||
border-bottom: 3px solid transparent;
|
||||
}
|
||||
|
||||
window#waybar.chromium #workspaces button {
|
||||
color: #3F3F3F;
|
||||
}
|
||||
|
||||
#workspaces button.focused {
|
||||
background: #64727D;
|
||||
border-bottom: 3px solid #ffffff;
|
||||
}
|
||||
|
||||
window#waybar.chromium #workspaces button.focused {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#workspaces button.urgent {
|
||||
background-color: #eb4d4b;
|
||||
}
|
||||
|
@ -142,6 +133,7 @@ label:focus {
|
|||
#custom-media {
|
||||
background: #66cc99;
|
||||
color: #2a5c45;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.custom-spotify {
|
||||
|
|
|
@ -109,7 +109,7 @@ bool waybar::ALabel::handleScroll(GdkEventScroll* e) {
|
|||
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"];
|
||||
if (format_icons.isObject()) {
|
||||
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()) {
|
||||
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];
|
||||
}
|
||||
if (format_icons.isString()) {
|
||||
|
@ -129,7 +129,10 @@ std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt)
|
|||
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
|
||||
std::vector<std::pair<std::string, uint8_t>> states;
|
||||
if (config_["states"].isObject()) {
|
||||
|
@ -140,10 +143,12 @@ std::string waybar::ALabel::getState(uint8_t value) {
|
|||
}
|
||||
}
|
||||
// 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;
|
||||
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);
|
||||
valid_state = state.first;
|
||||
} else {
|
||||
|
|
|
@ -20,7 +20,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
|||
height_ = 0;
|
||||
width_ = 1;
|
||||
}
|
||||
window.set_size_request(width_, height_);
|
||||
|
||||
auto gtk_window = window.gobj();
|
||||
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 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;
|
||||
if (config["position"] == "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);
|
||||
|
||||
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) {
|
||||
|
|
|
@ -153,6 +153,7 @@ void waybar::Client::handleName(void * data, struct zxdg_output_v1 * /*xdg_
|
|||
wl_output_destroy(output->output);
|
||||
zxdg_output_v1_destroy(output->xdg_output);
|
||||
} else {
|
||||
wl_display_roundtrip(client->wl_display);
|
||||
for (const auto &config : configs) {
|
||||
client->bars.emplace_back(std::make_unique<Bar>(output.get(), config));
|
||||
Glib::RefPtr<Gdk::Screen> screen = client->bars.back()->window.get_screen();
|
||||
|
|
|
@ -7,9 +7,11 @@ waybar::IModule* waybar::Factory::makeModule(const std::string& name) const {
|
|||
auto hash_pos = name.find('#');
|
||||
auto ref = name.substr(0, hash_pos);
|
||||
auto id = hash_pos != std::string::npos ? name.substr(hash_pos + 1) : "";
|
||||
#ifndef NO_FILESYSTEM
|
||||
if (ref == "battery") {
|
||||
return new waybar::modules::Battery(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SWAY
|
||||
if (ref == "sway/mode") {
|
||||
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") {
|
||||
return new waybar::modules::Clock(id, config_[name]);
|
||||
}
|
||||
#ifdef HAVE_DBUSMENU
|
||||
#if defined(HAVE_DBUSMENU) && !defined(NO_FILESYSTEM)
|
||||
if (ref == "tray") {
|
||||
return new waybar::modules::SNI::Tray(id, bar_, config_[name]);
|
||||
}
|
||||
|
|
|
@ -47,21 +47,21 @@ void waybar::modules::Battery::worker() {
|
|||
|
||||
void waybar::modules::Battery::getBatteries() {
|
||||
try {
|
||||
for (auto const& node : fs::directory_iterator(data_dir_)) {
|
||||
for (auto& node : fs::directory_iterator(data_dir_)) {
|
||||
if (!fs::is_directory(node)) {
|
||||
continue;
|
||||
}
|
||||
auto dir_name = node.path().filename();
|
||||
auto bat_defined = config_["bat"].isString();
|
||||
if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) &&
|
||||
fs::exists(node / "capacity") && fs::exists(node / "uevent") &&
|
||||
fs::exists(node / "status")) {
|
||||
batteries_.push_back(node);
|
||||
fs::exists(node.path() / "capacity") && fs::exists(node.path() / "uevent") &&
|
||||
fs::exists(node.path() / "status")) {
|
||||
batteries_.push_back(node.path());
|
||||
}
|
||||
auto adap_defined = config_["adapter"].isString();
|
||||
if (((adap_defined && dir_name == config_["adapter"].asString()) || !adap_defined) &&
|
||||
fs::exists(node / "online")) {
|
||||
adapter_ = node;
|
||||
fs::exists(node.path() / "online")) {
|
||||
adapter_ = node.path();
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
uint16_t total = 0;
|
||||
uint32_t total_current = 0;
|
||||
std::string status = "Unknown";
|
||||
for (auto const& bat : batteries_) {
|
||||
uint16_t capacity;
|
||||
uint32_t current_now;
|
||||
std::string _status;
|
||||
std::ifstream(bat / "capacity") >> capacity;
|
||||
std::ifstream(bat / "status") >> _status;
|
||||
std::ifstream(bat / "current_now") >> current_now;
|
||||
if (_status != "Unknown") {
|
||||
status = _status;
|
||||
}
|
||||
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();
|
||||
return {capacity, status};
|
||||
return {capacity, total_current, status};
|
||||
} catch (const std::exception& e) {
|
||||
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()) {
|
||||
bool online;
|
||||
std::ifstream(adapter_ / "online") >> online;
|
||||
if (capacity == 100) {
|
||||
return "Full";
|
||||
}
|
||||
return online ? "Charging" : "Discharging";
|
||||
if (online) {
|
||||
return "Charging";
|
||||
}
|
||||
return "Discharging";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
auto waybar::modules::Battery::update() -> void {
|
||||
auto [capacity, status] = getInfos();
|
||||
auto [capacity, current_now, status] = getInfos();
|
||||
if (status == "Unknown") {
|
||||
status = getAdapterStatus(capacity);
|
||||
status = getAdapterStatus(capacity, current_now);
|
||||
}
|
||||
if (tooltipEnabled()) {
|
||||
label_.set_tooltip_text(status);
|
||||
}
|
||||
std::transform(status.begin(), status.end(), status.begin(), ::tolower);
|
||||
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()->add_class(status);
|
||||
old_status_ = status;
|
||||
if (!state.empty() && config_["format-" + status + "-" + state].isString()) {
|
||||
|
@ -134,7 +151,7 @@ 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))));
|
||||
label_.set_markup(fmt::format(
|
||||
format, fmt::arg("capacity", capacity), fmt::arg("icon", getIcon(capacity, state))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ std::thread waybar::modules::MPD::event_listener() {
|
|||
try {
|
||||
if (connection_ == nullptr) {
|
||||
// Retry periodically if no connection
|
||||
update();
|
||||
dp.emit();
|
||||
std::this_thread::sleep_for(interval_);
|
||||
} else {
|
||||
waitForEvent();
|
||||
|
|
|
@ -3,31 +3,27 @@
|
|||
|
||||
waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
|
||||
: ALabel(config, "{ifname}", 60),
|
||||
family_(AF_INET),
|
||||
ifid_(-1),
|
||||
last_ext_iface_(-1),
|
||||
family_(config["family"] == "ipv6" ? AF_INET6 : AF_INET),
|
||||
efd_(-1),
|
||||
ev_fd_(-1),
|
||||
cidr_(-1),
|
||||
signal_strength_dbm_(0),
|
||||
signal_strength_(0) {
|
||||
signal_strength_(0),
|
||||
frequency_(0) {
|
||||
label_.set_name("network");
|
||||
if (!id.empty()) {
|
||||
label_.get_style_context()->add_class(id);
|
||||
}
|
||||
createInfoSocket();
|
||||
createEventSocket();
|
||||
if (config_["interface"].isString()) {
|
||||
ifid_ = if_nametoindex(config_["interface"].asCString());
|
||||
ifname_ = config_["interface"].asString();
|
||||
if (ifid_ <= 0) {
|
||||
throw std::runtime_error("Can't found network interface");
|
||||
}
|
||||
} else {
|
||||
ifid_ = getExternalInterface();
|
||||
if (ifid_ > 0) {
|
||||
auto default_iface = getPreferredIface();
|
||||
if (default_iface != -1) {
|
||||
char ifname[IF_NAMESIZE];
|
||||
if_indextoname(ifid_, ifname);
|
||||
if_indextoname(default_iface, ifname);
|
||||
ifname_ = ifname;
|
||||
}
|
||||
getInterfaceAddress();
|
||||
}
|
||||
dp.emit();
|
||||
worker();
|
||||
|
@ -42,39 +38,42 @@ waybar::modules::Network::~Network() {
|
|||
if (efd_ > -1) {
|
||||
close(efd_);
|
||||
}
|
||||
if (info_sock_ != nullptr) {
|
||||
nl_socket_drop_membership(info_sock_, RTMGRP_LINK);
|
||||
nl_socket_drop_membership(info_sock_, RTMGRP_IPV4_IFADDR);
|
||||
nl_close(info_sock_);
|
||||
nl_socket_free(info_sock_);
|
||||
if (ev_sock_ != nullptr) {
|
||||
nl_socket_drop_membership(ev_sock_, RTNLGRP_LINK);
|
||||
nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
|
||||
nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
|
||||
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) {
|
||||
nl_close(sk_);
|
||||
nl_socket_free(sk_);
|
||||
if (sock_ != nullptr) {
|
||||
nl_close(sock_);
|
||||
nl_socket_free(sock_);
|
||||
}
|
||||
}
|
||||
|
||||
void waybar::modules::Network::createInfoSocket() {
|
||||
info_sock_ = nl_socket_alloc();
|
||||
if (nl_connect(info_sock_, NETLINK_ROUTE) != 0) {
|
||||
ev_sock_ = nl_socket_alloc();
|
||||
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");
|
||||
}
|
||||
if (nl_socket_add_membership(info_sock_, RTMGRP_LINK) != 0) {
|
||||
throw std::runtime_error("Can't add membership");
|
||||
}
|
||||
if (nl_socket_add_membership(info_sock_, RTMGRP_IPV4_IFADDR) != 0) {
|
||||
throw std::runtime_error("Can't add membership");
|
||||
}
|
||||
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);
|
||||
nl_socket_add_membership(ev_sock_, RTNLGRP_LINK);
|
||||
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
|
||||
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
|
||||
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV4_ROUTE);
|
||||
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV6_ROUTE);
|
||||
efd_ = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (efd_ < 0) {
|
||||
throw std::runtime_error("Can't create epoll");
|
||||
}
|
||||
{
|
||||
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.data.fd = ev_fd_;
|
||||
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_);
|
||||
struct epoll_event event = {0};
|
||||
auto fd = nl_socket_get_fd(ev_sock_);
|
||||
struct epoll_event event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
|
||||
event.data.fd = fd;
|
||||
if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) {
|
||||
|
@ -93,14 +93,14 @@ void waybar::modules::Network::createInfoSocket() {
|
|||
}
|
||||
|
||||
void waybar::modules::Network::createEventSocket() {
|
||||
sk_ = nl_socket_alloc();
|
||||
if (genl_connect(sk_) != 0) {
|
||||
sock_ = nl_socket_alloc();
|
||||
if (genl_connect(sock_) != 0) {
|
||||
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");
|
||||
}
|
||||
nl80211_id_ = genl_ctrl_resolve(sk_, "nl80211");
|
||||
nl80211_id_ = genl_ctrl_resolve(sock_, "nl80211");
|
||||
if (nl80211_id_ < 0) {
|
||||
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);
|
||||
if (ec > 0) {
|
||||
for (auto i = 0; i < ec; i++) {
|
||||
if (events[i].data.fd == nl_socket_get_fd(info_sock_)) {
|
||||
nl_recvmsgs_default(info_sock_);
|
||||
if (events[i].data.fd == nl_socket_get_fd(ev_sock_)) {
|
||||
nl_recvmsgs_default(ev_sock_);
|
||||
} else {
|
||||
thread_.stop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (ec == -1) {
|
||||
thread_.stop();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -138,7 +136,7 @@ auto waybar::modules::Network::update() -> void {
|
|||
if (config_["tooltip-format"].isString()) {
|
||||
tooltip_format = config_["tooltip-format"].asString();
|
||||
}
|
||||
if (ifid_ <= 0 || ipaddr_.empty()) {
|
||||
if (ifid_ <= 0 || !linked_) {
|
||||
if (config_["format-disconnected"].isString()) {
|
||||
default_format_ = config_["format-disconnected"].asString();
|
||||
}
|
||||
|
@ -156,6 +154,14 @@ auto waybar::modules::Network::update() -> void {
|
|||
tooltip_format = config_["tooltip-format-ethernet"].asString();
|
||||
}
|
||||
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 {
|
||||
if (config_["format-wifi"].isString()) {
|
||||
default_format_ = config_["format-wifi"].asString();
|
||||
|
@ -179,6 +185,7 @@ auto waybar::modules::Network::update() -> void {
|
|||
fmt::arg("netmask", netmask_),
|
||||
fmt::arg("ipaddr", ipaddr_),
|
||||
fmt::arg("cidr", cidr_),
|
||||
fmt::arg("frequency", frequency_),
|
||||
fmt::arg("icon", getIcon(signal_strength_, connectiontype)));
|
||||
label_.set_markup(text);
|
||||
if (tooltipEnabled()) {
|
||||
|
@ -191,6 +198,7 @@ auto waybar::modules::Network::update() -> void {
|
|||
fmt::arg("netmask", netmask_),
|
||||
fmt::arg("ipaddr", ipaddr_),
|
||||
fmt::arg("cidr", cidr_),
|
||||
fmt::arg("frequency", frequency_),
|
||||
fmt::arg("icon", getIcon(signal_strength_, connectiontype)));
|
||||
label_.set_tooltip_text(tooltip_text);
|
||||
} 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
|
||||
int waybar::modules::Network::getExternalInterface() {
|
||||
static const uint32_t route_buffer_size = 8192;
|
||||
|
@ -333,6 +326,7 @@ int waybar::modules::Network::getExternalInterface() {
|
|||
} while (true);
|
||||
|
||||
out:
|
||||
last_ext_iface_ = ifidx;
|
||||
return ifidx;
|
||||
}
|
||||
|
||||
|
@ -343,14 +337,23 @@ void waybar::modules::Network::getInterfaceAddress() {
|
|||
netmask_.clear();
|
||||
cidr_ = 0;
|
||||
int success = getifaddrs(&ifaddr);
|
||||
if (success == 0) {
|
||||
if (success != 0) {
|
||||
return;
|
||||
}
|
||||
ifa = ifaddr;
|
||||
while (ifa != nullptr && ipaddr_.empty() && netmask_.empty()) {
|
||||
if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_) {
|
||||
if (strcmp(ifa->ifa_name, ifname_.c_str()) == 0) {
|
||||
ipaddr_ = inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr);
|
||||
netmask_ = inet_ntoa(((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr);
|
||||
cidrRaw = ((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr;
|
||||
if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_ &&
|
||||
ifa->ifa_name == ifname_) {
|
||||
char ipaddr[INET6_ADDRSTRLEN];
|
||||
ipaddr_ = inet_ntop(family_,
|
||||
&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;
|
||||
while (cidrRaw) {
|
||||
cidr += cidrRaw & 1;
|
||||
|
@ -358,20 +361,23 @@ void waybar::modules::Network::getInterfaceAddress() {
|
|||
}
|
||||
cidr_ = cidr;
|
||||
}
|
||||
}
|
||||
ifa = ifa->ifa_next;
|
||||
}
|
||||
freeifaddrs(ifaddr);
|
||||
}
|
||||
}
|
||||
|
||||
int waybar::modules::Network::netlinkRequest(void *req, uint32_t reqlen, uint32_t groups) {
|
||||
struct sockaddr_nl sa = {};
|
||||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_groups = groups;
|
||||
struct iovec iov = {req, reqlen};
|
||||
struct msghdr msg = {&sa, sizeof(sa), &iov, 1, nullptr, 0, 0};
|
||||
return sendmsg(nl_socket_get_fd(info_sock_), &msg, 0);
|
||||
struct msghdr msg = {
|
||||
.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) {
|
||||
|
@ -379,57 +385,126 @@ int waybar::modules::Network::netlinkResponse(void *resp, uint32_t resplen, uint
|
|||
sa.nl_family = AF_NETLINK;
|
||||
sa.nl_groups = groups;
|
||||
struct iovec iov = {resp, resplen};
|
||||
struct msghdr msg = {&sa, sizeof(sa), &iov, 1, nullptr, 0, 0};
|
||||
auto ret = recvmsg(nl_socket_get_fd(info_sock_), &msg, 0);
|
||||
struct msghdr msg = {
|
||||
.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) {
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
|
||||
int ret = 0;
|
||||
auto net = static_cast<waybar::modules::Network *>(data);
|
||||
bool need_update = false;
|
||||
for (nlmsghdr *nh = nlmsg_hdr(msg); NLMSG_OK(nh, ret); nh = NLMSG_NEXT(nh, ret)) {
|
||||
if (nh->nlmsg_type == RTM_NEWADDR) {
|
||||
need_update = true;
|
||||
bool waybar::modules::Network::checkInterface(int if_index, std::string name) {
|
||||
if (config_["interface"].isString()) {
|
||||
return config_["interface"].asString() == name ||
|
||||
wildcardMatch(config_["interface"].asString(), name);
|
||||
}
|
||||
if (nh->nlmsg_type < RTM_NEWADDR) {
|
||||
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
|
||||
if (rtif->ifi_index == static_cast<int>(net->ifid_)) {
|
||||
need_update = true;
|
||||
if (!(rtif->ifi_flags & IFF_RUNNING)) {
|
||||
net->disconnected();
|
||||
net->dp.emit();
|
||||
return NL_SKIP;
|
||||
auto external_iface = getExternalInterface();
|
||||
if (external_iface == -1) {
|
||||
// Try with lastest working external iface
|
||||
return last_ext_iface_ == if_index;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (net->ifid_ <= 0 && !net->config_["interface"].isString()) {
|
||||
for (uint8_t i = 0; i < MAX_RETRY; i += 1) {
|
||||
net->ifid_ = net->getExternalInterface();
|
||||
if (net->ifid_ > 0) {
|
||||
ifa = ifaddr;
|
||||
ifid_ = -1;
|
||||
while (ifa != nullptr) {
|
||||
if (wildcardMatch(config_["interface"].asString(), ifa->ifa_name)) {
|
||||
ifid_ = if_nametoindex(ifa->ifa_name);
|
||||
break;
|
||||
}
|
||||
// Need to wait before get external interface
|
||||
net->thread_.sleep_for(std::chrono::seconds(1));
|
||||
ifa = ifa->ifa_next;
|
||||
}
|
||||
if (net->ifid_ > 0) {
|
||||
freeifaddrs(ifaddr);
|
||||
return ifid_;
|
||||
}
|
||||
}
|
||||
ifid_ = getExternalInterface();
|
||||
if (ifid_ > 0) {
|
||||
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;
|
||||
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) {
|
||||
if (net->ifid_ > 0) {
|
||||
net->getInfo();
|
||||
} else if (nh->nlmsg_type == RTM_DELADDR) {
|
||||
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
|
@ -464,7 +539,7 @@ int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
|
|||
}
|
||||
net->parseEssid(bss);
|
||||
net->parseSignal(bss);
|
||||
// TODO(someone): parse quality
|
||||
net->parseFreq(bss);
|
||||
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) {
|
||||
if (bss[NL80211_BSS_STATUS] == nullptr) {
|
||||
return false;
|
||||
|
@ -520,7 +602,6 @@ bool waybar::modules::Network::associatedOrJoined(struct nlattr **bss) {
|
|||
}
|
||||
|
||||
auto waybar::modules::Network::getInfo() -> void {
|
||||
getInterfaceAddress();
|
||||
struct nl_msg *nl_msg = nlmsg_alloc();
|
||||
if (nl_msg == nullptr) {
|
||||
return;
|
||||
|
@ -532,5 +613,44 @@ auto waybar::modules::Network::getInfo() -> void {
|
|||
nlmsg_free(nl_msg);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value
|
|||
// events are configured
|
||||
if (!config["on-scroll-up"].isString() && !config["on-scroll-down"].isString()) {
|
||||
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
|
||||
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_) {
|
||||
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;
|
||||
if (e->direction == GDK_SCROLL_UP) {
|
||||
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 (volume_ + 1 < 100) {
|
||||
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->muted_ = i->mute != 0;
|
||||
pa->desc_ = i->description;
|
||||
pa->monitor_ = i->monitor_source_name;
|
||||
pa->port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown";
|
||||
pa->dp.emit();
|
||||
}
|
||||
|
@ -192,7 +198,7 @@ auto waybar::modules::Pulseaudio::update() -> void {
|
|||
label_.get_style_context()->add_class("muted");
|
||||
} else {
|
||||
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 =
|
||||
config_["format-bluetooth"].isString() ? config_["format-bluetooth"].asString() : format;
|
||||
label_.get_style_context()->add_class("bluetooth");
|
||||
|
|
|
@ -130,8 +130,13 @@ std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::st
|
|||
|
||||
void Host::addRegisteredItem(std::string 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_));
|
||||
on_add_(items_.back());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace waybar::modules::SNI
|
|
@ -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);
|
||||
}
|
||||
|
||||
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->dbus_menu = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Item::makeMenu(GdkEventButton* const& ev) {
|
||||
if (gtk_menu == nullptr) {
|
||||
if (!menu.empty()) {
|
||||
void Item::makeMenu(GdkEventButton* const& ev) {
|
||||
if (gtk_menu == nullptr && !menu.empty()) {
|
||||
dbus_menu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
|
||||
if (dbus_menu != nullptr) {
|
||||
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_CHECK_VERSION(3, 22, 0)
|
||||
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);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
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)) {
|
||||
} else {
|
||||
proxy_->call("ContextMenu", parameters);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -14,11 +14,6 @@ Watcher::Watcher()
|
|||
watcher_(sn_watcher_skeleton_new()) {}
|
||||
|
||||
Watcher::~Watcher() {
|
||||
if (bus_name_id_ != 0) {
|
||||
Gio::DBus::unown_name(bus_name_id_);
|
||||
bus_name_id_ = 0;
|
||||
}
|
||||
|
||||
if (hosts_ != nullptr) {
|
||||
g_slist_free_full(hosts_, gfWatchFree);
|
||||
hosts_ = nullptr;
|
||||
|
@ -28,7 +23,8 @@ Watcher::~Watcher() {
|
|||
g_slist_free_full(items_, gfWatchFree);
|
||||
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) {
|
||||
|
|
|
@ -25,16 +25,23 @@ void Window::onEvent(const struct Ipc::ipc_response& res) { getTree(); }
|
|||
|
||||
void Window::onCmd(const struct Ipc::ipc_response& res) {
|
||||
try {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto payload = parser_.parse(res.payload);
|
||||
auto [nb, id, name, app_id] = getFocusedNode(payload);
|
||||
if (!app_id_.empty()) {
|
||||
bar_.window.get_style_context()->remove_class(app_id_);
|
||||
}
|
||||
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");
|
||||
}
|
||||
} 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");
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -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_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;
|
||||
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||
window.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
|
||||
}
|
||||
// Launch 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) {
|
||||
if (res.type == IPC_GET_WORKSPACES) {
|
||||
|
@ -194,7 +205,11 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name));
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Workspaces: " << e.what() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -208,7 +223,7 @@ const std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterat
|
|||
else if (!prev && it != workspaces_.end())
|
||||
++it;
|
||||
if (!prev && it == workspaces_.end()) {
|
||||
return (*(++workspaces_.begin()))["name"].asString();
|
||||
return (*(workspaces_.begin()))["name"].asString();
|
||||
}
|
||||
return (*it)["name"].asString();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone);
|
||||
}
|
||||
#ifdef FILESYSTEM_EXPERIMENTAL
|
||||
if (!std::experimental::filesystem::exists(file_path_)) {
|
||||
#else
|
||||
if (!std::filesystem::exists(file_path_)) {
|
||||
#endif
|
||||
std::ifstream temp(file_path_);
|
||||
if (!temp.is_open()) {
|
||||
throw std::runtime_error("Can't open " + file_path_);
|
||||
}
|
||||
label_.set_name("temperature");
|
||||
|
@ -35,8 +32,11 @@ auto waybar::modules::Temperature::update() -> void {
|
|||
} else {
|
||||
label_.get_style_context()->remove_class("critical");
|
||||
}
|
||||
label_.set_markup(fmt::format(
|
||||
format, fmt::arg("temperatureC", temperature_c), fmt::arg("temperatureF", temperature_f)));
|
||||
auto max_temp = config_["critical-threshold"].isInt() ? config_["critical-threshold"].asInt() : 0;
|
||||
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() {
|
||||
|
|
Loading…
Reference in New Issue