Merge pull request #68 from harishkrupo/master
Add configuration options for widgets on mouse events
This commit is contained in:
commit
c3e185546d
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue