use new method in MidiPatchManager to use MIDNAM data when setting a MidiTimeAxisView
[ardour.git] / gtk2_ardour / editor_ops.cc
index d730bb772aeebe5e34df786e49046435e548811a..195d4d16436b6bbb41aa9e926eafbe0dcbd9abfc 100644 (file)
@@ -1,21 +1,32 @@
 /*
-    Copyright (C) 2000-2004 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.
-
-*/
+ * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
+ * Copyright (C) 2005-2009 Sampo Savolainen <v2@iki.fi>
+ * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
+ * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
+ * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
+ * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
+ * Copyright (C) 2007-2017 Tim Mayberry <mojofunk@gmail.com>
+ * Copyright (C) 2013-2016 Colin Fletcher <colin.m.fletcher@googlemail.com>
+ * Copyright (C) 2013-2017 John Emmas <john@creativepost.co.uk>
+ * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
+ * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
+ * Copyright (C) 2015 AndrĂ© Nusser <andre.nusser@googlemail.com>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
 
 /* Note: public Editor methods are documented in public_editor.h */
 
 #include "ardour/legatize.h"
 #include "ardour/region_factory.h"
 #include "ardour/reverse.h"
+#include "ardour/selection.h"
 #include "ardour/session.h"
 #include "ardour/session_playlists.h"
+#include "ardour/source.h"
 #include "ardour/strip_silence.h"
 #include "ardour/transient_detector.h"
+#include "ardour/transport_master_manager.h"
 #include "ardour/transpose.h"
 #include "ardour/vca_manager.h"
 
 #include "canvas/canvas.h"
 
 #include "actions.h"
+#include "ardour_message.h"
+#include "ardour_ui.h"
 #include "audio_region_view.h"
 #include "audio_streamview.h"
 #include "audio_time_axis.h"
@@ -80,6 +96,7 @@
 #include "editor_cursors.h"
 #include "editor_drag.h"
 #include "editor_regions.h"
+#include "editor_sources.h"
 #include "editor_routes.h"
 #include "gui_thread.h"
 #include "insert_remove_time_dialog.h"
 #include "transpose_dialog.h"
 #include "transform_dialog.h"
 #include "ui_config.h"
+#include "utils.h"
 #include "vca_time_axis.h"
 
 #include "pbd/i18n.h"
@@ -137,6 +155,7 @@ Editor::undo (uint32_t n)
        if (_drags->active ()) {
                _drags->abort ();
        }
