Fix horizontal positioning of PC flags.
[ardour.git] / gtk2_ardour / editor.cc
index 2edc155159e15fcc8fbe57edcc5fdbda315ed6e7..0932a046e08f492e78456a4bf5a634bdeb5a9268 100644 (file)
 #include <gtkmm2ext/window_title.h>
 #include <gtkmm2ext/choice.h>
 
-#include <ardour/audio_track.h>
 #include <ardour/audio_diskstream.h>
-#include <ardour/plugin_manager.h>
-#include <ardour/location.h>
+#include <ardour/audio_track.h>
 #include <ardour/audioplaylist.h>
 #include <ardour/audioregion.h>
+#include <ardour/location.h>
 #include <ardour/midi_region.h>
-#include <ardour/session_route.h>
+#include <ardour/plugin_manager.h>
+#include <ardour/profile.h>
+#include <ardour/route_group.h>
 #include <ardour/session_directory.h>
+#include <ardour/session_route.h>
 #include <ardour/session_state_utils.h>
 #include <ardour/tempo.h>
 #include <ardour/utils.h>
-#include <ardour/profile.h>
 
 #include <control_protocol/control_protocol.h>
 
@@ -87,6 +88,8 @@
 #include "actions.h"
 #include "tempo_lines.h"
 #include "analysis_window.h"
+#include "bundle_manager.h"
+#include "global_port_matrix.h"
 
 #include "i18n.h"
 
@@ -260,12 +263,6 @@ Editor::Editor ()
        selection = new Selection (this);
        cut_buffer = new Selection (this);
 
-       selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
-       selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
-       selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
-       selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
-       selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
-
        clicked_regionview = 0;
        clicked_axisview = 0;
        clicked_routeview = 0;
@@ -304,7 +301,8 @@ Editor::Editor ()
        _show_waveforms_recording = true;
        first_action_message = 0;
        show_gain_after_trim = false;
-       ignore_route_list_reorder = false;
+       route_redisplay_does_not_sync_order_keys = false;
+       route_redisplay_does_not_reset_order_keys = false;
        no_route_list_redisplay = false;
        verbose_cursor_on = true;
        route_removal = false;
@@ -344,7 +342,6 @@ Editor::Editor ()
        _new_regionviews_show_envelope = false;
        current_timefx = 0;
        in_edit_group_row_change = false;
-       last_canvas_frame = 0;
        playhead_cursor = 0;
        button_release_can_deselect = true;
        _dragging_playhead = false;
@@ -353,6 +350,10 @@ Editor::Editor ()
        select_new_marker = false;
        zoomed_to_region = false;
        rhythm_ferret = 0;
+       _bundle_manager = 0;
+        for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
+               _global_port_matrix[*i] = 0;
+       }
        allow_vertical_scroll = false;
        no_save_visual = false;
        need_resize_line = false;
@@ -365,7 +366,6 @@ Editor::Editor ()
        scrubbing_direction = 0;
 
        sfbrowser = 0;
-       ignore_route_order_sync = false;
 
        location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
        location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
@@ -376,6 +376,7 @@ Editor::Editor ()
        range_marker_drag_rect = 0;
        marker_drag_line = 0;
        set_midi_edit_mode (MidiEditPencil, true);
+       _edit_point = EditAtMouse;
        set_mouse_mode (MouseObject, true);
 
        frames_per_unit = 2048; /* too early to use reset_zoom () */
@@ -385,108 +386,121 @@ Editor::Editor ()
        set_zoom_focus (ZoomFocusLeft);
        zoom_range_clock.ValueChanged.connect (mem_fun(*this, &Editor::zoom_adjustment_changed));
 
-       initialize_rulers ();
-       initialize_canvas ();
-
-       edit_controls_vbox.set_spacing (0);
-       horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::scroll_canvas_horizontally), false);
-       vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
-       track_canvas->signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
-
-       controls_layout.add (edit_controls_vbox);
-       controls_layout.set_name ("EditControlsBase");
-       controls_layout.add_events (Gdk::SCROLL_MASK);
-       controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
-       
-       controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
-       controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
-       controls_layout_size_request_connection = controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
-
-       edit_vscrollbar.set_adjustment (vertical_adjustment);
-       edit_hscrollbar.set_adjustment (horizontal_adjustment);
-
-       edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
-       edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
-       edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
-
-       edit_hscrollbar.set_name ("EditorHScrollbar");
-
-       build_cursors ();
-       setup_toolbar ();
-       setup_midi_toolbar ();
-
-       edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
-       
-       ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
-       ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
-                       0.0, 1.0, 100.0, 1.0));
-       pad_line_1->property_color_rgba() = 0xFF0000FF;
-       pad_line_1->show();
-       time_pad->show();
-
-       time_canvas_vbox.pack_start (*_ruler_separator, false, false);
-       time_canvas_vbox.pack_start (*minsec_ruler, false, false);
-       time_canvas_vbox.pack_start (*smpte_ruler, false, false);
-       time_canvas_vbox.pack_start (*frames_ruler, false, false);
-       time_canvas_vbox.pack_start (*bbt_ruler, false, false);
-       //time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
-       time_canvas_vbox.set_size_request (-1, -1);
        bbt_label.set_name ("EditorTimeButton");
        bbt_label.set_size_request (-1, (int)timebar_height);
        bbt_label.set_alignment (1.0, 0.5);
        bbt_label.set_padding (5,0);
