fix crash when copy'ing latent plugins
[ardour.git] / libs / gtkmm2ext / dndtreeview.cc
index f230fc42b2bd0af85a8830aa2fc007a1006a89aa..4686702074237411a6d9cf0bf6624d86e35a63ff 100644 (file)
@@ -1,4 +1,24 @@
+/*
+    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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
 #include <cstdio>
+#include <iostream>
 
 #include <gtkmm2ext/dndtreeview.h>
 
@@ -9,95 +29,115 @@ using namespace Gtk;
 using namespace Glib;
 using namespace Gtkmm2ext;
 
-DnDTreeView::DnDTreeView ()
+DnDTreeViewBase::DragData DnDTreeViewBase::drag_data;
+
+DnDTreeViewBase::DnDTreeViewBase ()
        : TreeView ()
+       , _drag_column (-1)
 {
        draggable.push_back (TargetEntry ("GTK_TREE_MODEL_ROW", TARGET_SAME_WIDGET));
-       
+       data_column = -1;
+
        enable_model_drag_source (draggable);
        enable_model_drag_dest (draggable);
-       
-       suggested_action = Gdk::DragAction (0);
+
+       suggested_action = Gdk::DragAction (0);
 }
 
 void
-DnDTreeView::add_object_drag (int column, string type_name)
-{
-       draggable.push_back (TargetEntry (type_name, TargetFlags(0)));
-       data_column = column;
+DnDTreeViewBase::on_drag_begin (Glib::RefPtr<Gdk::DragContext> const & context) {
+       if (_drag_column >= 0) {
+               /* this code is a customized drop-in replacement for
+                * Gtk::TreeView::on_drag_begin().
+                * We can use it's cleanup function for the generated Pixmap
+                */
 
-       enable_model_drag_source (draggable);
-       enable_model_drag_dest (draggable);
-}
+               TreeModel::Path path;
+               TreeViewColumn* column;
+               int cell_x;
+               int cell_y;
 
-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);
+               if (!get_path_at_pos ((int)press_start_x, (int)press_start_y, path, column, cell_x, cell_y)) {
+                       return;
+               }
+
+               TreeIter iter = get_model()->get_iter (path);
+               int x_offset, y_offset, width, height;
+
+               Gdk::Rectangle unused;
+               TreeViewColumn* clm = get_column(_drag_column);
+
+               clm->cell_set_cell_data (get_model(), iter, false, false);
+               clm->cell_get_size (unused, x_offset, y_offset, width, height);
+
+               Glib::RefPtr<Gdk::Pixmap> pixmap = Gdk::Pixmap::create (get_root_window(), width, height);
+
+               CellRenderer* cell_renderer = clm->get_first_cell ();
+               Gdk::Rectangle cell_background (0, 0, width, height);
+               Gdk::Rectangle cell_size (x_offset, y_offset, width, height);
 
-       char* buf = new char[sz];
-       SerializedObjectPointers* sr = new (buf) SerializedObjectPointers;
-       
-       sr->cnt = cnt;
-       sr->size = sz;
+               // the cell-renderer only clears the background if
+               // cell->cell_background_set and priv->cell_background
+               Gdk::Color clr = get_style()->get_bg(STATE_NORMAL);
+               // code dup from gtk_cell_renderer_render() to clear the background:
+               cairo_t *cr = gdk_cairo_create (Glib::unwrap(pixmap));
+               gdk_cairo_rectangle (cr, (cell_background).gobj());
+               gdk_cairo_set_source_color (cr, clr.gobj());
+               cairo_fill (cr);
+               cairo_destroy (cr);
 
-       snprintf (sr->type, sizeof (sr->type), "%s", type.c_str());
+               // gtkmm wants a "window", gtk itself is happy with a "drawable",
+               // cell_renderer->render (pixmap, *this, cell_area, cell_area, cell_area, 0);
+               // We ain't got no window, so use gtk directly:
+               gtk_cell_renderer_render (cell_renderer->gobj(),
+                               Glib::unwrap(pixmap), ((Gtk::Widget*)this)->gobj(),
+                               (cell_background).gobj(),
+                               (cell_size).gobj(),
+                               (cell_size).gobj(),
+                               ((GtkCellRendererState)(0)));
 
-       cnt = 0;
+               context->set_icon (pixmap->get_colormap(),
+                               pixmap, Glib::RefPtr<Gdk::Bitmap>(NULL),
+                               width / 2 + 1, cell_y + 1);
 
-       for (TreeSelection::ListHandle_Path::iterator x = selection->begin(); x != selection->end(); ++x, ++cnt) {
-               TreeModel::Row row = *(model->get_iter (*x));
-               row.get_value (data_column, sr->ptr[cnt]);
+       } else {
+               Gtk::TreeView::on_drag_begin (context);
        }
-       
-       return sr;
+       start_object_drag ();
 }
 
 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 {
-               
-               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);
-               
-       }
+DnDTreeViewBase::on_drag_end (Glib::RefPtr<Gdk::DragContext> const & context) {
+       Gtk::TreeView::on_drag_end (context);
+       end_object_drag ();
 }
 
-void 
-DnDTreeView::on_drag_data_received(const RefPtr<DragContext>& context, int x, int y, const SelectionData& selection_data, guint info, guint time)
+void
+DnDTreeViewBase::add_drop_targets (list<TargetEntry>& targets)
 {
-       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 {
-               /* 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));
-               }
-               
-               context->drag_finish (true, false, time);
-               
+       for (list<TargetEntry>::iterator i = targets.begin(); i != targets.end(); ++i) {
+               draggable.push_back (*i);
        }
+
+       enable_model_drag_source (draggable);
+       enable_model_drag_dest (draggable);
 }
 
+void
+DnDTreeViewBase::add_object_drag (int column, string type_name)
+{
+       draggable.push_back (TargetEntry (type_name, TargetFlags(0)));
+       data_column = column;
+       object_type = type_name;
 
+       enable_model_drag_source (draggable);
+       enable_model_drag_dest (draggable);
+}
+
+bool
+DnDTreeViewBase::on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time)
+{
+       suggested_action = Gdk::DragAction (0);
+       drag_data.source = 0;
+       return TreeView::on_drag_drop (context, x, y, time);
+}