fixes for drag-n-drop broken by use of boost::shared_ptr<T>
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 20 Sep 2006 16:24:24 +0000 (16:24 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 20 Sep 2006 16:24:24 +0000 (16:24 +0000)
git-svn-id: svn://localhost/ardour2/trunk@923 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/SConscript
gtk2_ardour/editor.h
gtk2_ardour/editor_canvas.cc
gtk2_ardour/redirect_box.cc
gtk2_ardour/redirect_box.h
libs/gtkmm2ext/dndtreeview.cc
libs/gtkmm2ext/gtkmm2ext/dndtreeview.h

index c1eba1ea1d1ad709a3f16ce0a4c741084d803785..eb82230e4982c0571b8536b37160dc35a16f8f45 100644 (file)
@@ -7,6 +7,7 @@ import glob
 Import('env install_prefix final_prefix config_prefix libraries i18n version')
 
 gtkardour = env.Copy()
+gtkmmtests = env.Copy()
 
 #
 # this defines the version number of the GTK interface to ardour
@@ -49,6 +50,19 @@ gtkardour.Merge ([
     libraries['jack']
 ])
 
+gtkmmtests.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+
+gtkmmtests.Merge ([
+    libraries['gtkmm2'],
+    libraries['glib2'],
+    libraries['glibmm2'],
+    libraries['pangomm'],
+    libraries['atkmm'],
+    libraries['gdkmm2'],
+    libraries['sigc2'],
+    libraries['gtk2']
+])
+
 if gtkardour['DMALLOC']:
        gtkardour.Merge([libraries['dmalloc']])
        gtkardour.Append(CCFLAGS='-DUSE_DMALLOC')
@@ -213,6 +227,10 @@ stest_files=Split("""
 stest.cc
 """)
 
+tt_files=Split ("""
+tt.cc
+""")
+
 extra_sources = []
 
 vst_files = [ 'vst_pluginui.cc' ]
@@ -249,6 +267,7 @@ ardourlib = gtkardour.SharedLibrary(target = 'ardourgtk', source = gtkardour_fil
 mtest = gtkardour.Program(target = 'mtest', source = mtest_files)
 itest = gtkardour.Program(target = 'itest', source = itest_files)
 rcu = gtkardour.Program(target = 'rcu', source = rcu_files)
+tt = gtkmmtests.Program(target = 'tt', source = tt_files)
 
 my_subst_dict = { }
 my_subst_dict['%INSTALL_PREFIX%'] = install_prefix
index dacfde83278beb2290a1ef5ce4455a6706713e2b..f5fb65e7e9c2bc1d87e2a5c389da651d434f7fa1 100644 (file)
@@ -702,14 +702,15 @@ class Editor : public PublicEditor
            }
            Gtk::TreeModelColumn<Glib::ustring> name;
            Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Region> > region;
-               Gtk::TreeModelColumn<Gdk::Color> color_;
+           Gtk::TreeModelColumn<Gdk::Color> color_;
        };
            
-       RegionListDisplayModelColumns    region_list_columns;
-       Gtkmm2ext::DnDTreeView           region_list_display;
-       Glib::RefPtr<Gtk::TreeStore>     region_list_model;
-       Glib::RefPtr<Gtk::ToggleAction>  toggle_full_region_list_action;
-       Glib::RefPtr<Gtk::ToggleAction>  toggle_show_auto_regions_action;
+       RegionListDisplayModelColumns          region_list_columns;
+       Gtkmm2ext::DnDTreeView<boost::shared_ptr<ARDOUR::Region> > region_list_display;
+
+       Glib::RefPtr<Gtk::TreeStore>           region_list_model;
+       Glib::RefPtr<Gtk::ToggleAction>        toggle_full_region_list_action;
+       Glib::RefPtr<Gtk::ToggleAction>        toggle_show_auto_regions_action;
 
        void region_list_selection_changed ();
        bool region_list_selection_filter (const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path, bool yn);
@@ -772,7 +773,7 @@ class Editor : public PublicEditor
        NamedSelectionDisplayModelColumns named_selection_columns;
        Glib::RefPtr<Gtk::TreeStore>     named_selection_model;
 
