}
void
-ARDOUR_UI::update_sample_rate (nframes_t ignored)
+ARDOUR_UI::update_sample_rate (nframes_t)
{
char buf[32];
ghost->set_colors();
ghosts.push_back (ghost);
- ghost->GoingAway.connect (*this, ui_bind (&RegionView::remove_ghost, this, _1), gui_context());
+ ghost->CatchDeletion.connect (*this, ui_bind (&RegionView::remove_ghost, this, _1), gui_context());
return ghost;
}
/* catch region going away */
- r->GoingAway.connect (*this, boost::bind (&AudioStreamView::remove_region_view, this, boost::weak_ptr<Region> (r)), gui_context());
+ r->DropReferences.connect (*this, boost::bind (&AudioStreamView::remove_region_view, this, boost::weak_ptr<Region> (r)), gui_context());
RegionViewAdded (region_view);
display_region(region_view);
/* catch regionview going away */
- region->GoingAway.connect (*this, boost::bind (&AutomationStreamView::remove_region_view, this, boost::weak_ptr<Region>(region)), gui_context());
+ region->DropReferences.connect (*this, boost::bind (&AutomationStreamView::remove_region_view, this, boost::weak_ptr<Region>(region)), gui_context());
RegionViewAdded (region_view);
using namespace ARDOUR;
list<Gdk::Color> AxisView::used_colors;
+PBD::Signal1<void,AxisView*> AxisView::CatchDeletion;
AxisView::AxisView (ARDOUR::Session* sess)
: SessionHandlePtr (sess)
AxisView::~AxisView()
{
-
}
Gdk::Color
#include <gdkmm/color.h>
#include "pbd/xml++.h"
-#include "pbd/destructible.h"
+#include "pbd/signals.h"
#include "ardour/session_handle.h"
* AxisView defines the abstract base class for time-axis trackviews and routes.
*
*/
-class AxisView : public virtual Selectable, public PBD::Destructible, public PBD::ScopedConnectionList, public ARDOUR::SessionHandlePtr
+class AxisView : public virtual Selectable, public PBD::ScopedConnectionList, public ARDOUR::SessionHandlePtr
{
public:
/**
virtual void set_marked_for_display (bool yn) {
_marked_for_display = yn;
}
+
+ static PBD::Signal1<void,AxisView*> CatchDeletion;
sigc::signal<void> Hiding;
using namespace Gnome;
using namespace Canvas;
-PBD::Signal1<void,CrossfadeView*> CrossfadeView::GoingAway;
+PBD::Signal1<void,CrossfadeView*> CrossfadeView::CatchDeletion;
CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent,
RouteTimeAxisView &tv,
CrossfadeView::~CrossfadeView ()
{
- GoingAway (this) ; /* EMIT_SIGNAL */
+ CatchDeletion (this) ; /* EMIT_SIGNAL */
}
void
bool visible() const { return _visible; }
void set_valid (bool yn);
- static PBD::Signal1<void,CrossfadeView*> GoingAway;
+ static PBD::Signal1<void,CrossfadeView*> CatchDeletion;
AudioRegionView& upper_regionview () const;
rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
rtv->view()->HeightChanged.connect (sigc::mem_fun (*this, &Editor::streamview_height_changed));
- rtv->GoingAway.connect (*this, boost::bind (&Editor::remove_route, this, rtv), gui_context());
+ route->DropReferences.connect (*this, boost::bind (&Editor::remove_route, this, rtv), gui_context());
}
_routes->routes_added (new_views);
TimeAxisView* next_tv = 0;
+ _routes->route_removed (tv);
+
if (tv == entered_track) {
entered_track = 0;
}
ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
}
}
+
}
void
}
/* </CMT Additions file="editor.cc"> */
-
-
-
-
-
/* <CMT Additions file="editor_canvas_events.cc"> */
bool
Editor::canvas_imageframe_item_view_event (GdkEvent *event, ArdourCanvas::Item* item, ImageFrameView *ifv)
row[route_display_columns.tv] = iftav;
route_list_display.get_selection()->select (row);
- iftav->GoingAway.connect (*this, boost::bind (&Editor::remove_route, this, (TimeAxisView*)iftav), gui_context());
+ iftav->CatchDeletion.connect (*this, boost::bind (&Editor::remove_route, this, (TimeAxisView*)iftav), gui_context());
iftav->gui_changed.connect(sigc::mem_fun(*this, &Editor::handle_gui_changes)) ;
}
row[route_display_columns.tv] = mta;
route_list_display.get_selection()->select (row);
- mta->GoingAway.connect (*this, boost::bind (&Editor::remove_route, this, (TimeAxisView*)mta), gui_context());
+ mta->CatchDeletion.connect (*this, boost::bind (&Editor::remove_route, this, (TimeAxisView*)mta), gui_context());
}
}
void
-Editor::location_flags_changed (Location *location, void *src)
+Editor::location_flags_changed (Location *location, void*)
{
ENSURE_GUI_THREAD (*this, &Editor::location_flags_changed, location, src)
}
void
-Editor::refresh_location_display_s (Change ignored)
+Editor::refresh_location_display_s (Change)
{
ENSURE_GUI_THREAD (*this, &Editor::refresh_location_display_s, ignored)
_session,
false);
current_mixer_strip->Hiding.connect (sigc::mem_fun(*this, &Editor::current_mixer_strip_hidden));
- current_mixer_strip->GoingAway.connect (*this, boost::bind (&Editor::current_mixer_strip_removed, this), gui_context());
+ current_mixer_strip->CatchDeletion.connect (*this, boost::bind (&Editor::current_mixer_strip_removed, this), gui_context());
#ifdef GTKOSX
current_mixer_strip->WidthChanged.connect (sigc::mem_fun(*this, &Editor::ensure_all_elements_drawn));
#endif
playhead_cursor->canvas_item.hide ();
- /* hide all tracks */
-
- _routes->hide_all_tracks (false);
-
/* rip everything out of the list displays */
_regions->clear ();
_routes->clear ();
_route_groups->clear ();
+ for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ delete *i;
+ }
+ track_views.clear ();
+
zoom_range_clock.set_session (0);
nudge_clock.set_session (0);
}
void
-EditorRouteGroups::flags_changed (void* src, RouteGroup* group)
+EditorRouteGroups::flags_changed (void*, RouteGroup* group)
{
ENSURE_GUI_THREAD (*this, &EditorRouteGroups::flags_changed, src, group)
void
EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
{
- /* this could require an order reset & sync */
+ if (!_session || _session->deletion_in_progress()) {
+ return;
+ }
+
+ /* this could require an order reset & sync */
_session->set_remote_control_ids();
_ignore_reorder = true;
redisplay ();
_ignore_reorder = false;
}
-
void
EditorRoutes::visible_changed (Glib::ustring const & path)
{
+ if (_session && _session->deletion_in_progress()) {
+ return;
+ }
+
TreeIter iter;
if ((iter = _model->get_iter (path))) {
(*x)->route()->gui_changed.connect (*this, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
(*x)->route()->NameChanged.connect (*this, boost::bind (&EditorRoutes::route_name_changed, this, wr), gui_context());
- (*x)->GoingAway.connect (*this, boost::bind (&EditorRoutes::route_removed, this, *x), gui_context());
if ((*x)->is_track()) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
}
void
-EditorRoutes::handle_gui_changes (string const & what, void *src)
+EditorRoutes::handle_gui_changes (string const & what, void*)
{
ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
void redisplay ();
void update_visibility ();
void routes_added (std::list<RouteTimeAxisView*> routes);
+ void route_removed (TimeAxisView *);
void hide_track_in_display (TimeAxisView &);
std::list<TimeAxisView*> views () const;
void hide_all_tracks (bool);
void reordered (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int *);
bool button_press (GdkEventButton *);
void route_name_changed (boost::weak_ptr<ARDOUR::Route>);
- void route_removed (TimeAxisView *);
void handle_gui_changes (std::string const &, void *);
void update_rec_display ();
void update_mute_display ();
}
void
-Editor::add_named_selection_to_named_selection_display (NamedSelection& selection)
+Editor::add_named_selection_to_named_selection_display (boost::shared_ptr<NamedSelection> selection)
{
TreeModel::Row row = *(named_selection_model->append());
row[named_selection_columns.text] = selection.name;
- row[named_selection_columns.selection] = &selection;
+ row[named_selection_columns.selection] = selection;
}
void
return;
}
- new NamedSelection (name, thelist); // creation will add it to the model
-
+ boost::shared_ptr<NamedSelection> ns (new NamedSelection (name, thelist));
+
/* make the one we just added be selected */
TreeModel::Children::iterator added = named_selection_model->children().end();
--added;
named_selection_display.get_selection()->select (*added);
+
} else {
error << _("No selectable material found in the currently selected time range") << endmsg;
}
return;
}
- ENSURE_GUI_THREAD (*this, &Editor::tempo_map_changed, ignored)
+ ENSURE_GUI_THREAD (*this, &Editor::tempo_map_changed ignored);
- if (tempo_lines)
+ if (tempo_lines) {
tempo_lines->tempo_map_changed();
+ }
compute_current_bbt_points(leftmost_frame, leftmost_frame + current_page_frames());
_session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers
using namespace ArdourCanvas;
using namespace ARDOUR;
-PBD::Signal1<void,GhostRegion*> GhostRegion::GoingAway;
+PBD::Signal1<void,GhostRegion*> GhostRegion::CatchDeletion;
GhostRegion::GhostRegion (ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxisView& source_tv, double initial_pos)
: trackview (tv)
GhostRegion::~GhostRegion ()
{
- GoingAway (this);
+ CatchDeletion (this);
delete base_rect;
delete group;
}
class MidiStreamView;
class TimeAxisView;
-class GhostRegion
+class GhostRegion
{
public:
GhostRegion(ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxisView& source_tv, double initial_unit_pos);
ArdourCanvas::Group* group;
ArdourCanvas::SimpleRect* base_rect;
- static PBD::Signal1<void,GhostRegion*> GoingAway;
+ static PBD::Signal1<void,GhostRegion*> CatchDeletion;
};
class AudioGhostRegion : public GhostRegion {
#ifndef __ardour_gtk_gui_thread_h__
#define __ardour_gtk_gui_thread_h__
+#include <cstdlib>
#include <gtkmm2ext/gtk_ui.h>
#include <boost/bind.hpp>
#include <boost/bind/protect.hpp>
-#define ENSURE_GUI_THREAD(obj,method, ...) \
- if (!Gtkmm2ext::UI::instance()->caller_is_self()) { \
- Gtkmm2ext::UI::instance()->call_slot (boost::bind ((method), &(obj), ## __VA_ARGS__)); \
- return;\
- }
+#define ENSURE_GUI_THREAD(obj,method, ...) if (!Gtkmm2ext::UI::instance()->caller_is_self()) { abort (); }
#define gui_context() Gtkmm2ext::UI::instance() /* a UICallback-derived object that specifies the event loop for GUI signal handling */
#define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__))
*/
ImageFrameTimeAxis::~ImageFrameTimeAxis ()
{
- GoingAway ; /* EMIT_SIGNAL */
+ CatchDeletion (this);
// Destroy all the marker views we may have associaited with this TimeAxis
for(MarkerTimeAxisList::iterator iter = marker_time_axis_list.begin(); iter != marker_time_axis_list.end(); ++iter)
else
{
marker_time_axis_list.push_back(marker_track) ;
- marker_track->GoingAway.connect (*this, boost::bind (&ImageFrameTimeAxis::remove_time_axis_view, this, marker_track, (void*)this), gui_context());
+ marker_track->CatchDeletion.connect (*this, boost::bind (&ImageFrameTimeAxis::remove_time_axis_view, this, marker_track, (void*)this), gui_context());
MarkerTimeAxisAdded(marker_track, src) ; /* EMIT_SIGNAL */
ret = true ;
using namespace ARDOUR ;
+PBD::Signal1<void,ImageFrameTimeAxisGroup*> ImageFrameTimeAxisGroup::CatchDeletion;
+
//---------------------------------------------------------------------------------------//
// Constructor / Desctructor
iter = next ;
}
- GoingAway ; /* EMIT_SIGNAL */
+ CatchDeletion ; /* EMIT_SIGNAL */
}
imageframe_views.push_front(ifv) ;
- ifv->GoingAway.connect (*this, boost::bind (&ImageFrameTimeAxisGroup::remove_imageframe_item, this, (void*)this), gui_context());
+ ifv->CatchDeletion.connect (*this, boost::bind (&ImageFrameTimeAxisGroup::remove_imageframe_item, this, (void*)this), gui_context());
ImageFrameAdded(ifv, src) ; /* EMIT_SIGNAL */
}
//---------------------------------------------------------------------------------//
// Emitted Signals
- sigc::signal<void> GoingAway ;
+ static sigc::signal<void,ImageFrameTimeAxisGroup*> CatchDeletion;
/**
* Emitted when this Group has been removed
- * This is different to the GoingAway signal in that this signal
+ * This is different to the CatchDeletion signal in that this signal
* is emitted during the deletion of this Time Axis, and not during
* the destructor, this allows us to capture the source of the deletion
* event
imageframe_groups.push_front(iftag) ;
- iftag->GoingAway.connect (*this, boost::bind (&ImageFrameTimeAxisView::remove_imageframe_group, this, iftag, (void*)this), gui_context());
+ iftag->CatchDeletion.connect (*this, boost::bind (&ImageFrameTimeAxisView::remove_imageframe_group, this, iftag, (void*)this), gui_context());
ImageFrameGroupAdded(iftag, src) ; /* EMIT_SIGNAL */
}
*/
ImageFrameView::~ImageFrameView()
{
- GoingAway (this);
+ CatchDeletion (this);
// destroy any marker items we have associated with this item
{
marker_view_list.push_back(item) ;
- item->GoingAway.connect (*this, boost::bind (&ImageFrameView::remove_marker_view_item, this, (void*)this), gui_context());
+ item->CatchDeletion.connect (*this, boost::bind (&ImageFrameView::remove_marker_view_item, this, (void*)this), gui_context());
MarkerViewAdded(item, src) ; /* EMIT_SIGNAL */
}
*/
~ImageFrameView() ;
- static sigc::signal<void,ImageFrameView*> GoingAway;
+ static PBD::Signal1<void,ImageFrameView*> CatchDeletion;
//---------------------------------------------------------------------------------------//
// Position and duration Accessors/Mutators
signal_delete_event().connect (sigc::mem_fun (*this, &PortInsertWindow::wm_delete), false);
- pi->GoingAway.connect (going_away_connection, boost::bind (&PortInsertWindow::plugin_going_away, this), gui_context());
+ pi->DropReferences.connect (going_away_connection, boost::bind (&PortInsertWindow::plugin_going_away, this), gui_context());
}
bool
using namespace std;
using namespace ARDOUR;
+PBD::Signal1<void,Marker*> Marker::CatchDeletion;
+
Marker::Marker (PublicEditor& ed, ArdourCanvas::Group& parent, guint32 rgba, const string& annotation,
Type type, nframes_t frame, bool handle_events)
Marker::~Marker ()
{
- drop_references ();
+ CatchDeletion (this); /* EMIT SIGNAL */
/* destroying the parent group destroys its contents, namely any polygons etc. that we added */
delete name_pixbuf;
#include <glib.h>
#include <libgnomecanvasmm/pixbuf.h>
+#include <sigc++/signal.h>
#include "ardour/ardour.h"
-#include "pbd/destructible.h"
+#include "pbd/signals.h"
#include "canvas.h"
class PublicEditor;
-class Marker : public PBD::Destructible
+class Marker : public sigc::trackable
{
public:
enum Type {
virtual ~Marker ();
+ static PBD::Signal1<void,Marker*> CatchDeletion;
+
ArdourCanvas::Item& the_item() const;
void add_line (ArdourCanvas::Group*, double y_origin, double initial_height);
*/
MarkerTimeAxis::~MarkerTimeAxis()
{
- GoingAway ; /* EMIT_SIGNAL */
+ CatchDeletion (this); /* EMIT_SIGNAL */
// destroy the view helper
// this handles removing and destroying individual marker items
ifv->add_marker_view_item(mv, src) ;
marker_view_list.push_front(mv) ;
- mv->GoingAway.connect (*this, boost::bind (&MarkerTimeAxisView::remove_marker_view, this, (void*)this), gui_context());
-
- MarkerViewAdded(mv,src) ; /* EMIT_SIGNAL */
+ mv->CatchDeletion.connect (*this, boost::bind (&MarkerTimeAxisView::remove_marker_view, this, _1), gui_context());
+
+ MarkerViewAdded(mv,src) ; /* EMIT_SIGNAL */
return(mv) ;
}
* @param src the identity of the object that initiated the change
*/
void
-MarkerTimeAxisView::remove_marker_view(MarkerView* mv, void* src)
+MarkerTimeAxisView::remove_marker_view(MarkerView* mv)
{
ENSURE_GUI_THREAD (*this, &MarkerTimeAxisView::remove_marker_view, mv, src)
using namespace ARDOUR ;
-sigc::signal<void,MarkerView*> MarkerView::GoingAway;
+PBD::Signal1<void,MarkerView*> MarkerView::CatchDeletion
//---------------------------------------------------------------------------------------//
// Constructor / Desctructor
*/
~MarkerView() ;
- static sigc::signal<void,MarkerView*> GoingAway;
+ static PBD::Signal1<void,MarkerView*> CatchDeletion;
//---------------------------------------------------------------------------------------//
// Marker Type Methods
}
}
- ghost->GoingAway.connect (*this, ui_bind (&RegionView::remove_ghost, this, _1), gui_context());
+ ghost->CatchDeletion.connect (*this, ui_bind (&RegionView::remove_ghost, this, _1), gui_context());
return ghost;
}
display_region (region_view, wfd);
/* catch regionview going away */
- region->GoingAway.connect (*this, boost::bind (&MidiStreamView::remove_region_view, this, region), gui_context());
+ region->DropReferences.connect (*this, boost::bind (&MidiStreamView::remove_region_view, this, region), gui_context());
RegionViewAdded (region_view);
MixerStrip::~MixerStrip ()
{
- drop_references ();
+ CatchDeletion (this);
delete input_selector;
delete output_selector;
_current_delivery = send;
send->set_metering (true);
- _current_delivery->GoingAway.connect (send_gone_connection, boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
+ _current_delivery->DropReferences.connect (send_gone_connection, boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
gain_meter().set_controls (_route, send->meter(), send->amp());
gain_meter().setup_meters ();
}
route->NameChanged.connect (*this, boost::bind (&Mixer_UI::strip_name_changed, this, strip), gui_context());
+ route->DropReferences.connect (*this, boost::bind (&Mixer_UI::remove_strip, this, strip), gui_context());
- strip->GoingAway.connect (*this, boost::bind (&Mixer_UI::remove_strip, this, strip), gui_context());
strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
}
group_model->clear ();
_selection.clear ();
+ track_model->clear ();
+
+ for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
+ delete (*i);
+ }
WindowTitle title(Glib::get_application_name());
title += _("Mixer");
add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window*> (this)), false);
- insert->GoingAway.connect (death_connection, boost::bind (&PluginUIWindow::plugin_going_away, this), gui_context());
+ insert->DropReferences.connect (death_connection, boost::bind (&PluginUIWindow::plugin_going_away, this), gui_context());
gint h = _pluginui->get_preferred_height ();
gint w = _pluginui->get_preferred_width ();
plugin_analysis_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_plugin_analysis));
plugin_analysis_expander.set_expanded(false);
- insert->GoingAway.connect (death_connection, boost::bind (&PlugUIBase::plugin_going_away, this), gui_context());
+ insert->DropReferences.connect (death_connection, boost::bind (&PlugUIBase::plugin_going_away, this), gui_context());
}
PlugUIBase::~PlugUIBase()
_route = r;
_route->processors_changed.connect (connections, ui_bind (&ProcessorBox::route_processors_changed, this, _1), gui_context());
- _route->GoingAway.connect (connections, boost::bind (&ProcessorBox::route_going_away, this), gui_context());
+ _route->DropReferences.connect (connections, boost::bind (&ProcessorBox::route_going_away, this), gui_context());
_route->NameChanged.connect (connections, boost::bind (&ProcessorBox::route_name_changed, this), gui_context());
redisplay_processors ();
, wait_for_data(false)
, _time_converter(r->session().tempo_map(), r->position())
{
- cerr << "RV " << this << " has ref on region " << _region->name() << endl;
}
RegionView::RegionView (const RegionView& other)
valid = false;
_pixel_width = other._pixel_width;
_height = other._height;
- cerr << "RV " << this << " has ref on region " << _region->name() << endl;
}
RegionView::RegionView (const RegionView& other, boost::shared_ptr<Region> other_region)
valid = false;
_pixel_width = other._pixel_width;
_height = other._height;
- cerr << "RV " << this << " has ref on region " << _region->name() << endl;
}
RegionView::RegionView (ArdourCanvas::Group* parent,
, wait_for_data(false)
, _time_converter(r->session().tempo_map(), r->position())
{
- cerr << "RV " << this << " has ref on region " << _region->name() << endl;
}
void
set_name ("ReturnUIWindow");
- r->GoingAway.connect (going_away_connection, boost::bind (&ReturnUIWindow::return_going_away, this), gui_context());
+ r->DropReferences.connect (going_away_connection, boost::bind (&ReturnUIWindow::return_going_away, this), gui_context());
signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
}
//route_select_list.rows().back().select ();
route->NameChanged.connect (*this, boost::bind (&RouteParams_UI::route_name_changed, this, boost::weak_ptr<Route>(route)), gui_context());
- route->GoingAway.connect (*this, boost::bind (&RouteParams_UI::route_removed, this, boost::weak_ptr<Route>(route)), gui_context());
+ route->DropReferences.connect (*this, boost::bind (&RouteParams_UI::route_removed, this, boost::weak_ptr<Route>(route)), gui_context());
}
}
SendUI *send_ui = new SendUI (this, send, _session);
cleanup_view();
- send->GoingAway.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::processor_going_away, this, boost::weak_ptr<Processor>(proc)), gui_context());
+ send->DropReferences.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::processor_going_away, this, boost::weak_ptr<Processor>(proc)), gui_context());
_active_view = send_ui;
redir_hpane.add2 (*_active_view);
ReturnUI *return_ui = new ReturnUI (this, retrn, _session);
cleanup_view();
- retrn->GoingAway.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::processor_going_away, this, boost::weak_ptr<Processor>(proc)), gui_context());
+ retrn->DropReferences.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::processor_going_away, this, boost::weak_ptr<Processor>(proc)), gui_context());
_active_view = return_ui;
redir_hpane.add2 (*_active_view);
GenericPluginUI *plugin_ui = new GenericPluginUI (plugin_insert, true);
cleanup_view();
- plugin_insert->plugin()->GoingAway.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::plugin_going_away, this, PreFader), gui_context());
+ plugin_insert->plugin()->DropReferences.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::plugin_going_away, this, PreFader), gui_context());
plugin_ui->start_updating (0);
_active_view = plugin_ui;
PortInsertUI *portinsert_ui = new PortInsertUI (this, _session, port_insert);
cleanup_view();
- port_insert->GoingAway.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::processor_going_away, this, boost::weak_ptr<Processor> (proc)), gui_context());
+ port_insert->DropReferences.connect (_processor_going_away_connection, boost::bind (&RouteParams_UI::processor_going_away, this, boost::weak_ptr<Processor> (proc)), gui_context());
_active_view = portinsert_ui;
redir_hpane.pack2 (*_active_view);
{
if (find (routes.begin(), routes.end(), r) == routes.end()) {
routes.push_back (r);
- r->GoingAway.connect (*this, boost::bind (&RouteRedirectSelection::removed, this, boost::weak_ptr<Route>(r)), gui_context());
+ r->DropReferences.connect (*this, boost::bind (&RouteRedirectSelection::removed, this, boost::weak_ptr<Route>(r)), gui_context());
RoutesChanged();
}
}
RouteTimeAxisView::~RouteTimeAxisView ()
{
- drop_references ();
- drop_connections ();
+ CatchDeletion (this);
for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
delete *i;
RouteUI::~RouteUI()
{
- /* derived classes should emit GoingAway so that they receive the signal
- when the object is still a legal derived instance.
- */
-
delete solo_menu;
delete mute_menu;
delete sends_menu;
cerr << "\n\nExpect to see route " << _route->name() << " be deleted\n";
_route.reset (); /* drop reference to route, so that it can be cleaned up */
-
route_connections.drop_connections ();
delete_when_idle (this);
}
}
if (self_destruct) {
- rp->GoingAway.connect (route_connections, boost::bind (&RouteUI::self_delete, this), gui_context());
+ rp->DropReferences.connect (route_connections, boost::bind (&RouteUI::self_delete, this), gui_context());
}
-
+
mute_button->set_controllable (_route->mute_control());
solo_button->set_controllable (_route->solo_control());
if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
- track->GoingAway.connect (*this, boost::bind (pmf, this, track), gui_context());
+ track->CatchDeletion.connect (*this, boost::bind (pmf, this, track), gui_context());
tracks.push_back (track);
} else {
tracks.erase (i);
for (list<TimeAxisView*>::const_iterator i = added.begin(); i != added.end(); ++i) {
void (Selection::*pmf)(TimeAxisView*) = &Selection::remove;
- (*i)->GoingAway.connect (*this, boost::bind (pmf, this, (*i)), gui_context());
+ (*i)->CatchDeletion.connect (*this, boost::bind (pmf, this, (*i)), gui_context());
}
if (!added.empty()) {
void (Selection::*pmf)(Marker*) = &Selection::remove;
- m->GoingAway.connect (*this, boost::bind (pmf, this, m), gui_context());
+ m->CatchDeletion.connect (*this, boost::bind (pmf, this, _1), gui_context());
markers.push_back (m);
MarkersChanged();
set_name ("SendUIWindow");
- s->GoingAway.connect (going_away_connection, boost::bind (&SendUIWindow::send_going_away, this), gui_context());
+ s->DropReferences.connect (going_away_connection, boost::bind (&SendUIWindow::send_going_away, this), gui_context());
signal_delete_event().connect (sigc::bind (
sigc::ptr_fun (just_hide_it),
if(gr) {
ghosts.push_back(gr);
- gr->GoingAway.connect (*this, ui_bind (&TimeAxisView::erase_ghost, this, _1), gui_context());
+ gr->CatchDeletion.connect (*this, ui_bind (&TimeAxisView::erase_ghost, this, _1), gui_context());
}
}
/**
* Emitted when this Group has been removed
- * This is different to the GoingAway signal in that this signal
+ * This is different to the CatchDeletion signal in that this signal
* is emitted during the deletion of this Time Axis, and not during
* the destructor, this allows us to capture the source of the deletion
* event
/**
* Emitted when this Visual Time Axis has been removed
- * This is different to the GoingAway signal in that this signal
+ * This is different to the CatchDeletion signal in that this signal
* is emitted during the deletion of this Time Axis, and not during
* the destructor, this allows us to capture the source of the deletion
* event
/* named selections */
- NamedSelection* named_selection_by_name (std::string name);
- void add_named_selection (NamedSelection *);
- void remove_named_selection (NamedSelection *);
+ boost::shared_ptr<NamedSelection> named_selection_by_name (std::string name);
+ void add_named_selection (boost::shared_ptr<NamedSelection>);
+ void remove_named_selection (boost::shared_ptr<NamedSelection>);
- template<class T> void foreach_named_selection (T& obj, void (T::*func)(NamedSelection&));
+ template<class T> void foreach_named_selection (T& obj, void (T::*func)(boost::shared_ptr<NamedSelection>));
PBD::Signal0<void> NamedSelectionAdded;
PBD::Signal0<void> NamedSelectionRemoved;
/* NAMED SELECTIONS */
mutable Glib::Mutex named_selection_lock;
- typedef std::set<NamedSelection *> NamedSelectionList;
+ typedef std::set<boost::shared_ptr<NamedSelection> > NamedSelectionList;
NamedSelectionList named_selections;
int load_named_selections (const XMLNode&);
protected:
ARDOUR::Session& _session;
virtual void session_going_away ();
+ virtual void insanity_check ();
};
class SessionHandlePtr
continue; /* XXX is this OK? */
}
- region->GoingAway.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
+ region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
_last_capture_regions.push_back (region);
AudioPlaylist::~AudioPlaylist ()
{
- drop_references ();
-
- /* drop connections to signals */
-
_crossfades.clear ();
}
AutomationList::~AutomationList()
{
- drop_references ();
}
boost::shared_ptr<Evoral::ControlList>
CoreAudioSource::~CoreAudioSource ()
{
- drop_references ();
}
int
non_realtime_input_change ();
set_align_style_from_io ();
- _route->GoingAway.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this));
+ _route->Destroyed.connect_same_thread (*this, boost::bind (&Diskstream::route_going_away, this));
}
void
}
_playlist->Modified.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_modified, this));
- _playlist->GoingAway.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
+ _playlist->DropReferences.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_deleted, this, boost::weak_ptr<Playlist>(_playlist)));
_playlist->RangesMoved.connect_same_thread (playlist_connections, boost::bind (&Diskstream::playlist_ranges_moved, this, _1));
}
set_name (sendto->name());
- _send_to->GoingAway.connect_same_thread (*this, boost::bind (&InternalSend::send_to_going_away, this));
+ _send_to->DropReferences.connect_same_thread (*this, boost::bind (&InternalSend::send_to_going_away, this));
_send_to->NameChanged.connect_same_thread (*this, boost::bind (&InternalSend::send_to_name_changed, this));
}
deactivate ();
cleanup ();
- drop_references ();
-
/* XXX who should close a plugin? */
// dlclose (module);
deactivate ();
cleanup ();
- drop_references ();
-
slv2_instance_free(_instance);
slv2_value_free(_name);
slv2_value_free(_author);
continue; /* XXX is this OK? */
}
- region->GoingAway.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
+ region->DropReferences.connect_same_thread (*this, boost::bind (&Diskstream::remove_region_from_last_capture, this, boost::weak_ptr<Region>(region)));
_last_capture_regions.push_back (region);
MidiPlaylist::~MidiPlaylist ()
{
- drop_references ();
-
- /* drop connections to signals */
}
template<typename Time>
bool
MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port)
{
+ DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", port->name()));
+
if (ioc & ~IO_IN) {
return false;
}
(*i)->set_name (new_name);
(*i)->use();
}
-
- NamedSelectionCreated (this);
}
NamedSelection::NamedSelection (Session& session, const XMLNode& node)
NamedSelection::~NamedSelection ()
{
for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
- (*i)->release ();
+ /* XXX who really owns these? us or the session? */
(*i)->drop_references ();
+ (*i)->release ();
}
}
PluginInsert::~PluginInsert ()
{
- drop_references ();
}
void
PortInsert::~PortInsert ()
{
- drop_references ();
}
void
_sources.push_back (src);
_master_sources.push_back (src);
- src->GoingAway.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
+ src->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(src)));
assert(_sources.size() > 0);
_positional_lock_style = AudioTime;
Region::~Region ()
{
DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
- drop_references ();
}
void
Region::source_deleted (boost::weak_ptr<Source>)
{
_sources.clear ();
- cerr << "Send drop ref signal from region " << ' ' << this << endl;
+
+ /* this is a very special case: at least one of the region's
+ sources has bee deleted, so invalidate all references to
+ ourselves.
+ */
+
drop_references ();
}
for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
_sources.push_back (*i);
- (*i)->GoingAway.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
+ (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
unique_srcs.insert (*i);
}
for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
_master_sources.push_back (*i);
if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->GoingAway.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
+ (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
}
}
}
Return::~Return ()
{
- drop_references ();
}
XMLNode&
// XXX: do we want to emit the signal here ? change call order.
processor->activate ();
}
+
processor->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false));
_output->set_user_latency (0);
routes->push_back (r);
r->join_route_group (this);
- r->GoingAway.connect_same_thread (*this, boost::bind (&RouteGroup::remove_when_going_away, this, boost::weak_ptr<Route> (r)));
+ r->DropReferences.connect_same_thread (*this, boost::bind (&RouteGroup::remove_when_going_away, this, boost::weak_ptr<Route> (r)));
_session.set_dirty ();
changed (); /* EMIT SIGNAL */
Send::~Send ()
{
- drop_references ();
}
void
AudioDiskstream::free_working_buffers();
- DEBUG_TRACE (DEBUG::Destruction, "delete named selections\n");
- for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ) {
- NamedSelectionList::iterator tmp;
+ /* tell everyone who is still standing that we're about to die */
+ drop_references ();
- tmp = i;
- ++tmp;
+ /* tell everyone to drop references and delete objects as we go */
- delete *i;
- i = tmp;
- }
+ DEBUG_TRACE (DEBUG::Destruction, "delete named selections\n");
+ named_selections.clear ();
DEBUG_TRACE (DEBUG::Destruction, "delete regions\n");
- for (RegionList::iterator i = regions.begin(); i != regions.end(); ) {
- RegionList::iterator tmp;
-
- tmp = i;
- ++tmp;
-
- boost::shared_ptr<Region> keep (i->second);
-
- DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for region %1 (%2); pre-ref = %3\n", i->second->name(), i->second.get(), i->second.use_count()));
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for region %1 ; pre-ref = %2\n", i->second->name(), i->second.use_count()));
i->second->drop_references ();
- DEBUG_TRACE(DEBUG::Destruction, string_compose ("region post ref = %1\n", i->second.use_count()));
- i = tmp;
}
-
regions.clear ();
DEBUG_TRACE (DEBUG::Destruction, "delete routes\n");
{
RCUWriter<RouteList> writer (routes);
boost::shared_ptr<RouteList> r = writer.get_copy ();
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for route %1 ; pre-ref = %2\n", (*i)->name(), (*i).use_count()));
(*i)->drop_references ();
}
+
r->clear ();
/* writer goes out of scope and updates master */
}
DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for diskstream %1 ; pre-ref = %2\n", (*i)->name(), (*i).use_count()));
(*i)->drop_references ();
}
+
dsl->clear ();
}
diskstreams.flush ();
DEBUG_TRACE (DEBUG::Destruction, "delete sources\n");
- for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
- SourceMap::iterator tmp;
-
- tmp = i;
- ++tmp;
-
+ for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for source %1 ; pre-ref = %2\n", i->second->path(), i->second.use_count()));
i->second->drop_references ();
-
- i = tmp;
}
sources.clear ();
-
DEBUG_TRACE (DEBUG::Destruction, "delete route groups\n");
for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
+
delete *i;
}
/* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
playlists.reset ();
- /* tell everyone who is still standing that we're about to die */
-
- drop_references ();
-
boost_debug_list_ptrs ();
DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
}
region->StateChanged.connect_same_thread (*this, boost::bind (&Session::region_changed, this, _1, boost::weak_ptr<Region>(region)));
- region->GoingAway.connect_same_thread (*this, boost::bind (&Session::remove_region, this, boost::weak_ptr<Region>(region)));
-
update_region_name_map (region);
}
}
if (result.second) {
- source->GoingAway.connect_same_thread (*this, boost::bind (&Session::remove_source, this, boost::weak_ptr<Source> (source)));
set_dirty();
}
return;
}
- bool existing = playlists->add (playlist);
- if (!existing) {
- playlist->GoingAway.connect_same_thread (*this, boost::bind (&Session::remove_playlist, this, boost::weak_ptr<Playlist>(playlist)));
- }
+ playlists->add (playlist);
if (unused) {
playlist->release();
void
Session::add_processor (Processor* processor)
{
- processor->GoingAway.connect_same_thread (*this, boost::bind (&Session::remove_processor, this, processor));
+ /* Session does not own Processors (they belong to a Route) but we do want to track
+ the arrival and departure of port inserts, sends and returns for naming
+ purposes.
+ */
+ processor->DropReferences.connect_same_thread (*this, boost::bind (&Session::remove_processor, this, processor));
set_dirty();
}
/* Named Selection management */
-NamedSelection *
+boost::shared_ptr<NamedSelection>
Session::named_selection_by_name (string name)
{
Glib::Mutex::Lock lm (named_selection_lock);
for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) {
if ((*i)->name == name) {
- return* i;
+ return *i;
}
}
- return 0;
+ return boost::shared_ptr<NamedSelection>();
}
void
-Session::add_named_selection (NamedSelection* named_selection)
+Session::add_named_selection (boost::shared_ptr<NamedSelection> named_selection)
{
{
Glib::Mutex::Lock lm (named_selection_lock);
named_selections.insert (named_selections.begin(), named_selection);
}
- for (list<boost::shared_ptr<Playlist> >::iterator i = named_selection->playlists.begin(); i != named_selection->playlists.end(); ++i) {
- add_playlist (*i);
- }
-
set_dirty();
NamedSelectionAdded (); /* EMIT SIGNAL */
}
void
-Session::remove_named_selection (NamedSelection* named_selection)
+Session::remove_named_selection (boost::shared_ptr<NamedSelection> named_selection)
{
bool removed = false;
NamedSelectionList::iterator i = find (named_selections.begin(), named_selections.end(), named_selection);
if (i != named_selections.end()) {
- delete (*i);
named_selections.erase (i);
set_dirty();
removed = true;
void
Session::sync_order_keys (std::string const & base)
{
+ if (deletion_in_progress()) {
+ return;
+ }
+
if (!Config->get_sync_all_route_ordering()) {
/* leave order keys as they are */
return;
: _session (s)
{
if (_session) {
- _session->GoingAway.connect_same_thread (_session_connections, boost::bind (&SessionHandlePtr::session_going_away, this));
+ _session->DropReferences.connect_same_thread (_session_connections, boost::bind (&SessionHandlePtr::session_going_away, this));
}
}
if (s) {
_session = s;
- _session->GoingAway.connect_same_thread (_session_connections, boost::bind (&SessionHandlePtr::session_going_away, this));
+ _session->DropReferences.connect_same_thread (_session_connections, boost::bind (&SessionHandlePtr::session_going_away, this));
}
}
SessionHandleRef::SessionHandleRef (Session& s)
: _session (s)
{
- _session.GoingAway.connect_same_thread (*this, boost::bind (&SessionHandleRef::session_going_away, this));
+ _session.DropReferences.connect_same_thread (*this, boost::bind (&SessionHandleRef::session_going_away, this));
+ _session.Destroyed.connect_same_thread (*this, boost::bind (&SessionHandleRef::insanity_check, this));
}
void
SessionHandleRef::session_going_away ()
{
- error << string_compose (_("programming error: %1"), "SessionHandleRef exists across sesssion deletion!") << endmsg;
+ /* a handleRef is allowed to exist at the time of DropReferences, but not at the time of Destroyed
+ */
+}
+
+void
+SessionHandleRef::insanity_check ()
+{
+ cerr << string_compose (_("programming error: %1"), "SessionHandleRef exists across sesssion deletion!") << endl;
}
++tmp;
DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for used playlist %1 ; pre-ref = %2\n", (*i)->name(), (*i).use_count()));
+ boost::shared_ptr<Playlist> keeper (*i);
(*i)->drop_references ();
i = tmp;
++tmp;
DEBUG_TRACE(DEBUG::Destruction, string_compose ("Dropping for unused playlist %1 ; pre-ref = %2\n", (*i)->name(), (*i).use_count()));
+ boost::shared_ptr<Playlist> keeper (*i);
(*i)->drop_references ();
i = tmp;
/* now delete any that were marked for deletion */
for (vector<boost::shared_ptr<Playlist> >::iterator x = playlists_tbd.begin(); x != playlists_tbd.end(); ++x) {
+ boost::shared_ptr<Playlist> keeper (*x);
(*x)->drop_references ();
}
SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
Processor::ProcessorCreated.connect_same_thread (*this, boost::bind (&Session::add_processor, this, _1));
- NamedSelection::NamedSelectionCreated.connect_same_thread (*this, boost::bind (&Session::add_named_selection, this, _1));
AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
/* there is pending state from a crashed capture attempt */
- if (AskAboutPendingState()) {
+ if (*AskAboutPendingState()) {
state_was_pending = true;
}
}
_nominal_frame_rate = atoi (prop->value());
if (_nominal_frame_rate != _current_frame_rate) {
- if (AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate)) {
+ if (*AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate)) {
return -1;
}
}
SndFileSource::~SndFileSource ()
{
- drop_references ();
-
if (sf) {
sf_close (sf);
sf = 0;
VSTPlugin::~VSTPlugin ()
{
deactivate ();
- drop_references ();
fst_close (_fst);
}
do_quit ();
} else if (req->type == CallSlot) {
-
+#ifndef NDEBUG
+ if (getenv ("DEBUG_THREADED_SIGNALS")) {
+ cerr << "call slot for " << name() << endl;
+ }
+#endif
req->the_slot ();
} else if (req->type == TouchDisplay) {
trace_connection.disconnect ();
if (onoff) {
- cerr << "enabling tracing for port " << _port.name() << endl;
trace_stream = o;
trace_prefix = prefix;
any.connect_same_thread (trace_connection, boost::bind (&Parser::trace_event, this, _1, _2, _3));
* an EOX. Actually, since EOX is a status byte, this
* code ALWAYS handles the end of a VARIABLELENGTH message.
*/
-
+
if (state == VARIABLELENGTH && statusbit) {
+
/* The message has ended, so process it */
/* add EOX to any sysex message */
}
cerr << dec << endl;
#endif
- if (msgindex > 0 && edit (msgbuf, msgindex) >= 0) {
+ if (msgindex > 0 && (edit.empty() || !(*edit (msgbuf, msgindex) >= 0))) {
if (!possible_mmc (msgbuf, msgindex) || _mmc_forward) {
if (!possible_mtc (msgbuf, msgindex) || _mtc_forward) {
if (!_offline) {
}
if (!_offline) {
any (*this, msgbuf, msgindex);
- }
+ }
}
}
case NEEDONEBYTE:
/* We've completed a 1 or 2 byte message. */
-
- if (edit (msgbuf, msgindex) == 0) {
+ if (edit.empty() || !(*edit (msgbuf, msgindex) == 0)) {
/* message not cancelled by an editor */
/* Controllable::remove() is static - no need to manage this connection */
- ctl.GoingAway.connect_same_thread (registry_connections, boost::bind (&Controllable::remove, ref (ctl)));
+ ctl.DropReferences.connect_same_thread (registry_connections, boost::bind (&Controllable::remove, &ctl));
}
void
-Controllable::remove (Controllable& ctl)
+Controllable::remove (Controllable* ctl)
{
Glib::RWLock::WriterLock lm (registry_lock);
for (Controllables::iterator i = registry.begin(); i != registry.end(); ++i) {
- if ((*i) == &ctl) {
+ if ((*i) == ctl) {
registry.erase (i);
break;
}
}
- if (!ctl.uri().empty()) {
- ControllablesByURI::iterator i = registry_by_uri.find (ctl.uri());
+ if (!ctl->uri().empty()) {
+ ControllablesByURI::iterator i = registry_by_uri.find (ctl->uri());
if (i != registry_by_uri.end()) {
registry_by_uri.erase (i);
}
#include <unistd.h>
+#include <iostream>
#include "pbd/stacktrace.h"
#include "pbd/abstract_ui.h"
using namespace std;
+static void do_not_delete_the_request_buffer (void*) { }
+
+template<typename R>
+Glib::StaticPrivate<typename AbstractUI<R>::RequestBuffer> AbstractUI<R>::per_thread_request_buffer;
+
template <typename RequestObject>
AbstractUI<RequestObject>::AbstractUI (const string& name)
: BaseUI (name)
{
- PBD::ThreadCreatedWithRequestSize.connect (mem_fun (*this, &AbstractUI<RequestObject>::register_thread));
+ void (AbstractUI<RequestObject>::*pmf)(string,pthread_t,string,uint32_t) = &AbstractUI<RequestObject>::register_thread;
+
+ /* better to make this connect a handler that runs in the UI event loop but the syntax seems hard, and
+ register_thread() is thread safe anyway.
+ */
+
+ PBD::ThreadCreatedWithRequestSize.connect_same_thread (new_thread_connection, boost::bind (pmf, this, _1, _2, _3, _4));
}
template <typename RequestObject> void
request_buffers[thread_id] = b;
}
- per_thread_request_buffer.set (b);
+ per_thread_request_buffer.set (b, do_not_delete_the_request_buffer);
}
template <typename RequestObject> RequestObject*
AbstractUI<RequestObject>::call_slot (const boost::function<void()>& f)
{
if (caller_is_self()) {
+#ifndef NDEBUG
+ if (getenv ("DEBUG_THREADED_SIGNALS")) {
+ std::cerr << "functor called in correct thread for " << name() << " , execute ...\n";
+ }
+#endif
f ();
return;
}
}
req->the_slot = f;
+#ifndef NDEBUG
+ if (getenv ("DEBUG_THREADED_SIGNALS")) {
+ std::cerr << "functor called in wrong thread for " << name() << " (from " << pthread_name() << ") send request ...\n";
+ }
+#endif
send_request (req);
}
#include <string>
#include <pthread.h>
-#include <sigc++/sigc++.h>
-
#include <glibmm/thread.h>
#include "pbd/receiver.h"
#include "pbd/ringbufferNPT.h"
+#include "pbd/signals.h"
#include "pbd/base_ui.h"
class Touchable;
Glib::Mutex request_buffer_map_lock;
RequestBufferMap request_buffers;
- Glib::Private<RequestBuffer> per_thread_request_buffer;
-
+ static Glib::StaticPrivate<RequestBuffer> per_thread_request_buffer;
+
Glib::Mutex request_list_lock;
std::list<RequestObject*> request_list;
void send_request (RequestObject *);
virtual void do_request (RequestObject *) = 0;
+ PBD::ScopedConnection new_thread_connection;
};
#endif /* __pbd_abstract_ui_h__ */
bool _touching;
static void add (Controllable&);
- static void remove (Controllable&);
+ static void remove (Controllable*);
typedef std::set<PBD::Controllable*> Controllables;
typedef std::map<std::string,PBD::Controllable*> ControllablesByURI;
class Destructible {
public:
- Destructible() : refs_dropped (false){}
- virtual ~Destructible () {}
+ Destructible() {}
+ virtual ~Destructible () { Destroyed(); }
- PBD::Signal0<void> GoingAway;
- void drop_references () { if (!refs_dropped) { GoingAway(); } refs_dropped = true; }
+ PBD::Signal0<void> Destroyed;
+ PBD::Signal0<void> DropReferences;
- private:
- bool refs_dropped;
+ void drop_references () { DropReferences(); }
};
}
: obj(a_object), before(a_before), after(a_after)
{
/* if the object dies, make sure that we die and that everyone knows about it */
- obj.GoingAway.connect_same_thread (obj_death_connection, boost::bind (&MementoCommand::object_died, this));
+ obj.Destroyed.connect_same_thread (obj_death_connection, boost::bind (&MementoCommand::object_died, this));
}
~MementoCommand () {
#include <string>
#include <stdint.h>
-#include <sigc++/sigc++.h>
+#include <pbd/signals.h>
int pthread_create_and_store (std::string name, pthread_t *thread, void * (*start_routine)(void *), void * arg);
void pthread_cancel_one (pthread_t thread);
namespace PBD {
extern void notify_gui_about_thread_creation (std::string, pthread_t, std::string, int requests = 256);
- extern void notify_gui_about_thread_exit (pthread_t);
-
- extern sigc::signal<void,pthread_t> ThreadLeaving;
- extern sigc::signal<void,std::string,pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
+ extern PBD::Signal4<void,std::string,pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
}
#endif /* __pbd_pthread_utils__ */
typename SignalType::result_type operator()() {
return _signal ();
}
+
+ bool empty() const { return _signal.empty(); }
private:
SignalType _signal;
return _signal (arg1);
}
+ bool empty() const { return _signal.empty(); }
+
private:
SignalType _signal;
};
return _signal (arg1, arg2);
}
+ bool empty() const { return _signal.empty(); }
+
private:
SignalType _signal;
};
return _signal (arg1, arg2, arg3);
}
+ bool empty() const { return _signal.empty(); }
+
+private:
+ SignalType _signal;
+};
+
+template<typename R, typename A1, typename A2, typename A3, typename A4>
+class Signal4 {
+public:
+ Signal4 () {}
+ typedef boost::signals2::signal<R(A1,A2,A3,A4)> SignalType;
+
+ void connect_same_thread (ScopedConnectionList& clist,
+ const typename SignalType::slot_function_type& slot) {
+ clist.add_connection (_signal.connect (slot));
+ }
+
+ void connect_same_thread (Connection& c,
+ const typename SignalType::slot_function_type& slot) {
+ c = _signal.connect (slot);
+ }
+
+ static void compositor (typename boost::function<void(A1,A2,A3)> f, PBD::EventLoop* event_loop, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
+ event_loop->call_slot (boost::bind (f, arg1, arg2, arg3, arg4));
+ }
+
+ void connect (ScopedConnectionList& clist,
+ const typename SignalType::slot_function_type& slot,
+ PBD::EventLoop* event_loop) {
+ clist.add_connection (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3, _4)));
+ }
+
+ void connect (Connection& c,
+ const typename SignalType::slot_function_type& slot,
+ PBD::EventLoop* event_loop) {
+ c = _signal.connect (_signal.connect (boost::bind (&compositor, slot, event_loop, _1, _2, _3, _4)));
+ }
+
+ typename SignalType::result_type operator()(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
+ return _signal (arg1, arg2, arg3, arg4);
+ }
+
+ bool empty() const { return _signal.empty(); }
+
private:
SignalType _signal;
};
typedef std::map<string,pthread_t> ThreadMap;
static ThreadMap all_threads;
static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t gui_notify_lock = PTHREAD_MUTEX_INITIALIZER;
namespace PBD {
- sigc::signal<void,pthread_t> ThreadLeaving;
- sigc::signal<void,std::string, pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
+ PBD::Signal4<void,std::string, pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
}
using namespace PBD;
void
PBD::notify_gui_about_thread_creation (std::string target_gui, pthread_t thread, std::string str, int request_count)
{
- pthread_mutex_lock (&gui_notify_lock);
ThreadCreatedWithRequestSize (target_gui, thread, str, request_count);
- pthread_mutex_unlock (&gui_notify_lock);
-}
-
-void
-PBD::notify_gui_about_thread_exit (pthread_t thread)
-{
- pthread_mutex_lock (&gui_notify_lock);
- ThreadLeaving (thread);
- pthread_mutex_unlock (&gui_notify_lock);
}
int
so there is no need to manage this connection.
*/
- action->GoingAway.connect_same_thread (*this, boost::bind (&command_death, this, action));
+ action->DropReferences.connect_same_thread (*this, boost::bind (&command_death, this, action));
actions.push_back (action);
}
{
uint32_t current_depth = UndoList.size();
- ut->GoingAway.connect_same_thread (*this, boost::bind (&UndoHistory::remove, this, ut));
+ ut->DropReferences.connect_same_thread (*this, boost::bind (&UndoHistory::remove, this, ut));
/* if the current undo history is larger than or equal to the currently
requested depth, then pop off at least 1 element to make space
*/
if (!route_exists) {
- route->GoingAway.connect (*this, boost::bind (&OSC::drop_route, this, boost::weak_ptr<Route> (route)), this);
+ route->DropReferences.connect (*this, boost::bind (&OSC::drop_route, this, boost::weak_ptr<Route> (route)), this);
}
}