+       bbt_label.hide ();
+       bbt_label.set_no_show_all();
        minsec_label.set_name ("EditorTimeButton");
        minsec_label.set_size_request (-1, (int)timebar_height);
        minsec_label.set_alignment (1.0, 0.5);
        minsec_label.set_padding (5,0);
+       minsec_label.hide ();
+       minsec_label.set_no_show_all();
        smpte_label.set_name ("EditorTimeButton");
        smpte_label.set_size_request (-1, (int)timebar_height);
        smpte_label.set_alignment (1.0, 0.5);
        smpte_label.set_padding (5,0);
+       smpte_label.hide ();
+       smpte_label.set_no_show_all();
        frame_label.set_name ("EditorTimeButton");
        frame_label.set_size_request (-1, (int)timebar_height);
        frame_label.set_alignment (1.0, 0.5);
        frame_label.set_padding (5,0);
+       frame_label.hide ();
+       frame_label.set_no_show_all();
 
        tempo_label.set_name ("EditorTimeButton");
        tempo_label.set_size_request (-1, (int)timebar_height);
        tempo_label.set_alignment (1.0, 0.5);
        tempo_label.set_padding (5,0);
+       tempo_label.hide();
+       tempo_label.set_no_show_all();
        meter_label.set_name ("EditorTimeButton");
        meter_label.set_size_request (-1, (int)timebar_height);
        meter_label.set_alignment (1.0, 0.5);
        meter_label.set_padding (5,0);
+       meter_label.hide();
+       meter_label.set_no_show_all();
        mark_label.set_name ("EditorTimeButton");
        mark_label.set_size_request (-1, (int)timebar_height);
        mark_label.set_alignment (1.0, 0.5);
        mark_label.set_padding (5,0);
+       mark_label.hide();
+       mark_label.set_no_show_all();
        cd_mark_label.set_name ("EditorTimeButton");
        cd_mark_label.set_size_request (-1, (int)timebar_height);
        cd_mark_label.set_alignment (1.0, 0.5);
        cd_mark_label.set_padding (5,0);
+       cd_mark_label.hide();
+       cd_mark_label.set_no_show_all();
        range_mark_label.set_name ("EditorTimeButton");
        range_mark_label.set_size_request (-1, (int)timebar_height);
        range_mark_label.set_alignment (1.0, 0.5);
        range_mark_label.set_padding (5,0);
+       range_mark_label.hide();
+       range_mark_label.set_no_show_all();
        transport_mark_label.set_name ("EditorTimeButton");
        transport_mark_label.set_size_request (-1, (int)timebar_height);
        transport_mark_label.set_alignment (1.0, 0.5);
        transport_mark_label.set_padding (5,0);
+       transport_mark_label.hide();
+       transport_mark_label.set_no_show_all();
 
-       ruler_label_vbox.pack_start (minsec_label, false, false);
-       ruler_label_vbox.pack_start (smpte_label, false, false);
-       ruler_label_vbox.pack_start (frame_label, false, false);
-       ruler_label_vbox.pack_start (bbt_label, false, false);
+       initialize_rulers ();
+       initialize_canvas ();
+
+       selection->TimeChanged.connect (mem_fun(*this, &Editor::time_selection_changed));
+       selection->TracksChanged.connect (mem_fun(*this, &Editor::track_selection_changed));
+       editor_regions_selection_changed_connection = selection->RegionsChanged.connect (mem_fun(*this, &Editor::region_selection_changed));
+       selection->PointsChanged.connect (mem_fun(*this, &Editor::point_selection_changed));
+       selection->MarkersChanged.connect (mem_fun(*this, &Editor::marker_selection_changed));
+
+       edit_controls_vbox.set_spacing (0);
+       horizontal_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::scroll_canvas_horizontally), false);
+       vertical_adjustment.signal_value_changed().connect (mem_fun(*this, &Editor::tie_vertical_scrolling), true);
+       track_canvas->signal_map_event().connect (mem_fun (*this, &Editor::track_canvas_map_handler));
+
+       controls_layout.add (edit_controls_vbox);
+       controls_layout.set_name ("EditControlsBase");
+       controls_layout.add_events (Gdk::SCROLL_MASK);
+       controls_layout.signal_scroll_event().connect (mem_fun(*this, &Editor::control_layout_scroll), false);
        
