taskbar: implement drag-and-drop task reordering

This commit is contained in:
bi4k8 2022-10-25 19:39:23 +00:00
parent 1374b0fce4
commit ff61e7bf4e
2 changed files with 87 additions and 2 deletions

View File

@ -74,6 +74,10 @@ class Task {
std::string app_id_;
uint32_t state_ = 0;
int32_t drag_start_x;
int32_t drag_start_y;
int32_t drag_start_button = -1;
private:
std::string repr() const;
std::string state_string(bool = false) const;
@ -105,6 +109,11 @@ class Task {
/* Callbacks for Gtk events */
bool handle_clicked(GdkEventButton *);
bool handle_button_release(GdkEventButton *);
bool handle_motion_notify(GdkEventMotion *);
void handle_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection_data, guint info, guint time);
void handle_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, Gtk::SelectionData selection_data, guint info, guint time);
public:
bool operator==(const Task &) const;

View File

@ -251,6 +251,10 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_handle_imp
.parent = tl_handle_parent,
};
static const std::vector<Gtk::TargetEntry> target_entries = {
Gtk::TargetEntry("WAYBAR_TOPLEVEL", Gtk::TARGET_SAME_APP, 0)
};
Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar,
struct zwlr_foreign_toplevel_handle_v1 *tl_handle, struct wl_seat *seat)
: bar_{bar},
@ -309,9 +313,19 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar,
/* Handle click events if configured */
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
config_["on-click-right"].isString()) {
}
button_.add_events(Gdk::BUTTON_PRESS_MASK);
button_.signal_button_press_event().connect(sigc::mem_fun(*this, &Task::handle_clicked), false);
}
button_.signal_button_release_event().connect(sigc::mem_fun(*this, &Task::handle_button_release), false);
button_.signal_motion_notify_event().connect(sigc::mem_fun(*this, &Task::handle_motion_notify), false);
button_.drag_source_set(target_entries, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE);
button_.drag_dest_set(target_entries, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_MOVE);
button_.signal_drag_data_get().connect(sigc::mem_fun(*this, &Task::handle_drag_data_get), false);
button_.signal_drag_data_received().connect(sigc::mem_fun(*this, &Task::handle_drag_data_received), false);
}
Task::~Task() {
@ -495,6 +509,14 @@ void Task::handle_closed() {
}
bool Task::handle_clicked(GdkEventButton *bt) {
/* filter out additional events for double/triple clicks */
if (bt->type == GDK_BUTTON_PRESS) {
/* save where the button press ocurred in case it becomes a drag */
drag_start_button = bt->button;
drag_start_x = bt->x;
drag_start_y = bt->y;
}
std::string action;
if (config_["on-click"].isString() && bt->button == 1)
action = config_["on-click"].asString();
@ -528,6 +550,60 @@ bool Task::handle_clicked(GdkEventButton *bt) {
return true;
}
bool Task::handle_button_release(GdkEventButton *bt) {
drag_start_button = -1;
return false;
}
bool Task::handle_motion_notify(GdkEventMotion *mn) {
if (drag_start_button == -1)
return false;
if ( button_.drag_check_threshold(drag_start_x, drag_start_y, mn->x, mn->y)) {
/* start drag in addition to other assigned action */
auto target_list = Gtk::TargetList::create(target_entries);
auto refptr = Glib::RefPtr<Gtk::TargetList>(target_list);
auto drag_context = button_.drag_begin(refptr, Gdk::DragAction::ACTION_MOVE, drag_start_button, (GdkEvent*)mn);
}
return false;
}
void Task::handle_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection_data, guint info, guint time)
{
spdlog::debug("drag_data_get");
void* button_addr = (void*)&this->button_;
selection_data.set(
"WAYBAR_TOPLEVEL",
32,
(const guchar *)&button_addr,
sizeof (gpointer));
}
void Task::handle_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, Gtk::SelectionData selection_data, guint info, guint time)
{
spdlog::debug("drag_data_received");
gpointer handle = *(gpointer*)selection_data.get_data();
auto dragged_button = (Gtk::Button*)handle;
if(dragged_button == &this->button_)
return;
auto parent_of_dragged = dragged_button->get_parent();
auto parent_of_dest = this->button_.get_parent();
if(parent_of_dragged != parent_of_dest)
return;
auto box = (Gtk::Box*)parent_of_dragged;
auto position_prop = box->child_property_position(this->button_);
auto position = position_prop.get_value();
box->reorder_child(*dragged_button, position);
}
bool Task::operator==(const Task &o) const { return o.id_ == id_; }
bool Task::operator!=(const Task &o) const { return o.id_ != id_; }