From d7d1ebd736ea0c7e464480ea6dee483598c5afad Mon Sep 17 00:00:00 2001 From: Harish Krupo Date: Mon, 29 Oct 2018 22:34:09 +0530 Subject: [PATCH] ALabel: Add support for configurable mouse events This patch adds 3 new configuration options applicable for subclasses of ALabel. The options can be used to execute user defined code in response to the 3 mouse events: * on-click: The left mouse button click * on-scroll-up * on-scroll-down This patch also modifies the behaviour of the format-alt toggle such that when the on-click event is configured, format-alt is toggled on any mouse click other than left click. When on-click is not defined, any mouse button would toggle format-alt. Signed-off-by: Harish Krupo --- include/ALabel.hpp | 39 ++++++++++------- include/util/command.hpp | 19 +++++++- src/ALabel.cpp | 93 +++++++++++++++++++++++++++++++++------- 3 files changed, 119 insertions(+), 32 deletions(-) diff --git a/include/ALabel.hpp b/include/ALabel.hpp index 4063171f..2baf0b10 100644 --- a/include/ALabel.hpp +++ b/include/ALabel.hpp @@ -6,21 +6,28 @@ namespace waybar { class ALabel : public IModule { - public: - ALabel(const Json::Value&, const std::string format); - virtual ~ALabel() = default; - virtual auto update() -> void; - virtual std::string getIcon(uint16_t, const std::string& alt = ""); - virtual operator Gtk::Widget &(); - protected: - Gtk::EventBox event_box_; - Gtk::Label label_; - const Json::Value& config_; - std::string format_; - private: - bool handleToggle(GdkEventButton* const& ev); - bool alt = false; - const std::string default_format_; + public: + ALabel(const Json::Value&, const std::string format); + virtual ~ALabel() = default; + virtual auto update() -> void; + virtual std::string getIcon(uint16_t, const std::string& alt = ""); + virtual operator Gtk::Widget&(); + + protected: + Gtk::EventBox event_box_; + Gtk::Label label_; + const Json::Value& config_; + std::string format_; + std::string button_press_cmd_ = ""; + std::string scroll_up_cmd_ = ""; + std::string scroll_down_cmd_ = ""; + std::mutex mutex_; + + private: + bool handleToggle(GdkEventButton* const& ev); + bool handleScroll(GdkEventScroll*); + bool alt = false; + const std::string default_format_; }; -} +} // namespace waybar diff --git a/include/util/command.hpp b/include/util/command.hpp index 18069580..8ff42bed 100644 --- a/include/util/command.hpp +++ b/include/util/command.hpp @@ -29,7 +29,24 @@ inline struct res exec(const std::string cmd) output.erase(output.length()-1); } int exit_code = WEXITSTATUS(pclose(fp)); - return { exit_code, output }; + return {exit_code, output}; } +inline bool forkExec(std::string cmd) { + if (cmd == "") return true; + + printf("fork exec command %s\n", cmd.c_str()); + int32_t pid = fork(); + + if (pid < 0) { + printf("Unable to exec cmd %s, error %s", cmd.c_str(), strerror(errno)); + return false; + } + + // Child executes the command + if (!pid) execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); + + return true; } + +} // namespace waybar::util::command diff --git a/src/ALabel.cpp b/src/ALabel.cpp index 70d17655..cb9448bf 100644 --- a/src/ALabel.cpp +++ b/src/ALabel.cpp @@ -1,4 +1,5 @@ #include "ALabel.hpp" +#include #include @@ -14,30 +15,94 @@ waybar::ALabel::ALabel(const Json::Value& config, const std::string format) } if (config_["format-alt"].isString()) { event_box_.add_events(Gdk::BUTTON_PRESS_MASK); - event_box_.signal_button_press_event() - .connect(sigc::mem_fun(*this, &ALabel::handleToggle)); + event_box_.signal_button_press_event().connect( + sigc::mem_fun(*this, &ALabel::handleToggle)); + } + + // configure events' user commands + if (config_["on-click"].isString()) { + std::string cmd = config_["on-click"].asString(); + event_box_.add_events(Gdk::BUTTON_PRESS_MASK); + event_box_.signal_button_press_event().connect( + sigc::mem_fun(*this, &ALabel::handleToggle)); + + button_press_cmd_ = cmd; + } + if (config_["on-scroll-up"].isString()) { + std::string cmd = config_["on-scroll-up"].asString(); + event_box_.add_events(Gdk::SCROLL_MASK); + event_box_.signal_scroll_event().connect( + sigc::mem_fun(*this, &ALabel::handleScroll)); + + scroll_up_cmd_ = cmd; + } + if (config_["on-scroll-down"].isString()) { + std::string cmd = config_["on-scroll-down"].asString(); + event_box_.add_events(Gdk::SCROLL_MASK); + event_box_.signal_scroll_event().connect( + sigc::mem_fun(*this, &ALabel::handleScroll)); + + scroll_down_cmd_ = cmd; } } -auto waybar::ALabel::update() -> void -{ +auto waybar::ALabel::update() -> void { // Nothing here } -bool waybar::ALabel::handleToggle(GdkEventButton* const& /*ev*/) -{ - alt = !alt; - if (alt) { - format_ = config_["format-alt"].asString(); +bool waybar::ALabel::handleToggle(GdkEventButton* const& e) { + if (button_press_cmd_ != "" && e->button == 1) { + waybar::util::command::forkExec(button_press_cmd_); } else { - format_ = default_format_; + alt = !alt; + if (alt) { + format_ = config_["format-alt"].asString(); + } else { + format_ = default_format_; + } } + dp.emit(); return true; } -std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt) -{ +bool waybar::ALabel::handleScroll(GdkEventScroll* e) { + + // Avoid concurrent scroll event + { + std::lock_guard lock(mutex_); + bool direction_up = false; + + if (e->direction == GDK_SCROLL_UP) { + direction_up = true; + } + if (e->direction == GDK_SCROLL_DOWN) { + direction_up = false; + } + if (e->direction == GDK_SCROLL_SMOOTH) { + gdouble delta_x, delta_y; + gdk_event_get_scroll_deltas(reinterpret_cast(e), + &delta_x, &delta_y); + if (delta_y < 0) { + direction_up = true; + } else if (delta_y > 0) { + direction_up = false; + } + } + + if (direction_up) + waybar::util::command::forkExec(scroll_up_cmd_); + else + waybar::util::command::forkExec(scroll_down_cmd_); + + dp.emit(); + } + + return true; +} + +std::string waybar::ALabel::getIcon(uint16_t percentage, + const std::string& alt) { auto format_icons = config_["format-icons"]; if (format_icons.isObject()) { if (!alt.empty() && format_icons[alt].isString()) { @@ -57,6 +122,4 @@ std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt) return ""; } -waybar::ALabel::operator Gtk::Widget &() { - return event_box_; -} +waybar::ALabel::operator Gtk::Widget&() { return event_box_; }