diff --git a/include/factory.hpp b/include/factory.hpp index 6521cbc9..0f770b97 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -73,6 +73,7 @@ #include "modules/jack.hpp" #endif #include "bar.hpp" +#include "modules/user.hpp" #include "modules/custom.hpp" #include "modules/temperature.hpp" diff --git a/include/modules/user.hpp b/include/modules/user.hpp new file mode 100644 index 00000000..41e7884e --- /dev/null +++ b/include/modules/user.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#include "AIconLabel.hpp" +#include "util/sleeper_thread.hpp" + +namespace waybar::modules { +class User : public AIconLabel { + public: + User(const std::string&, const Json::Value&); + ~User() = default; + auto update() -> void; + + private: + util::SleeperThread thread_; + + Glib::RefPtr pixbuf_; + + static constexpr inline int defaultUserImageWidth_ = 20; + static constexpr inline int defaultUserImageHeight_ = 20; + + long uptime_as_seconds(); + std::string get_user_login(); + std::string get_user_home_dir(); + std::string get_default_user_avatar_path(); + void init_default_user_avatar(int width, int height); + void init_user_avatar(const std::string& path, int width, int height); + void init_avatar(const Json::Value& config); + void init_update_worker(); +}; +} // namespace waybar::modules diff --git a/meson.build b/meson.build index ed72ffdc..aab5a492 100644 --- a/meson.build +++ b/meson.build @@ -150,6 +150,7 @@ src_files = files( 'src/modules/disk.cpp', 'src/modules/idle_inhibitor.cpp', 'src/modules/temperature.cpp', + 'src/modules/user.cpp', 'src/main.cpp', 'src/bar.cpp', 'src/client.cpp', diff --git a/src/factory.cpp b/src/factory.cpp index a4f25e2e..9b9dde89 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -84,6 +84,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "clock") { return new waybar::modules::Clock(id, config_[name]); } + if (ref == "user") { + return new waybar::modules::User(id, config_[name]); + } if (ref == "disk") { return new waybar::modules::Disk(id, config_[name]); } diff --git a/src/modules/user.cpp b/src/modules/user.cpp new file mode 100644 index 00000000..88da0a45 --- /dev/null +++ b/src/modules/user.cpp @@ -0,0 +1,114 @@ +#include "modules/user.hpp" + +#include +#include +#include + +#include +#include +#include + +#if HAVE_CPU_LINUX +#include +#endif + +#if HAVE_CPU_BSD +#include +#endif + +namespace waybar::modules { +User::User(const std::string& id, const Json::Value& config) + : AIconLabel(config, "user", id, "{user} {work_H}:{work_M}", 60, false, false, true) { + if (AIconLabel::iconEnabled()) { + this->init_avatar(AIconLabel::config_); + } + this->init_update_worker(); +} + +long User::uptime_as_seconds() { + long uptime = 0; + +#if HAVE_CPU_LINUX + struct sysinfo s_info; + if (0 == sysinfo(&s_info)) { + uptime = s_info.uptime; + } +#endif + +#if HAVE_CPU_BSD + struct timespec s_info; + if (0 == clock_gettime(CLOCK_UPTIME_PRECISE, &s_info)) { + uptime = s_info.tv_sec; + } +#endif + + return uptime; +} + +std::string User::get_user_login() { return Glib::get_user_name(); } + +std::string User::get_user_home_dir() { return Glib::get_home_dir(); } + +void User::init_update_worker() { + this->thread_ = [this] { + ALabel::dp.emit(); + auto now = std::chrono::system_clock::now(); + auto diff = now.time_since_epoch() % ALabel::interval_; + this->thread_.sleep_for(ALabel::interval_ - diff); + }; +} + +void User::init_avatar(const Json::Value& config) { + int height = + config["height"].isUInt() ? config["height"].asUInt() : this->defaultUserImageHeight_; + int width = config["width"].isUInt() ? config["width"].asUInt() : this->defaultUserImageWidth_; + + if (config["avatar"].isString()) { + std::string userAvatar = config["avatar"].asString(); + if (!userAvatar.empty()) { + this->init_user_avatar(userAvatar, width, height); + return; + } + } + + this->init_default_user_avatar(width, width); +} + +std::string User::get_default_user_avatar_path() { + return this->get_user_home_dir() + "/" + ".face"; +} + +void User::init_default_user_avatar(int width, int height) { + this->init_user_avatar(this->get_default_user_avatar_path(), width, height); +} + +void User::init_user_avatar(const std::string& path, int width, int height) { + this->pixbuf_ = Gdk::Pixbuf::create_from_file(path, width, height); + AIconLabel::image_.set(this->pixbuf_); +} + +auto User::update() -> void { + std::string systemUser = this->get_user_login(); + std::transform(systemUser.cbegin(), systemUser.cend(), systemUser.begin(), + [](unsigned char c) { return std::toupper(c); }); + + long uptimeSeconds = this->uptime_as_seconds(); + auto workSystemTimeSeconds = std::chrono::seconds(uptimeSeconds); + auto currentSystemTime = std::chrono::system_clock::now(); + auto startSystemTime = currentSystemTime - workSystemTimeSeconds; + long workSystemDays = uptimeSeconds / 86400; + + auto label = fmt::format(ALabel::format_, fmt::arg("up_H", fmt::format("{:%H}", startSystemTime)), + fmt::arg("up_M", fmt::format("{:%M}", startSystemTime)), + fmt::arg("up_d", fmt::format("{:%d}", startSystemTime)), + fmt::arg("up_m", fmt::format("{:%m}", startSystemTime)), + fmt::arg("up_Y", fmt::format("{:%Y}", startSystemTime)), + fmt::arg("work_d", workSystemDays), + fmt::arg("work_H", fmt::format("{:%H}", workSystemTimeSeconds)), + fmt::arg("work_M", fmt::format("{:%M}", workSystemTimeSeconds)), + fmt::arg("work_S", fmt::format("{:%S}", workSystemTimeSeconds)), + fmt::arg("user", systemUser)); + ALabel::label_.set_markup(label); + ALabel::update(); +} +}; // namespace waybar::modules