+       controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
+       controls_layout.signal_button_release_event().connect (mem_fun(*this, &Editor::edit_controls_button_release));
+       controls_layout_size_request_connection = controls_layout.signal_size_request().connect (mem_fun (*this, &Editor::controls_layout_size_request));
+
+       edit_vscrollbar.set_adjustment (vertical_adjustment);
+       edit_hscrollbar.set_adjustment (horizontal_adjustment);
+
+       edit_hscrollbar.signal_button_press_event().connect (mem_fun(*this, &Editor::hscrollbar_button_press), false);
+       edit_hscrollbar.signal_button_release_event().connect (mem_fun(*this, &Editor::hscrollbar_button_release), false);
+       edit_hscrollbar.signal_size_allocate().connect (mem_fun(*this, &Editor::hscrollbar_allocate));
+
+       edit_hscrollbar.set_name ("EditorHScrollbar");
+
+       build_cursors ();
+       setup_toolbar ();
+       setup_midi_toolbar ();
+
+       edit_point_clock.ValueChanged.connect (mem_fun(*this, &Editor::edit_point_clock_changed));
+       
+       ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
+       ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
+                       0.0, 1.0, 100.0, 1.0));
+       pad_line_1->property_color_rgba() = 0xFF0000FF;
+       pad_line_1->show();
+       time_pad->show();
+
+       //time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
+       //time_canvas_vbox.set_size_request (-1, -1);
+
        ruler_label_event_box.add (ruler_label_vbox);   
        ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
        ruler_label_event_box.set_name ("TimebarLabelBase");
        ruler_label_event_box.signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_label_button_release));
 
-       time_button_vbox.pack_start (meter_label, false, false);
-       time_button_vbox.pack_start (tempo_label, false, false);
-       time_button_vbox.pack_start (mark_label, false, false);
-
        time_button_event_box.add (time_button_vbox);
        time_button_event_box.set_name ("TimebarLabelBase");
        time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
@@ -660,7 +674,7 @@ Editor::Editor ()
        region_list_display.append_column (_("Used"), region_list_columns.used);
        region_list_display.append_column (_("Path"), region_list_columns.path);
        region_list_display.set_headers_visible (true);
-       region_list_display.set_grid_lines (TREE_VIEW_GRID_LINES_BOTH);
+       //region_list_display.set_grid_lines (TREE_VIEW_GRID_LINES_BOTH);
        
        CellRendererText* region_name_cell = dynamic_cast<CellRendererText*>(region_list_display.get_column_cell_renderer (0));
        region_name_cell->property_editable() = true;
@@ -694,7 +708,7 @@ Editor::Editor ()
        region_list_display.signal_key_release_event().connect (mem_fun(*this, &Editor::region_list_display_key_release));
        region_list_display.signal_button_press_event().connect (mem_fun(*this, &Editor::region_list_display_button_press), false);
        region_list_display.signal_button_release_event().connect (mem_fun(*this, &Editor::region_list_display_button_release));
-       region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
+       region_list_change_connection = region_list_display.get_selection()->signal_changed().connect (mem_fun(*this, &Editor::region_list_selection_changed));
        // region_list_display.signal_popup_menu().connect (bind (mem_fun (*this, &Editor::show_region_list_display_context_menu), 1, 0));
        
        //ARDOUR_UI::instance()->secondary_clock.mode_changed.connect (mem_fun(*this, &Editor::redisplay_regions));
@@ -878,10 +892,8 @@ Editor::~Editor()
        }
 #endif
 
-       if (track_canvas) {
-               delete track_canvas;
-               track_canvas = 0;
-       }
+       delete track_canvas;
+       track_canvas = 0;
 }
 
 void
@@ -938,20 +950,22 @@ Editor::set_entered_track (TimeAxisView* tav)
 void
 Editor::show_window ()
 {
-       show_all_children ();
-       
-       /* re-hide editor list if necessary */
-       editor_list_button_toggled ();
+       if (! is_visible ()) {
+               show_all ();
 
-       /* now reset all audio_time_axis heights, because widgets might need
-          to be re-hidden
-       */
-       
-       TimeAxisView *tv;
+                /* re-hide editor list if necessary */
+                editor_list_button_toggled ();
+
+               /* now reset all audio_time_axis heights, because widgets might need
+                  to be re-hidden
+               */
+
+               TimeAxisView *tv;
        
-       for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-               tv = (static_cast<TimeAxisView*>(*i));
-               tv->reset_height ();
+               for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+                       tv = (static_cast<TimeAxisView*>(*i));
+                       tv->reset_height ();
+               }
        }
 
        present ();
@@ -1093,8 +1107,6 @@ Editor::access_action (std::string action_group, std::string action_item)
 
        ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::access_action), action_group, action_item));
 
