X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fgtkmm2ext%2Fgtkmm2ext%2Fdndtreeview.h;h=dd58f77a4c6760a5e9e26c33d37cff111ae0fe62;hb=4dc63966f0872efe768dad61eb9b8785d06b92d1;hp=fbc5ea90ef1604b665e0f00d73246c2dacf00082;hpb=666e0870554705f4fb466fc6b188fe9b4000ca49;p=ardour.git diff --git a/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h index fbc5ea90ef..dd58f77a4c 100644 --- a/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h +++ b/libs/gtkmm2ext/gtkmm2ext/dndtreeview.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2007 Paul Davis + Copyright (C) 2000-2007 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,17 +26,19 @@ #include #include +#include "gtkmm2ext/visibility.h" + namespace Gtkmm2ext { template -struct SerializedObjectPointers { +struct /*LIBGTKMM2EXT_API*/ SerializedObjectPointers { uint32_t size; uint32_t cnt; char type[32]; DataType data[0]; }; -class DnDTreeViewBase : public Gtk::TreeView +class LIBGTKMM2EXT_API DnDTreeViewBase : public Gtk::TreeView { private: public: @@ -45,6 +47,11 @@ class DnDTreeViewBase : public Gtk::TreeView void add_drop_targets (std::list&); void add_object_drag (int column, std::string type_name); + + void on_drag_begin (Glib::RefPtr const & context) { + Gtk::TreeView::on_drag_begin (context); + start_object_drag (); + } void on_drag_leave(const Glib::RefPtr& context, guint time) { suggested_action = context->get_suggested_action(); @@ -62,30 +69,50 @@ class DnDTreeViewBase : public Gtk::TreeView std::list draggable; Gdk::DragAction suggested_action; int data_column; + std::string object_type; + + struct DragData { + DragData () : source (0) {} + + Gtk::TreeView* source; + int data_column; + std::string object_type; + }; + + static DragData drag_data; + + void start_object_drag () { + drag_data.source = this; + drag_data.data_column = data_column; + drag_data.object_type = object_type; + } }; template -class DnDTreeView : public DnDTreeViewBase +class /*LIBGTKMM2EXT_API*/ DnDTreeView : public DnDTreeViewBase { public: - DnDTreeView() {} + DnDTreeView() {} ~DnDTreeView() {} - sigc::signal signal_object_drop; + sigc::signal&,Gtk::TreeView*,int,int,Glib::RefPtr&> signal_drop; void on_drag_data_get(const Glib::RefPtr& context, Gtk::SelectionData& selection_data, guint info, guint time) { if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") { - + TreeView::on_drag_data_get (context, selection_data, info, time); - - } else if (data_column >= 0) { - - Gtk::TreeSelection::ListHandle_Path selection = get_selection()->get_selected_rows (); - SerializedObjectPointers* sr = serialize_pointers (get_model(), &selection, selection_data.get_target()); - selection_data.set (8, (guchar*)sr, sr->size); + + } else if (selection_data.get_target() == object_type) { + + /* we don't care about the data passed around by DnD, but + we have to provide something otherwise it will stop. + */ + + guchar c; + selection_data.set (8, (guchar*)&c, 1); } } - + void on_drag_data_received(const Glib::RefPtr& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time) { if (suggested_action) { /* this is a drag motion callback. just update the status to @@ -100,66 +127,49 @@ class DnDTreeView : public DnDTreeViewBase TreeView::on_drag_data_received (context, x, y, selection_data, info, time); - } else if (data_column >= 0) { - - /* object D-n-D */ - - const void* data = selection_data.get_data(); - const SerializedObjectPointers* sr = reinterpret_cast *>(data); - - if (sr) { - signal_object_drop (sr->type, sr->cnt, sr->data); - } + + } else if (selection_data.get_target() == object_type) { + end_object_drag (const_cast& > (context), x, y); + } else { /* some kind of target type added by the app, which will be handled by a signal handler */ } } - private: - - SerializedObjectPointers* serialize_pointers (Glib::RefPtr model, - Gtk::TreeSelection::ListHandle_Path* selection, - Glib::ustring type) { - - /* this nasty chunk of code is here because X's DnD protocol (probably other graphics UI's too) - requires that we package up the entire data collection for DnD in a single contiguous region - (so that it can be trivially copied between address spaces). We don't know the type of DataType so - we have to mix-and-match C and C++ programming techniques here to get the right result. - - The C trick is to use the "someType foo[0];" declaration trick to create a zero-sized array at the - end of a SerializedObjectPointerssize(); - uint32_t sz = (sizeof (DataType) * cnt) + sizeof (SerializedObjectPointers); + /** + * This can be called by the Treeview itself or by some other + * object that wants to get the list of dragged items. + */ - char* buf = new char[sz]; - SerializedObjectPointers* sr = (SerializedObjectPointers*) buf; + void get_object_drag_data (std::list& l, Gtk::TreeView** source) { - for (uint32_t i = 0; i < cnt; ++i) { - new ((void *) &sr->data[i]) DataType (); + if (drag_data.source == 0) { + return; } + + Glib::RefPtr model = drag_data.source->get_model(); + DataType v; + Gtk::TreeSelection::ListHandle_Path selection = drag_data.source->get_selection()->get_selected_rows (); - sr->cnt = cnt; - sr->size = sz; - snprintf (sr->type, sizeof (sr->type), "%s", type.c_str()); - - cnt = 0; - - for (Gtk::TreeSelection::ListHandle_Path::iterator x = selection->begin(); x != selection->end(); ++x, ++cnt) { - model->get_iter (*x)->get_value (data_column, sr->data[cnt]); + for (Gtk::TreeSelection::ListHandle_Path::iterator x = selection.begin(); x != selection.end(); ++x) { + model->get_iter (*x)->get_value (drag_data.data_column, v); + l.push_back (v); } + + *source = drag_data.source; + } - return sr; + private: + void end_object_drag (Glib::RefPtr& context, int x, int y) { + std::list l; + Gtk::TreeView* source; + get_object_drag_data (l, &source); + signal_drop (l, source, x, y, context); } + }; } // namespace - + #endif /* __gtkmm2ext_dndtreeview_h__ */