mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-31 07:52:42 +01:00 
			
		
		
		
	taskbar: implement drag-and-drop task reordering
This commit is contained in:
		| @@ -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_.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_; } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bi4k8
					bi4k8