+       paste_count = 0;
 
        if (_session) {
                _session->undo (n);
@@ -161,6 +180,7 @@ Editor::redo (uint32_t n)
        if (_drags->active ()) {
                _drags->abort ();
        }
+       paste_count = 0;
 
        if (_session) {
        _session->redo (n);
@@ -177,9 +197,6 @@ Editor::split_regions_at (MusicSample where, RegionSelection& regions)
 {
        bool frozen = false;
 
-       RegionSelection pre_selected_regions = selection->regions;
-       bool working_on_selection = !pre_selected_regions.empty();
-
        list<boost::shared_ptr<Playlist> > used_playlists;
        list<RouteTimeAxisView*> used_trackviews;
 
@@ -267,22 +284,23 @@ Editor::split_regions_at (MusicSample where, RegionSelection& regions)
                EditorThaw(); /* Emit Signal */
        }
 
-       if (working_on_selection) {
-               // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
-
-               RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
-               /* There are three classes of regions that we might want selected after
-                  splitting selected regions:
-                   - regions selected before the split operation, and unaffected by it
-                   - newly-created regions before the split
-                   - newly-created regions after the split
-                */
-
-               if (rsas & Existing) {
-                       // region selections that existed before the split.
-                       selection->add (pre_selected_regions);
-               }
+       RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
 
+       //if the user has "Clear Selection" as their post-split behavior, then clear the selection
+       if (!latest_regionviews.empty() && (rsas == None)) {
+               selection->clear_objects();
+               selection->clear_time();
+               //but leave track selection intact
+       }
+       
+       //if the user doesn't want to preserve the "Existing" selection, then clear the selection
+       if (!(rsas & Existing)) {
+               selection->clear_objects();
+               selection->clear_time();
+       }
+       
+       //if the user wants newly-created regions to be selected, then select them:
+       if (mouse_mode == MouseObject) {
                for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
                        if ((*ri)->region()->position() < where.sample) {
                                // new regions created before the split
@@ -439,7 +457,7 @@ Editor::nudge_forward (bool next, bool force_playhead)
                                                loc->set_end (max_samplepos, false, true, divisions);
                                        }
                                        if (loc->is_session_range()) {
-                                               _session->set_end_is_free (false);
+                                               _session->set_session_range_is_free (false);
                                        }
                                }
                                if (!in_command) {
@@ -533,7 +551,7 @@ Editor::nudge_backward (bool next, bool force_playhead)
                                                loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
                                        }
                                        if (loc->is_session_range()) {
-                                               _session->set_end_is_free (false);
+                                               _session->set_session_range_is_free (false);
                                        }
                                }
                                if (!in_command) {
@@ -729,6 +747,7 @@ Editor::build_region_boundary_cache ()
 
        /* if no snap selections are set, boundary cache should be left empty */
        if ( interesting_points.empty() ) {
+               _region_boundary_cache_dirty = false;
                return;
        }
 
@@ -748,6 +767,11 @@ Editor::build_region_boundary_cache ()
                }
        }
 
+       //allow regions to snap to the video start (if any) as if it were a "region"
+       if (ARDOUR_UI::instance()->video_timeline) {
+               region_boundary_cache.push_back (ARDOUR_UI::instance()->video_timeline->get_video_start_offset());
+       }
+
        std::pair<samplepos_t, samplepos_t> ext = session_gui_extents (false);
        samplepos_t session_end = ext.second;
 
@@ -1779,7 +1803,13 @@ Editor::temporal_zoom (samplecnt_t fpp)
        new_page_size = (samplepos_t) floor (_visible_canvas_width * nfpp);
        half_page_size = new_page_size / 2;
 
-       switch (zoom_focus) {
+       Editing::ZoomFocus zf = zoom_focus;
+
+       if (zf == ZoomFocusEdit && _edit_point == EditAtMouse) {
+               zf = ZoomFocusMouse;
+       }
+
+       switch (zf) {
        case ZoomFocusLeft:
                leftmost_after_zoom = current_leftmost;
                break;
@@ -1849,9 +1879,7 @@ Editor::temporal_zoom (samplecnt_t fpp)
        case ZoomFocusEdit:
                /* try to keep the edit point in the same place */
                where = get_preferred_edit_position ();
-
-               if (where > 0) {
-
+               {
                        double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
 
                        if (l < 0) {
@@ -1861,10 +1889,6 @@ Editor::temporal_zoom (samplecnt_t fpp)
                        } else {
                                leftmost_after_zoom = (samplepos_t) l;
                        }
-
-               } else {
-                       /* edit point not defined */
-                       return;
                }
                break;
 
@@ -2143,7 +2167,7 @@ Editor::temporal_zoom_to_sample (bool coarser, samplepos_t sample)
 
 
 bool
-Editor::choose_new_marker_name(string &name) {
+Editor::choose_new_marker_name(string &name, bool is_range) {
 
        if (!UIConfiguration::instance().get_name_new_markers()) {
                /* don't prompt user for a new name */
@@ -2154,7 +2178,11 @@ Editor::choose_new_marker_name(string &name) {
 
        dialog.set_prompt (_("New Name:"));
 
-       dialog.set_title (_("New Location Marker"));
+       if (is_range) {
+               dialog.set_title(_("New Range"));
+       } else {
+               dialog.set_title (_("New Location Marker"));
+       }
 
        dialog.set_name ("MarkNameWindow");
        dialog.set_size_request (250, -1);
@@ -2195,6 +2223,9 @@ Editor::add_location_from_selection ()
        samplepos_t end = selection->time[clicked_selection].end;
 
        _session->locations()->next_available_name(rangename,"selection");
+       if (!choose_new_marker_name(rangename, true)) {
+               return;
+       }
        Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
 
        begin_reversible_command (_("add marker"));
@@ -2251,6 +2282,8 @@ Editor::set_session_start_from_playhead ()
 
                commit_reversible_command ();
        }
+
+       _session->set_session_range_is_free (false);
 }
 
 void
@@ -2276,7 +2309,7 @@ Editor::set_session_end_from_playhead ()
                commit_reversible_command ();
        }
 
-       _session->set_end_is_free (false);
+       _session->set_session_range_is_free (false);
 }
 
 
@@ -2524,7 +2557,7 @@ Editor::unhide_ranges ()
 /* INSERT/REPLACE */
 
 void
-Editor::insert_region_list_selection (float times)
+Editor::insert_source_list_selection (float times)
 {
        RouteTimeAxisView *tv = 0;
        boost::shared_ptr<Playlist> playlist;
@@ -2547,7 +2580,7 @@ Editor::insert_region_list_selection (float times)
                return;
        }
 
-       boost::shared_ptr<Region> region = _regions->get_single_selection ();
+       boost::shared_ptr<Region> region = _sources->get_single_selection ();
        if (region == 0) {
                return;
        }
@@ -2587,7 +2620,7 @@ Editor::transition_to_rolling (bool fwd)
        }
 
        if (_session->config.get_external_sync()) {
-               switch (Config->get_sync_source()) {
+               switch (TransportMasterManager::instance().current()->type()) {
                case Engine:
                        break;
                default:
@@ -3192,8 +3225,18 @@ Editor::separate_regions_between (const TimeSelection& ts)
                }
        }
 
-       if (in_command) {
-//             selection->set (new_selection);
+       if (in_command) {
+
+               RangeSelectionAfterSplit rsas = Config->get_range_selection_after_split();
+
+               //if our config preference says to clear the selection, clear the Range selection
+               if (rsas == ClearSel) {
+                       selection->clear_time();
+                       //but leave track selection intact
+               } else if (rsas == ForceSel) {
+                       //note: forcing the regions to be selected *might* force a tool-change to Object here
+                       selection->set(new_selection);  
+               }
 
                commit_reversible_command ();
        }
@@ -3949,7 +3992,7 @@ Editor::freeze_route ()
        }
 
        if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
-               MessageDialog d (
+               ArdourMessageDialog d (
                        _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
                          "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
                        );
@@ -3959,9 +4002,9 @@ Editor::freeze_route ()
        }
 
        if (clicked_routeview->track()->has_external_redirects()) {
-               MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
-                                                  "Freezing will only process the signal as far as the first send/insert/return."),
-                                                clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
+               ArdourMessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
+                                                        "Freezing will only process the signal as far as the first send/insert/return."),
+                                                      clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
 
                d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
                d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
@@ -4010,7 +4053,7 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
 
                        if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
-                               MessageDialog d (
+                               ArdourMessageDialog d (
                                        _("You can't perform this operation because the processing of the signal "
                                          "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
                                          "You can do this without processing, which is a different operation.")
@@ -4429,12 +4472,15 @@ Editor::remove_clicked_region ()
        begin_reversible_command (_("remove region"));
 
        boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
+       boost::shared_ptr<Region> region = clicked_regionview->region();
 
        playlist->clear_changes ();
        playlist->clear_owned_changes ();
-       playlist->remove_region (clicked_regionview->region());
-       if (Config->get_edit_mode() == Ripple)
-               playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
+       playlist->remove_region (region);
+
+       if (Config->get_edit_mode() == Ripple) {
+               playlist->ripple (region->position(), - region->length(), boost::shared_ptr<Region>());
+       }
 
        /* We might have removed regions, which alters other regions' layering_index,
           so we need to do a recursive diff here.
@@ -4448,6 +4494,32 @@ Editor::remove_clicked_region ()
 }
 
 
+void
+Editor::recover_regions (ARDOUR::RegionList regions)
+{
+#ifdef RECOVER_REGIONS_IS_WORKING
+       begin_reversible_command (_("recover regions"));
+
+       for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+               boost::shared_ptr<ARDOUR::Source> source = (*i)->source();
+
+               RouteList routes = _session->get_routelist();
+               for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
+                       boost::shared_ptr<ARDOUR::Track> track = boost::dynamic_pointer_cast<Track>(*it);
+                       if (track) {
+                               //ToDo
+                               if (source->captured_for() == track->) {
+                                       //_session->add_command(new StatefulDiffCommand (playlist));    
+                               }
+                       }
+               }
+       }
+
+       commit_reversible_command ();
+#endif
+}
+
+
 /** Remove the selected regions */
 void
 Editor::remove_selected_regions ()
@@ -5109,6 +5181,95 @@ Editor::remove_last_capture ()
        }
 }
 
+void
+Editor::tag_regions (RegionList regions)
+{
+       ArdourDialog d (_("Tag Last Capture"), true, false);
+       Entry entry;
+       Label label (_("Tag:"));
+       HBox hbox;
+
+       hbox.set_spacing (6);
+       hbox.pack_start (label, false, false);
+       hbox.pack_start (entry, true, true);
+
+       d.get_vbox()->set_border_width (12);
+       d.get_vbox()->pack_start (hbox, false, false);
+
+       d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+       d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+       d.set_size_request (300, -1);
+
+       entry.set_text (_("Good"));
+       entry.select_region (0, -1);
+
+       entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
+
+       d.show_all ();
+
+       entry.grab_focus();
+
+       int const ret = d.run();
+
+       d.hide ();
+
+       if (ret != RESPONSE_OK) {
+               return;
+       }
+
+       std::string tagstr = entry.get_text();
+       strip_whitespace_edges (tagstr);
+       
+       if (!tagstr.empty()) {
+               for (RegionList::iterator r = regions.begin(); r != regions.end(); r++) {
+                       (*r)->set_tags(tagstr);
+               }
+                       
+               _regions->redisplay ();
+       }
+}
+
+void
+Editor::tag_selected_region ()
+{
+       std::list<boost::shared_ptr<Region> > rlist;
+
+       RegionSelection rs = get_regions_from_selection_and_entered ();
+       for (RegionSelection::iterator r = rs.begin(); r != rs.end(); r++) {
+               rlist.push_back((*r)->region());
+       }
+
+       tag_regions(rlist);
+}
+
+void
+Editor::tag_last_capture ()
+{
+       if (!_session) {
+               return;
+       }
+
+       std::list<boost::shared_ptr<Region> > rlist;
+
+       std::list<boost::shared_ptr<Source> > srcs;
+       _session->get_last_capture_sources (srcs);
+       for (std::list<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+               boost::shared_ptr<ARDOUR::Source> source = (*i);
+               if (source) {
+
+                       set<boost::shared_ptr<Region> > regions;
+                       RegionFactory::get_regions_using_source (source, regions);
+                       for (set<boost::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); r++) {
+                               rlist.push_back(*r);
+                       }
+
+               }
+       }
+       
+       tag_regions(rlist);
+}
+
 void
 Editor::normalize_region ()
 {
@@ -6004,7 +6165,9 @@ Editor::toggle_mute ()
                        first = false;
                }
 
-               cl->push_back (stav->stripable()->mute_control());
+               boost::shared_ptr<MuteControl> mc = stav->stripable()->mute_control();
+               cl->push_back (mc);
+               mc->start_touch (_session->audible_sample ());
        }
 
        _session->set_controls (cl, new_state, Controllable::UseGroup);
@@ -6399,7 +6562,31 @@ Editor::split_region ()
        //if no range was selected, try to find some regions to split
        if (current_mouse_mode() == MouseObject || current_mouse_mode() == MouseRange ) {  //don't try this for Internal Edit, Stretch, Draw, etc.
 
-               RegionSelection rs = get_regions_from_selection_and_edit_point ();
+               RegionSelection rs;
+
+               //new behavior:  the Split action will prioritize the entered_regionview rather than selected regions.
+               //this fixes the unexpected case where you point at a region, but
+               //  * nothing happens OR
+               //  * some other region (maybe off-screen) is split.
+               //NOTE:  if the entered_regionview is /part of the selection/ then we should operate on the selection as usual
+               if (_edit_point == EditAtMouse && entered_regionview && !entered_regionview->selected()) {
+                       rs.add (entered_regionview);
+               } else {
+                       rs = selection->regions;   //might be empty
+               }
+
+               if (rs.empty()) {
+                       TrackViewList tracks = selection->tracks;
+
+                       if (!tracks.empty()) {
+                               /* no region selected or entered, but some selected tracks:
+                                * act on all regions on the selected tracks at the edit point
+                                */
+                               samplepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, false);
+                               get_regions_at(rs, where, tracks);
+                       }
+               }
+
                const samplepos_t pos = get_preferred_edit_position();
                const int32_t division = get_grid_music_divisions (0);
                MusicSample where (pos, division);
@@ -6409,86 +6596,19 @@ Editor::split_region ()
                }
 
                split_regions_at (where, rs);
