fix: Handle mouse button click/scroll events

This commit is contained in:
Michael Carlberg 2016-10-10 18:05:58 +02:00
parent 8af7388c93
commit c687b07cd0
10 changed files with 311 additions and 156 deletions

View File

@ -23,7 +23,11 @@
LEMONBUDDY_NS
class bar {
namespace bar_signals {
delegate::Signal1<string> action_click;
};
class bar : public xpp::event::sink<evt::button_press> {
public:
/**
* Construct bar
@ -53,6 +57,8 @@ class bar {
parser_signals::unicode_text_write.disconnect(this, &bar::draw_character);
if (m_tray.align != alignment::NONE)
tray_signals::report_slotcount.disconnect(this, &bar::on_tray_report);
if (m_sinkattached)
m_connection.detach_sink(this, 1);
m_window.destroy();
}
@ -393,6 +399,9 @@ class bar {
// }}}
m_connection.attach_sink(this, 1);
m_sinkattached = true;
m_connection.flush();
} //}}}
@ -455,6 +464,19 @@ class bar {
m_pixmap, m_window, m_gcontexts.at(gc::BL), 0, 0, 0, 0, m_bar.width, m_bar.height);
m_connection.copy_area(
m_pixmap, m_window, m_gcontexts.at(gc::BR), 0, 0, 0, 0, m_bar.width, m_bar.height);
for (auto&& action : m_actions) {
if (action.active) {
m_log.warn("Action block not closed");
m_log.warn("action.command = %s", action.command);
} else {
m_log.trace("bar: Action details");
m_log.trace("action.command = %s", action.command);
m_log.trace("action.mousebtn = %i", static_cast<int>(action.mousebtn));
m_log.trace("action.start_x = %i", action.start_x);
m_log.trace("action.end_x = %i", action.end_x);
}
}
} //}}}
/**
@ -471,6 +493,51 @@ class bar {
return m_tray;
} // }}}
/**
* Mouse button event handler
*/
void handle(const evt::button_press& evt) { // {{{
std::lock_guard<threading_util::spin_lock> lck(m_lock);
{
m_log.trace("bar: Received button press event: %i at pos(%i, %i)",
static_cast<int>(evt->detail), evt->event_x, evt->event_y);
mousebtn button = static_cast<mousebtn>(evt->detail);
for (auto&& action : m_actions) {
if (action.active) {
m_log.trace("bar: Ignoring action: unclosed)");
continue;
} else if (action.mousebtn != button) {
m_log.trace("bar: Ignoring action: button mismatch");
continue;
} else if (action.start_x > evt->event_x) {
m_log.trace(
"bar: Ignoring action: start_x(%i) > event_x(%i)", action.start_x, evt->event_x);
continue;
} else if (action.end_x < evt->event_x) {
m_log.trace("bar: Ignoring action: end_x(%i) < event_x(%i)", action.end_x, evt->event_x);
continue;
}
m_log.info("Found matching input area");
m_log.trace("action.command = %s", action.command);
m_log.trace("action.mousebtn = %i", static_cast<int>(action.mousebtn));
m_log.trace("action.start_x = %i", action.start_x);
m_log.trace("action.end_x = %i", action.end_x);
if (!bar_signals::action_click.empty())
bar_signals::action_click.emit(action.command);
else
m_log.warn("No signal handler's connected to 'action_click'");
return;
}
m_log.warn("No matching input area found");
}
} // }}}
protected:
/**
* Handle alignment update
@ -480,7 +547,14 @@ class bar {
return;
m_log.trace("bar: alignment_change(%i)", static_cast<int>(align));
m_bar.align = align;
if (align == alignment::LEFT) {
m_xpos = m_borders[border::LEFT].size;
} else if (align == alignment::RIGHT) {
m_xpos = m_borders[border::RIGHT].size;
} else {
m_xpos = 0;
}
} //}}}
/**
@ -523,6 +597,7 @@ class bar {
m_log.trace("bar: action_block_open(%i, %s)", static_cast<int>(btn), cmd);
action_block action;
action.active = true;
action.align = m_bar.align;
action.mousebtn = btn;
action.start_x = m_xpos;
action.command = cmd;
@ -538,10 +613,26 @@ class bar {
auto n_actions = m_actions.size();
while (n_actions--) {
action_block& action = m_actions[n_actions];
if (!action.active || action.mousebtn != btn)
continue;
action.end_x = m_xpos;
action.active = false;
if (action.align == alignment::CENTER) {
auto width = action.end_x - action.start_x;
auto center = m_bar.width / 2;
auto x1 = center - width / 2;
auto x2 = center + width / 2;
action.start_x = x1;
action.end_x = x2;
} else if (action.align == alignment::RIGHT) {
auto x1 = m_bar.width - action.end_x;
auto x2 = m_bar.width - action.start_x;
action.start_x = x1;
action.end_x = x2;
}
}
} //}}}
@ -761,6 +852,8 @@ class bar {
map<gc, gcontext> m_gcontexts;
vector<action_block> m_actions;
stateflag m_sinkattached{false};
string m_prevdata;
int m_xpos{0};
int m_attributes{0};

View File

@ -11,6 +11,7 @@
#include "components/x11/tray.hpp"
#include "components/x11/types.hpp"
#include "config.hpp"
#include "utils/command.hpp"
#include "utils/inotify.hpp"
#include "utils/process.hpp"
#include "utils/socket.hpp"
@ -66,6 +67,7 @@ class controller {
}
m_log.trace("controller: Deconstruct bar instance");
bar_signals::action_click.disconnect(this, &controller::on_module_click);
m_bar.reset();
if (m_traymanager) {
@ -143,6 +145,8 @@ class controller {
if (dump_wmname) {
std::cout << m_bar->settings().wmname << std::endl;
return;
} else if (!to_stdout) {
bar_signals::action_click.connect(this, &controller::on_module_click);
}
} catch (const std::exception& err) {
throw application_error("Failed to setup bar renderer: " + string{err.what()});
@ -452,6 +456,34 @@ class controller {
m_bar->parse(contents);
}
void on_module_click(string input) {
std::lock_guard<threading_util::spin_lock> lck(m_lock);
for (auto&& block : m_modules) {
for (auto&& module : block.second) {
if (!module->receive_events())
continue;
if (module->handle_event(input))
return;
}
}
m_log.trace("controller: Unrecognized input '%s'", input);
m_log.trace("controller: Forwarding input to shell");
auto command = command_util::make_command("/usr/bin/env\nsh\n-c\n"+ input);
try {
command->exec(false);
command->tail([this](std::string output){
m_log.trace("> %s", output);
});
command->wait();
} catch (const application_error& err) {
m_log.err(err.what());
}
}
private:
connection& m_connection;
registry m_registry{m_connection};

View File

@ -234,7 +234,7 @@ class parser {
} // }}}
mousebtn parse_action_btn(string data) { // {{{
if (isdigit(data[0] - '0'))
if (isdigit(data[0]))
return static_cast<mousebtn>(data[0] - '0');
else if (!m_actions.empty())
return static_cast<mousebtn>(m_actions.back());

View File

@ -305,27 +305,29 @@ namespace modules {
return true;
}
bool handle_command(string cmd) {
bool handle_event(string cmd) {
if (cmd.find(EVENT_CLICK) == string::npos || cmd.length() <= strlen(EVENT_CLICK))
return false;
// if (cmd.find(EVENT_CLICK) == string::npos || cmd.length() <= strlen(EVENT_CLICK))
// return false;
//
// stringstream payload_s;
//
// payload_s << "desktop -f " << m_monitor << ":^"
// << std::atoi(cmd.substr(strlen(EVENT_CLICK)).c_str());
//
// int payload_fd;
// string socket_path = get_socket_path();
//
// if ((payload_fd = io_util::socket::open(socket_path)) == -1)
// m_log.err("%s: Failed to open socket '%s'", name(), socket_path);
// else if (!send_payload(payload_fd, generate_payload(payload_s.str())))
// m_log.err("%s: Failed to change desktop", name());
//
// close(payload_fd);
//
// return true;
try {
auto ipc = bspwm_util::make_subscriber();
auto command = string_util::from_stream(stringstream() << "desktop -f " << m_monitor << ":^"
<< cmd.substr(strlen(EVENT_CLICK)));
auto payload = bspwm_util::make_payload(command);
m_log.info("%s: Sending command to ipc handler '%s'", name(), command);
ipc->send(payload->data, payload->len, 0);
ipc->disconnect();
} catch (const system_error& err) {
m_log.err("%s: %s", name(), err.what());
}
return true;
}
bool receive_events() const {
return true;
}
private:

View File

@ -49,6 +49,18 @@ namespace modules {
return tag == TAG_DATE;
}
bool handle_event(string cmd) {
if (cmd == EVENT_TOGGLE) {
m_detailed = !m_detailed;
wakeup();
}
return cmd == EVENT_TOGGLE;
}
bool receive_events() const {
return true;
}
private:
static constexpr auto TAG_DATE = "<date>";

View File

@ -206,14 +206,18 @@ namespace modules {
return true;
}
// bool handle_command(string cmd) {
// if (cmd.find(EVENT_CLICK) == string::npos || cmd.length() < strlen(EVENT_CLICK))
// return false;
//
// m_ipc->send_command("workspace number " + cmd.substr(strlen(EVENT_CLICK)));
//
// return true;
// }
bool handle_event(string cmd) {
if (cmd.find(EVENT_CLICK) == string::npos || cmd.length() < strlen(EVENT_CLICK))
return false;
m_ipc->send_command("workspace number " + cmd.substr(strlen(EVENT_CLICK)));
return true;
}
bool receive_events() const {
return true;
}
private:
static constexpr auto DEFAULT_WS_ICON = "workspace_icon-default";

View File

@ -97,32 +97,36 @@ namespace modules {
return true;
}
// bool handle_command(string cmd) {
// if (cmd.compare(0, strlen(EVENT_MENU_OPEN), EVENT_MENU_OPEN) == 0) {
// auto level = cmd.substr(strlen(EVENT_MENU_OPEN));
//
// if (level.empty())
// level = "0";
//
// m_level = std::atoi(level.c_str());
//
// if (m_level >= (int)m_levels.size()) {
// m_log.err("%s: Cannot open unexisting menu level '%d'", name(), level);
// m_level = -1;
// }
//
// } else if (cmd == EVENT_MENU_CLOSE) {
// m_level = -1;
// } else {
// m_level = -1;
// broadcast();
// return false;
// }
//
// broadcast();
//
// return true;
// }
bool handle_event(string cmd) {
if (cmd.compare(0, strlen(EVENT_MENU_OPEN), EVENT_MENU_OPEN) == 0) {
auto level = cmd.substr(strlen(EVENT_MENU_OPEN));
if (level.empty())
level = "0";
m_level = std::atoi(level.c_str());
if (m_level >= (int)m_levels.size()) {
m_log.err("%s: Cannot open unexisting menu level '%d'", name(), level);
m_level = -1;
}
} else if (cmd == EVENT_MENU_CLOSE) {
m_level = -1;
} else {
m_level = -1;
broadcast();
return false;
}
broadcast();
return true;
}
bool receive_events() const {
return true;
}
private:
static constexpr auto TAG_LABEL_TOGGLE = "<label-toggle>";

View File

@ -155,8 +155,8 @@ namespace modules {
virtual void refresh() = 0;
virtual string contents() = 0;
virtual bool handle_command(string cmd) = 0;
virtual bool register_for_events() const = 0;
virtual bool handle_event(string cmd) = 0;
virtual bool receive_events() const = 0;
delegate::Signal1<string> on_update;
};
@ -216,11 +216,11 @@ namespace modules {
return m_cache;
}
bool handle_command(string cmd) {
return CAST_MODULE(Impl)->handle_command(cmd);
bool handle_event(string cmd) {
return CAST_MODULE(Impl)->handle_event(cmd);
}
bool register_for_events() const {
bool receive_events() const {
return false;
}

View File

@ -267,51 +267,57 @@ namespace modules {
return true;
}
// bool handle_command(string cmd) {
// if (cmd.compare(0, 3, "mpd") != 0)
// return false;
//
// try {
// auto mpd = make_unique<Connection>(m_log, m_host, m_port, m_pass);
// auto status = mpd->get_status();
//
// if (cmd == EVENT_PLAY)
// mpd->play();
// else if (cmd == EVENT_PAUSE)
// mpd->pause(!(status->match_state(mpdstate::PAUSED)));
// else if (cmd == EVENT_STOP)
// mpd->stop();
// else if (cmd == EVENT_PREV)
// mpd->prev();
// else if (cmd == EVENT_NEXT)
// mpd->next();
// else if (cmd == EVENT_REPEAT_ONE)
// mpd->set_single(!status->single);
// else if (cmd == EVENT_REPEAT)
// mpd->set_repeat(!status->repeat);
// else if (cmd == EVENT_RANDOM)
// mpd->set_random(!status->random);
// else if (cmd.compare(0, strlen(EVENT_SEEK), EVENT_SEEK) == 0) {
// auto s = cmd.substr(strlen(EVENT_SEEK));
// int percentage = 0;
// if (s.empty())
// return false;
// if (s[0] == '+') {
// percentage = status->get_elapsed_percentage() + std::atoi(s.substr(1).c_str());
// } else if (s[0] == '-') {
// percentage = status->get_elapsed_percentage() - std::atoi(s.substr(1).c_str());
// } else {
// percentage = std::atoi(s.c_str());
// }
// mpd->seek(status->get_songid(), status->get_seek_position(percentage));
// } else
// return false;
// } catch (const mpd_exception& e) {
// m_log.err(e.what());
// }
//
// return true;
// }
bool handle_event(string cmd) {
if (cmd.compare(0, 3, "mpd") != 0)
return false;
try {
auto mpd = make_unique<mpdconnection>(m_log, m_host, m_port, m_pass);
mpd->connect();
auto status = mpd->get_status();
if (cmd == EVENT_PLAY)
mpd->play();
else if (cmd == EVENT_PAUSE)
mpd->pause(!(status->match_state(mpdstate::PAUSED)));
else if (cmd == EVENT_STOP)
mpd->stop();
else if (cmd == EVENT_PREV)
mpd->prev();
else if (cmd == EVENT_NEXT)
mpd->next();
else if (cmd == EVENT_REPEAT_ONE)
mpd->set_single(!status->single());
else if (cmd == EVENT_REPEAT)
mpd->set_repeat(!status->repeat());
else if (cmd == EVENT_RANDOM)
mpd->set_random(!status->random());
else if (cmd.compare(0, strlen(EVENT_SEEK), EVENT_SEEK) == 0) {
auto s = cmd.substr(strlen(EVENT_SEEK));
int percentage = 0;
if (s.empty())
return false;
if (s[0] == '+') {
percentage = status->get_elapsed_percentage() + std::atoi(s.substr(1).c_str());
} else if (s[0] == '-') {
percentage = status->get_elapsed_percentage() - std::atoi(s.substr(1).c_str());
} else {
percentage = std::atoi(s.c_str());
}
mpd->seek(status->get_songid(), status->get_seek_position(percentage));
} else
return false;
} catch (const mpd_exception& e) {
m_log.err("%s: %s", name(), e.what());
}
return true;
}
bool receive_events() const {
return true;
}
private:
// static const int PROGRESSBAR_THREAD_SYNC_COUNT = 10;

View File

@ -114,7 +114,7 @@ namespace modules {
}
bool has_event() {
if (m_has_changed)
if (m_updated)
return true;
try {
@ -135,7 +135,7 @@ namespace modules {
}
bool update() {
m_has_changed = false;
m_updated = false;
// Consume any other pending events
if (m_master_mixer)
@ -187,11 +187,19 @@ namespace modules {
string get_output() {
m_builder->cmd(mousebtn::LEFT, EVENT_TOGGLE_MUTE);
if (!m_muted && m_volume < 100)
m_builder->cmd(mousebtn::SCROLL_UP, EVENT_VOLUME_UP);
else
m_log.trace("%s: Not adding scroll up handler (muted or volume = 100)", name());
if (!m_muted && m_volume > 0)
m_builder->cmd(mousebtn::SCROLL_DOWN, EVENT_VOLUME_DOWN);
else
m_log.trace("%s: Not adding scroll down handler (muted or volume = 0)", name());
m_builder->node(module::get_output());
return m_builder->flush();
}
@ -211,51 +219,45 @@ namespace modules {
return true;
}
// bool handle_command(string cmd) {
// if (cmd.length() < strlen(EVENT_PREFIX))
// return false;
// if (std::strncmp(cmd.c_str(), EVENT_PREFIX, 3) != 0)
// return false;
//
// // std::lock_guard<concurrency::SpinLock> lck(this->update_lock);
//
// alsa_mixer* master_mixer = nullptr;
// alsa_mixer* other_mixer = nullptr;
//
// if (m_master_mixer)
// master_mixer = m_master_mixer.get();
//
// if (master_mixer == nullptr)
// return false;
//
// if (m_headphone_mixer && m_headphone_ctrl && m_headphone_ctrl->test_device_plugged())
// other_mixer = m_headphone_mixer.get();
// else if (m_speaker_mixer)
// other_mixer = m_speaker_mixer.get();
//
// if (std::strncmp(cmd.c_str(), EVENT_TOGGLE_MUTE, strlen(EVENT_TOGGLE_MUTE)) == 0) {
// // Toggle mute state
// master_mixer->set_mute(m_muted);
// if (other_mixer != nullptr)
// other_mixer->set_mute(m_muted);
// } else if (std::strncmp(cmd.c_str(), EVENT_VOLUME_UP, strlen(EVENT_VOLUME_UP)) == 0) {
// // Increase volume
// master_mixer->set_volume(math_util::cap<float>(master_mixer->get_volume() + 5, 0, 100));
// if (other_mixer != nullptr)
// other_mixer->set_volume(math_util::cap<float>(other_mixer->get_volume() + 5, 0, 100));
// } else if (std::strncmp(cmd.c_str(), EVENT_VOLUME_DOWN, strlen(EVENT_VOLUME_DOWN)) == 0) {
// // Decrease volume
// master_mixer->set_volume(math_util::cap<float>(master_mixer->get_volume() - 5, 0, 100));
// if (other_mixer != nullptr)
// other_mixer->set_volume(math_util::cap<float>(other_mixer->get_volume() - 5, 0, 100));
// } else {
// return false;
// }
//
// m_has_changed = true;
//
// return true;
// }
bool handle_event(string cmd) {
if (cmd.compare(0, 3, EVENT_PREFIX) != 0)
return false;
if (!m_master_mixer)
return false;
alsa_mixer* master_mixer = m_master_mixer.get();
alsa_mixer* other_mixer = nullptr;
if (m_headphone_mixer && m_headphone_ctrl && m_headphone_ctrl->test_device_plugged())
other_mixer = m_headphone_mixer.get();
else if (m_speaker_mixer)
other_mixer = m_speaker_mixer.get();
if (cmd.compare(0, strlen(EVENT_TOGGLE_MUTE), EVENT_TOGGLE_MUTE) == 0) {
master_mixer->set_mute(m_muted);
if (other_mixer != nullptr)
other_mixer->set_mute(m_muted);
} else if (cmd.compare(0, strlen(EVENT_VOLUME_UP), EVENT_VOLUME_UP) == 0) {
master_mixer->set_volume(math_util::cap<float>(master_mixer->get_volume() + 5, 0, 100));
if (other_mixer != nullptr)
other_mixer->set_volume(math_util::cap<float>(other_mixer->get_volume() + 5, 0, 100));
} else if (cmd.compare(0, strlen(EVENT_VOLUME_DOWN), EVENT_VOLUME_DOWN) == 0) {
master_mixer->set_volume(math_util::cap<float>(master_mixer->get_volume() - 5, 0, 100));
if (other_mixer != nullptr)
other_mixer->set_volume(math_util::cap<float>(other_mixer->get_volume() - 5, 0, 100));
} else {
return false;
}
m_updated = true;
return true;
}
bool receive_events() const {
return true;
}
private:
static constexpr auto FORMAT_VOLUME = "format-volume";
@ -287,7 +289,7 @@ namespace modules {
int m_headphone_ctrl_numid = -1;
int m_volume = 0;
bool m_muted = false;
bool m_has_changed = false;
bool m_updated = false;
bool m_headphones = false;
};
}