-       cout<< "OSC: Recieved: "<< action_item << endl;
-
        RefPtr<Action> act;
        act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
 
@@ -1169,18 +1181,20 @@ Editor::center_screen_internal (nframes64_t frame, float page)
 void
 Editor::handle_new_duration ()
 {
+       if (!session) {
+               return;
+       }
+
        ENSURE_GUI_THREAD (mem_fun (*this, &Editor::handle_new_duration));
+       nframes64_t new_end = session->current_end_frame() + (nframes64_t) floorf (current_page_frames() * 0.10f);
 
-       nframes64_t new_end = session->get_maximum_extent() + (nframes64_t) floorf (current_page_frames() * 0.10f);
-                                 
-       if (new_end > last_canvas_frame) {
-               last_canvas_frame = new_end;
-               horizontal_adjustment.set_upper (last_canvas_frame / frames_per_unit);
-               //reset_scrolling_region ();
-       }
+       horizontal_adjustment.set_upper (new_end / frames_per_unit);
+       horizontal_adjustment.set_page_size (current_page_frames()/frames_per_unit);
 
-       horizontal_adjustment.set_value (leftmost_frame/frames_per_unit);
-       //cerr << "Editor::handle_new_duration () called ha v:l:u:ps:lcf = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << last_canvas_frame << endl;//DEBUG
+       if (horizontal_adjustment.get_value() + canvas_width > horizontal_adjustment.get_upper()) {
+               horizontal_adjustment.set_value (horizontal_adjustment.get_upper() - canvas_width);
+       }
+       //cerr << "Editor::handle_new_duration () called ha v:l:u:ps:lcf = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << endl;//DEBUG
 }
 
 void
@@ -1268,11 +1282,23 @@ Editor::connect_to_session (Session *t)
 
        edit_groups_changed ();
 
+       edit_point_clock.set_mode(AudioClock::BBT);
        edit_point_clock.set_session (session);
        zoom_range_clock.set_session (session);
        _playlist_selector->set_session (session);
        nudge_clock.set_session (session);
-       nudge_clock.set (session->frame_rate() * 5); // default of 5 seconds
+       if (Profile->get_sae()) {
+               BBT_Time bbt;
+               bbt.bars = 0;
+               bbt.beats = 0;
+               bbt.ticks = 120;
+               nframes_t pos = session->tempo_map().bbt_duration_at (0, bbt, 1);
+               nudge_clock.set_mode(AudioClock::BBT);
+               nudge_clock.set (pos, true, 0, AudioClock::BBT);
+               
+       } else {
+               nudge_clock.set (session->frame_rate() * 5, true, 0, AudioClock::SMPTE); // default of 5 seconds
+       }
 
        playhead_cursor->canvas_item.show ();
 
@@ -1330,16 +1356,16 @@ Editor::connect_to_session (Session *t)
        redisplay_named_selections ();
        redisplay_snapshots ();
 
+       restore_ruler_visibility ();
+       //tempo_map_changed (Change (0));
+       session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
+
        initial_route_list_display ();
 
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
        }
 
-       restore_ruler_visibility ();
-       //tempo_map_changed (Change (0));
-       session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
-
        start_scrolling ();
 
        /* don't show master bus in a new session */
@@ -1881,10 +1907,11 @@ void
 Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> region, Menu_Helpers::MenuList& edit_items)
 {
        using namespace Menu_Helpers;
+       Gtk::MenuItem* foo_item;
        Menu     *region_menu = manage (new Menu);
        MenuList& items       = region_menu->items();
        region_menu->set_name ("ArdourContextMenu");
-       
+
        boost::shared_ptr<AudioRegion> ar;
        boost::shared_ptr<MidiRegion>  mr;
 
@@ -2023,7 +2050,12 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
 
        /* range related stuff */
 
-       items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_location_from_audio_region)));
+       items.push_back (MenuElem (_("Add Single Range"), mem_fun (*this, &Editor::add_location_from_audio_region)));
+       items.push_back (MenuElem (_("Add Range Markers"), mem_fun (*this, &Editor::add_locations_from_audio_region)));
+       if (selection->regions.size() < 2) {
+               items.back().set_sensitive (false);
+       }
+
        items.push_back (MenuElem (_("Set Range Selection"), mem_fun (*this, &Editor::set_selection_from_region)));
        items.push_back (SeparatorElem());
                         
@@ -2046,7 +2078,15 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
        trim_menu->set_name ("ArdourContextMenu");
        
        trim_items.push_back (MenuElem (_("Start to edit point"), mem_fun(*this, &Editor::trim_region_from_edit_point)));
+       foo_item = &trim_items.back();
+       if (_edit_point == EditAtMouse) {
+               foo_item->set_sensitive (false);
+       }
        trim_items.push_back (MenuElem (_("Edit point to end"), mem_fun(*this, &Editor::trim_region_to_edit_point)));
