fixes for drag-n-drop broken by use of boost::shared_ptr<T>

git-svn-id: svn://localhost/ardour2/trunk@923 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2006-09-20 16:24:24 +00:00
parent d89e7ff299
commit 41bc62b35b
7 changed files with 156 additions and 134 deletions

View file

@ -7,6 +7,7 @@ import glob
Import('env install_prefix final_prefix config_prefix libraries i18n version') Import('env install_prefix final_prefix config_prefix libraries i18n version')
gtkardour = env.Copy() gtkardour = env.Copy()
gtkmmtests = env.Copy()
# #
# this defines the version number of the GTK interface to ardour # this defines the version number of the GTK interface to ardour
@ -49,6 +50,19 @@ gtkardour.Merge ([
libraries['jack'] 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']: if gtkardour['DMALLOC']:
gtkardour.Merge([libraries['dmalloc']]) gtkardour.Merge([libraries['dmalloc']])
gtkardour.Append(CCFLAGS='-DUSE_DMALLOC') gtkardour.Append(CCFLAGS='-DUSE_DMALLOC')
@ -213,6 +227,10 @@ stest_files=Split("""
stest.cc stest.cc
""") """)
tt_files=Split ("""
tt.cc
""")
extra_sources = [] extra_sources = []
vst_files = [ 'vst_pluginui.cc' ] 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) mtest = gtkardour.Program(target = 'mtest', source = mtest_files)
itest = gtkardour.Program(target = 'itest', source = itest_files) itest = gtkardour.Program(target = 'itest', source = itest_files)
rcu = gtkardour.Program(target = 'rcu', source = rcu_files) rcu = gtkardour.Program(target = 'rcu', source = rcu_files)
tt = gtkmmtests.Program(target = 'tt', source = tt_files)
my_subst_dict = { } my_subst_dict = { }
my_subst_dict['%INSTALL_PREFIX%'] = install_prefix my_subst_dict['%INSTALL_PREFIX%'] = install_prefix

View file

@ -702,14 +702,15 @@ class Editor : public PublicEditor
} }
Gtk::TreeModelColumn<Glib::ustring> name; Gtk::TreeModelColumn<Glib::ustring> name;
Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Region> > region; Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Region> > region;
Gtk::TreeModelColumn<Gdk::Color> color_; Gtk::TreeModelColumn<Gdk::Color> color_;
}; };
RegionListDisplayModelColumns region_list_columns; RegionListDisplayModelColumns region_list_columns;
Gtkmm2ext::DnDTreeView region_list_display; 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::TreeStore> region_list_model;
Glib::RefPtr<Gtk::ToggleAction> toggle_show_auto_regions_action; Glib::RefPtr<Gtk::ToggleAction> toggle_full_region_list_action;
Glib::RefPtr<Gtk::ToggleAction> toggle_show_auto_regions_action;
void region_list_selection_changed (); void region_list_selection_changed ();
bool region_list_selection_filter (const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path, bool yn); 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; NamedSelectionDisplayModelColumns named_selection_columns;
Glib::RefPtr<Gtk::TreeStore> named_selection_model; Glib::RefPtr<Gtk::TreeStore> named_selection_model;
Gtkmm2ext::DnDTreeView named_selection_display; Gtkmm2ext::DnDTreeView<ARDOUR::NamedSelection*> named_selection_display;
Gtk::ScrolledWindow named_selection_scroller; Gtk::ScrolledWindow named_selection_scroller;
void name_selection(); void name_selection();
@ -1429,9 +1430,9 @@ class Editor : public PublicEditor
Glib::RefPtr<Gtk::TreeSelection> route_display_selection; Glib::RefPtr<Gtk::TreeSelection> route_display_selection;
gint route_list_compare_func (Gtk::TreeModel::iterator, Gtk::TreeModel::iterator); gint route_list_compare_func (Gtk::TreeModel::iterator, Gtk::TreeModel::iterator);
Gtkmm2ext::DnDTreeView route_list_display; Gtkmm2ext::DnDTreeView<boost::shared_ptr<ARDOUR::Route> > route_list_display;
Gtk::ScrolledWindow route_list_scroller; Gtk::ScrolledWindow route_list_scroller;
Gtk::Menu* route_list_menu; Gtk::Menu* route_list_menu;
bool route_list_display_button_press (GdkEventButton*); 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); bool route_list_selection_filter (const Glib::RefPtr<Gtk::TreeModel>& model, const Gtk::TreeModel::Path& path, bool yn);

View file

@ -488,11 +488,12 @@ Editor::drop_regions (const RefPtr<Gdk::DragContext>& context,
const SelectionData& data, const SelectionData& data,
guint info, guint time) 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) { 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; boost::shared_ptr<AudioRegion> ar;
if ((ar = boost::dynamic_pointer_cast<AudioRegion>(r)) != 0) { if ((ar = boost::dynamic_pointer_cast<AudioRegion>(r)) != 0) {

View file

@ -156,9 +156,9 @@ RedirectBox::~RedirectBox ()
} }
void 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; return;
} }
@ -167,7 +167,7 @@ RedirectBox::object_drop (string type, uint32_t cnt, void** ptr)
list<boost::shared_ptr<Redirect> > redirects; list<boost::shared_ptr<Redirect> > redirects;
for (uint32_t n = 0; n < cnt; ++n) { 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); paste_redirect_list (redirects);

View file

@ -119,10 +119,10 @@ class RedirectBox : public Gtk::HBox
Gtk::EventBox redirect_eventbox; Gtk::EventBox redirect_eventbox;
Gtk::HBox redirect_hpacker; Gtk::HBox redirect_hpacker;
Gtkmm2ext::DnDTreeView redirect_display; Gtkmm2ext::DnDTreeView<boost::shared_ptr<ARDOUR::Redirect> > redirect_display;
Gtk::ScrolledWindow redirect_scroller; 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; Width _width;

View file

@ -10,7 +10,7 @@ using namespace Gtk;
using namespace Glib; using namespace Glib;
using namespace Gtkmm2ext; using namespace Gtkmm2ext;
DnDTreeView::DnDTreeView () DnDTreeViewBase::DnDTreeViewBase ()
: TreeView () : TreeView ()
{ {
draggable.push_back (TargetEntry ("GTK_TREE_MODEL_ROW", TARGET_SAME_WIDGET)); draggable.push_back (TargetEntry ("GTK_TREE_MODEL_ROW", TARGET_SAME_WIDGET));
@ -23,7 +23,7 @@ DnDTreeView::DnDTreeView ()
} }
void 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) { for (list<TargetEntry>::iterator i = targets.begin(); i != targets.end(); ++i) {
draggable.push_back (*i); draggable.push_back (*i);
@ -33,7 +33,7 @@ DnDTreeView::add_drop_targets (list<TargetEntry>& targets)
} }
void 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))); draggable.push_back (TargetEntry (type_name, TargetFlags(0)));
data_column = column; data_column = column;
@ -42,86 +42,11 @@ DnDTreeView::add_object_drag (int column, string type_name)
enable_model_drag_dest (draggable); 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 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); suggested_action = Gdk::DragAction (0);
return TreeView::on_drag_drop (context, x, y, time); return TreeView::on_drag_drop (context, x, y, time);
} }

View file

@ -9,60 +9,136 @@
namespace Gtkmm2ext { 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: private:
public: public:
DnDTreeView (); DnDTreeViewBase ();
~DnDTreeView() {} ~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_drop_targets (std::list<Gtk::TargetEntry>&);
void add_object_drag (int column, std::string type_name); 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) { void on_drag_leave(const Glib::RefPtr<Gdk::DragContext>& context, guint time) {
suggested_action = context->get_suggested_action(); suggested_action = context->get_suggested_action();
TreeView::on_drag_leave (context, time); TreeView::on_drag_leave (context, time);
} }
bool on_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) { bool on_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time) {
suggested_action = context->get_suggested_action(); suggested_action = context->get_suggested_action();
return TreeView::on_drag_motion (context, x, y, time); 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: bool on_drag_drop(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint time);
protected:
std::list<Gtk::TargetEntry> draggable; std::list<Gtk::TargetEntry> draggable;
Gdk::DragAction suggested_action; Gdk::DragAction suggested_action;
int data_column; int data_column;
};
SerializedObjectPointers* serialize_pointers (Glib::RefPtr<Gtk::TreeModel> m,
Gtk::TreeSelection::ListHandle_Path*, template<class DataType>
Glib::ustring type); 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 } // namespace