-       Gtkmm2ext::DnDTreeView named_selection_display;
+       Gtkmm2ext::DnDTreeView<ARDOUR::NamedSelection*> named_selection_display;
        Gtk::ScrolledWindow    named_selection_scroller;
 
        void name_selection();
@@ -1429,9 +1430,9 @@ class Editor : public PublicEditor
        Glib::RefPtr<Gtk::TreeSelection> route_display_selection;
 
        gint route_list_compare_func (Gtk::TreeModel::iterator, Gtk::TreeModel::iterator);
-       Gtkmm2ext::DnDTreeView   route_list_display; 
-       Gtk::ScrolledWindow      route_list_scroller;
-       Gtk::Menu*               route_list_menu;
+       Gtkmm2ext::DnDTreeView<boost::shared_ptr<ARDOUR::Route> > route_list_display; 
+       Gtk::ScrolledWindow                   route_list_scroller;
+       Gtk::Menu*                            route_list_menu;
 
        bool route_list_display_button_press (GdkEventButton*);
        bool route_list_selection_filter (const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path, bool yn);
index 6798242642dee4a9cf2c673a16ac157c8f2d96b4..26995c39ef36f98fa5e597bb62408dc688b1b091 100644 (file)
@@ -488,11 +488,12 @@ Editor::drop_regions (const RefPtr<Gdk::DragContext>& context,
                      const SelectionData& data,
                      guint info, guint time)
 {
-       const DnDTreeView::SerializedObjectPointers* sr = reinterpret_cast<const DnDTreeView::SerializedObjectPointers*> (data.get_data());
+       const SerializedObjectPointers<boost::shared_ptr<Region> >* sr = 
+               reinterpret_cast<const SerializedObjectPointers<boost::shared_ptr<Region> > *> (data.get_data());
 
        for (uint32_t i = 0; i < sr->cnt; ++i) {
 
-               boost::shared_ptr<Region> r (reinterpret_cast<Region*> (sr->ptr[i]));
+               boost::shared_ptr<Region> r = sr->data[i];
                boost::shared_ptr<AudioRegion> ar;
 
                if ((ar = boost::dynamic_pointer_cast<AudioRegion>(r)) != 0) {
index 48562f1ffb6a33dcb1fea82de9f43c34cb8eb175..fcd04c9bd7c51dd4bc7e676af9d5d36f56c12612 100644 (file)
@@ -156,9 +156,9 @@ RedirectBox::~RedirectBox ()
 }
 
 void
-RedirectBox::object_drop (string type, uint32_t cnt, void** ptr)
+RedirectBox::object_drop (string type, uint32_t cnt, const boost::shared_ptr<Redirect>* ptr)
 {
-       if (type != "redirects" || cnt == 0 || ptr == 0) {
+       if (type != "redirects" || cnt == 0 || !ptr) {
                return;
        }
 
@@ -167,7 +167,7 @@ RedirectBox::object_drop (string type, uint32_t cnt, void** ptr)
        list<boost::shared_ptr<Redirect> > redirects;
        
        for (uint32_t n = 0; n < cnt; ++n) {
-               redirects.push_back (boost::shared_ptr<Redirect> ((Redirect*) ptr[n]));
+               redirects.push_back (ptr[n]);
        }
        
        paste_redirect_list (redirects);
index 51c17cad51e21086f82449929fcb2a3eabf1e131..ead3b0dfb814dbfd4391671649184c39f877f800 100644 (file)
@@ -119,10 +119,10 @@ class RedirectBox : public Gtk::HBox
        
        Gtk::EventBox          redirect_eventbox;
        Gtk::HBox              redirect_hpacker;
-       Gtkmm2ext::DnDTreeView redirect_display;
+       Gtkmm2ext::DnDTreeView<boost::shared_ptr<ARDOUR::Redirect> > redirect_display;
        Gtk::ScrolledWindow    redirect_scroller;
 
-       void object_drop (std::string type, uint32_t cnt, void**);
+       void object_drop (std::string type, uint32_t cnt, const boost::shared_ptr<ARDOUR::Redirect>*);
 
        Width _width;
        
index 83955861cfec9e1364a66e64a0bd743e9f31b274..7baedd41212d6ec848e6f437fb35fbd002ab8528 100644 (file)
@@ -10,7 +10,7 @@ using namespace Gtk;
 using namespace Glib;
 using namespace Gtkmm2ext;
 
-DnDTreeView::DnDTreeView ()
+DnDTreeViewBase::DnDTreeViewBase ()
        : TreeView ()
 {
        draggable.push_back (TargetEntry ("GTK_TREE_MODEL_ROW", TARGET_SAME_WIDGET));
@@ -23,7 +23,7 @@ DnDTreeView::DnDTreeView ()
 }
 
 void
-DnDTreeView::add_drop_targets (list<TargetEntry>& targets)
+DnDTreeViewBase::add_drop_targets (list<TargetEntry>& targets)
 {
        for (list<TargetEntry>::iterator i = targets.begin(); i != targets.end(); ++i) {
                draggable.push_back (*i);
@@ -33,7 +33,7 @@ DnDTreeView::add_drop_targets (list<TargetEntry>& targets)
 }      
 
 void
-DnDTreeView::add_object_drag (int column, string type_name)
+DnDTreeViewBase::add_object_drag (int column, string type_name)
 {
        draggable.push_back (TargetEntry (type_name, TargetFlags(0)));
        data_column = column;
@@ -42,86 +42,11 @@ DnDTreeView::add_object_drag (int column, string type_name)
        enable_model_drag_dest (draggable);
 }
 
-DnDTreeView::SerializedObjectPointers* 
-DnDTreeView::serialize_pointers (RefPtr<TreeModel> model, TreeSelection::ListHandle_Path* selection, ustring type)
-{
-       uint32_t cnt = selection->size();
-       uint32_t sz = (sizeof (void*) * cnt) + sizeof (SerializedObjectPointers);
-
-       cerr << "lets plan to serialize " << cnt << " from selection\n";
-
-       char* buf = new char[sz];
-       SerializedObjectPointers* sr = new (buf) SerializedObjectPointers;
-       
-       sr->cnt = cnt;
-       sr->size = sz;
-
-       snprintf (sr->type, sizeof (sr->type), "%s", type.c_str());
-
-       cnt = 0;
-
-       for (TreeSelection::ListHandle_Path::iterator x = selection->begin(); x != selection->end(); ++x, ++cnt) {
-               cerr << "getting next item\n";
-               TreeModel::Row row = *(model->get_iter (*x));
-               row.get_value (data_column, sr->ptr[cnt]);
-       }
-
-       cerr << "returning an SR with size = " << sr->size << endl;
-       return sr;
-}
-
-void
-DnDTreeView::on_drag_data_get(const RefPtr<DragContext>& context, 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);
-               
-               cerr << "selection data set to contain " << sr->size << endl;
-       }
-}
-
-void 
-DnDTreeView::on_drag_data_received(const RefPtr<DragContext>& context, int x, int y, const SelectionData& selection_data, guint info, guint time)
-{
-       if (suggested_action) {
-               /* this is a drag motion callback. just update the status to
-                  say that we are still dragging, and that's it.
-               */
-               suggested_action = Gdk::DragAction (0);
-               TreeView::on_drag_data_received (context, x, y, selection_data, info, time);
-               return;
-       }
-
-       if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") {
-               
-               TreeView::on_drag_data_received (context, x, y, selection_data, info, time);
-               
-       } else if (data_column >= 0) {
-
-               /* object D-n-D */
-               
-               const SerializedObjectPointers* sr = reinterpret_cast<const SerializedObjectPointers *>(selection_data.get_data());
-               
-               if (sr) {
-                       signal_object_drop (sr->type, sr->cnt, const_cast<void**>(sr->ptr));
-               }
-
-       } else {
-               /* some kind of target type added by the app, which will be handled by a signal handler */
-       }
-}
-
 bool 
-DnDTreeView::on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time)
+DnDTreeViewBase::on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time)
 {
        suggested_action = Gdk::DragAction (0);
        return TreeView::on_drag_drop (context, x, y, time);
 }
 