+       foo_item = &trim_items.back();
+       if (_edit_point == EditAtMouse) {
+               foo_item->set_sensitive (false);
+       }
        trim_items.push_back (MenuElem (_("Trim To Loop"), mem_fun(*this, &Editor::trim_region_to_loop)));
        trim_items.push_back (MenuElem (_("Trim To Punch"), mem_fun(*this, &Editor::trim_region_to_punch)));
                             
@@ -2055,6 +2095,10 @@ Editor::add_region_context_items (StreamView* sv, boost::shared_ptr<Region> regi
 
        items.push_back (MenuElem (_("Split"), (mem_fun(*this, &Editor::split_region))));
        region_edit_menu_split_item = &items.back();
+       
+       if (_edit_point == EditAtMouse) {
+               region_edit_menu_split_item->set_sensitive (false);
+       }
 
        items.push_back (MenuElem (_("Make mono regions"), (mem_fun(*this, &Editor::split_multichannel_region))));
        region_edit_menu_split_multichannel_item = &items.back();
@@ -2300,7 +2344,7 @@ Editor::set_snap_to (SnapType st)
        case SnapToAEighthBeat:
        case SnapToAQuarterBeat:
        case SnapToAThirdBeat:
-               compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(edit_packer.get_width() * frames_per_unit));
+               compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
                update_tempo_based_rulers ();
                break;
 
@@ -2410,23 +2454,56 @@ Editor::set_state (const XMLNode& node)
                _id = prop->value ();
        }
 
-       if ((geometry = find_named_node (node, "geometry")) == 0) {
+       g.base_width = default_width;
+       g.base_height = default_height;
+       x = 1;
+       y = 1;
+       xoff = 0;
+       yoff = 21;
 
-               g.base_width = default_width;
-               g.base_height = default_height;
-               x = 1;
-               y = 1;
-               xoff = 0;
-               yoff = 21;
+       if ((geometry = find_named_node (node, "geometry")) != 0) {
 
-       } else {
+               XMLProperty* prop;
 
-               g.base_width = atoi(geometry->property("x-size")->value());
-               g.base_height = atoi(geometry->property("y-size")->value());
-               x = atoi(geometry->property("x-pos")->value());
-               y = atoi(geometry->property("y-pos")->value());
-               xoff = atoi(geometry->property("x-off")->value());
-               yoff = atoi(geometry->property("y-off")->value());
+               if ((prop = geometry->property("x_size")) == 0) {
+                       prop = geometry->property ("x-size");
+               }
+               if (prop) {
+                       g.base_width = atoi(prop->value());
+               }
+               if ((prop = geometry->property("y_size")) == 0) {
+                       prop = geometry->property ("y-size");
+               }
+               if (prop) {
+                       g.base_height = atoi(prop->value());
+               }
+
+               if ((prop = geometry->property ("x_pos")) == 0) {
+                       prop = geometry->property ("x-pos");
+               }
+               if (prop) {
+                       x = atoi (prop->value());
+
+               }
+               if ((prop = geometry->property ("y_pos")) == 0) {
+                       prop = geometry->property ("y-pos");
+               }
+               if (prop) {
+                       y = atoi (prop->value());
+               }
+
+               if ((prop = geometry->property ("x_off")) == 0) {
+                       prop = geometry->property ("x-off");
+               }
+               if (prop) {
+                       xoff = atoi (prop->value());
+               }
+               if ((prop = geometry->property ("y_off")) == 0) {
+                       prop = geometry->property ("y-off");
+               }
+               if (prop) {
+                       yoff = atoi (prop->value());
+               }
        }
 
        set_default_size (g.base_width, g.base_height);
@@ -2652,19 +2729,23 @@ Editor::get_state ()
 
 
 
-TimeAxisView *
+/** @param y y offset from the top of all trackviews.
+ *  @return pair: TimeAxisView that y is over, layer index.
+ *  TimeAxisView may be 0.  Layer index is the layer number if the TimeAxisView is valid and is
+ *  in stacked region display mode, otherwise 0.
+ */
+std::pair<TimeAxisView *, layer_t>
 Editor::trackview_by_y_position (double y)
 {
        for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
 
-               TimeAxisView *tv;
-
-               if ((tv = (*iter)->covers_y_position (y)) != 0) {
-                       return tv;
+               std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
+               if (r.first) {
+                       return r;
                }
        }
 
-       return 0;
+       return std::make_pair ( (TimeAxisView *) 0, 0);
 }
 
 void
@@ -2933,7 +3014,7 @@ Editor::setup_toolbar ()
 #ifdef GTKOSX
        const guint32 FUDGE = 38; // Combo's are stupid - they steal space from the entry for the button
 #else
-       const guint32 FUDGE = 18; // Combo's are stupid - they steal space from the entry for the button
+       const guint32 FUDGE = 24; // Combo's are stupid - they steal space from the entry for the button
 #endif
 
        /* Mode Buttons (tool selection) */
@@ -2988,7 +3069,9 @@ Editor::setup_toolbar ()
 
        vector<string> edit_mode_strings;
        edit_mode_strings.push_back (edit_mode_to_string (Slide));
-       edit_mode_strings.push_back (edit_mode_to_string (Splice));
+       if (!Profile->get_sae()) {
+               edit_mode_strings.push_back (edit_mode_to_string (Splice));
+       }
        edit_mode_strings.push_back (edit_mode_to_string (Lock));
 
        edit_mode_selector.set_name ("EditModeSelector");
@@ -3002,6 +3085,10 @@ Editor::setup_toolbar ()
        mouse_mode_tearoff = manage (new TearOff (*mode_box));
        mouse_mode_tearoff->set_name ("MouseModeBase");
 
+       if (Profile->get_sae()) {
+               mouse_mode_tearoff->set_can_be_torn_off (false);
+       }
+
        mouse_mode_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
                                                  &mouse_mode_tearoff->tearoff_window()));
        mouse_mode_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
