Merge pull request #68 from harishkrupo/master

Add configuration options for widgets on mouse events
pull/72/head
Alex 2018-10-30 16:32:37 +01:00 committed by GitHub
commit c3e185546d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 210 additions and 48 deletions

View File

@ -6,21 +6,28 @@
namespace waybar { namespace waybar {
class ALabel : public IModule { class ALabel : public IModule {
public: public:
ALabel(const Json::Value&, const std::string format); ALabel(const Json::Value&, const std::string format);
virtual ~ALabel() = default; virtual ~ALabel() = default;
virtual auto update() -> void; virtual auto update() -> void;
virtual std::string getIcon(uint16_t, const std::string& alt = ""); virtual std::string getIcon(uint16_t, const std::string& alt = "");
virtual operator Gtk::Widget &(); virtual operator Gtk::Widget&();
protected:
Gtk::EventBox event_box_; protected:
Gtk::Label label_; Gtk::EventBox event_box_;
const Json::Value& config_; Gtk::Label label_;
std::string format_; const Json::Value& config_;
private: std::string format_;
bool handleToggle(GdkEventButton* const& ev); std::string button_press_cmd_ = "";
bool alt = false; std::string scroll_up_cmd_ = "";
const std::string default_format_; 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

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <pulse/pulseaudio.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <pulse/pulseaudio.h>
#include <pulse/volume.h>
#include <algorithm> #include <algorithm>
#include "ALabel.hpp" #include "ALabel.hpp"
@ -18,6 +19,8 @@ class Pulseaudio : public ALabel {
static void contextStateCb(pa_context*, void*); static void contextStateCb(pa_context*, void*);
static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*); static void sinkInfoCb(pa_context*, const pa_sink_info*, int, void*);
static void serverInfoCb(pa_context*, const pa_server_info*, void*); static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*);
bool handleScroll(GdkEventScroll* e);
const std::string getPortIcon() const; const std::string getPortIcon() const;
@ -26,9 +29,11 @@ class Pulseaudio : public ALabel {
pa_context* context_; pa_context* context_;
uint32_t sink_idx_{0}; uint32_t sink_idx_{0};
uint16_t volume_; uint16_t volume_;
pa_cvolume pa_volume_;
bool muted_; bool muted_;
std::string port_name_; std::string port_name_;
std::string desc_; std::string desc_;
bool scrolling_;
}; };
} } // namespace waybar::modules

View File

@ -29,7 +29,24 @@ inline struct res exec(const std::string cmd)
output.erase(output.length()-1); output.erase(output.length()-1);
} }
int exit_code = WEXITSTATUS(pclose(fp)); 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

View File