-
        }
 }
 
 void
 Editor::select_next_stripable (bool routes_only)
 {
-       if (selection->tracks.empty()) {
-               selection->set (track_views.front());
-               return;
-       }
-
-       TimeAxisView* current = selection->tracks.front();
-
-       bool valid;
-       do {
-               for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-
-                       if (*i == current) {
-                               ++i;
-                               if (i != track_views.end()) {
-                                       current = (*i);
-                               } else {
-                                       current = (*(track_views.begin()));
-                                       //selection->set (*(track_views.begin()));
-                               }
-                               break;
-                       }
-               }
-
-               if (routes_only) {
-                       RouteUI* rui = dynamic_cast<RouteUI *>(current);
-                       valid = rui && rui->route()->active();
-               } else {
-                       valid = 0 != current->stripable ().get();
-               }
-
-       } while (current->hidden() || !valid);
-
-       selection->set (current);
-
-       ensure_time_axis_view_is_visible (*current, false);
+       _session->selection().select_next_stripable (false, routes_only);
 }
 
 void
 Editor::select_prev_stripable (bool routes_only)
 {
-       if (selection->tracks.empty()) {
-               selection->set (track_views.front());
-               return;
-       }
-
-       TimeAxisView* current = selection->tracks.front();
-
-       bool valid;
-       do {
-               for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
-
-                       if (*i == current) {
-                               ++i;
-                               if (i != track_views.rend()) {
-                                       current = (*i);
-                               } else {
-                                       current = *(track_views.rbegin());
-                               }
-                               break;
-                       }
-               }
-               if (routes_only) {
-                       RouteUI* rui = dynamic_cast<RouteUI *>(current);
-                       valid = rui && rui->route()->active();
-               } else {
-                       valid = 0 != current->stripable ().get();
-               }
-
-       } while (current->hidden() || !valid);
-
-       selection->set (current);
-
-       ensure_time_axis_view_is_visible (*current, false);
+       _session->selection().select_prev_stripable (false, routes_only);
 }
 
 void