@@ -3130,6 +3217,10 @@ Editor::setup_toolbar ()
        tools_tearoff = manage (new TearOff (*hbox));
        tools_tearoff->set_name ("MouseModeBase");
 
+       if (Profile->get_sae()) {
+               tools_tearoff->set_can_be_torn_off (false);
+       }
+
        tools_tearoff->Detach.connect (bind (mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox), 
                                             &tools_tearoff->tearoff_window()));
        tools_tearoff->Attach.connect (bind (mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox), 
@@ -3161,12 +3252,10 @@ Editor::setup_toolbar ()
 }
 
 void
-Editor::midi_panic_toggle ()
+Editor::midi_panic_button_pressed ()
 {
        if (session) {
                session->midi_panic();
-               midi_panic_button.set_active (false);
-               midi_panic_button.set_state (STATE_NORMAL);
        }
 }
 
@@ -3201,18 +3290,18 @@ Editor::setup_midi_toolbar ()
        midi_tool_button_box.pack_start(midi_tool_pencil_button, true, true);
        midi_tool_button_box.pack_start(midi_tool_select_button, true, true);
        midi_tool_button_box.pack_start(midi_tool_resize_button, true, true);
-       midi_tool_button_box.pack_start(midi_tool_erase_button, true, true);
+       midi_tool_button_box.pack_start(midi_tool_erase_button , true, true);
        midi_tool_button_box.set_homogeneous(true);
 
        midi_tool_pencil_button.set_name ("MouseModeButton");
        midi_tool_select_button.set_name ("MouseModeButton");
        midi_tool_resize_button.set_name ("MouseModeButton");
-       midi_tool_erase_button.set_name ("MouseModeButton");
+       midi_tool_erase_button .set_name ("MouseModeButton");
 
        ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_pencil_button, _("Add/Move/Stretch Notes"));
        ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_select_button, _("Select/Move Notes"));
        ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_resize_button, _("Resize Notes"));
-       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button, _("Erase Notes"));
+       ARDOUR_UI::instance()->tooltips().set_tip (midi_tool_erase_button,  _("Erase Notes"));
 
        midi_tool_pencil_button.unset_flags (CAN_FOCUS);
        midi_tool_select_button.unset_flags (CAN_FOCUS);
@@ -3228,12 +3317,20 @@ Editor::setup_midi_toolbar ()
        midi_tool_erase_button.signal_toggled().connect (bind (mem_fun(*this,
                                &Editor::midi_edit_mode_toggled), Editing::MidiEditErase));
 
+       
+       /* Midi sound notes */
+       midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
+       midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
+       ARDOUR_UI::instance()->tooltips().set_tip (midi_sound_notes, _("Sound Notes"));
+       midi_sound_notes.unset_flags (CAN_FOCUS);
+       
        /* Panic */
        
-       VBox* panic_box = manage (new VBox);
+       HBox* panic_box = manage (new HBox);
        midi_panic_button.set_name("MidiPanicButton");
        midi_panic_button.signal_pressed().connect (
-                       mem_fun(this, &Editor::midi_panic_toggle));
+                       mem_fun(this, &Editor::midi_panic_button_pressed));
+       panic_box->pack_start (midi_sound_notes , true, true);
        panic_box->pack_start (midi_panic_button, true, true);
        
        /* Pack everything in... */
@@ -3298,12 +3395,19 @@ Editor::convert_drop_to_paths (vector<ustring>& paths,
                }
   
                /* Parse the "uri-list" format that Nautilus provides, 
-                  where each pathname is delimited by \r\n
+                  where each pathname is delimited by \r\n.
+
+                  THERE MAY BE NO NULL TERMINATING CHAR!!!
                */