@ -1,4 +1,5 @@
#include "ALabel.hpp" #include "ALabel.hpp"
#include <util/command.hpp>
#include <iostream> #include <iostream>
@ -14,30 +15,94 @@ waybar::ALabel::ALabel(const Json::Value& config, const std::string format)
} }
if (config_["format-alt"].isString()) { if (config_["format-alt"].isString()) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK); event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event() event_box_.signal_button_press_event().connect(
.connect(sigc::mem_fun(*this, &ALabel::handleToggle)); 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 // Nothing here
} }
bool waybar::ALabel::handleToggle(GdkEventButton* const& /*ev*/) bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
{ if (button_press_cmd_ != "" && e->button == 1) {
alt = !alt; waybar::util::command::forkExec(button_press_cmd_);
if (alt) {
format_ = config_["format-alt"].asString();
} else { } else {
format_ = default_format_; alt = !alt;
if (alt) {
format_ = config_["format-alt"].asString();
} else {
format_ = default_format_;
}
} }
dp.emit(); dp.emit();
return true; 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<std::mutex> 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<const GdkEvent*>(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"]; auto format_icons = config_["format-icons"];
if (format_icons.isObject()) { if (format_icons.isObject()) {
if (!alt.empty() && format_icons[alt].isString()) { if (!alt.empty() && format_icons[alt].isString()) {
@ -57,6 +122,4 @@ std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt)
return ""; return "";
} }
waybar::ALabel::operator Gtk::Widget &() { waybar::ALabel::operator Gtk::Widget&() { return event_box_; }
return event_box_;
}

View File

@ -1,9 +1,14 @@
#include "modules/pulseaudio.hpp" #include "modules/pulseaudio.hpp"
waybar::modules::Pulseaudio::Pulseaudio(const Json::Value& config) waybar::modules::Pulseaudio::Pulseaudio(const Json::Value &config)
: ALabel(config, "{volume}%"), mainloop_(nullptr), mainloop_api_(nullptr), : ALabel(config, "{volume}%"),
context_(nullptr), sink_idx_(0), volume_(0), muted_(false) mainloop_(nullptr),
{ mainloop_api_(nullptr),
context_(nullptr),
sink_idx_(0),
volume_(0),
muted_(false),
scrolling_(false) {
label_.set_name("pulseaudio"); label_.set_name("pulseaudio");
mainloop_ = pa_threaded_mainloop_new(); mainloop_ = pa_threaded_mainloop_new();
if (mainloop_ == nullptr) { if (mainloop_ == nullptr) {
@ -26,10 +31,18 @@ waybar::modules::Pulseaudio::Pulseaudio(const Json::Value& config)
throw std::runtime_error("pa_mainloop_run() failed."); throw std::runtime_error("pa_mainloop_run() failed.");
} }
pa_threaded_mainloop_unlock(mainloop_); pa_threaded_mainloop_unlock(mainloop_);
// define the pulse scroll events only when no user provided
// events are configured
if (!config["on-scroll-up"].isString() &&
!config["on-scroll-down"].isString()) {
event_box_.add_events(Gdk::SCROLL_MASK);
event_box_.signal_scroll_event().connect(
sigc::mem_fun(*this, &Pulseaudio::handleScroll));
}
} }
waybar::modules::Pulseaudio::~Pulseaudio() waybar::modules::Pulseaudio::~Pulseaudio() {
{
mainloop_api_->quit(mainloop_api_, 0); mainloop_api_->quit(mainloop_api_, 0);
pa_threaded_mainloop_stop(mainloop_); pa_threaded_mainloop_stop(mainloop_);
pa_threaded_mainloop_free(mainloop_); pa_threaded_mainloop_free(mainloop_);
@ -58,6 +71,47 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data)
} }
} }
bool waybar::modules::Pulseaudio::handleScroll(GdkEventScroll *e) {
// Avoid concurrent scroll event
bool direction_up = false;
// XXX/TODO: Change of 100 corresponds to 1%, does that always hold true?
uint16_t change = 100;
pa_cvolume pa_volume = pa_volume_;
if (scrolling_) {
return false;
}
scrolling_ = true;
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<const GdkEvent *>(e), &delta_x,
&delta_y);
if (delta_y < 0) {
direction_up = true;
} else if (delta_y > 0) {
direction_up = false;
}
}
if (direction_up) {
if (volume_ + 1 < 100) pa_cvolume_inc(&pa_volume, change);
} else {
if (volume_ - 1 > 0) pa_cvolume_dec(&pa_volume, change);
}
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume,
volumeModifyCb, this);
return true;
}
/* /*
* Called when an event we subscribed to occurs. * Called when an event we subscribed to occurs.
*/ */
@ -75,16 +129,29 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context* context,
} }
} }
/*
* Called in response to a volume change request
*/
void waybar::modules::Pulseaudio::volumeModifyCb(pa_context *c, int success,
void *data) {
auto pa = static_cast<waybar::modules::Pulseaudio *>(data);
if (success) {
pa_context_get_sink_info_by_index(pa->context_, pa->sink_idx_, sinkInfoCb,
data);
}
}
/* /*
* Called when the requested sink information is ready. * Called when the requested sink information is ready.
*/ */
void waybar::modules::Pulseaudio::sinkInfoCb(pa_context* /*context*/, void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/,
const pa_sink_info* i, int /*eol*/, void* data) const pa_sink_info *i, int /*eol*/,
{ void *data) {
if (i != nullptr) { if (i != nullptr) {
auto pa = static_cast<waybar::modules::Pulseaudio *>(data); auto pa = static_cast<waybar::modules::Pulseaudio *>(data);
float volume = static_cast<float>(pa_cvolume_avg(&(i->volume))) pa->pa_volume_ = i->volume;
/ float{PA_VOLUME_NORM}; float volume = static_cast<float>(pa_cvolume_avg(&(pa->pa_volume_))) /
float{PA_VOLUME_NORM};
pa->sink_idx_ = i->index; pa->sink_idx_ = i->index;
pa->volume_ = std::round(volume * 100.0f); pa->volume_ = std::round(volume * 100.0f);
pa->muted_ = i->mute != 0; pa->muted_ = i->mute != 0;
@ -141,8 +208,11 @@ auto waybar::modules::Pulseaudio::update() -> void
label_.get_style_context()->remove_class("muted"); label_.get_style_context()->remove_class("muted");
label_.get_style_context()->add_class("bluetooth"); label_.get_style_context()->add_class("bluetooth");
} }
label_.set_label(fmt::format(format, label_.set_label(
fmt::arg("volume", volume_), fmt::format(format, fmt::arg("volume", volume_),
fmt::arg("icon", getIcon(volume_, getPortIcon())))); fmt::arg("icon", getIcon(volume_, getPortIcon()))));
label_.set_tooltip_text(desc_); label_.set_tooltip_text(desc_);
if (scrolling_) {
scrolling_ = false;
}
} }