@@ -6573,7 +6693,7 @@ Editor::set_auto_punch_range ()
                        set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
                        _session->config.set_punch_out(true);
                }
-       } else  {
+       } else {
                if (_session->config.get_punch_out()) {
                        _session->config.set_punch_out(false);
                }
@@ -6619,7 +6739,7 @@ Editor::set_session_extents_from_selection ()
                commit_reversible_command ();
        }
 
-       _session->set_end_is_free (false);
+       _session->set_session_range_is_free (false);
 }
 
 void
@@ -6929,10 +7049,10 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
        if (positions.size() > 20 && can_ferret) {
                std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
-               MessageDialog msg (msgstr,
-                                  false,
-                                  Gtk::MESSAGE_INFO,
-                                  Gtk::BUTTONS_OK_CANCEL);
+               ArdourMessageDialog msg (msgstr,
+                                        false,
+                                        Gtk::MESSAGE_INFO,
+                                        Gtk::BUTTONS_OK_CANCEL);
 
                if (can_ferret) {
                        msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
@@ -6942,8 +7062,6 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
                }
 
                msg.set_title (_("Excessive split?"));
-               msg.present ();
-
                int response = msg.run();
                msg.hide ();
 
@@ -7145,7 +7263,7 @@ Editor::snap_regions_to_grid ()
                (*r)->region()->clear_changes ();
 
                MusicSample start ((*r)->region()->first_sample (), 0);
-               snap_to (start, RoundNearest, SnapToGrid);
+               snap_to (start, RoundNearest, SnapToGrid_Unscaled, true);
                (*r)->region()->set_position (start.sample, start.division);
                _session->add_command(new StatefulDiffCommand ((*r)->region()));
        }