-       
-               const char* p = data.get_text().c_str();
+
+               ustring txt = data.get_text();
+               const char* p;
                const char* q;
 
+               p = (const char *) malloc (txt.length() + 1);
+               txt.copy ((char *) p, txt.length(), 0);
+               ((char*)p)[txt.length()] = '\0';
+
                while (p)
                {
                        if (*p != '#')
@@ -3312,8 +3416,9 @@ Editor::convert_drop_to_paths (vector<ustring>& paths,
                                        p++;
                                
                                q = p;
-                               while (*q && (*q != '\n') && (*q != '\r'))
+                               while (*q && (*q != '\n') && (*q != '\r')) {
                                        q++;
+                               }
                                
                                if (q > p)
                                {
@@ -3332,6 +3437,8 @@ Editor::convert_drop_to_paths (vector<ustring>& paths,
                                p++;
                }
 
+               free ((void*)p);
+               
                if (uris.empty()) {
                        return -1;
                }
@@ -3426,7 +3533,7 @@ Editor::restore_state (State *state)
 
        *selection = *state->selection;
        time_selection_changed ();
-       region_selection_changed ();   
+       region_selection_changed ();
 
        /* XXX other selection change handlers? */
 }
@@ -3630,7 +3737,11 @@ Editor::cycle_edit_mode ()
 {
        switch (Config->get_edit_mode()) {
        case Slide:
-               Config->set_edit_mode (Splice);
+               if (Profile->get_sae()) {
+                       Config->set_edit_mode (Lock);
+               } else {
+                       Config->set_edit_mode (Splice);
+               }
                break;
        case Splice:
                Config->set_edit_mode (Lock);
@@ -3903,12 +4014,23 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
        static int32_t done;
        XMLNode* geometry;
 
-       if ((geometry = find_named_node (*node, "geometry")) == 0) {
-               width = default_width;
-               height = default_height;
-       } else {
-               width = atoi(geometry->property("x-size")->value());
-               height = atoi(geometry->property("y-size")->value());
+       width = default_width;
+       height = default_height;
+
+       if ((geometry = find_named_node (*node, "geometry")) != 0) {
+
+               if ((prop = geometry->property ("x_size")) == 0) {
+                       prop = geometry->property ("x-size");
+               }
+               if (prop) {
+                       width = atoi (prop->value());
+               }
+               if ((prop = geometry->property ("y_size")) == 0) {
+                       prop = geometry->property ("y-size");
+               }
+               if (prop) {
+                       height = atoi (prop->value());
+               }
        }
 
        if (which == static_cast<Paned*> (&edit_pane)) {
@@ -4050,7 +4172,8 @@ Editor::end_location_changed (Location* location)
 {
        ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::end_location_changed), location));
        //reset_scrolling_region ();
-       horizontal_adjustment.set_upper ( location->start());
+       nframes64_t session_span = location->start() + (nframes64_t) floorf (current_page_frames() * 0.10f);
+       horizontal_adjustment.set_upper (session_span / frames_per_unit);
 }
 
 int
@@ -4522,12 +4645,14 @@ void
 Editor::use_visual_state (VisualState& vs)
 {
        no_save_visual = true;
+       no_route_list_redisplay = true;
 
        vertical_adjustment.set_value (vs.y_position);
 
        set_zoom_focus (vs.zoom_focus);
        reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
-
+       zoomed_to_region = vs.zoomed_to_region;
+       
        for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
                TrackViewList::iterator t;
 
@@ -4538,10 +4663,14 @@ Editor::use_visual_state (VisualState& vs)
                }
        }
 
+
        if (!vs.track_states.empty()) {
                update_route_visibility ();
        } 
-       
+
+       no_route_list_redisplay = false;
+       redisplay_route_list ();
+
        no_save_visual = false;
 }
 
@@ -4579,6 +4708,8 @@ Editor::set_frames_per_unit (double fpu)
 void
 Editor::post_zoom ()
 {
+       nframes64_t cef = 0;
+
        // convert fpu to frame count
 
        nframes64_t frames = (nframes64_t) floor (frames_per_unit * canvas_width);
@@ -4599,9 +4730,16 @@ Editor::post_zoom ()
                }
        }
 
+
        ZoomChanged (); /* EMIT_SIGNAL */
 
        reset_hscrollbar_stepping ();