+
index 82bb7651b9de3122fda2bb958ff0871c86d26d9a..f8beb75873fcb4c5d3051edab5286c0c400ad96e 100644 (file)
 
 namespace Gtkmm2ext {
 
-class DnDTreeView : public Gtk::TreeView 
-{
+template<class DataType>
+struct SerializedObjectPointers {
+    uint32_t size;
+    uint32_t cnt;
+    char     type[32];
+    DataType data[0];
+};
 
+class DnDTreeViewBase : public Gtk::TreeView 
+{
   private:
   public:
-       DnDTreeView ();
-       ~DnDTreeView() {}
+       DnDTreeViewBase ();
+       ~DnDTreeViewBase() {}
 
-       /* this is the structure pointed to if add_object_drag() is called
-          and a drop happens on a destination which has declared itself
-          willing to accept a target of the type named in the call
-          to add_object_drag().
-       */
-       
-       struct SerializedObjectPointers {
-           uint32_t size;
-           uint32_t cnt;
-           char     type[32];
-           void*    ptr[0];
-       };
-       
        void add_drop_targets (std::list<Gtk::TargetEntry>&);
        void add_object_drag (int column, std::string type_name);
-       sigc::signal<void,std::string,uint32_t,void**> signal_object_drop;
        
-       void on_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context) {
-               TreeView::on_drag_begin (context);
-       }
-       void on_drag_end(const Glib::RefPtr<Gdk::DragContext>& context) {
-               TreeView::on_drag_end (context);
-       }
-       void on_drag_data_delete(const Glib::RefPtr<Gdk::DragContext>& context) {
-               TreeView::on_drag_data_delete (context);
-       }
        void on_drag_leave(const Glib::RefPtr<Gdk::DragContext>& context, guint time) {
-           suggested_action = context->get_suggested_action();
-           TreeView::on_drag_leave (context, time);
+               suggested_action = context->get_suggested_action();
+               TreeView::on_drag_leave (context, time);
        }
+
        bool on_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) {
                suggested_action = context->get_suggested_action();
                return TreeView::on_drag_motion (context, x, y, time);
        }
+
        bool on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time);