@@ -7360,15 +7478,15 @@ Editor::playhead_forward_to_grid ()
                        _session->request_locate (0);
                }
        } else {
-               
+
                if (pos.sample < max_samplepos - 1) {
                        pos.sample += 2;
-                       snap_to_internal (pos, RoundUpAlways, SnapToGrid, false, true);
+                       pos = snap_to_grid (pos, RoundUpAlways, SnapToGrid_Scaled);
                        _session->request_locate (pos.sample);
                }
        }
 
-       
+
        /* keep PH visible in window */
        if (pos.sample > (_leftmost_sample + current_page_samples() *0.9)) {
                reset_x_origin (pos.sample - (current_page_samples()*0.9));
@@ -7393,23 +7511,23 @@ Editor::playhead_backward_to_grid ()
                        _session->request_locate (0);
                }
        } else {
-               
+
                if (pos.sample > 2) {
                        pos.sample -= 2;
-                       snap_to_internal (pos, RoundDownAlways, SnapToGrid, false, true);
+                       pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled);
                }
 
                //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
                //also see:  jump_backward_to_mark
                if (_session->transport_rolling()) {
                        if ((playhead_cursor->current_sample() - pos.sample) < _session->sample_rate()/2) {
-                               snap_to_internal (pos, RoundDownAlways, SnapToGrid, false, true);
+                               pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled);
                        }
                }
 
                _session->request_locate (pos.sample, _session->transport_rolling());
        }