+
+       if (session) {
+               cef = session->current_end_frame() + (current_page_frames() / 10);// Add a little extra so we can see the end marker
+       }
+       horizontal_adjustment.set_upper (cef / frames_per_unit);
+
        //reset_scrolling_region ();
 
        if (playhead_cursor) {
@@ -4648,34 +4786,47 @@ Editor::idle_visual_changer ()
        VisualChange::Type p = pending_visual_change.pending;
        pending_visual_change.pending = (VisualChange::Type) 0;
 
+#ifdef FIX_THIS_FOR_V3
+       double last_time_origin = horizontal_adjustment.get_value();
+#endif
+
        if (p & VisualChange::ZoomLevel) {
                set_frames_per_unit (pending_visual_change.frames_per_unit);
 
                compute_fixed_ruler_scale ();
-               compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(edit_packer.get_width() * pending_visual_change.frames_per_unit));
-               compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(edit_packer.get_width() * pending_visual_change.frames_per_unit));
+               compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
+               compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
                update_tempo_based_rulers ();
        }
        if (p & VisualChange::TimeOrigin) {
+               horizontal_adjustment.set_value (pending_visual_change.time_origin / frames_per_unit);
+       }
 
-               nframes64_t csf=0, cef=0;
-               nframes64_t current_time_origin = (nframes64_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
-
-               if (session) {
-                       csf = session->current_start_frame();
-                       cef = session->current_end_frame() + (current_page_frames() / 24);// Add a little extra so we can see the end marker
-               }
-
-               /* if we seek beyond the current end of the canvas, move the end */
+       nframes64_t csf=0, cef=0;
+       nframes64_t current_time_origin = (nframes64_t) floor (horizontal_adjustment.get_value() * frames_per_unit);
+       
+       if (session) {
+               csf = session->current_start_frame();
+               cef = session->current_end_frame();
+       }
+       
+       /* if we seek beyond the current end of the canvas, move the end */
 
-               if (current_time_origin != pending_visual_change.time_origin) {
-                       last_canvas_frame = (cef > (pending_visual_change.time_origin + current_page_frames())) ? cef : pending_visual_change.time_origin + current_page_frames();
-                       horizontal_adjustment.set_upper ((cef - csf) / frames_per_unit);
-                       horizontal_adjustment.set_value (pending_visual_change.time_origin / frames_per_unit);
-               } else {
-                       update_fixed_rulers();
-                       redisplay_tempo (true);
-               }
+#ifdef FIX_THIS_FOR_V3
+       if (last_time_origin == horizontal_adjustment.get_value() ) {
+               /* changed signal not emitted */
+               update_fixed_rulers ();
+               redisplay_tempo (true);
+       }
+#endif
+       
+       if (current_time_origin != pending_visual_change.time_origin) {
+               cef += current_page_frames() / 10; // Add a little extra so we can see the end marker
+               horizontal_adjustment.set_upper (cef / frames_per_unit);
+               horizontal_adjustment.set_value (pending_visual_change.time_origin / frames_per_unit);
+       } else {
+               update_fixed_rulers();
+               redisplay_tempo (true);
        }
        //cerr << "Editor::idle_visual_changer () called ha v:l:u:ps:fpu = " << horizontal_adjustment.get_value() << ":" << horizontal_adjustment.get_lower() << ":" << horizontal_adjustment.get_upper() << ":" << horizontal_adjustment.get_page_size() << ":" << frames_per_unit << endl;//DEBUG
        pending_visual_change.idle_handler_id = -1;
@@ -4684,7 +4835,7 @@ Editor::idle_visual_changer ()
 
 struct EditorOrderTimeAxisSorter {
     bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
-           return a->order < b->order;
+           return a->order () < b->order ();
     }
 };
        
@@ -4983,6 +5134,26 @@ Editor::show_rhythm_ferret ()
        rhythm_ferret->present ();
 }
 
+void
+Editor::show_bundle_manager ()
+{
+       if (_bundle_manager == 0) {
+               _bundle_manager = new BundleManager (*session);
+       }
+
+       _bundle_manager->show ();
+}
+
+void
+Editor::show_global_port_matrix (ARDOUR::DataType t)
+{
+       if (_global_port_matrix[t] == 0) {
+               _global_port_matrix[t] = new GlobalPortMatrixWindow (*session, t);
+       }
+
+       _global_port_matrix[t]->show ();
+}
+
 void
 Editor::first_idle ()
 {
@@ -5001,10 +5172,11 @@ Editor::first_idle ()
        for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
                (*t)->first_idle();
        }
+
+       // first idle adds route children (automation tracks), so we need to redisplay here
+       redisplay_route_list();
        
-       if (dialog) {
-               delete dialog;
-       }
+       delete dialog;
 
        _have_idled = true;
 }
@@ -5156,7 +5328,7 @@ Editor::add_to_idle_resize (TimeAxisView* view, uint32_t h)
 {
        if (resize_idle_id < 0) {
                resize_idle_id = g_idle_add (_idle_resizer, this);
-       }
+       } 
 
        resize_idle_target = h;
 
@@ -5174,6 +5346,7 @@ Editor::idle_resize ()
                (*i)->idle_resize (resize_idle_target);
        }
        pending_resizes.clear();
+       flush_canvas ();
        resize_idle_id = -1;
        return false;
 }