diff --git a/include/factory.hpp b/include/factory.hpp index 3855ce2..3954dac 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -42,6 +42,9 @@ #ifdef HAVE_LIBEVDEV #include "modules/keyboard_state.hpp" #endif +#ifdef HAVE_UPOWER +#include "modules/upower/upower.hpp" +#endif #ifdef HAVE_LIBPULSE #include "modules/pulseaudio.hpp" #endif diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp new file mode 100644 index 0000000..ede6d7f --- /dev/null +++ b/include/modules/upower/upower.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "ALabel.hpp" +#include "gtkmm/box.h" +#include "gtkmm/image.h" +#include "gtkmm/label.h" + +namespace waybar::modules { + +class UPower : public AModule { + public: + UPower(const std::string &, const Json::Value &); + ~UPower(); + auto update() -> void; + + private: + static void deviceAdded_cb(UpClient *client, UpDevice *device, gpointer data); + static void deviceRemoved_cb(UpClient *client, const gchar *object_path, gpointer data); + static void deviceNotify_cb(gpointer data); + void removeDevice(const std::string devicePath); + void addDevice(UpDevice *device); + void setDisplayDevice(); + void resetDevices(); + static void clicked(); + + Gtk::Box box_; + Gtk::Image icon_; + Gtk::Label label_; + + UpClient *client = NULL; + UpDevice *displayDevice = NULL; + std::map devices; +}; + +} // namespace waybar::modules diff --git a/meson.build b/meson.build index dcc6187..d34ce95 100644 --- a/meson.build +++ b/meson.build @@ -92,6 +92,7 @@ sigcpp = dependency('sigc++-2.0') libepoll = dependency('epoll-shim', required: false) libnl = dependency('libnl-3.0', required: get_option('libnl')) libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl')) +upower_glib = dependency('upower-glib', required: get_option('upower_glib')) libpulse = dependency('libpulse', required: get_option('pulseaudio')) libudev = dependency('libudev', required: get_option('libudev')) libevdev = dependency('libevdev', required: get_option('libevdev')) @@ -203,6 +204,11 @@ if libnl.found() and libnlgen.found() src_files += 'src/modules/network.cpp' endif +if upower_glib.found() + add_project_arguments('-DHAVE_UPOWER', language: 'cpp') + src_files += 'src/modules/upower/upower.cpp' +endif + if libpulse.found() add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp') src_files += 'src/modules/pulseaudio.cpp' @@ -288,6 +294,7 @@ executable( giounix, libnl, libnlgen, + upower_glib, libpulse, libudev, libepoll, @@ -296,7 +303,7 @@ executable( gtk_layer_shell, libsndio, tz_dep, - xkbregistry + xkbregistry ], include_directories: [include_directories('include')], install: true, diff --git a/meson_options.txt b/meson_options.txt index 230a53d..d2e9847 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,6 +3,7 @@ option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl suppo option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev support for udev related features') option('libevdev', type: 'feature', value: 'auto', description: 'Enable libevdev support for evdev related features') option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio') +option('upower_glib', type: 'feature', value: 'auto', description: 'Enable support for upower') option('systemd', type: 'feature', value: 'auto', description: 'Install systemd user service unit') option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') diff --git a/src/factory.cpp b/src/factory.cpp index 900653b..a866c37 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -12,6 +12,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { return new waybar::modules::Battery(id, config_[name]); } #endif +#ifdef HAVE_UPOWER + if (ref == "upower") { + return new waybar::modules::UPower(id, config_[name]); + } +#endif #ifdef HAVE_SWAY if (ref == "sway/mode") { return new waybar::modules::sway::Mode(id, config_[name]); diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp new file mode 100644 index 0000000..c455c52 --- /dev/null +++ b/src/modules/upower/upower.cpp @@ -0,0 +1,126 @@ +#include "modules/upower/upower.hpp" + +#include +#include +#include + +namespace waybar::modules { +UPower::UPower(const std::string& id, const Json::Value& config) + : AModule(config, "tray", id), + box_(Gtk::ORIENTATION_HORIZONTAL, 0), + icon_(), + label_(), + devices() { + box_.pack_start(icon_); + box_.pack_start(label_); + event_box_.add(box_); + + GError* error = NULL; + client = up_client_new_full(NULL, &error); + if (client == NULL) { + throw std::runtime_error("Unable to create UPower client!"); + } + + g_signal_connect(client, "device-added", G_CALLBACK(deviceAdded_cb), this); + g_signal_connect(client, "device-removed", G_CALLBACK(deviceRemoved_cb), this); + g_signal_connect(client, "notify", G_CALLBACK(deviceNotify_cb), this); + + resetDevices(); + + dp.emit(); +} + +UPower::~UPower() {} + +void UPower::clicked() { printf("CLICK\n"); } + +void UPower::deviceAdded_cb(UpClient* client, UpDevice* device, gpointer data) { + UPower* up = static_cast(data); + up->addDevice(device); + up->setDisplayDevice(); + // Update the widget + up->dp.emit(); +} +void UPower::deviceRemoved_cb(UpClient* client, const gchar* object_path, gpointer data) { + UPower* up = static_cast(data); + up->removeDevice(object_path); + up->setDisplayDevice(); + // Update the widget + up->dp.emit(); +} +void UPower::deviceNotify_cb(gpointer data) { + UPower* up = static_cast(data); + // Update the widget + up->dp.emit(); +} + +void UPower::removeDevice(const std::string devicePath) { devices.erase(devicePath); } + +void UPower::addDevice(UpDevice* device) { + if (device) { + const gchar* objectPath = up_device_get_object_path(device); + devices[objectPath] = device; + g_signal_connect(devices[objectPath], "notify", G_CALLBACK(deviceNotify_cb), this); + } +} + +void UPower::setDisplayDevice() { + displayDevice = up_client_get_display_device(client); + g_signal_connect(displayDevice, "notify", G_CALLBACK(deviceNotify_cb), this); +} + +/** Removes all devices and adds the current devices */ +void UPower::resetDevices() { + // Removes all devices + if (devices.size() > 0) { + auto it = devices.cbegin(); + while (it != devices.cend()) { + devices.erase(it++); + } + } + + // Adds all devices + GPtrArray* newDevices = up_client_get_devices2(client); + for (guint i = 0; i < newDevices->len; i++) { + UpDevice* device = (UpDevice*)g_ptr_array_index(newDevices, i); + if (device) addDevice(device); + } + + setDisplayDevice(); + + // Update the widget + dp.emit(); +} + +auto UPower::update() -> void { + printf("UPDATE!\n"); + + UpDeviceKind kind; + UpDeviceState state; + double percentage; + gboolean is_power_supply; + gboolean is_present; + gchar* icon_name; + + g_object_get(displayDevice, + "kind", + &kind, + "state", + &state, + "is-present", + &is_present, + "power-supply", + &is_power_supply, + "percentage", + &percentage, + "icon-name", + &icon_name, + NULL); + + printf("ICON: %s\n", icon_name); + + // Call parent update + AModule::update(); +} + +} // namespace waybar::modules