-       
+
        /* keep PH visible in window */
        if (pos.sample < (_leftmost_sample + current_page_samples() *0.1)) {
                reset_x_origin (pos.sample - (current_page_samples()*0.1));
@@ -7477,6 +7595,10 @@ Editor::_remove_tracks ()
                return;
        }
 
+       if (!ARDOUR_UI_UTILS::engine_is_running ()) {
+               return;
+       }
+
        vector<string> choices;
        string prompt;
        int ntracks = 0;
@@ -7513,19 +7635,17 @@ Editor::_remove_tracks ()
        }
 
        if (special_bus && !Config->get_allow_special_bus_removal()) {
-               MessageDialog msg (_("That would be bad news ...."),
-                                  false,
-                                  Gtk::MESSAGE_INFO,
-                                  Gtk::BUTTONS_OK);
-               msg.set_secondary_text (string_compose (_(
-                                                               "Removing the master or monitor bus is such a bad idea\n\
+               ArdourMessageDialog msg (_("That would be bad news ...."),
+                                        false,
+                                        Gtk::MESSAGE_INFO,
+                                        Gtk::BUTTONS_OK);
+               msg.set_secondary_text (string_compose (_("Removing the master or monitor bus is such a bad idea\n\
 that %1 is not going to allow it.\n\
 \n\
 If you really want to do this sort of thing\n\
 edit your ardour.rc file to set the\n\
 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
 
-               msg.present ();
                msg.run ();
                return;
        }
@@ -7641,17 +7761,15 @@ void
 Editor::do_insert_time ()
 {
        if (selection->tracks.empty()) {
-               MessageDialog msg (_("You must first select some tracks to Insert Time."),
-                                  true, MESSAGE_INFO, BUTTONS_OK, true);
-               msg.set_position (WIN_POS_MOUSE);
+               ArdourMessageDialog msg (_("You must first select some tracks to Insert Time."),
+                                  true, MESSAGE_INFO, BUTTONS_OK, true);
                msg.run ();
                return;
        }
 
        if (Config->get_edit_mode() == Lock) {
-               MessageDialog msg (_("You cannot insert time in Lock Edit mode."),
-                                  true, MESSAGE_INFO, BUTTONS_OK, true);
-               msg.set_position (WIN_POS_MOUSE);
+               ArdourMessageDialog msg (_("You cannot insert time in Lock Edit mode."),
+                                        true, MESSAGE_INFO, BUTTONS_OK, true);
                msg.run ();
                return;
        }
@@ -7708,7 +7826,7 @@ Editor::insert_time (
                if (all_playlists) {
                        RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
                        if (rtav && rtav->track ()) {
-                               vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
+                               vector<boost::shared_ptr<Playlist> > all = _session->playlists()->playlists_for_track (rtav->track ());
                                for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
                                        pl.insert (*p);
                                }
@@ -7816,17 +7934,15 @@ void
 Editor::do_remove_time ()
 {
        if (selection->tracks.empty()) {
-               MessageDialog msg (_("You must first select some tracks to Remove Time."),
-                                  true, MESSAGE_INFO, BUTTONS_OK, true);
-               msg.set_position (WIN_POS_MOUSE);
+               ArdourMessageDialog msg (_("You must first select some tracks to Remove Time."),
+                                        true, MESSAGE_INFO, BUTTONS_OK, true);
                msg.run ();
                return;
        }
 
        if (Config->get_edit_mode() == Lock) {
-               MessageDialog msg (_("You cannot remove time in Lock Edit mode."),
-                                  true, MESSAGE_INFO, BUTTONS_OK, true);
-               msg.set_position (WIN_POS_MOUSE);
+               ArdourMessageDialog msg (_("You cannot remove time in Lock Edit mode."),
+                                        true, MESSAGE_INFO, BUTTONS_OK, true);
                msg.run ();
                return;
        }
@@ -8055,7 +8171,8 @@ Editor::fit_tracks (TrackViewList & tracks)
        double first_y_pos = DBL_MAX;
 
        if (h < TimeAxisView::preset_height (HeightSmall)) {
-               MessageDialog msg (_("There are too many tracks to fit in the current window"));
+               ArdourMessageDialog msg (_("There are too many tracks to fit in the current window"));
+               msg.run ();
                /* too small to be displayed */
                return;
        }