taskbar: implement drag-and-drop task reordering
parent
1374b0fce4
commit
ff61e7bf4e
|
@ -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;
|
||||
|
|
|
@ -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_.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_; }
|
||||
|
|
Loading…
Reference in New Issue