-       void on_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection_data, guint info, guint time);
-       void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time);
 
-  private:
+  protected:
        std::list<Gtk::TargetEntry> draggable;
        Gdk::DragAction             suggested_action;
        int                         data_column;
-       
-       SerializedObjectPointers* serialize_pointers (Glib::RefPtr<Gtk::TreeModel> m, 
-                                                     Gtk::TreeSelection::ListHandle_Path*,
-                                                     Glib::ustring type);
+};
+
+template<class DataType>
+class DnDTreeView : public DnDTreeViewBase
+{
+  public:
+       DnDTreeView() {} 
+       ~DnDTreeView() {}
+
+       sigc::signal<void,std::string,uint32_t,const DataType*> signal_object_drop;
+
+       void on_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& 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<DataType>* sr = serialize_pointers (get_model(), &selection, selection_data.get_target());
+                       selection_data.set (8, (guchar*)sr, sr->size);
+               }
+       }
+
+       void on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& 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
+                          say that we are still dragging, and that's it.
+                       */
+                       suggested_action = Gdk::DragAction (0);
+                       TreeView::on_drag_data_received (context, x, y, selection_data, info, time);
+                       return;
+               }
+               
+               if (selection_data.get_target() == "GTK_TREE_MODEL_ROW") {
+                       
+                       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<DataType>* sr = reinterpret_cast<const SerializedObjectPointers<DataType> *>(data);
+                       
+                       if (sr) {
+                               signal_object_drop (sr->type, sr->cnt, sr->data);
+                       }
+                       
+               } else {
+                       /* some kind of target type added by the app, which will be handled by a signal handler */
+               }
+       }
+
+  private:
+
+       SerializedObjectPointers<DataType>* serialize_pointers (Glib::RefPtr<Gtk::TreeModel> 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 SerializedObjectPointers<DataType object. Then we allocate a raw memory buffer that extends
+                  past that array and thus provides space for however many DataType items we actually want to pass
+                  around.
+
+                  The C++ trick is to use the placement operator new() syntax to initialize that extra
+                  memory properly.
+               */
+               
+               uint32_t cnt = selection->size();
+               uint32_t sz = (sizeof (DataType) * cnt) + sizeof (SerializedObjectPointers<DataType>);
+
+               char* buf = new char[sz];
+               SerializedObjectPointers<DataType>* sr = (SerializedObjectPointers<DataType>*) buf;
+
+               for (uint32_t i = 0; i < cnt; ++i) {
+                       new ((void *) &sr->data[i]) DataType ();
+               }
+               
+               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]);
+               }
+
+               return sr;
+       }
 };
 
 } // namespace