diff --git a/include/ALabel.hpp b/include/ALabel.hpp index 433d5a67..d8e0f882 100644 --- a/include/ALabel.hpp +++ b/include/ALabel.hpp @@ -11,7 +11,7 @@ namespace waybar { class ALabel : public IModule { public: ALabel(const Json::Value &, const std::string format, uint16_t interval = 0); - virtual ~ALabel() = default; + virtual ~ALabel(); virtual auto update() -> void; virtual std::string getIcon(uint16_t, const std::string &alt = ""); virtual operator Gtk::Widget &(); @@ -30,6 +30,9 @@ class ALabel : public IModule { virtual bool handleToggle(GdkEventButton *const &ev); virtual bool handleScroll(GdkEventScroll *); + + private: + std::vector pid_; }; } // namespace waybar diff --git a/include/modules/custom.hpp b/include/modules/custom.hpp index 7f4c50d7..42663fd5 100644 --- a/include/modules/custom.hpp +++ b/include/modules/custom.hpp @@ -33,6 +33,7 @@ class Custom : public ALabel { waybar::util::command::res output_; waybar::util::JsonParser parser_; FILE* fp_; + int pid_; }; } // namespace waybar::modules diff --git a/include/modules/idle_inhibitor.hpp b/include/modules/idle_inhibitor.hpp index 83b13e62..5ce324da 100644 --- a/include/modules/idle_inhibitor.hpp +++ b/include/modules/idle_inhibitor.hpp @@ -19,6 +19,7 @@ class IdleInhibitor : public ALabel { const Bar& bar_; std::string status_; struct zwp_idle_inhibitor_v1* idle_inhibitor_; + int pid_; }; } // namespace waybar::modules diff --git a/include/util/command.hpp b/include/util/command.hpp index 873c7752..aa3271f9 100644 --- a/include/util/command.hpp +++ b/include/util/command.hpp @@ -11,12 +11,7 @@ struct res { std::string out; }; -inline struct res exec(const std::string cmd) { - FILE* fp(popen(cmd.c_str(), "r")); - if (!fp) { - return {-1, ""}; - } - +inline std::string read(FILE* fp) { std::array buffer = {0}; std::string output; while (feof(fp) == 0) { @@ -29,24 +24,75 @@ inline struct res exec(const std::string cmd) { if (!output.empty() && output[output.length() - 1] == '\n') { output.erase(output.length() - 1); } - int exit_code = WEXITSTATUS(pclose(fp)); - return {exit_code, output}; + return output; } -inline bool forkExec(std::string cmd) { - if (cmd == "") return true; +inline int close(FILE* fp, pid_t pid) { + int stat; + + fclose(fp); + while (waitpid(pid, &stat, 0) == -1) { + if (errno != EINTR) { + stat = -1; + break; + } + } + + return stat; +} + +inline FILE* open(const std::string cmd, int& pid) { + if (cmd == "") return nullptr; + int fd[2]; + pipe(fd); + + pid_t child_pid = fork(); + + if (child_pid < 0) { + printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno)); + return nullptr; + } + + if (!child_pid) { + ::close(fd[0]); + dup2(fd[1], 1); + setpgid(child_pid, child_pid); + execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); + exit(0); + } else { + ::close(fd[1]); + } + pid = child_pid; + return fdopen(fd[0], "r"); +} + +inline struct res exec(std::string cmd) { + int pid; + auto fp = command::open(cmd, pid); + if (!fp) return {-1, ""}; + auto output = command::read(fp); + auto stat = command::close(fp, pid); + return {WEXITSTATUS(stat), output}; +} + +inline int32_t forkExec(std::string cmd) { + if (cmd == "") return -1; int32_t pid = fork(); if (pid < 0) { printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno)); - return false; + return pid; } // Child executes the command - if (!pid) execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); + if (!pid) { + setpgid(pid, pid); + execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); + exit(0); + } - return true; + return pid; } } // namespace waybar::util::command diff --git a/include/util/json.hpp b/include/util/json.hpp index 4ce3ca59..3f83172f 100644 --- a/include/util/json.hpp +++ b/include/util/json.hpp @@ -7,14 +7,13 @@ namespace waybar::util { struct JsonParser { JsonParser() : reader_(builder_.newCharReader()) {} - const Json::Value parse(const std::string& data, std::size_t size = 0) const { + const Json::Value parse(const std::string& data) const { Json::Value root(Json::objectValue); if (data.empty()) { return root; } std::string err; - auto data_size = size > 0 ? size : data.size(); - 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; } diff --git a/resources/config b/resources/config index b2d8cc01..9aa669f5 100644 --- a/resources/config +++ b/resources/config @@ -68,7 +68,8 @@ "format-alt": "{:%Y-%m-%d}" }, "cpu": { - "format": "{usage}% " + "format": "{usage}% ", + "tooltip": false }, "memory": { "format": "{}% " diff --git a/resources/style.css b/resources/style.css index c29569ad..a528f859 100644 --- a/resources/style.css +++ b/resources/style.css @@ -74,6 +74,10 @@ window#waybar.hidded { animation-direction: alternate; } +label:focus { + background-color: #000000; +} + #cpu { background: #2ecc71; color: #000000; diff --git a/src/ALabel.cpp b/src/ALabel.cpp index a2e711c7..f72a90fe 100644 --- a/src/ALabel.cpp +++ b/src/ALabel.cpp @@ -32,21 +32,29 @@ waybar::ALabel::ALabel(const Json::Value& config, const std::string format, uint } } +waybar::ALabel::~ALabel() { + for (const auto &pid : pid_) { + if (pid != -1) { + kill(-pid, 9); + } + } +} + auto waybar::ALabel::update() -> void { // Nothing here } bool waybar::ALabel::handleToggle(GdkEventButton* const& e) { if (config_["on-click"].isString() && e->button == 1) { - waybar::util::command::forkExec(config_["on-click"].asString()); + pid_.push_back(waybar::util::command::forkExec(config_["on-click"].asString())); } else if (config_["on-click-middle"].isString() && e->button == 2) { - waybar::util::command::forkExec(config_["on-click-middle"].asString()); + pid_.push_back(waybar::util::command::forkExec(config_["on-click-middle"].asString())); } else if (config_["on-click-right"].isString() && e->button == 3) { - waybar::util::command::forkExec(config_["on-click-right"].asString()); + pid_.push_back(waybar::util::command::forkExec(config_["on-click-right"].asString())); } else if (config_["on-click-forward"].isString() && e->button == 8) { - waybar::util::command::forkExec(config_["on-click-backward"].asString()); + pid_.push_back(waybar::util::command::forkExec(config_["on-click-backward"].asString())); } else if (config_["on-click-backward"].isString() && e->button == 9) { - waybar::util::command::forkExec(config_["on-click-forward"].asString()); + pid_.push_back(waybar::util::command::forkExec(config_["on-click-forward"].asString())); } if (config_["format-alt-click"].isUInt() && e->button == config_["format-alt-click"].asUInt()) { alt_ = !alt_; @@ -82,9 +90,9 @@ bool waybar::ALabel::handleScroll(GdkEventScroll* e) { } } if (direction_up && config_["on-scroll-up"].isString()) { - waybar::util::command::forkExec(config_["on-scroll-up"].asString()); + pid_.push_back(waybar::util::command::forkExec(config_["on-scroll-up"].asString())); } else if (config_["on-scroll-down"].isString()) { - waybar::util::command::forkExec(config_["on-scroll-down"].asString()); + pid_.push_back(waybar::util::command::forkExec(config_["on-scroll-down"].asString())); } dp.emit(); return true; diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp index 358db817..4dbb80ab 100644 --- a/src/modules/custom.cpp +++ b/src/modules/custom.cpp @@ -1,7 +1,7 @@ #include "modules/custom.hpp" waybar::modules::Custom::Custom(const std::string& name, const Json::Value& config) - : ALabel(config, "{}"), name_(name), fp_(nullptr) { + : ALabel(config, "{}"), name_(name), fp_(nullptr), pid_(-1) { label_.set_name("custom-" + name_); if (config_["exec"].isString()) { if (interval_.count() > 0) { @@ -14,9 +14,9 @@ waybar::modules::Custom::Custom(const std::string& name, const Json::Value& conf } waybar::modules::Custom::~Custom() { - if (fp_) { - pclose(fp_); - fp_ = nullptr; + if (pid_ != -1) { + kill(-pid_, 9); + pid_ = -1; } } @@ -40,17 +40,18 @@ void waybar::modules::Custom::delayWorker() { void waybar::modules::Custom::continuousWorker() { auto cmd = config_["exec"].asString(); - fp_ = popen(cmd.c_str(), "r"); + pid_ = -1; + fp_ = util::command::open(cmd, pid_); if (!fp_) { throw std::runtime_error("Unable to open " + cmd); } - thread_ = [this] { + thread_ = [&] { char* buff = nullptr; size_t len = 0; if (getline(&buff, &len, fp_) == -1) { int exit_code = 1; if (fp_) { - exit_code = WEXITSTATUS(pclose(fp_)); + exit_code = WEXITSTATUS(util::command::close(fp_, pid_)); fp_ = nullptr; } thread_.stop(); diff --git a/src/modules/idle_inhibitor.cpp b/src/modules/idle_inhibitor.cpp index 7840542f..8eeab619 100644 --- a/src/modules/idle_inhibitor.cpp +++ b/src/modules/idle_inhibitor.cpp @@ -3,7 +3,11 @@ waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar, const Json::Value& config) - : ALabel(config, "{status}"), bar_(bar), status_("deactivated"), idle_inhibitor_(nullptr) { + : ALabel(config, "{status}"), + bar_(bar), + status_("deactivated"), + idle_inhibitor_(nullptr), + pid_(-1) { label_.set_name("idle_inhibitor"); if (!id.empty()) { label_.get_style_context()->add_class(id); @@ -19,6 +23,10 @@ waybar::modules::IdleInhibitor::~IdleInhibitor() { zwp_idle_inhibitor_v1_destroy(idle_inhibitor_); idle_inhibitor_ = nullptr; } + if (pid_ != -1) { + kill(-pid_, 9); + pid_ = -1; + } } auto waybar::modules::IdleInhibitor::update() -> void { @@ -43,7 +51,7 @@ bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) { status_ = "activated"; } if (config_["on-click"].isString() && e->button == 1) { - waybar::util::command::forkExec(config_["on-click"].asString()); + pid_ = waybar::util::command::forkExec(config_["on-click"].asString()); } } else { ALabel::handleToggle(e); diff --git a/src/modules/sway/ipc/client.cpp b/src/modules/sway/ipc/client.cpp index de110b33..7c5db7c5 100644 --- a/src/modules/sway/ipc/client.cpp +++ b/src/modules/sway/ipc/client.cpp @@ -104,7 +104,7 @@ struct Ipc::ipc_response Ipc::recv(int fd) { } total += res; } - auto parsed = parser_.parse(&payload.front(), data32[0]); + auto parsed = parser_.parse(&payload.front()); return {data32[0], data32[1], parsed}; }