taskbar: implement drag-and-drop task reordering
parent
1374b0fce4
commit
ff61e7bf4e
|
@ -74,6 +74,10 @@ class Task {
|
||||||
std::string app_id_;
|
std::string app_id_;
|
||||||
uint32_t state_ = 0;
|
uint32_t state_ = 0;
|
||||||
|
|
||||||
|
int32_t drag_start_x;
|
||||||
|
int32_t drag_start_y;
|
||||||
|
int32_t drag_start_button = -1;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string repr() const;
|
std::string repr() const;
|
||||||
std::string state_string(bool = false) const;
|
std::string state_string(bool = false) const;
|
||||||
|
@ -105,6 +109,11 @@ class Task {
|
||||||
|
|
||||||
/* Callbacks for Gtk events */
|
/* Callbacks for Gtk events */
|
||||||
bool handle_clicked(GdkEventButton *);
|
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:
|
public:
|
||||||
bool operator==(const Task &) const;
|
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,
|
.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,
|
Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar,
|
||||||
struct zwlr_foreign_toplevel_handle_v1 *tl_handle, struct wl_seat *seat)
|
struct zwlr_foreign_toplevel_handle_v1 *tl_handle, struct wl_seat *seat)
|
||||||
: bar_{bar},
|
: bar_{bar},
|
||||||
|
@ -309,9 +313,19 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar,
|
||||||
/* Handle click events if configured */
|
/* Handle click events if configured */
|
||||||
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
|
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
|
||||||
config_["on-click-right"].isString()) {
|
config_["on-click-right"].isString()) {
|
||||||
|
}
|
||||||
|
|
||||||
button_.add_events(Gdk::BUTTON_PRESS_MASK);
|
button_.add_events(Gdk::BUTTON_PRESS_MASK);
|
||||||
button_.signal_button_press_event().connect(sigc::mem_fun(*this, &Task::handle_clicked), false);
|
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() {
|
Task::~Task() {
|
||||||
|
@ -495,6 +509,14 @@ void Task::handle_closed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Task::handle_clicked(GdkEventButton *bt) {
|
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;
|
std::string action;
|
||||||
if (config_["on-click"].isString() && bt->button == 1)
|
if (config_["on-click"].isString() && bt->button == 1)
|
||||||
action = config_["on-click"].asString();
|
action = config_["on-click"].asString();
|
||||||
|
@ -528,6 +550,60 @@ bool Task::handle_clicked(GdkEventButton *bt) {
|
||||||
return true;
|
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_; }
|
||||||
|
|
||||||
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