[SCM] ardour/master: Sync with upstream VCS r8077.

adiknoth-guest at users.alioth.debian.org adiknoth-guest at users.alioth.debian.org
Mon Feb 14 17:33:42 UTC 2011


The following commit has been merged in the master branch:
commit 60568198ea658bec2ac3ab6f72a796b2d9e27d1c
Author: Adrian Knoth <adi at drcomp.erfurt.thur.de>
Date:   Mon Feb 14 17:32:27 2011 +0100

    Sync with upstream VCS r8077.
    
    A few fixes have been incorporated upstream. Let's provide those to our
    users.

diff --git a/debian/patches/000_sync_vcs.patch b/debian/patches/000_sync_vcs.patch
new file mode 100644
index 0000000..e1b11ae
--- /dev/null
+++ b/debian/patches/000_sync_vcs.patch
@@ -0,0 +1,4618 @@
+From: Adrian Knoth <adi at drcomp.erfurt.thur.de>
+Description: Sync with upstream VCS revision 8077
+Origin: git://repo.or.cz/ardour2.git
+Forwarded: Not-needed
+--- a/ardour.rc.in
++++ b/ardour.rc.in
+@@ -1,8 +1,8 @@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <Ardour>
+-  <MIDI-port tag="%MIDITAG%" device="ardour" type="%MIDITYPE%" mode="duplex"/>
+-  <MIDI-port tag="control" device="ardour" type="%MIDITYPE%" mode="duplex"/>
+-  <MIDI-port tag="mcu" device="ardour" type="%MIDITYPE%" mode="duplex"/>
++  <MIDI-port tag="%MIDITAG%" device="%MIDI_DEVICE_NAME%" type="%MIDITYPE%" mode="duplex"/>
++  <MIDI-port tag="control" device="%MIDI_DEVICE_NAME%" type="%MIDITYPE%" mode="duplex"/>
++  <MIDI-port tag="mcu" device="%MIDI_DEVICE_NAME%" type="%MIDITYPE%" mode="duplex"/>
+   <Config>
+     <Option name="minimum-disk-io-bytes" value="262144"/>
+     <Option name="track-buffer-seconds" value="5.000000"/>
+--- a/gtk2_ardour/ardev_common.sh.in
++++ b/gtk2_ardour/ardev_common.sh.in
+@@ -11,9 +11,9 @@
+     echo USING OLD CLEARLOOKS
+     export GTK_PATH=~/.ardour2:libs/clearlooks-older
+ fi
+-export VAMP_PATH=libs/vamp-plugins:$VAMP_PATH
++export VAMP_PATH=libs/vamp-plugins${VAMP_PATH:+:$VAMP_PATH}
+ 
+-export LD_LIBRARY_PATH=libs/vamp-sdk:libs/surfaces/control_protocol:libs/ardour:libs/midi++2:libs/pbd:libs/rubberband:libs/soundtouch:libs/gtkmm2ext:libs/sigc++2:libs/glibmm2:libs/gtkmm2/atk:libs/gtkmm2/pango:libs/gtkmm2/gdk:libs/gtkmm2/gtk:libs/libgnomecanvasmm:libs/libsndfile:libs/appleutility:$LD_LIBRARY_PATH
++export LD_LIBRARY_PATH=libs/vamp-sdk:libs/surfaces/control_protocol:libs/ardour:libs/midi++2:libs/pbd:libs/rubberband:libs/soundtouch:libs/gtkmm2ext:libs/sigc++2:libs/glibmm2:libs/gtkmm2/atk:libs/gtkmm2/pango:libs/gtkmm2/gdk:libs/gtkmm2/gtk:libs/libgnomecanvasmm:libs/libsndfile:libs/appleutility${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+ 
+ # DYLD_LIBRARY_PATH is for darwin.
+ export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH
+--- a/gtk2_ardour/ardour.sh.in
++++ b/gtk2_ardour/ardour.sh.in
+@@ -1,8 +1,8 @@
+ #!/bin/sh
+ 
+-export GTK_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2:$GTK_PATH
++export GTK_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2${GTK_PATH:+:$GTK_PATH}
+ 
+-export LD_LIBRARY_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2:$LD_LIBRARY_PATH 
++export LD_LIBRARY_PATH=%INSTALL_PREFIX%/%LIBDIR%/ardour2${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+ # DYLD_LIBRARY_PATH is for Darwin
+ export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
+ 
+--- a/gtk2_ardour/ardour_ui.cc
++++ b/gtk2_ardour/ardour_ui.cc
+@@ -34,6 +34,7 @@
+ 
+ #include <gtkmm/messagedialog.h>
+ #include <gtkmm/accelmap.h>
++#include <gtkmm2ext/application.h>
+ 
+ #include <pbd/error.h>
+ #include <pbd/basename.h>
+@@ -643,6 +644,11 @@
+ void
+ ARDOUR_UI::startup ()
+ {
++	Application* app = Application::instance();
++
++	app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
++	app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
++
+ 	string name, path;
+ 	
+ 	new_session_dialog = new NewSessionDialog();
+@@ -653,7 +659,9 @@
+ 	if (audio_setup) {
+ 		new_session_dialog->engine_control.set_state (*audio_setup);
+ 	}
+-	
++
++	app->ready ();
++
+ 	if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
+ 		return;
+ 	}
+@@ -2347,6 +2355,7 @@
+ ARDOUR_UI::idle_load (const Glib::ustring& path)
+ {
+ 	if (session) {
++
+ 		if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
+ 			/* /path/to/foo => /path/to/foo, foo */
+ 			load_session (path, basename_nosuffix (path));
+@@ -2354,13 +2363,13 @@
+ 			/* /path/to/foo/foo.ardour => /path/to/foo, foo */
+ 			load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
+ 		}
++
+ 	} else {
+ 
+ 		ARDOUR_COMMAND_LINE::session_name = path;
+ 
+ 		if (new_session_dialog) {
+ 
+-
+ 			/* make it break out of Dialog::run() and
+ 			   start again.
+ 			 */
+--- a/gtk2_ardour/ardour_ui_ed.cc
++++ b/gtk2_ardour/ardour_ui_ed.cc
+@@ -891,9 +891,6 @@
+ 	}
+ 
+ 	app->set_menu_bar (*menu_bar);
+-
+-	app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
+-	app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
+ }
+ 
+ void
+--- a/gtk2_ardour/audio_streamview.cc
++++ b/gtk2_ardour/audio_streamview.cc
+@@ -378,6 +378,8 @@
+ 	list<RegionView *>::iterator i, tmp;
+ 	list<CrossfadeView*>::iterator xi, tmpx;
+ 
++        cerr << "REDISPLAY diskstream\n";
++
+ 	for (i = region_views.begin(); i != region_views.end(); ++i) {
+ 		(*i)->set_valid (false);
+ 	}
+@@ -424,6 +426,7 @@
+ 	/* now fix layering */
+ 
+ 	for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
++                cerr << "Layering call for " << (*i)->region()->name() << endl;
+ 		region_layered (*i);
+ 	}
+ }
+--- a/gtk2_ardour/canvas-waveview.c
++++ b/gtk2_ardour/canvas-waveview.c
+@@ -1246,12 +1246,12 @@
+ 		max = waveview->cache->data[cache_index].max;
+ 		min = waveview->cache->data[cache_index].min;
+ 		
+-		if (max >= 1.0) {
++		if (max >= 0.98853) { // -0.9dBFS
+ 			max = 1.0;
+ 			next_clip_max = 1;
+ 		}
+ 		
+-		if (min <= -1.0) {
++		if (min <= -0.98853) { // ditto
+ 			min = -1.0;
+ 			next_clip_min = 1;
+ 		}
+--- a/gtk2_ardour/editor_audio_import.cc
++++ b/gtk2_ardour/editor_audio_import.cc
+@@ -164,7 +164,9 @@
+ 		}
+ 
+ 		SrcQuality quality = sfbrowser->get_src_quality();
++                
+ 
++                cerr << "Start import of " << paths.size() << " at " << where << endl;
+ 
+ 		if (sfbrowser->copy_files_btn.get_active()) {
+ 			do_import (paths, chns, mode, quality, where);
+@@ -289,6 +291,7 @@
+ 	boost::shared_ptr<AudioTrack> track;
+ 	vector<ustring> to_import;
+ 	int nth = 0;
++        bool use_timestamp = (pos == -1);
+ 
+ 	if (interthread_progress_window == 0) {
+ 		build_interthread_progress_window ();
+@@ -339,6 +342,11 @@
+ 				/* NOTREACHED*/
+ 			}
+ 
++                        /* have to reset this for every file we handle */
++
++                        if (use_timestamp) {
++                                pos = -1;
++                        }
+ 
+ 			switch (chns) {
+ 			case Editing::ImportDistinctFiles:
+@@ -682,14 +690,6 @@
+ 	
+ 	use_timestamp = (pos == -1);
+ 
+-	if (use_timestamp) {
+-		if (sources[0]->natural_position() != 0) {
+-			pos = sources[0]->natural_position();
+-		} else {
+-			pos = get_preferred_edit_position ();
+-		}
+-	}
+-
+ 	if (target_regions == 1) {
+ 
+ 		/* take all the sources we have and package them up as a region */
+@@ -699,8 +699,8 @@
+ 				   (RegionFactory::create (sources, 0, sources[0]->length(), region_name, 0,
+ 							   Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));
+ 							   
+-        if (use_timestamp) {
+-		    ar->special_set_position(sources[0]->natural_position());
++                if (use_timestamp) {
++                        ar->special_set_position(sources[0]->natural_position());
+ 		}
+ 		
+ 		regions.push_back (ar);
+@@ -750,16 +750,57 @@
+ 	}
+ 
+ 	int n = 0;
++        nframes_t rlen = 0;
++
++        cerr << "About to add " << regions.size() << endl;
+ 
+         for (vector<boost::shared_ptr<AudioRegion> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
+-                
++
++                if (use_timestamp) {
++                        
++                        cerr << "Using timestamp to place region " << (*r)->name() << endl;
++
++                        /* get timestamp for this region */
++
++                        const boost::shared_ptr<Source> s ((*r)->get_sources().front());
++                        const boost::shared_ptr<AudioSource> as = boost::dynamic_pointer_cast<AudioSource> (s);
++                        
++                        assert (as);
++                        
++                        if (as->natural_position() != 0) {
++                                pos = as->natural_position();
++                                cerr << "\tgot " << pos << " from source TC info\n";
++                        } else if (target_tracks == 1) {
++                                /* hmm, no timestamp available, put it after the previous region
++                                 */
++                                if (n == 0) {
++                                        pos = get_preferred_edit_position ();
++                                        cerr << "\tno timestamp, first file, use edit pos = " << pos << endl;
++                                } else {
++                                        pos += rlen;
++                                        cerr << "\tpacked-sequence-shuffle to " << pos << endl;
++                                }
++                        } else {
++                                pos = get_preferred_edit_position ();
++                                cerr << "\tmultitracks, using edit position = " << pos << endl;
++                        }
++                                
++                }
++
++                cerr << "Actually inserting at " << pos << endl;
++
+                 finish_bringing_in_audio (*r, input_chan, output_chan, pos, mode, track);
+ 
++                rlen = (*r)->length();
++
+                 if (target_tracks != 1) {
+                         track.reset ();
+-		} else {
+-			pos += (*r)->length();
+-		} 
++                } else { 
++                        if (!use_timestamp) {
++                                /* line each one up right after the other */
++                                pos += (*r)->length();
++                        }
++                }
+ 	}
+ 
+ 	/* setup peak file building in another thread */
+--- a/gtk2_ardour/editor_canvas.cc
++++ b/gtk2_ardour/editor_canvas.cc
+@@ -107,13 +107,8 @@
+ 	track_canvas->set_center_scroll_region (false);
+ 	track_canvas->set_dither (Gdk::RGB_DITHER_NONE);
+ 
+-	Glib::RefPtr<Gdk::Screen> screen = get_screen();
+-
+-	if (!screen) {
+-		screen = Gdk::Screen::get_default();
+-	}
+-	physical_screen_width = screen->get_width ();
+-	physical_screen_height = screen->get_height ();
++	gint phys_width = physical_screen_width (Glib::RefPtr<Gdk::Window>());
++	gint phys_height = physical_screen_height (Glib::RefPtr<Gdk::Window>());
+ 
+ 	/* stuff for the verbose canvas cursor */
+ 
+@@ -144,21 +139,21 @@
+ 
+ #ifdef GTKOSX
+ 	/*XXX please don't laugh. this actually improves canvas performance on osx */
+-	bogus_background_rect =  new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, max_canvas_coordinate/3, physical_screen_height);
++	bogus_background_rect =  new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, max_canvas_coordinate/3, phys_height);
+ 	bogus_background_rect->property_outline_pixels() = 0;
+ #endif
+-	transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, physical_screen_height);
++	transport_loop_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, phys_height);
+ 	transport_loop_range_rect->property_outline_pixels() = 1;
+ 	transport_loop_range_rect->hide();
+ 
+-	transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, physical_screen_height);
++	transport_punch_range_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, phys_height);
+ 	transport_punch_range_rect->property_outline_pixels() = 0;
+ 	transport_punch_range_rect->hide();
+ 
+ 	_background_group = new ArdourCanvas::Group (*track_canvas->root());
+ 	_master_group = new ArdourCanvas::Group (*track_canvas->root());
+ 
+-	range_marker_drag_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, physical_screen_height);
++	range_marker_drag_rect = new ArdourCanvas::SimpleRect (*time_line_group, 0.0, 0.0, 0.0, phys_height);
+ 	range_marker_drag_rect->hide ();
+ 
+ 	_trackview_group = new ArdourCanvas::Group (*_master_group);
+@@ -166,60 +161,60 @@
+ 
+ 	meter_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ 	if (Profile->get_sae()) {
+-		meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, physical_screen_width, timebar_height - 1);
++		meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, phys_width, timebar_height - 1);
+ 		meter_bar->property_outline_pixels() = 1;
+ 	} else {
+-		meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, physical_screen_width, timebar_height);
++		meter_bar = new ArdourCanvas::SimpleRect (*meter_bar_group, 0.0, 0.0, phys_width, timebar_height);
+ 		meter_bar->property_outline_pixels() = 0;
+ 	}
+ 	meter_bar->property_outline_what() = (0x1 | 0x8);
+ 
+ 	tempo_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ 	if (Profile->get_sae()) {
+-		tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++		tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ 		tempo_bar->property_outline_pixels() = 1;
+ 	} else {
+-		tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++		tempo_bar = new ArdourCanvas::SimpleRect (*tempo_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ 		tempo_bar->property_outline_pixels() = 0;
+ 	}
+ 	tempo_bar->property_outline_what() = (0x1 | 0x8);
+ 
+ 	range_marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ 	if (Profile->get_sae()) {
+-		range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++		range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ 		range_marker_bar->property_outline_pixels() = 1;
+ 	} else {
+-		range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++		range_marker_bar = new ArdourCanvas::SimpleRect (*range_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ 		range_marker_bar->property_outline_pixels() = 0;
+ 	}
+ 	range_marker_bar->property_outline_what() = (0x1 | 0x8);
+ 	
+ 	transport_marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ 	if (Profile->get_sae()) {
+-		transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0,  physical_screen_width, (timebar_height - 1));
++		transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0,  phys_width, (timebar_height - 1));
+ 		transport_marker_bar->property_outline_pixels() = 1;
+ 	} else {
+-		transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0,  physical_screen_width, (timebar_height));
++		transport_marker_bar = new ArdourCanvas::SimpleRect (*transport_marker_bar_group, 0.0, 0.0,  phys_width, (timebar_height));
+ 		transport_marker_bar->property_outline_pixels() = 0;
+ 	}
+ 	transport_marker_bar->property_outline_what() = (0x1 | 0x8);
+ 
+ 	marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ 	if (Profile->get_sae()) {
+-		marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++		marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ 		marker_bar->property_outline_pixels() = 1;
+ 	} else {
+-		marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++		marker_bar = new ArdourCanvas::SimpleRect (*marker_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ 		marker_bar->property_outline_pixels() = 0;
+ 	}
+ 	marker_bar->property_outline_what() = (0x1 | 0x8);
+ 	
+ 	cd_marker_bar_group = new ArdourCanvas::Group (*track_canvas->root ());
+ 	if (Profile->get_sae()) {
+-		cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height - 1));
++		cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height - 1));
+ 		cd_marker_bar->property_outline_pixels() = 1;
+ 	} else {
+-		cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, physical_screen_width, (timebar_height));
++		cd_marker_bar = new ArdourCanvas::SimpleRect (*cd_marker_bar_group, 0.0, 0.0, phys_width, (timebar_height));
+ 		cd_marker_bar->property_outline_pixels() = 0;
+ 	}
+  	cd_marker_bar->property_outline_what() = (0x1 | 0x8);
+@@ -235,7 +230,7 @@
+ 	cd_marker_group = new ArdourCanvas::Group (*timebar_group, 0.0, 0.0);
+ 
+ 	marker_drag_line_points.push_back(Gnome::Art::Point(0.0, 0.0));
+-	marker_drag_line_points.push_back(Gnome::Art::Point(0.0, physical_screen_height));
++	marker_drag_line_points.push_back(Gnome::Art::Point(0.0, phys_height));
+ 
+ 	marker_drag_line = new ArdourCanvas::Line (*timebar_group);
+ 	marker_drag_line->property_width_pixels() = 1;
+@@ -258,14 +253,14 @@
+ 	transport_punchin_line->property_x1() = 0.0;
+ 	transport_punchin_line->property_y1() = 0.0;
+ 	transport_punchin_line->property_x2() = 0.0;
+-	transport_punchin_line->property_y2() = physical_screen_height;
++	transport_punchin_line->property_y2() = phys_height;
+ 	transport_punchin_line->hide ();
+ 	
+ 	transport_punchout_line  = new ArdourCanvas::SimpleLine (*_master_group);
+ 	transport_punchout_line->property_x1() = 0.0;
+ 	transport_punchout_line->property_y1() = 0.0;
+ 	transport_punchout_line->property_x2() = 0.0;
+-	transport_punchout_line->property_y2() = physical_screen_height;
++	transport_punchout_line->property_y2() = phys_height;
+ 	transport_punchout_line->hide();
+ 	
+ 	// used to show zoom mode active zooming
+@@ -382,24 +377,20 @@
+ void
+ Editor::controls_layout_size_request (Requisition* req)
+ {
+-	TreeModel::Children rows = route_display_model->children();
+-	TreeModel::Children::iterator i;
+ 	double pos;
+ 	bool changed = false;
+ 
+-	for (pos = 0, i = rows.begin(); i != rows.end(); ++i) {
+-		TimeAxisView *tv = (*i)[route_display_columns.tv];
+-		if (tv != 0) {
+-			pos += tv->effective_height;
+-		}
++	pos = 0;
++	for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
++		pos += (*i)->effective_height;
+ 	}
+ 
+-	gint height = min ((gint) pos, (gint) (physical_screen_height - 600));
++	gint height = min ((gint) pos, (gint) (physical_screen_height (get_window()) - 600));
+ 	gint width = max (edit_controls_vbox.get_width(),  controls_layout.get_width());
+ 
+ 	/* don't get too big. the fudge factors here are just guesses */
+ 
+-	width =  min (width, (gint) (physical_screen_width - 300));
++	width =  min (width, (gint) (physical_screen_width (get_window()) - 300));
+ 
+ 	if ((req->width != width) || (req->height != height)) {
+ 		changed = true;
+--- a/gtk2_ardour/editor.h
++++ b/gtk2_ardour/editor.h
+@@ -330,10 +330,6 @@
+ 	void toggle_measure_visibility ();
+ 	void toggle_logo_visibility ();
+ 
+-	double get_physical_screen_width () const { return physical_screen_width; };
+-	double physical_screen_width;
+-	double physical_screen_height;
+-
+ 	/* SMPTE timecode & video sync */
+ 
+ 	void smpte_fps_chosen (ARDOUR::SmpteFormat format);
+--- a/gtk2_ardour/editor_mouse.cc
++++ b/gtk2_ardour/editor_mouse.cc
+@@ -3996,8 +3996,6 @@
+ 		drag_info.x_constrained = !drag_info.x_constrained;
+ 	}
+ 
+-        cerr << "drag done, copy ? " << drag_info.copy << " x-const ? " << drag_info.x_constrained << endl;
+-
+ 	if (drag_info.copy) {
+ 		if (drag_info.x_constrained) {
+ 			op_string = _("fixed time region copy");
+@@ -4037,8 +4035,6 @@
+ 			continue;
+ 		}
+                 
+-                cerr << "drag delta = " << drag_delta << " rpos was " << rv->region()->position() << endl;
+-
+ 		if (changed_position && !drag_info.x_constrained && (mouse_mode != MouseRange)) {
+ 			where = rv->region()->position() - drag_delta;
+ 		} else {
+@@ -4074,8 +4070,6 @@
+ 				session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
+ 			}
+ 
+-                        cerr << "Adding region @ " << new_region->position() << " at " << where << endl;
+-
+ 			to_playlist->add_region (new_region, where);
+ 
+ 			c.disconnect ();
+@@ -4409,8 +4403,6 @@
+ 		return;
+ 	}
+ 
+-        cerr << "got " << new_regions.size() << " regions in selection grab\n";
+-
+ 	/* XXX fix me one day to use all new regions */
+ 	
+ 	boost::shared_ptr<Region> region (new_regions.front());
+--- a/gtk2_ardour/editor_selection.cc
++++ b/gtk2_ardour/editor_selection.cc
+@@ -611,8 +611,8 @@
+ 			*/
+ 			
+ 			
+-			first_frame = entered_regionview->region()->position();
+-			last_frame = entered_regionview->region()->last_frame();
++			first_frame = clicked_regionview->region()->position();
++			last_frame = clicked_regionview->region()->last_frame();
+ 			
+ 			for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ 				if ((*i)->region()->position() < first_frame) {
+@@ -639,9 +639,9 @@
+ 			   the this one and any selected ones.
+ 			*/
+ 
+-			if (!selection->selected (entered_regionview)) {
++			if (!selection->selected (clicked_regionview)) {
+ 
+-				AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&entered_regionview->get_time_axis_view());
++				AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&clicked_regionview->get_time_axis_view());
+ 
+ 				if (atv) {
+ 
+--- a/gtk2_ardour/editor_tempodisplay.cc
++++ b/gtk2_ardour/editor_tempodisplay.cc
+@@ -45,6 +45,7 @@
+ #include "ardour_ui.h"
+ #include "time_axis_view.h"
+ #include "tempo_lines.h"
++#include "utils.h"
+ 
+ #include "i18n.h"
+ 
+@@ -196,7 +197,7 @@
+ 	}
+ 
+ 	if (tempo_lines == 0) {
+-		tempo_lines = new TempoLines(*track_canvas, time_line_group, physical_screen_height);
++		tempo_lines = new TempoLines(*track_canvas, time_line_group, physical_screen_height (get_window()));
+ 	}
+ 
+ 	tempo_lines->draw(*current_bbt_points, frames_per_unit);
+--- a/gtk2_ardour/engine_dialog.cc
++++ b/gtk2_ardour/engine_dialog.cc
+@@ -3,9 +3,11 @@
+ #include <fstream>
+ #include <map>
+ 
++#include <boost/scoped_ptr.hpp>
+ #include <glibmm.h>
+ #include <gtkmm/messagedialog.h>
+ #include <pbd/xml++.h>
++#include <pbd/epa.h>
+ 
+ #ifdef __APPLE__
+ #include <CoreAudio/CoreAudio.h>
+@@ -400,6 +402,8 @@
+ 		cmd.push_back ("-R");
+ 		cmd.push_back ("-P");
+ 		cmd.push_back (to_string ((uint32_t) floor (priority_spinner.get_value()), std::dec));
++	} else {
++		cmd.push_back ("-r"); /* override jackd's default --realtime */
+ 	}
+ 
+ 	if (unlock_memory_button.get_active()) {
+@@ -558,6 +562,17 @@
+ bool
+ EngineControl::engine_running ()
+ {
++        EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
++        boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
++
++        /* revert all environment settings back to whatever they were when ardour started
++         */
++
++        if (global_epa) {
++                current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
++                global_epa->restore ();
++        }
++	
+ 	jack_status_t status;
+ 	jack_client_t* c = jack_client_open ("ardourprobe", JackNoStartServer, &status);
+ 
+--- a/gtk2_ardour/export_range_markers_dialog.cc
++++ b/gtk2_ardour/export_range_markers_dialog.cc
+@@ -111,7 +111,6 @@
+ ExportRangeMarkersDialog::get_target_filepath(string path, string filename, string postfix)
+ {
+ 	string target_filepath = Glib::build_filename (path, filename + postfix);
+-	struct stat statbuf;
+ 	
+ 	for (int counter=1; Glib::file_test (target_filepath, Glib::FILE_TEST_EXISTS); counter++) {
+ 		// while file exists	
+--- a/gtk2_ardour/lv2_plugin_ui.cc
++++ b/gtk2_ardour/lv2_plugin_ui.cc
+@@ -18,11 +18,16 @@
+ 
+ */
+ 
++#include <pbd/pthread_utils.h>
++
+ #include <ardour/insert.h>
+ #include <ardour/lv2_plugin.h>
+ 
++#include <gtkmm2ext/gtk_ui.h>
++
+ #include "ardour_ui.h"
+ #include "lv2_plugin_ui.h"
++#include "gui_thread.h"
+ 
+ using namespace Gtk;
+ using namespace ARDOUR;
+@@ -35,10 +40,14 @@
+              uint32_t         format,
+              const void*      buffer)
+ {
+-	//cout << "lv2_ui_write" << endl;
+ 	LV2PluginUI* me = (LV2PluginUI*)controller;
++
++        if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
++                PBD::notify_gui_about_thread_creation (pthread_self(), me->_lv2->name());
++        }
++
+ 	if (*(float*)buffer != me->_values[port_index]) {
+-		//cout << "set_parameter " << port_index << ":"  << *(float*)buffer << endl;
++		// cout << "set_parameter " << port_index << ":"  << *(float*)buffer << endl;
+ 		me->_lv2->set_parameter(port_index, *(float*)buffer);
+   }
+ }
+@@ -66,6 +75,8 @@
+ 		return;
+ 	}
+ 
++        ENSURE_GUI_THREAD(bind (mem_fun (*this, &LV2PluginUI::parameter_update), port_index, val));
++
+ 	const LV2UI_Descriptor* ui_desc = slv2_ui_instance_get_descriptor(_inst);
+ 	LV2UI_Handle ui_handle = slv2_ui_instance_get_handle(_inst);
+ 	if (ui_desc->port_event) {
+@@ -120,6 +131,7 @@
+ LV2PluginUI::LV2PluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<LV2Plugin> lv2p)
+ 	: PlugUIBase (pi)
+ 	, _lv2(lv2p)
++        , _current_ui_thread (0)
+ 	, _inst(NULL)
+ 	, _values(NULL)
+ 	, _external_ui_ptr(NULL)
+--- a/gtk2_ardour/lv2_plugin_ui.h
++++ b/gtk2_ardour/lv2_plugin_ui.h
+@@ -58,11 +58,11 @@
+ 	boost::shared_ptr<ARDOUR::LV2Plugin> _lv2;
+ 	std::vector<int> _output_ports;
+ 	sigc::connection _screen_update_connection;
+-	
+-	Gtk::Widget*   _gui_widget;
+-	SLV2UIInstance _inst;
+-	float*         _values;
+-
++        pthread_t        _current_ui_thread;
++	Gtk::Widget*     _gui_widget;
++	SLV2UIInstance   _inst;
++	float*           _values;
++        
+ 	struct lv2_external_ui_host _external_ui_host;
+ 	LV2_Feature _external_ui_feature;
+ 	struct lv2_external_ui* _external_ui_ptr;
+--- a/gtk2_ardour/main.cc
++++ b/gtk2_ardour/main.cc
+@@ -19,6 +19,8 @@
+ 
+ #include <cstdlib>
+ #include <signal.h>
++#include <cerrno>
++#include <fstream>
+ 
+ #include <sigc++/bind.h>
+ #include <gtkmm/settings.h>
+@@ -28,6 +30,7 @@
+ #include <pbd/textreceiver.h>
+ #include <pbd/failed_constructor.h>
+ #include <pbd/pthread_utils.h>
++#include <pbd/epa.h>
+ 
+ #include <jack/jack.h>
+ 
+@@ -66,17 +69,18 @@
+ 
+ #include <mach-o/dyld.h>
+ #include <sys/param.h>
+-#include <fstream>
+ 
+ extern void set_language_preference (); // cocoacarbon.mm
+ 
+ void
+-fixup_bundle_environment ()
++fixup_bundle_environment (int argc, char* argv[])
+ {
+ 	if (!getenv ("ARDOUR_BUNDLED")) {
+ 		return;
+ 	}
+ 	
++        EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true));
++
+ 	set_language_preference ();
+ 
+ 	char execpath[MAXPATHLEN+1];
+@@ -95,6 +99,15 @@
+ 	*/
+ 
+ 	path = dir_path;
++
++	/* JACK is often in /usr/local/bin and since Info.plist refuses to 
++	   set PATH, we have to force this in order to discover a running
++	   instance of JACK ...
++	*/
++	
++	path += ':';
++	path += "/usr/local/bin";
++
+ 	if (cstr) {
+ 		path += ':';
+ 		path += cstr;
+@@ -102,15 +115,17 @@
+ 	setenv ("PATH", path.c_str(), 1);
+ 
+ 	path = dir_path;
+-	path += "/../Resources";
++	path += "/../Resources:";
+ 	path += dir_path;
+-	path += "/../Resources/Surfaces";
++	path += "/../Resources/Surfaces:";
+ 	path += dir_path;
+-	path += "/../Resources/Panners";
++	path += "/../Resources/Panners:";
+ 
+ 	setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
+ 
+-	path = dir_path;
++        path = get_user_ardour_path ();
++        path += ':';
++	path += dir_path;
+ 	path += "/../Resources/icons:";
+ 	path += dir_path;
+ 	path += "/../Resources/pixmaps:";
+@@ -163,23 +178,16 @@
+ 	
+ 	setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
+ 
+-	cstr = getenv ("LV2_PATH");
+-	if (cstr) {
+-		path = cstr;
+-		path += ':';
+-	} else {
+-		path = "";
+-	}
+-	path += dir_path;
+-	path += "/../Plugins";
+-	
+-	setenv ("LV2_PATH", path.c_str(), 1);
+-
+ 	path = dir_path;
+ 	path += "/../Frameworks/clearlooks";
+ 
+ 	setenv ("GTK_PATH", path.c_str(), 1);
+ 
++        /* unset GTK_RC_FILES so that we only load the RC files that we define
++         */
++
++        unsetenv ("GTK_RC_FILES");
++
+ 	if (!ARDOUR::translations_are_disabled ()) {
+ 
+ 		path = dir_path;
+@@ -249,6 +257,152 @@
+ 	}
+ }
+ 
++#else
++
++void
++fixup_bundle_environment (int argc, char* argv[])
++{
++	if (!getenv ("ARDOUR_BUNDLED")) {
++		return;
++	}
++
++        EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
++	
++	Glib::ustring exec_path = argv[0];
++	Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (exec_path));
++	Glib::ustring path;
++	const char *cstr = getenv ("PATH");
++
++	/* ensure that we find any bundled executables (e.g. JACK),
++	   and find them before any instances of the same name
++	   elsewhere in PATH
++	*/
++
++        /* note that this function is POSIX/Linux specific, so using / as 
++           a dir separator in this context is just fine.
++        */
++
++	path = dir_path;
++	path += "/etc:";
++	path += dir_path;
++	path += "/lib/surfaces:";
++	path += dir_path;
++	path += "/lib/panners:";
++
++	setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
++
++        path = get_user_ardour_path ();
++        path += ':';
++	path += dir_path;
++	path += "/etc/icons:";
++	path += dir_path;
++	path += "/etc/pixmaps:";
++	path += dir_path;
++	path += "/share:";
++	path += dir_path;
++	path += "/etc";
++
++	setenv ("ARDOUR_PATH", path.c_str(), 1);
++	setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
++	setenv ("ARDOUR_DATA_PATH", path.c_str(), 1);
++
++	path = dir_path;
++	path += "/etc";
++	setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
++
++	cstr = getenv ("LADSPA_PATH");
++	if (cstr) {
++		path = cstr;
++		path += ':';
++	} else {
++		path = "";
++	}
++	path += dir_path;
++	path += "/lib/plugins";
++	
++	setenv ("LADSPA_PATH", path.c_str(), 1);
++
++	cstr = getenv ("VAMP_PATH");
++	if (cstr) {
++		path = cstr;
++		path += ':';
++	} else {
++		path = "";
++	}
++	path += dir_path;
++	path += "/lib";
++	
++	setenv ("VAMP_PATH", path.c_str(), 1);
++
++	cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
++	if (cstr) {
++		path = cstr;
++		path += ':';
++	} else {
++		path = "";
++	}
++	path += dir_path;
++	path += "/lib/surfaces";
++	
++	setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
++
++	path = dir_path;
++	path += "/lib/clearlooks";
++
++	setenv ("GTK_PATH", path.c_str(), 1);
++
++        /* unset GTK_RC_FILES so that we only load the RC files that we define
++         */
++
++        unsetenv ("GTK_RC_FILES");
++
++	if (!ARDOUR::translations_are_disabled ()) {
++                path = dir_path;
++                path += "/share/locale";
++                
++                localedir = strdup (path.c_str());
++                setenv ("GTK_LOCALEDIR", localedir, 1);
++        }
++
++	/* write a pango.rc file and tell pango to use it. we'd love
++	   to put this into the Ardour.app bundle and leave it there,
++	   but the user may not have write permission. so ... 
++
++	   we also have to make sure that the user ardour directory
++	   actually exists ...
++	*/
++
++	if (g_mkdir_with_parents (ARDOUR::get_user_ardour_path().c_str(), 0755) < 0) {
++		error << string_compose (_("cannot create user ardour folder %1 (%2)"), ARDOUR::get_user_ardour_path(), strerror (errno))
++		      << endmsg;
++	} else {
++
++                Glib::ustring mpath;
++
++		path = Glib::build_filename (ARDOUR::get_user_ardour_path(), "pango.rc");
++
++		std::ofstream pangorc (path.c_str());
++		if (!pangorc) {
++			error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
++                } else {
++                        mpath = Glib::build_filename (ARDOUR::get_user_ardour_path(), "pango.modules");
++                        
++			pangorc << "[Pango]\nModuleFiles=";
++			pangorc << mpath << endl;
++			pangorc.close ();
++                }
++
++                setenv ("PANGO_RC_FILE", path.c_str(), 1);
++
++                /* similar for GDK pixbuf loaders, but there's no RC file required
++                   to specify where it lives.
++                */
++
++                mpath = Glib::build_filename (ARDOUR::get_user_ardour_path(), "gdk-pixbuf.loaders");
++                setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
++	}
++}
++
+ #endif
+ 
+ static gboolean
+@@ -312,10 +466,8 @@
+ #endif
+ {
+ 	vector<Glib::ustring> null_file_list;
+-	
+-#ifdef __APPLE__
+-	fixup_bundle_environment ();
+-#endif
++
++	fixup_bundle_environment (argc, argv);
+ 
+         Glib::thread_init();
+ 
+--- a/gtk2_ardour/po/cs.po
++++ b/gtk2_ardour/po/cs.po
+@@ -8,7 +8,7 @@
+ #, fuzzy
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk-ardour 0.347.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2008-10-20 19:01+0100\n"
+ "PO-Revision-Date: 2010-02-03 13:57-0500\n"
+--- a/gtk2_ardour/po/de.po
++++ b/gtk2_ardour/po/de.po
+@@ -7,7 +7,7 @@
+ # Robert Schwede <robert-schwede at gmx.de>, 2009.
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk-ardour 0.347.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-07-05 19:46+0100\n"
+ "PO-Revision-Date: 2009-08-12 10:14+0100\n"
+--- a/gtk2_ardour/po/el.po
++++ b/gtk2_ardour/po/el.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk-ardour 0.347.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2005-01-11 13:00+0200\n"
+ "PO-Revision-Date: 2007-04-11 02:27+0200\n"
+--- a/gtk2_ardour/po/es.po
++++ b/gtk2_ardour/po/es.po
+@@ -1,6 +1,6 @@
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: Ardour gtk2 translation\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-01-22 19:05+0100\n"
+ "PO-Revision-Date: \n"
+--- a/gtk2_ardour/po/fr.po
++++ b/gtk2_ardour/po/fr.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: PACKAGE VERSION\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-04-27 16:38+0200\n"
+ "PO-Revision-Date: 2010-04-27 16:39+0100\n"
+--- a/gtk2_ardour/po/it.po
++++ b/gtk2_ardour/po/it.po
+@@ -1,6 +1,6 @@
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: 2.8.1\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "POT-Creation-Date: \n"
+ "PO-Revision-Date: \n"
+ "Last-Translator: Emanuele Costantini <sound at ecciproduzioni.com>\n"
+--- a/gtk2_ardour/po/nn.po
++++ b/gtk2_ardour/po/nn.po
+@@ -5,12 +5,12 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: PACKAGE VERSION\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-12-24 15:13+0100\n"
+ "PO-Revision-Date: 2010-01-17 21:11+0100\n"
+ "Last-Translator: Eivind Ødegård <gingermig at yahoo.no>\n"
+-"Language-Team: LANGUAGE <LL at li.org>\n"
++"Language-Team: \n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+--- a/gtk2_ardour/po/pt.po
++++ b/gtk2_ardour/po/pt.po
+@@ -8,7 +8,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ardour 0.688.4\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-06-27 13:00-0400\n"
+ "PO-Revision-Date: 2005-08-15 21:50-0000\n"
+--- a/gtk2_ardour/po/pt_PT.po
++++ b/gtk2_ardour/po/pt_PT.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: gtk2_ardour rev.1702\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2007-04-08 13:00+0100\n"
+ "PO-Revision-Date: 2007-04-15 19:00+0100\n"
+--- a/gtk2_ardour/po/ru.po
++++ b/gtk2_ardour/po/ru.po
+@@ -6,7 +6,7 @@
+ # Alexandre Prokoudine <alexandre.prokoudine at gmail.com>, 2006, 2007, 2009
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ru_RU\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-01-20 01:34+0300\n"
+ "PO-Revision-Date: 2010-01-20 04:25+0300\n"
+--- a/gtk2_ardour/po/sv.po
++++ b/gtk2_ardour/po/sv.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ardour-gtk 1.0.2\n"
++"Project-Id-Version: gtk2_ardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-06-12 22:09+0200\n"
+ "PO-Revision-Date: 2006-06-26 23:57+GMT+1\n"
+--- a/gtk2_ardour/public_editor.h
++++ b/gtk2_ardour/public_editor.h
+@@ -152,7 +152,6 @@
+ 	virtual void toggle_follow_playhead () = 0;
+ 	virtual bool follow_playhead() const = 0;
+ 	virtual bool dragging_playhead() const = 0;
+-	virtual double get_physical_screen_width() const = 0;
+ 	virtual void ensure_float (Gtk::Window&) = 0;
+ 	virtual void show_window () = 0;
+ 	virtual TrackViewList* get_valid_views (TimeAxisView*, ARDOUR::RouteGroup* grp = 0) = 0;
+--- a/gtk2_ardour/SConscript
++++ b/gtk2_ardour/SConscript
+@@ -291,6 +291,7 @@
+ 	extra_sources += lv2_files
+ 	gtkardour.Append (CCFLAGS="-DHAVE_LV2")
+ 	gtkardour.Merge ([libraries['slv2']])
++	gtkardour.Merge ([libraries['rasqal']])
+ 
+ 
+ if gtkardour['GTKOSX']:
+--- a/gtk2_ardour/sfdb_ui.cc
++++ b/gtk2_ardour/sfdb_ui.cc
+@@ -979,6 +979,7 @@
+ 			}
+ 			if (same_size) {
+ 				channel_strings.push_back (_("all files in one track"));
++				channel_strings.push_back (_("merge files"));
+ 			}
+ 			
+ 		}
+--- a/gtk2_ardour/streamview.cc
++++ b/gtk2_ardour/streamview.cc
+@@ -61,7 +61,7 @@
+ 	canvas_rect = new ArdourCanvas::SimpleRect (*_background_group);
+ 	canvas_rect->property_x1() = 0.0;
+ 	canvas_rect->property_y1() = 0.0;
+-	canvas_rect->property_x2() = _trackview.editor.get_physical_screen_width();
++	canvas_rect->property_x2() = physical_screen_width (_trackview.editor.get_window());
+ 	canvas_rect->property_y2() = (double) tv.current_height();
+ 
+ 	canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);  // outline ends and bottom 
+--- a/gtk2_ardour/utils.cc
++++ b/gtk2_ardour/utils.cc
+@@ -861,6 +861,7 @@
+ 	return alpha ? ((guint (src) << 8) - src) / alpha : 0;
+ }
+ 
++
+ void
+ convert_bgra_to_rgba (guint8 const* src,
+ 		      guint8*       dst,
+@@ -870,20 +871,42 @@
+ 	guint8 const* src_pixel = src;
+ 	guint8*       dst_pixel = dst;
+ 	
+-	for (int y = 0; y < height; y++)
+-		for (int x = 0; x < width; x++)
+-		{
+-			dst_pixel[0] = convert_color_channel (src_pixel[2],
+-							      src_pixel[3]);
+-			dst_pixel[1] = convert_color_channel (src_pixel[1],
+-							      src_pixel[3]);
+-			dst_pixel[2] = convert_color_channel (src_pixel[0],
+-							      src_pixel[3]);
+-			dst_pixel[3] = src_pixel[3];
+-			
+-			dst_pixel += 4;
+-			src_pixel += 4;
+-		}
++	for (int y = 0; y < height; y++) {
++	  for (int x = 0; x < width; x++) {
++#if G_BYTE_ORDER == G_LITTLE_ENDIAN
++	    /* Cairo [ B G R A ] is actually  [ B G R A ] in memory SOURCE
++	                                        0 1 2 3
++	       Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
++	    */
++	    dst_pixel[0] = convert_color_channel (src_pixel[2],
++						  src_pixel[3]); // R [0] <= [ 2 ]
++	    dst_pixel[1] = convert_color_channel (src_pixel[1],
++						  src_pixel[3]); // G [1] <= [ 1 ]
++	    dst_pixel[2] = convert_color_channel (src_pixel[0],  
++						  src_pixel[3]); // B [2] <= [ 0 ]
++	    dst_pixel[3] = src_pixel[3]; // alpha
++	    
++#elif G_BYTE_ORDER == G_BIG_ENDIAN
++	    /* Cairo [ B G R A ] is actually  [ A R G B ] in memory SOURCE
++	                                        0 1 2 3
++	       Pixbuf [ R G B A ] is actually [ R G B A ] in memory DEST
++	    */
++	    dst_pixel[0] = convert_color_channel (src_pixel[1],
++						  src_pixel[0]); // R [0] <= [ 1 ]
++	    dst_pixel[1] = convert_color_channel (src_pixel[2],
++						  src_pixel[0]); // G [1] <= [ 2 ]
++	    dst_pixel[2] = convert_color_channel (src_pixel[3],
++						  src_pixel[0]); // B [2] <= [ 3 ]
++	    dst_pixel[3] = src_pixel[0]; // alpha
++	    
++#else
++#error ardour does not currently support PDP-endianess
++#endif			
++
++	    dst_pixel += 4;
++	    src_pixel += 4;
++	  }
++	}
+ }
+ 
+ Glib::RefPtr<Gdk::Pixbuf>
+@@ -917,3 +940,33 @@
+ 
+ 	return buf;
+ }
++
++int
++physical_screen_height (Glib::RefPtr<Gdk::Window> win)
++{
++        GdkScreen* scr = gdk_screen_get_default();
++
++        if (win) {
++                GdkRectangle r;
++                gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
++                gdk_screen_get_monitor_geometry (scr, monitor, &r);
++                return r.height;
++        } else {
++                return gdk_screen_get_height (scr);
++        }
++}
++
++int
++physical_screen_width (Glib::RefPtr<Gdk::Window> win)
++{
++        GdkScreen* scr = gdk_screen_get_default();
++        
++        if (win) {
++                GdkRectangle r;
++                gint monitor = gdk_screen_get_monitor_at_window (scr, win->gobj());
++                gdk_screen_get_monitor_geometry (scr, monitor, &r);
++                return r.width;
++        } else {
++                return gdk_screen_get_width (scr);
++        }
++}
+--- a/gtk2_ardour/utils.h
++++ b/gtk2_ardour/utils.h
+@@ -100,4 +100,7 @@
+ 					       int clip_width,
+ 					       int clip_height);
+ 
++int physical_screen_height (Glib::RefPtr<Gdk::Window>);
++int physical_screen_width (Glib::RefPtr<Gdk::Window>);
++
+ #endif /* __ardour_gtk_utils_h__ */
+--- a/libs/ardour/ardour/automation_event.h
++++ b/libs/ardour/ardour/automation_event.h
+@@ -83,6 +83,7 @@
+ 
+ 	void freeze();
+ 	void thaw ();
++        int8_t frozen() const { return _frozen; }
+ 
+ 	AutomationEventList::size_type size() const { return events.size(); }
+ 	bool empty() const { return events.empty(); }
+--- a/libs/ardour/ardour/configuration_variable.h
++++ b/libs/ardour/ardour/configuration_variable.h
+@@ -24,6 +24,7 @@
+ #include <ostream>
+ 
+ #include <pbd/xml++.h>
++#include <pbd/enumwriter.h>
+ 
+ #include "ardour/utils.h"
+ 
+@@ -113,9 +114,9 @@
+ 					if ((prop = child->property ("name")) != 0) {
+ 						if (prop->value() == _name) {
+ 							if ((prop = child->property ("value")) != 0) {
+-								std::stringstream ss;
+-								ss << prop->value();
+-								ss >> value;
++                                                                std::stringstream ss;
++                                                                ss << enum_validate (value, prop->value());
++                                                                ss >> value;
+ 								_owner = (ConfigVariableBase::Owner)(_owner |owner);
+ 								return true;
+ 							}
+@@ -138,12 +139,12 @@
+ 			for (oiter = olist.begin(); oiter != olist.end(); ++oiter) {
+ 				
+ 				option = *oiter;
+-				
++                                
+ 				if (option->name() == _name) {
+ 					if ((opt_prop = option->property ("val")) != 0) {
+-						std::stringstream ss;
+-						ss << opt_prop->value();
+-						ss >> value;
++                                                std::stringstream ss;
++                                                ss << enum_validate (value, opt_prop->value());
++                                                ss >> value;
+ 						_owner = (ConfigVariableBase::Owner)(_owner |owner);
+ 						return true;
+ 					}
+--- a/libs/ardour/audioengine.cc
++++ b/libs/ardour/audioengine.cc
+@@ -22,9 +22,12 @@
+ #include <vector>
+ #include <sstream>
+ 
++#include <boost/scoped_ptr.hpp>
++
+ #include <glibmm/timer.h>
+ #include <pbd/pthread_utils.h>
+ #include <pbd/stacktrace.h>
++#include <pbd/epa.h>
+ 
+ #include <ardour/audioengine.h>
+ #include <ardour/buffer.h>
+@@ -332,7 +335,10 @@
+ 
+ 	IO::CycleStart (nframes);
+ 
+-	if (_freewheeling) {
++	/* test if we are freewheeling and there are freewheel signals connected.
++           ardour should act normally even when freewheeling unless /it/ is exporting */
++
++	if (_freewheeling && !Freewheel.empty()) {
+ 		if (Freewheel (nframes)) {
+ 			jack_set_freewheel (_priv_jack, false);
+ 		}
+@@ -667,7 +673,7 @@
+ AudioEngine::connect (const string& source, const string& destination)
+ {
+         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
+-	
++
+ 	string s = make_port_name_non_relative (source);
+ 	string d = make_port_name_non_relative (destination);
+ 
+@@ -1116,10 +1122,20 @@
+ int
+ AudioEngine::connect_to_jack (string client_name)
+ {
++        EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
++        boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
+ 	jack_options_t options = JackNullOption;
+ 	jack_status_t status;
+ 	const char *server_name = NULL;
+ 
++        /* revert all environment settings back to whatever they were when ardour started
++         */
++
++        if (global_epa) {
++                current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
++                global_epa->restore ();
++        }
++
+ 	jack_client_name = client_name; /* might be reset below */
+ 	_jack = jack_client_open (jack_client_name.c_str(), options, &status, server_name);
+ 
+@@ -1276,7 +1292,7 @@
+ 			error << string_compose (_("Disconnected from JACK while reconnecting. You should quit %1 now."), PROGRAM_NAME) << endmsg;
+ 			return -1;
+ 		}
+-		
++
+ 		if ((err = jack_connect (_priv_jack, (*i).first.c_str(), (*i).second.c_str())) != 0) {
+ 			if (err != EEXIST) {
+ 				error << string_compose (_("could not reconnect %1 and %2 (err = %3)"),
+--- a/libs/ardour/audioregion.cc
++++ b/libs/ardour/audioregion.cc
+@@ -735,7 +735,7 @@
+ 			child->add_child_nocopy (_fade_in.get_state ());
+ 		}
+ 
+-		child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes"));
++		child->add_property (X_("active"), (_flags & FadeIn) ? X_("yes") : X_("no"));
+ 		
+ 		child = node.add_child (X_("FadeOut"));
+ 		
+@@ -745,7 +745,7 @@
+ 			child->add_child_nocopy (_fade_out.get_state ());
+ 		}
+ 		
+-		child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes"));
++		child->add_property (X_("active"), (_flags & FadeOut) ? X_("yes") : X_("no"));
+ 	}
+ 	
+ 	child = node.add_child ("Envelope");
+--- a/libs/ardour/audio_unit.cc
++++ b/libs/ardour/audio_unit.cc
+@@ -446,17 +446,26 @@
+ 		throw failed_constructor ();
+ 	}
+ 	
+-	AURenderCallbackStruct renderCallbackInfo;
+-
+-	renderCallbackInfo.inputProc = _render_callback;
+-	renderCallbackInfo.inputProcRefCon = this;
++	TRACE_API ("count global elements\n");
++	unit->GetElementCount (kAudioUnitScope_Global, global_elements);
++	TRACE_API ("count input elements\n");
++	unit->GetElementCount (kAudioUnitScope_Input, input_elements);
++	TRACE_API ("count output elements\n");
++	unit->GetElementCount (kAudioUnitScope_Output, output_elements);
+ 
+-	TRACE_API ("set render callback in input scope\n");
+-	if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
+-					 0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
+-		cerr << "cannot install render callback (err = " << err << ')' << endl;
+-		throw failed_constructor();
+-	}
++        if (input_elements > 0) {
++                AURenderCallbackStruct renderCallbackInfo;
++                
++                renderCallbackInfo.inputProc = _render_callback;
++                renderCallbackInfo.inputProcRefCon = this;
++                
++                TRACE_API ("set render callback in input scope\n");
++                if ((err = unit->SetProperty (kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 
++                                              0, (void*) &renderCallbackInfo, sizeof(renderCallbackInfo))) != 0) {
++                        cerr << "cannot install render callback (err = " << err << ')' << endl;
++                        throw failed_constructor();
++                }
++        }
+ 
+ 	/* tell the plugin about tempo/meter/transport callbacks in case it wants them */
+ 
+@@ -475,13 +484,6 @@
+ 			   &info,
+ 			   sizeof (HostCallbackInfo));
+ 
+-	TRACE_API ("count global elements\n");
+-	unit->GetElementCount (kAudioUnitScope_Global, global_elements);
+-	TRACE_API ("count input elements\n");
+-	unit->GetElementCount (kAudioUnitScope_Input, input_elements);
+-	TRACE_API ("count output elements\n");
+-	unit->GetElementCount (kAudioUnitScope_Output, output_elements);
+-
+ 	/* these keep track of *configured* channel set up,
+ 	   not potential set ups.
+ 	*/
+--- a/libs/ardour/crossfade.cc
++++ b/libs/ardour/crossfade.cc
+@@ -711,10 +711,13 @@
+ 	nframes_t val;
+ 
+ 	if ((prop = node.property ("position")) != 0) {
+-		sscanf (prop->value().c_str(), "%" PRIu32, &val);
+-		if (val != _position) {
+-			_position = val;
+-			what_changed = Change (what_changed | PositionChanged);
++		if (sscanf (prop->value().c_str(), "%" PRIu32, &val) == 1) {
++			if (val != _position) {
++				_position = val;
++				what_changed = Change (what_changed | PositionChanged);
++			}
++		} else {
++			warning << _("can't read value from crossfade position property") << endmsg;
+ 		}
+ 	} else {
+ 		warning << _("old-style crossfade information - no position information") << endmsg;
+@@ -751,12 +754,14 @@
+ 
+ 	if ((prop = node.property ("length")) != 0) {
+ 
+-		sscanf (prop->value().c_str(), "%" PRIu32, &val);
+-		if (val != _length) {
+-			_length = atol (prop->value().c_str());
+-			what_changed = Change (what_changed | LengthChanged);
++		if (sscanf (prop->value().c_str(), "%" PRIu32, &val) == 1) {
++			if (val != _length) {
++				_length = atol (prop->value().c_str());
++				what_changed = Change (what_changed | LengthChanged);
++			}
++		} else {
++			warning << _("can't read value from crossfade length property") << endmsg;		
+ 		}
+-
+ 	} else {
+ 		
+ 		/* XXX this branch is legacy code from before
+@@ -798,6 +803,11 @@
+ 		}
+ 	}
+ 
++        if (_fade_in.size() < 2) {
++                cerr << "Fade in data missing any points! Crossfade will be lost!\n";
++                return -1;
++        }
++
+ 	_fade_in.front()->value=0.0;
+ 	_fade_in.back()->value=1.0;
+ 
+@@ -826,6 +836,11 @@
+ 		}
+ 	}
+ 
++        if (_fade_out.size() < 2) {
++                cerr << "Fade out data missing any points! Crossfade will be lost!\n";
++                return -1;
++        }
++
+ 	_fade_out.front()->value=1.0;
+ 	_fade_out.back()->value=0.0;
+ 
+--- a/libs/ardour/curve.cc
++++ b/libs/ardour/curve.cc
+@@ -312,7 +312,7 @@
+ 		return;
+ 	}
+ 
+- 	if (npoints == 1 ) {
++ 	if (npoints == 1) {
+  	
+  		for (i = 0; i < veclen; ++i) {
+  			vec[i] = events.front()->value;
+@@ -355,17 +355,18 @@
+ 
+ 	rx = lx;
+ 
++	/* note: if there are veclen elements in the output,
++	   there are only veclen-1 steps between them.
++	*/
++	
+ 	if (veclen > 1) {
+-
+-		/* note: if there are veclen elements in the output,
+-		   there are only veclen-1 steps between them.
+-		*/
+-
+ 		dx = (hx - lx) / (veclen-1);
+-
+-		for (i = 0; i < veclen; ++i, rx += dx) {
+-			vec[i] = multipoint_eval (rx);
+-		}
++	} else {
++		dx = 0;
++	}
++	
++	for (i = 0; i < veclen; ++i, rx += dx) {
++		vec[i] = multipoint_eval (rx);
+ 	}
+ }
+ 
+--- a/libs/ardour/enums.cc
++++ b/libs/ardour/enums.cc
+@@ -147,6 +147,7 @@
+ 
+ 	REGISTER_ENUM (Slide);
+ 	REGISTER_ENUM (Splice);	
++	REGISTER_ENUM (Lock);	
+ 	REGISTER (_EditMode);
+ 
+ 	REGISTER_ENUM (Start);
+--- a/libs/ardour/po/el.po
++++ b/libs/ardour/po/el.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour 0.664.0\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2003-06-29 21:03+0200\n"
+ "PO-Revision-Date: 2007-04-16 00:38+0200\n"
+--- a/libs/ardour/po/es.po
++++ b/libs/ardour/po/es.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: Ardour\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-01-17 23:34+0100\n"
+ "PO-Revision-Date: \n"
+--- a/libs/ardour/po/fr.po
++++ b/libs/ardour/po/fr.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: PACKAGE VERSION\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2010-04-27 16:38+0200\n"
+ "PO-Revision-Date: 2010-04-27 16:39+0100\n"
+--- a/libs/ardour/po/it.po
++++ b/libs/ardour/po/it.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour 0.664.0\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-06-29 21:03-0400\n"
+ "PO-Revision-Date: 2003-05-21 12:50+0500\n"
+--- a/libs/ardour/po/nn.po
++++ b/libs/ardour/po/nn.po
+@@ -6,7 +6,7 @@
+ # Eivind Ødegård <gingermig at yahoo.no>, 2009.
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: nn_NO\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-12-24 15:13+0100\n"
+ "PO-Revision-Date: 2010-01-09 23:28+0100\n"
+--- a/libs/ardour/po/pl.po
++++ b/libs/ardour/po/pl.po
+@@ -5,7 +5,7 @@
+ # Piotr Zaryk <pzaryk at gmail.com>, 2008.
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour2\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: Piotr Zaryk <pzaryk at gmail.com>\n"
+ "POT-Creation-Date: 2008-04-03 16:16+0200\n"
+ "PO-Revision-Date: 2008-04-10 10:51+0100\n"
+--- a/libs/ardour/po/ru.po
++++ b/libs/ardour/po/ru.po
+@@ -6,7 +6,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: libardour 0.716.1\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2009-10-05 17:23+0400\n"
+ "PO-Revision-Date: 2009-10-06 02:59+0300\n"
+--- a/libs/ardour/po/sv.po
++++ b/libs/ardour/po/sv.po
+@@ -5,7 +5,7 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: ardour\n"
++"Project-Id-Version: libardour\n"
+ "Report-Msgid-Bugs-To: \n"
+ "POT-Creation-Date: 2006-10-03 00:39+0200\n"
+ "PO-Revision-Date: 2006-10-03 01:09+GMT+1\n"
+--- a/libs/ardour/SConscript
++++ b/libs/ardour/SConscript
+@@ -320,6 +320,7 @@
+ 	
+ if ardour['LV2']:
+ 	ardour.Merge ([ libraries['slv2'] ])
++	ardour.Merge ([ libraries['rasqal'] ])
+ 
+ if ardour['LIBLO']:
+ 	ardour.Merge ([ libraries['lo'] ])
+--- a/libs/ardour/session.cc
++++ b/libs/ardour/session.cc
+@@ -2631,7 +2631,7 @@
+ 
+ 	nframes_t max = get_maximum_extent ();
+ 
+-	if (max > end_location->end()) {
++	if ( (max > end_location->end() ) && _end_location_is_free ) {
+ 		end_location->set_end (max);
+ 		set_dirty();
+ 		DurationChanged(); /* EMIT SIGNAL */
+--- a/libs/ardour/session_transport.cc
++++ b/libs/ardour/session_transport.cc
+@@ -941,7 +941,6 @@
+ 		for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
+ 			if ((*i)->realtime_set_speed ((*i)->speed(), true)) {
+ 				todo = PostTransportWork (todo | PostTransportSpeed);
+-				break;
+ 			}
+ 		}
+ 		
+--- a/libs/ardour/tempo.cc
++++ b/libs/ardour/tempo.cc
+@@ -299,7 +299,21 @@
+ void
+ TempoMap::move_tempo (TempoSection& tempo, const BBT_Time& when)
+ {
+-	if (move_metric_section (tempo, when) == 0) {
++	/* a new tempo always starts a new bar on the first beat */
++	BBT_Time when_rounded = when;
++	int force_state_changed = 0;
++
++	if (when_rounded.beats != 1) {
++		when_rounded.beats = 1;
++		when_rounded.bars++;
++		force_state_changed = 1;
++	}
++
++	/* new tempo *always* start on a beat. */
++		
++	when_rounded.ticks = 0;
++
++	if ((move_metric_section (tempo, when_rounded) == 0) || force_state_changed) {
+ 		StateChanged (Change (0));
+ 	}
+ }
+@@ -307,7 +321,21 @@
+ void
+ TempoMap::move_meter (MeterSection& meter, const BBT_Time& when)
+ {
+-	if (move_metric_section (meter, when) == 0) {
++	/* a new meter always starts a new bar on the first beat */
++	BBT_Time when_rounded = when;
++	int force_state_changed = 0;
++
++	if (when_rounded.beats != 1) {
++		when_rounded.beats = 1;
++		when_rounded.bars++;
++		force_state_changed = 1;
++	}
++
++	/* new meters *always* start on a beat. */
++		
++	when_rounded.ticks = 0;
++
++	if ((move_metric_section (meter, when_rounded) == 0) || force_state_changed) {
+ 		StateChanged (Change (0));
+ 	}
+ }
+--- a/libs/gtkmm2ext/barcontroller.cc
++++ b/libs/gtkmm2ext/barcontroller.cc
+@@ -146,7 +146,6 @@
+ 	
+ 	stringstream stream;
+ 	string str;
+-	size_t found;
+ 
+ 	char buf[128];
+ 
+--- a/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
++++ b/libs/gtkmm2ext/gtkmm2ext/gtk_ui.h
+@@ -51,6 +51,7 @@
+ 
+ class TextViewer;
+ 
++extern BaseUI::RequestType NullRequest;
+ extern BaseUI::RequestType ErrorMessage;
+ extern BaseUI::RequestType Quit;
+ extern BaseUI::RequestType CallSlot;
+@@ -77,6 +78,10 @@
+     void *arg;
+     const char *msg2;
+     sigc::slot<void> slot;
++
++    UIRequest () {
++            type = NullRequest;
++    }
+     
+     ~UIRequest () { 
+ 	    if (type == ErrorMessage && msg) {
+--- a/libs/gtkmm2ext/gtk_ui.cc
++++ b/libs/gtkmm2ext/gtk_ui.cc
+@@ -52,6 +52,7 @@
+ pthread_t UI::gui_thread;
+ UI       *UI::theGtkUI = 0;
+ 
++BaseUI::RequestType Gtkmm2ext::NullRequest = BaseUI::new_request_type();
+ BaseUI::RequestType Gtkmm2ext::ErrorMessage = BaseUI::new_request_type();
+ BaseUI::RequestType Gtkmm2ext::Quit = BaseUI::new_request_type();
+ BaseUI::RequestType Gtkmm2ext::TouchDisplay = BaseUI::new_request_type();
+--- a/libs/pbd/enumwriter.cc
++++ b/libs/pbd/enumwriter.cc
+@@ -174,6 +174,98 @@
+ 	return string();
+ }
+ 
++string
++EnumWriter::validate_string (EnumRegistration& er, const string& str)
++{
++        int val;
++
++        if (er.values.empty()) {
++                return str;
++        }
++
++        if (er.bitwise) {
++                /* Legal values consist of OR-ed masks of zero or more values defined an enum.
++                   Since we only ever check the legal bits, any value is acceptable,
++                   including zero.
++                */
++                return str;
++        } 
++
++        val = atoi (str.c_str());
++
++        /* not bitwise: Legal values consist of discrete values defined by an enum */
++
++        for (vector<int>::iterator i = er.values.begin(); i != er.values.end(); ++i) {
++                if (*i == val) {
++                        return str; /* string is a legal representation of a enumerated single value */
++                }
++        } 
++        
++        string enum_name = _("unknown enumeration");
++        
++        for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) {
++                if (&er == &(*x).second) {
++                        enum_name = (*x).first;
++                }
++        }
++
++        warning << string_compose (_("Illegal value loaded for %1 (%2) - %3 used instead"),
++                                   enum_name, val, er.names.front()) 
++                << endmsg;
++
++        stringstream ss;
++        ss << er.values.front();
++
++        return ss.str();
++}
++
++string
++EnumWriter::typed_validate (const string& type, const string& value_str) 
++{
++        for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) {
++                if (x->first == type) {
++                        return validate_string (x->second, value_str);
++                }
++        }        
++
++        /* not a known enum */
++
++        return value_str;
++}
++
++int
++EnumWriter::validate (EnumRegistration& er, int val)
++{
++        if (er.values.empty()) {
++                return val;
++        }
++
++        if (er.bitwise) {
++                return val;
++        }
++
++        vector<int>::iterator i;
++        string enum_name = _("unknown enumeration");
++        
++        for (Registry::iterator x = registry.begin(); x != registry.end(); ++x) {
++                if (&er == &(*x).second) {
++                        enum_name = (*x).first;
++                }
++        }
++        
++
++        for (i = er.values.begin(); i != er.values.end(); ++i) {
++                if (*i == val) {
++                        return val;
++                }
++        }
++        
++        warning << string_compose (_("Illegal value loaded for %1 (%2) - %3 used instead"),
++                                   enum_name, val, er.names.front()) 
++                << endmsg;
++        return er.values.front();
++}
++
+ int
+ EnumWriter::read_bits (EnumRegistration& er, string str)
+ {
+@@ -186,14 +278,16 @@
+ 	/* catch old-style hex numerics */
+ 
+ 	if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
+-		return strtol (str.c_str(), (char **) 0, 16);
++		int val = strtol (str.c_str(), (char **) 0, 16);
++                return validate (er, val);
+ 	}
+ 
+ 	/* catch old style dec numerics */
+ 
+ 	if (strspn (str.c_str(), "0123456789") == str.length()) {
+-		return strtol (str.c_str(), (char **) 0, 10);
+-	}
++		int val = strtol (str.c_str(), (char **) 0, 10);
++                return validate (er, val);
++        }
+ 
+ 	do {
+ 		
+@@ -231,14 +325,16 @@
+ 	/* catch old-style hex numerics */
+ 
+ 	if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
+-		return strtol (str.c_str(), (char **) 0, 16);
++		int val = strtol (str.c_str(), (char **) 0, 16);
++                return validate (er, val);
+ 	}
+ 
+ 	/* catch old style dec numerics */
+ 
+ 	if (strspn (str.c_str(), "0123456789") == str.length()) {
+-		return strtol (str.c_str(), (char **) 0, 10);
+-	}
++		int val = strtol (str.c_str(), (char **) 0, 10);
++                return validate (er, val);
++        }
+ 
+ 	for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
+ 		if (str == (*s) || nocase_cmp (str, *s) == 0) {
+--- /dev/null
++++ b/libs/pbd/epa.cc
+@@ -0,0 +1,130 @@
++/*
++    Copyright (C) 2010 Paul Davis 
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++*/
++
++#include <cstdlib>
++#include <iostream>
++
++#include "pbd/epa.h"
++#include "pbd/strsplit.h"
++
++#ifdef __APPLE__
++#include <crt_externs.h>
++#define environ (*_NSGetEnviron())
++#else
++extern char** environ;
++#endif
++
++using namespace PBD;
++using namespace std;
++
++EnvironmentalProtectionAgency* EnvironmentalProtectionAgency::_global_epa = 0;
++
++EnvironmentalProtectionAgency::EnvironmentalProtectionAgency (bool arm, const std::string& envname)
++        : _armed (arm)
++        , _envname (envname)
++{
++        if (_armed) {
++                save ();
++        }
++}
++
++EnvironmentalProtectionAgency::~EnvironmentalProtectionAgency()
++{
++        if (_armed) {
++                restore ();
++        }
++}
++
++void
++EnvironmentalProtectionAgency::arm ()
++{
++        _armed = true;
++}
++
++void
++EnvironmentalProtectionAgency::save ()
++{
++	/* do this to avoid lots of calls to _NSGetEnviron() on OS X */
++
++	char** the_environ = environ;
++
++        e.clear ();
++
++        if (!_envname.empty()) {
++                
++                /* fetch environment from named environment variable, rather than "environ"
++                 */
++
++                const char* estr = getenv (_envname.c_str());
++
++                if (!estr) {
++                        return;
++                }
++                
++                /* parse line by line, and save into "e" 
++                 */
++
++                vector<string> lines;
++                split (estr, lines, '\n');
++
++                for (vector<string>::iterator i = lines.begin(); i != lines.end(); ++i) {
++
++                        string estring = *i;
++                        string::size_type equal = estring.find_first_of ('=');
++                        
++                        if (equal == string::npos) {
++                                /* say what? an environ value without = ? */
++                                continue;
++                        }
++                        
++                        string before = estring.substr (0, equal);
++                        string after = estring.substr (equal+1);
++                        
++                        e.insert (pair<string,string>(before,after));
++                }
++                
++        } else {
++
++                /* fetch environment from "environ"
++                 */
++
++                for (size_t i = 0; the_environ[i]; ++i) {
++                        
++                        string estring = the_environ[i];
++                        string::size_type equal = estring.find_first_of ('=');
++                        
++                        if (equal == string::npos) {
++                                /* say what? an environ value without = ? */
++                                continue;
++                        }
++                        
++                        string before = estring.substr (0, equal);
++                        string after = estring.substr (equal+1);
++                        
++                        e.insert (pair<string,string>(before,after));
++                }
++        }
++}                         
++void
++EnvironmentalProtectionAgency::restore () const
++{
++        for (map<string,string>::const_iterator i = e.begin(); i != e.end(); ++i) {
++                setenv (i->first.c_str(), i->second.c_str(), 1);
++        }
++}                         
+--- a/libs/pbd/pbd/abstract_ui.cc
++++ b/libs/pbd/pbd/abstract_ui.cc
+@@ -1,4 +1,5 @@
+ #include <unistd.h>
++#include <cstdlib>
+ 
+ #include <pbd/abstract_ui.h>
+ #include <pbd/pthread_utils.h>
+@@ -8,11 +9,22 @@
+ 
+ using namespace std;
+ 
++template<typename RequestBuffer> void 
++cleanup_request_buffer (void* ptr)
++{
++        RequestBuffer* rb = (RequestBuffer*) ptr;
++
++        {
++                Glib::Mutex::Lock lm (rb->ui.request_buffer_map_lock);
++                rb->dead = true;
++        }
++}
++
+ template <typename RequestObject>
+ AbstractUI<RequestObject>::AbstractUI (string name, bool with_signal_pipes)
+ 	: BaseUI (name, with_signal_pipes)
+ {
+-	if (pthread_key_create (&thread_request_buffer_key, 0)) {
++	if (pthread_key_create (&thread_request_buffer_key, cleanup_request_buffer<RequestBuffer>)) {
+ 		cerr << _("cannot create thread request buffer key") << endl;
+ 		throw failed_constructor();
+ 	}
+@@ -30,10 +42,24 @@
+ template <typename RequestObject> void
+ AbstractUI<RequestObject>::register_thread_with_request_count (pthread_t thread_id, string thread_name, uint32_t num_requests)
+ {
+-	RequestBuffer* b = new RequestBuffer (num_requests);
++	RequestBuffer* rbuf = static_cast<RequestBuffer*>(pthread_getspecific (thread_request_buffer_key));
+ 
++        /* we require that the thread being registered is the caller */
++
++        if (thread_id != pthread_self()) {
++                cerr << "thread attempts to register some other thread with the UI named " << name() << endl;
++                abort ();
++        }
++
++        if (rbuf) {
++                /* this thread is already registered with this AbstractUI */
++                return;
++        }
++
++	RequestBuffer* b = new RequestBuffer (num_requests, *this);
++        
+ 	{
+-        Glib::Mutex::Lock lm (request_buffer_map_lock);
++                Glib::Mutex::Lock lm (request_buffer_map_lock);
+ 		request_buffers[thread_id] = b;
+ 	}
+ 
+@@ -93,33 +119,42 @@
+ 
+ 	request_buffer_map_lock.lock ();
+ 
+-	for (i = request_buffers.begin(); i != request_buffers.end(); ++i) {
++	for (i = request_buffers.begin(); i != request_buffers.end(); ) {
+ 
+ 		RequestBufferVector vec;
+ 
+-		while (true) {
+-
+-			/* we must process requests 1 by 1 because
+-			   the request may run a recursive main
+-			   event loop that will itself call
+-			   handle_ui_requests. when we return
+-			   from the request handler, we cannot
+-			   expect that the state of queued requests
+-			   is even remotely consistent with
+-			   the condition before we called it.
+-			*/
+-
+-			i->second->get_read_vector (&vec);
+-
+-			if (vec.len[0] == 0) {
+-				break;
+-			} else {
+-				request_buffer_map_lock.unlock ();
+-				do_request (vec.buf[0]);
+-				request_buffer_map_lock.lock ();
+-				i->second->increment_read_ptr (1);
+-			} 
+-		}
++                if ((*i).second->dead) {
++                        delete (*i).second;
++                        RequestBufferMapIterator tmp = i;
++                        ++tmp;
++                        request_buffers.erase (i);
++                        i = tmp;
++                } else {
++                        while (true) {
++                                
++                                /* we must process requests 1 by 1 because
++                                   the request may run a recursive main
++                                   event loop that will itself call
++                                   handle_ui_requests. when we return
++                                   from the request handler, we cannot
++                                   expect that the state of queued requests
++                                   is even remotely consistent with
++                                   the condition before we called it.
++                                */
++                                
++                                i->second->get_read_vector (&vec);
++                                
++                                if (vec.len[0] == 0) {
++                                        break;
++                                } else {
++                                        request_buffer_map_lock.unlock ();
++                                        do_request (vec.buf[0]);
++                                        request_buffer_map_lock.lock ();
++                                        i->second->increment_read_ptr (1);
++                                } 
++                        }
++                        ++i;
++                }
+ 	}
+ 
+ 	request_buffer_map_lock.unlock ();
+--- a/libs/pbd/pbd/abstract_ui.h
++++ b/libs/pbd/pbd/abstract_ui.h
+@@ -58,12 +58,21 @@
+ 	void register_thread_with_request_count (pthread_t, std::string, uint32_t num_requests);
+ 	void unregister_thread (pthread_t);
+ 
++        Glib::Mutex request_buffer_map_lock;
++
+   protected:
+-	typedef RingBufferNPT<RequestObject> RequestBuffer;
++        struct RequestBuffer : public RingBufferNPT<RequestObject> {
++                bool dead;
++                AbstractUI<RequestObject>& ui;
++                RequestBuffer (uint32_t size, AbstractUI<RequestObject>& uir) 
++                        : RingBufferNPT<RequestObject> (size)
++                        , dead (false) 
++                        , ui (uir) {}
++        };
++
+ 	typedef typename RequestBuffer::rw_vector RequestBufferVector;
+ 	typedef typename std::map<pthread_t,RequestBuffer*>::iterator RequestBufferMapIterator;
+ 
+-    Glib::Mutex request_buffer_map_lock;
+ 	typedef std::map<pthread_t,RequestBuffer*> RequestBufferMap;
+ 	RequestBufferMap request_buffers;
+ 	pthread_key_t thread_request_buffer_key;
+--- a/libs/pbd/pbd/enumwriter.h
++++ b/libs/pbd/pbd/enumwriter.h
+@@ -18,6 +18,9 @@
+     $Id$
+ */
+ 
++#ifndef __pbd_enumwriter_h__
++#define __pbd_enumwriter_h__
++
+ #include <map>
+ #include <string>
+ #include <vector>
+@@ -45,6 +48,7 @@
+ 	int         read  (std::string type, std::string value);
+ 
+ 	void add_to_hack_table (std::string str, std::string hacked_str);
++        std::string typed_validate (const std::string& type, const std::string&);
+ 
+   private:
+ 	struct EnumRegistration {
+@@ -68,10 +72,16 @@
+ 
+ 	static EnumWriter* _instance;
+ 	static std::map<std::string,std::string> hack_table;
++
++        int validate (EnumRegistration& er, int value);
++
++        std::string validate_string (EnumRegistration& er, const std::string&);
+ };
+ 
+ }
+ 
++#define enum_validate(v,str) PBD::EnumWriter::instance().typed_validate (typeid(v).name(),str)
+ #define enum_2_string(e) (PBD::EnumWriter::instance().write (typeid(e).name(), e))
+ #define string_2_enum(str,e) (PBD::EnumWriter::instance().read (typeid(e).name(), (str)))
+ 
++#endif /* __pbd_enumwriter_h__ */
+--- /dev/null
++++ b/libs/pbd/pbd/epa.h
+@@ -0,0 +1,49 @@
++/*
++    Copyright (C) 2010 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.
++
++*/
++
++#ifndef __libpbd_epa_h__
++#define __libpbd_epa_h__
++
++#include <map>
++#include <string>
++
++namespace PBD {
++
++class EnvironmentalProtectionAgency {
++  public:
++        EnvironmentalProtectionAgency (bool arm = true, const std::string& envname = std::string());
++        ~EnvironmentalProtectionAgency ();
++        
++        void arm ();
++        void save ();
++        void restore () const;
++        
++        static EnvironmentalProtectionAgency* get_global_epa () { return _global_epa; }
++        static void set_global_epa (EnvironmentalProtectionAgency* epa) { _global_epa = epa; }
++        
++  private:
++        bool _armed;
++        std::string _envname;
++        std::map<std::string,std::string> e;
++        static EnvironmentalProtectionAgency* _global_epa;
++};
++
++}
++
++#endif /* __libpbd_epa_h__ */
+--- a/libs/pbd/SConscript
++++ b/libs/pbd/SConscript
+@@ -26,6 +26,7 @@
+ controllable.cc
+ enumwriter.cc
+ dmalloc.cc
++epa.cc
+ error.cc
+ fpu.cc
+ id.cc
+--- a/libs/pbd/undo.cc
++++ b/libs/pbd/undo.cc
+@@ -40,6 +40,8 @@
+ {
+ 	_name = rhs._name;
+ 	_clearing = false;
++        _timestamp = rhs._timestamp;
++
+ 	clear ();
+ 	actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end());
+ }
+--- a/libs/surfaces/mackie/mackie_control_protocol.cc
++++ b/libs/surfaces/mackie/mackie_control_protocol.cc
+@@ -622,9 +622,15 @@
+ 	cout << "MIDI::Port::ALSA_Sequencer " << MIDI::Port::ALSA_Sequencer << endl;
+ 	cout << "MIDI::Port::Unknown " << MIDI::Port::Unknown << endl;
+ #endif
+-	if ( string( midi_port.device() ) == string( "ardour" ) && midi_port.type() == MIDI::Port::ALSA_Sequencer )
++        string pname (PROGRAM_NAME);
++        std::transform(pname.begin(), pname.end(), pname.begin(), ::tolower);
++
++	if ( string( midi_port.device() ) == pname && midi_port.type() == MIDI::Port::ALSA_Sequencer )
+ 	{
+-		throw MackieControlException( "The Mackie MCU driver will not use a port with device=ardour" );
++                ostringstream s;
++                s << "The Mackie MCU driver will not use a port with device=";
++                s << pname;
++		throw MackieControlException( s.str());
+ 	}
+ 	else if ( midi_port.type() == MIDI::Port::ALSA_Sequencer )
+ 	{
+--- a/libs/surfaces/mackie/mackie_port.cc
++++ b/libs/surfaces/mackie/mackie_port.cc
+@@ -488,6 +488,12 @@
+ 				state.sign = ( raw_bytes[2] & 0x40 ) == 0 ? 1 : -1; 
+ 				// bytes[2] & 0b00111111 (0x3f) gives delta
+ 				state.ticks = ( raw_bytes[2] & 0x3f);
++                                if (state.ticks == 0) {
++                                        /* euphonix and perhaps other devices send zero
++                                           when they mean 1, we think.
++                                        */
++                                        state.ticks = 1;
++                                }
+ 				state.delta = float( state.ticks ) / float( 0x3f );
+ 				
+ 				/*
+--- a/SConstruct
++++ b/SConstruct
+@@ -545,6 +545,14 @@
+ 	else:
+ 		print 'LV2 support is not enabled (SLV2 not found or older than 0.6.0)'
+ 		env['LV2'] = 0
++
++	if conf.CheckPKGVersion('rasqal', '0.9.14'):
++		libraries['rasqal'] = LibraryInfo()
++		libraries['rasqal'].ParseConfig('pkg-config --cflags --libs rasqal')
++	else:
++		print 'LV2 support is not enabled (Rasqal, required by SLV2, not found)'
++		env['LV2'] = 0
++
+ 	conf.Finish()
+ else:
+ 	print 'LV2 support is not enabled.  Build with \'scons LV2=1\' to enable.'
+@@ -1027,6 +1035,9 @@
+     print "It appears you don't have the required MIDI libraries installed. For Linux this means you are missing the development package for ALSA libraries."
+     sys.exit (1)
+ 
++pname = env['PROGRAM_NAME']
++subst_dict['%MIDI_DEVICE_NAME%'] = pname.lower()
++
+ env = conf.Finish()
+ 
+ if env['GTKOSX']:
+@@ -1226,6 +1237,15 @@
+ if env['RUBBERBAND']:
+     timefx_subdirs += ['libs/rubberband']
+ 
++#
++# Tools
++#
++if env['IS_OSX'] == 0 :
++	tools_subdirs = [ 'tools/sanity_check' ]
++else:
++	tools_subdirs = [ ]
++
++
+ opts.Save('scache.conf', env)
+ Help(opts.GenerateHelpText(env))
+ 
+@@ -1403,7 +1423,7 @@
+ for subdir in coredirs:
+     SConscript (subdir + '/SConscript')
+ 
+-for sublistdir in [ subdirs, timefx_subdirs, gtk_subdirs, surface_subdirs ]:
++for sublistdir in [ subdirs, timefx_subdirs, gtk_subdirs, surface_subdirs, tools_subdirs ]:
+     for subdir in sublistdir:
+         SConscript (subdir + '/SConscript')
+ 
+--- /dev/null
++++ b/tools/linux_packaging/ardour.sh.in
+@@ -0,0 +1,40 @@
++#!/bin/sh
++
++#LD_LIBRARY_PATH needs to be set (empty) so that epa can swap between the original and the bundled version
++export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++
++export PREBUNDLE_ENV="$(env)"
++
++BIN_DIR=$(dirname $(readlink -f $0))
++INSTALL_DIR=$(dirname $BIN_DIR)
++LIB_DIR=$INSTALL_DIR/lib
++ETC_DIR=$INSTALL_DIR/etc
++USER_ARDOUR_DIR=$HOME/.ardour2
++
++if [ ! -d $USER_ARDOUR_DIR ] ; then
++    mkdir -p $USER_ARDOUR_DIR || exit 1
++fi
++
++# this triggers code in main() that will reset runtime environment variables
++# to point to directories inside the ardour package
++
++export ARDOUR_BUNDLED=true
++
++# this is edited by the build script to include relevant environment variables
++
++%ENV%
++
++export GTK_PATH=$INSTALL_DIR${GTK_PATH:+:$GTK_PATH}
++export GTK_MODULES=""		# Disable extra modules from being loaded by gtk (example, libcanberra-gtk-module.so)
++export LD_LIBRARY_PATH=$INSTALL_DIR/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++
++# create install-location-dependent config files for Pango and GDK image loaders
++# We have to do this every time because its possible that BIN_DIR has changed
++
++sed "s?@ROOTDIR@/modules?$LIB_DIR/modules?" < $ETC_DIR/pango.modules.in > $USER_ARDOUR_DIR/pango.modules
++sed "s?@ROOTDIR@/loaders?$LIB_DIR/loaders?" < $ETC_DIR/gdk-pixbuf.loaders.in > $USER_ARDOUR_DIR/gdk-pixbuf.loaders
++
++exec $INSTALL_DIR/bin/ardour-%VER% "$@"
++
++
++
+--- /dev/null
++++ b/tools/linux_packaging/build
+@@ -0,0 +1,619 @@
++#!/bin/bash
++
++#
++
++. ./buildenv
++
++# script for pulling together a Linux app bundle.
++#
++# This will create a bundle for a single architecture.
++# Execute this scirpt on both x86 and x86_64 and then use
++# package to merge the 2 bundles into a final package with the
++# installer.
++
++SAE=
++MIXBUS=
++INTERNAL_JACK=1
++WITH_LADSPA=0
++STRIP=1
++PRINT_SYSDEPS=
++WITH_NLS=
++EXTERNAL_JACK=
++VENDOR=Ardour ;
++
++if [ $# -eq 0 ] ; then
++	echo ""	 
++	echo "ERROR - Please specify build type"
++	echo "	  --public"
++	echo "	  --sae"
++	echo ""	 
++	exit 1
++fi
++
++while [ $# -gt 0 ] ; do
++	echo "arg = $1"
++	case $1 in
++
++	#
++	# top level build targets
++	#
++
++	--sae)
++		WITH_NLS= ; 
++		SAE=1 ; 
++		INTERNAL_JACK=1; 
++		WITH_LADSPA=1; 
++		STRIP=1; 
++		APPNAME=Ardour ;
++		shift ;;
++	--mixbus)
++		MIXBUS=1; 
++		WITH_NLS=1 ; 
++		SAE= ; 
++		INTERNAL_JACK=; 
++		WITH_LADSPA=; 
++		STRIP=1; 
++		APPNAME=Mixbus ;
++		VENDOR=Harrison ;
++		shift ;;
++	--public)
++		WITH_NLS=1 ; 
++		SAE= ; 
++		INTERNAL_JACK=; 
++		WITH_LADSPA=; 
++		STRIP=1; 
++		APPNAME=Ardour ;
++		shift ;;
++	--allinone)
++		SAE= ; 
++		WITH_NLS= ; 
++		INTERNAL_JACK=1; 
++		WITH_LADSPA=1; 
++		STRIP=1; 
++		shift ;;
++	--test) SAE= ; INTERNAL_JACK=; WITH_LADSPA=; STRIP= ; shift ;;
++
++	#
++	# specific build flags
++	#
++
++	--nojack) INTERNAL_JACK= ; shift ;;
++	--noladspa) WITH_LADSPA= ; shift ;;
++	--nostrip) STRIP= ; shift ;;
++	--sysdeps) PRINT_SYSDEPS=1; shift ;;
++	--nls) WITH_NLS=1 ; shift ;;
++	--external_jack) EXTERNAL_JACK=$2; shift ; shift ;;
++
++	*)
++		#catch all for unknown arguments
++		echo ""
++		echo "!!! ERROR !!! - Unknown argument $1"
++		echo ""
++		exit 1
++		;;
++	esac
++done
++
++if [ x$EXTERNAL_JACK != x -a x$INTERNAL_JACK != x ] ; then
++	echo "It makes no sense to package JACK internally and externally. Please pick one."
++fi
++
++release_version=`grep -m 1 '^ardour_version' ../../SConstruct | cut -d' ' -f 3 | sed "s/'//g"`
++svn_version=`grep -m 1 'svn_revision =' ../../libs/ardour/svn_revision.cc | cut -d' ' -f 6 | sed 's/[";]//g'`
++echo "Version is $release_version / $svn_version"
++info_string="$release_version/$svn_version built on `hostname` by `whoami` on `date`"
++echo "Info string is $info_string"
++
++# Figure out our CPU type
++case `uname -m` in
++	i[3456789]86|x86|i86pc)
++		echo "Architecture is x86"
++		ARCH='x86'
++		ARCH_BITS='32-bit'
++		;;
++	x86_64|amd64|AMD64)
++		echo "Architecture is x86_64"
++		ARCH='x86_64'
++		ARCH_BITS='64-bit'
++		;;
++	*)
++		echo ""
++		echo "ERROR - Unknown architecture `uname -m`"
++		echo ""
++		exit 1
++		;;
++esac
++
++# setup directory structure
++
++APPDIR=${APPNAME}_${ARCH}-${release_version}_${svn_version}
++APPBIN=$APPDIR/bin
++APPLIB=$APPDIR/lib
++Libraries=$APPLIB
++Etc=$APPDIR/etc
++Shared=$APPDIR/share
++Plugins=$APPLIB/plugins
++Surfaces=$APPLIB/surfaces
++Panners=$APPLIB/panners
++Locale=$Shared/locale
++Modules=$Libraries/modules
++Loaders=$Libraries/loaders
++
++
++if [ x$PRINT_SYSDEPS != x ] ; then
++#
++# print system dependencies
++#
++
++	for file in $APPBIN/* $Libraries/* $Modules/* $Plugins/*.so ; do 
++		if ! file $file | grep -qs Mach-O ; then
++			continue
++		fi
++		otool -L $file | awk '{print $1}' | egrep -v "(^@executable_path|^Ardour[0-9][.0-9]*.app)" 
++	done | sort | uniq
++	exit 0
++fi
++
++echo "Removing old $APPDIR tree ..."
++rm -rf $APPDIR/
++
++echo "Building new app directory structure ..."
++
++# only bother to make the longest paths
++
++mkdir -p $APPDIR
++mkdir -p $APPBIN
++mkdir -p $APPLIB
++mkdir -p $Etc
++mkdir -p $Plugins
++mkdir -p $Modules
++mkdir -p $Loaders
++mkdir -p $Shared
++mkdir -p $Locale
++mkdir -p $Surfaces
++mkdir -p $Panners
++mkdir -p $Shared/templates
++mkdir -p $Shared/doc
++
++# maybe set variables
++ENVIRONMENT=environment
++rm -f $ENVIRONMENT
++touch $ENVIRONMENT
++
++if test x$SAE != x ; then
++	echo "export ARDOUR_SAE=true" >> $ENVIRONMENT
++	#
++	# current default for SAE version is German keyboard layout without a keypad
++	#
++	echo export ARDOUR_KEYBOARD_LAYOUT=de-nokeypad >> $ENVIRONMENT
++	echo export ARDOUR_UI_CONF=ardour2_ui_sae.conf >> $ENVIRONMENT
++	echo export ARDOUR2_UI_RC=ardour2_ui_dark_sae.rc >> $ENVIRONMENT
++elif test x$MIXBUS != x ; then
++	echo export ARDOUR_MIXBUS=true >> $ENVIRONMENT
++	#
++	# current default for MIXBUS version is US keyboard layout without a keypad
++	#
++	echo export ARDOUR_KEYBOARD_LAYOUT=us-nokeypad >> $ENVIRONMENT
++	echo export ARDOUR_UI_CONF=ardour2_ui.conf >> $ENVIRONMENT
++	echo export ARDOUR2_UI_RC=ardour2_ui_dark.rc >> $ENVIRONMENT
++fi
++
++#
++# if we're not going to bundle JACK, make sure we can find
++# jack in the places where it might be
++#
++
++echo export 'PATH=/usr/local/bin:/opt/bin:$PATH' >> $ENVIRONMENT
++
++# create startup helper script
++
++sed -e "/^%ENV%/r $ENVIRONMENT" -e '/^%ENV%/d' -e 's/%VER%/'"${release_version}"'/' < ardour.sh.in > $APPBIN/ardour2
++rm $ENVIRONMENT && chmod 775 $APPBIN/ardour2
++MAIN_EXECUTABLE=ardour-$release_version
++
++echo "Copying ardour executable ...."
++cp ../../gtk2_ardour/$MAIN_EXECUTABLE $APPBIN
++if test x$STRIP != x ; then
++	strip $APPBIN/$MAIN_EXECUTABLE
++fi
++
++# copy locale files
++if test x$WITH_NLS != x ; then
++	echo "NLS support ..."
++	echo "I hope you remembered to run scons msgupdate!"
++	LINGUAS=
++	files=`find ../../gtk2_ardour/ -name "*.mo"`
++
++	if [ -z "$files" ]; then
++		echo ""
++		echo "!!!! WARNING !!!! - Did not find any .mo files in ../../gtk2_ardour"
++		echo ""
++	fi
++ 
++	for file in $files 
++	do
++		echo $file
++		lang=`basename $file | sed 's/\.mo//'`
++		mkdir -p $Locale/$lang/LC_MESSAGES
++		cp $file $Locale/$lang/LC_MESSAGES/gtk2_ardour.mo
++		LINGUAS="$LINGUAS $lang"
++	done
++
++	files=`find ../../libs/ardour/ -name "*.mo"`
++
++	if [ -z "$files" ]; then
++		echo ""
++		echo "!!!! WARNING !!!! - Did not find any .mo files in ../../libs/ardour"
++		echo ""
++	fi
++
++	for file in $files 
++	do
++		echo $file
++		lang=`basename $file | sed 's/\.mo//'`
++		mkdir -p $Locale/$lang/LC_MESSAGES
++		cp $file $Locale/$lang/LC_MESSAGES/libardour.mo
++	done
++
++	GTK_MESSAGES="atk10.mo gdk-pixbuf.mo gtk20-properties.mo gtk20.mo atk10.mo glib20.mo"
++	LOCALEROOT=/usr/share/locale
++
++	for l in $LINGUAS ; do
++		echo "Copying GTK i18n files for $l..."
++		for MO in $GTK_MESSAGES ; do 
++			if [ -f $LOCALEROOT/$l/LC_MESSAGES/$MO ] ; then
++				cp $LOCALEROOT/$l/LC_MESSAGES/$MO $Locale/$l/LC_MESSAGES
++			else
++				# try with just the language spec
++				just_lang=`echo $l | sed 's/_[A-Z][A-Z]$//'`
++				if [ -f $LOCALEROOT/$just_lang/LC_MESSAGES/$MO ] ; then
++					cp $LOCALEROOT/$just_lang/LC_MESSAGES/$MO $Locale/$just_lang/LC_MESSAGES
++				fi
++			fi
++		done
++	done
++else
++	echo "Skipping NLS support"
++fi
++
++### Find gtk ###
++GTKROOT=`pkg-config --libs-only-L gtk+-2.0 | sed -e "s/-L//" -e "s/[[:space:]]//g"`
++if [ ! -z "$GTKROOT" ]; then
++	echo "Found GTKROOT using pkg-config"
++elif [ -d /usr/lib/gtk-2.0 ]; then
++	GTKROOT="/usr/lib"
++elif [ -d /usr/local/lib/gtk-2.0 ]; then
++	GTKROOT="/usr/local/lib"
++else
++	echo ""
++	echo "!!! ERROR !!! - Unable to locate gtk-2.0 directory. Packager will exit"
++	echo ""
++	exit 1
++fi
++
++echo "GTKROOT is ${GTKROOT}"
++versionDir=`ls ${GTKROOT}/gtk-2.0/ | grep "[0-9]*\.[0-9]*\.[0-9]*"`
++
++num=0
++for name in $versionDir ; do
++	num=$(($num + 1))
++done
++
++if [ $num -eq 1 ]; then
++	GTKLIB=${GTKROOT}/gtk-2.0/$versionDir
++	echo "GTKLIB is ${GTKLIB}"
++else
++	echo ""
++	echo "!!! ERROR !!! - More than one gtk-2.0 version found in ${GTKROOT}/gtk-2.0/  ( $versionDir ). Packager will exit"
++	echo ""
++	exit 1
++fi
++
++
++### Find pango ###
++PANGOROOT=`pkg-config --libs-only-L pango | sed -e "s/-L//" -e "s/[[:space:]]//g"`
++if [ ! -z "$PANGOROOT" ]; then
++	echo "Found PANGOROOT using pkg-config"
++elif [ -d /usr/lib/pango ]; then
++	PANGOROOT="/usr/lib"
++elif [ -d /usr/local/lib/pango ]; then
++	PANGOROOT="/usr/local/lib"
++else
++	echo ""
++	echo "!!! ERROR !!! - Unable to locate pango directory. Packager will exit"
++	echo ""
++	exit 1
++fi
++
++echo "PANGOROOT is ${PANGOROOT}"
++versionDir=`ls ${PANGOROOT}/pango/ | grep "[0-9]*\.[0-9]*\.[0-9]*"`
++
++num=0
++for name in $versionDir ; do
++	num=$(($num + 1))
++done
++
++if [ $num -eq 1 ]; then
++	PANGOLIB=${PANGOROOT}/pango/$versionDir
++	echo "PANGOLIB is ${PANGOLIB}"
++else
++	echo ""
++	echo "!!! ERROR !!! - More than one pango version found in ${PANGOROOT}/pango/  ( $versionDir ). Packager will exit"
++	echo ""
++	exit 1
++fi
++
++
++### Find gdk-pixbuf ###
++GDKPIXBUFROOT=`pkg-config --libs-only-L gdk-pixbuf-2.0 | sed -e "s/-L//" -e "s/[[:space:]]//g"`
++if [ ! -z "$GDKPIXBUFROOT" ]; then
++	echo "Found GDKPIXBUFROOT using pkg-config"
++elif [ -d /usr/lib/gdk-pixbuf-2.0 ]; then
++	GDKPIXBUFROOT="/usr/lib/gdk-pixbuf-2.0"
++elif [ -d /usr/local/lib/gdk-pixbuf-2.0 ]; then
++	GDKPIXBUFROOT="/usr/local/lib/gdk-pixbuf-2.0"
++elif [ -d ${GTKLIB}/loaders ]; then  #odd ball case
++	GDKPIXBUFROOT=${GTKROOT}
++	GDKPIXBUFLIB=${GTKLIB}
++else
++	echo ""
++	echo "!!! ERROR !!! - Unable to locate gdk-pixbuf-2.0 directory. Packager will exit"
++	echo ""
++	exit 1
++fi
++
++echo "GDKPIXBUFROOT is ${GDKPIXBUFROOT}"
++
++if [ -z ${GDKPIXBUFLIB} ]; then
++	versionDir=`ls ${GDKPIXBUFROOT}/gdk-pixbuf-2.0/ | grep "[0-9]*\.[0-9]*\.[0-9]*"`
++
++	num=0
++	for name in $versionDir ; do
++		num=$(($num + 1))
++	done
++
++	if [ $num -eq 1 ]; then
++		GDKPIXBUFLIB=${GDKPIXBUFROOT}/gdk-pixbuf-2.0/$versionDir
++		echo "GDKPIXBUFLIB is ${GDKPIXBUFLIB}"
++	else
++		echo ""
++		echo "!!! ERROR !!! - More than one gdk-pixbuf-2.0 version found in ${GDKPIXBUFROOT}/pango/  ( $versionDir ). Packager will exit"
++		echo ""
++		exit 1
++	fi
++fi
++
++
++
++echo "Copying all Pango modules ..."
++cp -R $PANGOLIB/modules/*.so $Modules
++
++echo "Copying all GDK Pixbuf loaders ..."
++cp -R $GDKPIXBUFLIB/loaders/*.so $Loaders
++
++pango-querymodules | sed "s?$PANGOLIB/?@ROOTDIR@/?" > $Etc/pango.modules.in
++gdk-pixbuf-query-loaders | sed "s?$GDKPIXBUFLIB/?@ROOTDIR@/?" > $Etc/gdk-pixbuf.loaders.in
++
++# We sort of rely on clearlooks, so include a version
++# this one is special - we will set GTK_PATH to $Libraries/clearlooks
++
++if [ ! -e ${GTKLIB}/engines/libclearlooks.so ]; then
++	echo ""
++	echo "!!! ERROR !!! - not able to locate libclearlooks.so"
++	echo ""
++	echo "Packager with exit"
++	exit 1
++fi
++
++echo "Copying clearlooks ..."
++cp ${GTKLIB}/engines/libclearlooks.so $Libraries
++mkdir -p $Libraries/clearlooks/engines
++(cd $Libraries/clearlooks/engines && ln -s ../../libclearlooks* libclearlooks.so )
++
++# LADSPA
++if test x$WITH_LADSPA != x ; then
++	if test x$SAE != x ; then
++		plugdir=sae_ladspa
++	elif test x$MIXBUS != x ; then
++		plugdir=mixbus_ladspa
++	else
++		plugdir=ladspa
++	fi
++	echo "Copying `ls $plugdir | wc -l` plugins ..."
++	if [ -d $plugdir ] ; then
++		cp -r $plugdir/* $Plugins
++	fi
++fi
++
++# XXX STILL NEED TO DO PANNERS FOR TRUNK
++cp ../../libs/surfaces/*/libardour_*.so* $Surfaces
++# hack ... move libardour_cp back into Libraries
++mv $Surfaces/libardour_cp.so* $Libraries
++
++# VAMP plugins that we use
++cp ../../libs/vamp-plugins/libardourvampplugins.so* $Libraries
++
++OURLIBDIR=../../libs
++OURLIBS=$OURLIBDIR/vamp-sdk:$OURLIBDIR/surfaces/control_protocol:$OURLIBDIR/ardour:$OURLIBDIR/midi++2:$OURLIBDIR/pbd:$OURLIBDIR/rubberband:$OURLIBDIR/soundtouch:$OURLIBDIR/gtkmm2ext:$OURLIBDIR/sigc++2:$OURLIBDIR/glibmm2:$OURLIBDIR/gtkmm2/atk:$OURLIBDIR/gtkmm2/pango:$OURLIBDIR/gtkmm2/gdk:$OURLIBDIR/gtkmm2/gtk:$OURLIBDIR/libgnomecanvasmm:$OURLIBDIR/libsndfile
++
++echo $OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++
++checkedIdx=0
++
++while [ true ] ; do 
++	missing=false
++	filelist=`find $APPLIB/ -type f`
++	filelist="$APPBIN/$MAIN_EXECUTABLE $filelist"
++
++	for file in $filelist  ; do 
++		if ! file $file | grep -qs ELF ; then
++			continue
++		fi
++
++		# speed this up a bit by not checking things multiple times.
++		for i in "${depCheckedList[@]}"; do
++			if [ $i == $file ]; then
++				continue 2
++			fi
++		done
++		depCheckedList[$checkIdx]=$file
++		checkIdx=$(($checkIdx + 1))
++		
++		# do not include libjack
++		deps=`LD_LIBRARY_PATH=$OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} ldd $file | awk '{print $3}'`
++
++		# LD_LIBRARY_PATH=$OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} ldd $file | egrep "(/opt/|/local/|libs/|/usr/lib|/gtk)" | grep -v 'libjack\.'
++		echo -n "."
++		for dep in $deps ; do
++			if test "not" = ${dep}; then 
++				echo ""
++				echo "!!! ERROR !!! - Missing dependant library for $file."
++				echo ""
++				(LD_LIBRARY_PATH=$OURLIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} ldd $file)
++				echo ""
++				echo "!!! ERROR !!! - See Above"
++				exit 1
++			fi
++
++			# don't use anything mapped at a specific address
++			if echo $dep | grep -qs '0x' ; then continue; fi
++			# don't include /lib
++			if echo $dep | grep -qs "^/lib/" ; then continue; fi
++			# don't include jack
++			if echo $dep | grep -qs libjack ; then continue; fi
++			# don't include any X Window libraries
++			if echo $dep | grep -qs libX ; then continue; fi  
++			if echo $dep | grep -qs libxcb ; then continue; fi  
++			# don't include libc
++			if echo $dep | grep -qs 'libc\.' ; then continue; fi
++			# don't include libstdc++
++			if echo $dep | grep -qs libstdc++ ; then continue; fi
++
++			base=`basename $dep`
++			if ! test -f $Libraries/$base; then
++				parent=$(basename ${file})
++				if echo $dep | grep -sq '^libs' ; then
++					echo "Copying dependant lib ../../$dep    (required by ${parent})"
++					cp ../../$dep $Libraries
++				else
++					echo "Copying dependant lib $dep    (required by ${parent})"
++					cp $dep $Libraries
++				fi
++				missing=true
++			fi
++		done
++	done
++	if test x$missing = xfalse ; then
++		# everything has been found
++		break
++	fi
++done
++echo
++
++# strip libraries
++if test x$STRIP != x ; then
++	echo Stripping libraries
++	find $APPLIB/ -name "*.so*" | xargs strip
++fi
++	
++find $APPLIB/ -name "*.so*" | xargs chmod a+rx
++
++echo "Copying other stuff to $APPDIR  ..."
++
++cp ../../gtk2_ardour/ergonomic-us.bindings	$Etc
++cp ../../gtk2_ardour/mnemonic-us.bindings  $Etc
++cp ../../gtk2_ardour/SAE-de-keypad.bindings  $Etc
++cp ../../gtk2_ardour/SAE-de-nokeypad.bindings  $Etc
++cp ../../gtk2_ardour/SAE-us-keypad.bindings  $Etc
++cp ../../gtk2_ardour/SAE-us-nokeypad.bindings  $Etc
++cp ../../gtk2_ardour/ardour.menus $Etc
++cp ../../gtk2_ardour/ardour-sae.menus $Etc
++if test x$SAE != x ; then
++	cp ../../ardour_system_sae.rc $Etc/ardour_system.rc
++	echo cp ../../ardour_system_sae.rc $Etc/ardour_system.rc
++	cp ../../instant.xml.sae $Etc/instant.xml
++	echo cp ../../instant.xml.sae $Etc/instant.xml
++else
++	cp ../../ardour_system.rc $Etc/ardour_system.rc
++	echo cp ../../ardour_system.rc $Etc/ardour_system.rc
++	cp ../../instant.xml $Etc/instant.xml
++	echo cp ../../instant.xml $Etc/instant.xml
++fi
++cp ../../gtk2_ardour/ardour2_ui_sae.conf $Etc
++cp ../../gtk2_ardour/ardour2_ui_default.conf $Etc
++cp ../../gtk2_ardour/ardour2_ui_default.conf $Etc/ardour2_ui.conf
++cp ../../gtk2_ardour/ardour2_ui_light.rc $Etc
++cp ../../gtk2_ardour/ardour2_ui_dark.rc $Etc
++cp ../../gtk2_ardour/ardour2_ui_light_sae.rc $Etc
++cp ../../gtk2_ardour/ardour2_ui_dark_sae.rc $Etc
++
++cp -r ../../gtk2_ardour/icons $Etc
++cp -r ../../gtk2_ardour/pixmaps $Etc
++
++#
++# put sooper sekrit ingredients here and they will be copied
++#
++
++if [ -d specialSauce ] ; then
++	cp -r specialSauce $Etc
++fi
++
++# share stuff
++
++cp -R ../../gtk2_ardour/splash.png $Shared
++cp ../../templates/*.template $Shared/templates/
++
++# go through and recursively remove any .svn dirs in the bundle
++for svndir in `find $APPDIR -name .svn -type d`; do
++	rm -rf $svndir
++done
++
++#
++# Add any documentation to the top level of the package
++# 
++
++if [ x$SAE != x ] ; then
++	
++	# SAE packaging
++	
++	echo "Adding SAE documentation"
++	cp HowToInstallArdourSAE.pdf "$Shared/doc/How To Install Ardour SAE.pdf"
++	cp SAE-de-keypad.pdf "$Shared/doc/Ardour SAE Shortcuts (keypad).pdf"
++	cp SAE-de-nokeypad.pdf "$Shared/doc/Ardour SAE Shortcuts.pdf"
++	
++elif [ x$MIXBUS != x ] ; then
++
++	# Mixbus packaging
++
++	echo "Adding Mixbus documentation"
++	cp MixBus_Install_QuickStart.pdf "$Shared/doc/Mixbus Install & Quick Start Guide.pdf"
++	
++	if [ -x $EXTERNAL_JACK != x ] ; then
++		cp $EXTERNAL_JACK $PRODUCT_PKG_DIR
++	fi
++fi
++
++#
++# Add the uninstaller
++#
++APP_VER_NAME=${APPNAME}-${release_version}_${svn_version}
++sed -e "s/%REPLACE_PGM%/${APPNAME}/" -e "s/%REPLACE_VENDOR%/${VENDOR}/" -e "s/%REPLACE_VERSION%/${release_version}/" -e "s/%REPLACE_BUILD%/${svn_version}/" < uninstall.sh.in > $APPBIN/${APP_VER_NAME}.uninstall.sh
++chmod a+x $APPBIN/${APP_VER_NAME}.uninstall.sh
++
++#Sanity Check file
++if [ -e ../sanity_check/sanityCheck ]; then
++	cp ../sanity_check/sanityCheck $APPBIN
++else
++	echo "!!!ERROR !!! sanityCheck program is missing. packager will exit without being complete"
++	exit 1
++fi
++
++echo "Building tarball ..."
++
++rm -f $APPDIR.tar.bz2
++tar -cjf $APPDIR.tar.bz2 $APPDIR
++
++rm -rf $APPDIR/
++
++echo "Done."
++
+--- /dev/null
++++ b/tools/linux_packaging/buildenv
+@@ -0,0 +1,8 @@
++GTK_PREFIX_DIR=/gtk/will/search/here
++
++if ! echo $LD_LIBRARY_PATH | grep -qs $GTK_PREFIX_DIR ; then
++   LD_LIBRARY_PATH=${GTK_PREFIX_DIR}/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
++   PATH=${GTK_PREFIX_DIR}/bin:$PATH
++   PKG_CONFIG_PATH=${GTK_PREFIX_DIR}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
++fi
++
+--- /dev/null
++++ b/tools/linux_packaging/install.sh
+@@ -0,0 +1,25 @@
++#!/bin/sh
++
++# Make sure we have a terminal for the user to see and then run
++# the real install script.
++
++# Some systems don't correctly set the PWD when a script is double-clicked,
++# so go ahead and figure out our path and make sure we are in that directory.
++
++SAVED_PWD=$PWD
++PKG_PATH=$(dirname $(readlink -f $0))
++cd ${PKG_PATH}
++
++if [ -z "$TERM" ] || [ "$TERM" = "dumb" ]; then
++	if which xterm > /dev/null; then
++		exec xterm -e ${PKG_PATH}/.stage2.run
++	elif which gnome-terminal > /dev/null; then
++		exec gnome-terminal -e ${PKG_PATH}/.stage2.run
++	elif which konsole > /dev/null; then
++		exec konsole -e ${PKG_PATH}/.stage2.run
++	fi
++else
++	${PKG_PATH}/.stage2.run
++fi
++
++cd ${SAVED_PWD}
+--- /dev/null
++++ b/tools/linux_packaging/package
+@@ -0,0 +1,90 @@
++#!/bin/bash
++
++# package
++
++# This will collect up the x86 and x86_64 bundles created by build
++# and package them together with an installer script.
++
++
++if [ $# -eq 0 ] ; then
++	echo ""	 
++	echo "ERROR - Please specify build type"
++	echo "	  --public"
++	echo "	  --sae"
++	echo ""	 
++	exit 1
++fi
++
++while [ $# -gt 0 ] ; do
++	echo "arg = $1"
++	case $1 in
++
++	#
++	# top level build targets
++	#
++
++	--sae)
++		APPNAME=Ardour ;
++		shift ;;
++	--mixbus)
++		APPNAME=Mixbus ;
++		shift ;;
++	--public)
++		APPNAME=Ardour ;
++		shift ;;
++
++	*)
++		#catch all for unknown arguments
++		echo ""
++		echo "!!! ERROR !!! - Unknown argument $1"
++		echo ""
++		exit 1
++		;;
++	esac
++done
++
++
++release_version=`grep -m 1 '^ardour_version' ../../SConstruct | cut -d' ' -f 3 | sed "s/'//g"`
++svn_version=`grep -m 1 'svn_revision =' ../../libs/ardour/svn_revision.cc | cut -d' ' -f 6 | sed 's/[";]//g'`
++
++X86_BUILD="${APPNAME}_x86-${release_version}_${svn_version}.tar.bz2"
++X86_64_BUILD="${APPNAME}_x86_64-${release_version}_${svn_version}.tar.bz2"
++PACKAGE="${APPNAME}-${release_version}_${svn_version}"
++
++if [ ! -e ${X86_BUILD} ]; then
++	echo ""
++	echo "!!! ERROR !!! - Can't locate x86 build file ${X86_BUILD}"
++	echo ""
++	exit 1
++fi
++
++if [ ! -e ${X86_64_BUILD} ]; then
++	echo ""
++	echo "!!! ERROR !!! - Can't locate x86_64 build file ${X86_64_BUILD}"
++	echo ""
++	exit 1
++fi
++
++echo "Cleaning up any old package files for this build"
++#Get rid of any old packages of this same name.
++rm -f ${PACKAGE}.tar.bz2
++rm -rf ${PACKAGE}
++
++
++echo "Creating new package dir..."
++mkdir ${PACKAGE}
++mv ${X86_BUILD} ${PACKAGE}
++mv ${X86_64_BUILD} ${PACKAGE}
++cp install.sh ${PACKAGE}
++cp stage2.run ${PACKAGE}/.stage2.run
++cp README ${PACKAGE}
++
++echo "Creating tarball..."
++tar -czf ${PACKAGE}.tar.gz ${PACKAGE}
++
++echo "Clean up"
++rm -rf ${PACKAGE}
++
++echo ""
++echo "Done"
++echo ""
+--- /dev/null
++++ b/tools/linux_packaging/README
+@@ -0,0 +1,35 @@
++* Installing Ardour:
++
++On most distributions, you can double-click the file "install.sh".
++
++Alternatively, you can use a Terminal to run the installer.  Navigate
++to the folder and run:
++	
++	./install.sh
++	
++The installer will ask for your root password, and copy the contents of
++the appropriate bundle (32-bit or 64-bit) to your /opt folder.
++
++
++* Links and Menu entries:
++
++In addition to installing the program, the installer will create:
++1) A desktop link to launch the Ardour application
++2) A menu entry in Gnome/KDE
++3) An uninstall script in the /opt folder.
++
++
++* Uninstaller:
++
++To uninstall Ardour, run the uninstaller script in the /opt folder
++(as root).  This will remove the app, desktop links, menu links, and
++the uninstaller itself.
++
++
++* Manual Installation:
++
++If you would prefer to install Ardour in a custom location, then you
++may simply unzip the appropriate package (32bit or 64bit) to your
++preferred location and run the Ardour application from the "bin"
++folder inside.
++
+--- /dev/null
++++ b/tools/linux_packaging/stage2.run
+@@ -0,0 +1,525 @@
++#!/bin/sh
++
++####################################
++#
++#	stage2.run
++#	Ardour/Mixbus bundle installer
++#	Todd Naugle
++#
++###################################
++
++
++
++PGM_NAME="Ardour"
++PGM_VENDOR="Ardour"
++PGM_EXEC_FILE="ardour2"
++
++INSTALL_DEST_BASE="/opt"
++
++PGM_NAME_LOWER=$(echo $PGM_NAME | tr '[:upper:]' '[:lower:]')
++
++#### Global Variables ####
++HAS_XDG="T"
++
++########################
++# Function Definitions
++########################
++
++VaildateYesNoQuestion ()
++{
++	# $1 = Question Text
++	
++	local INPUT_OK="n"
++	local USER_INPUT=""
++
++	until test "y" = $INPUT_OK;
++	do
++		echo ""
++		read -p "$1 [y/n]: " USER_INPUT
++		echo ""
++
++		if [ ! -z $USER_INPUT ]; 
++		then		
++			if [ "Y" = $USER_INPUT -o "y" = $USER_INPUT -o "n" = $USER_INPUT -o "N" = $USER_INPUT ];
++			then
++				INPUT_OK="y"
++			fi
++		fi
++	done
++	
++	echo $USER_INPUT | tr '[:upper:]' '[:lower:]'
++	
++}
++
++SystemInstall ()
++{
++
++	# Determine which software install app to use and then install requested package
++	# $1 = Package Name
++
++	if which yum > /dev/null;
++	then
++		sudo yum -y install $1
++		rtrn=$?
++
++		if [ $rtrn -ne 0 ];
++		then
++			echo ""
++			echo "!!! ERROR !!! yum install failed for an unknown reason."
++			echo "Please install package $1 after this installer completes."
++			echo ""
++		fi
++
++	elif which apt-get > /dev/null;
++	then
++		sudo apt-get -y install $1
++		rtrn=$?
++
++		if [ $rtrn -ne 0 ];
++		then
++			echo ""
++			echo "!!! ERROR !!! apt-get install failed for an unknown reason."
++			echo "Please install package $1 after this installer completes."
++			echo ""
++		fi
++
++	else
++		echo ""
++		echo "!!! ERROR !!! - Not able to detect which software install tool to use (yum or apt-get)."
++		echo "Please install package $1 using the system software install tool."
++		echo ""
++		rtrn=1
++	fi
++	
++	return $rtrn
++
++}
++
++########################################################################
++#                                 Main
++########################################################################
++
++# If you double click a script, some systems don't get the PWD correct.
++# Force it to be correct
++PKG_PATH=$(dirname $(readlink -f $0))
++cd ${PKG_PATH}
++
++echo ""
++echo "Welcome to the ${PGM_NAME} installer"
++echo ""
++
++##############
++# Check sudo
++##############
++
++if ! sudo date;
++then
++	echo ""
++	echo "!!! ERROR !!!"
++	echo ""
++	echo "Either you don't know the root password or the user is not allowed to sudo"
++	echo "Please correct this and run the installer again (hint: use visudo to edit sudoers file)"
++	echo ""
++	read -p "Press ENTER to exit installer:" BLAH
++	exit 1
++fi
++
++############################
++# Determine processor type
++############################
++
++case `uname -m` in
++	i[3456789]86|x86|i86pc)
++		echo "Architecture is x86"
++		ARCH='x86'
++		;;
++	x86_64|amd64|AMD64)
++		echo "Architecture is x86_64"
++		ARCH='x86_64'
++		;;
++	*)
++		echo ""
++		echo "!!! ERROR !!! - Unknown architecture `uname -m`"
++		echo ""
++		read -p "Press ENTER to exit installer:" BLAH
++		exit 1
++		;;
++esac
++
++# untar the correct bundle for us to install
++echo "Unpacking bundle for $ARCH"
++tar -xjf ${PGM_NAME}_${ARCH}-*.tar.bz2
++BUNDLE_DIR=$(basename `find -maxdepth 1 -type d -name "${PGM_NAME}_${ARCH}-*"`)
++
++
++#######################
++# Check for xdg utils
++#######################
++
++XDG_MENU_VER=$(xdg-desktop-menu --version 2> /dev/null)
++if [ -z "$XDG_MENU_VER" ];
++then
++	echo "System does not have xdg-desktop-menu installed"
++	HAS_XDG="F"
++fi
++
++XDG_ICON_VER=$(xdg-icon-resource --version 2> /dev/null)
++if [ -z "$XDG_ICON_VER" ];
++then
++	echo "System does not have xdg-icon-resource installed"
++	HAS_XDG="F"
++fi
++
++#################################################
++# Check if system libs are OK (libc, etc)
++#################################################
++
++echo ""
++echo "Checking system libs to see if they are compatible with ${PGM_NAME}."
++echo ""
++
++LIB_ERROR="F"
++LD_PATH=`pwd`/${BUNDLE_DIR}/lib
++
++# check the main App
++LDD_RESULT=$(LD_LIBRARY_PATH=${LD_PATH} ldd ${BUNDLE_DIR}/bin/${PGM_NAME_LOWER}-* 2>&1 > /dev/null)
++
++if [ -n "$LDD_RESULT" ];
++then
++	echo "$LDD_RESULT"
++	LIB_ERROR="T"
++fi
++	
++# check the libs
++LIB_FILES=$(find ${BUNDLE_DIR}/lib -name "*.so")
++
++for path in $LIB_FILES
++do
++	LDD_RESULT=$(LD_LIBRARY_PATH=${LD_PATH} ldd $path 2>&1 > /dev/null)
++	if [ -n "$LDD_RESULT" ];
++	then
++		echo "$LDD_RESULT"
++		LIB_ERROR="T"
++	fi
++done
++
++if test "T" = $LIB_ERROR;
++then
++	echo ""
++	echo "!!! ERROR !!! - Missing library detected!"
++	echo "This system does not have the correct libs to run ${PGM_NAME}."
++	echo "Installation will not complete. Please use a compatible distro."
++	echo ""
++	read -p "Press ENTER to exit installer:" BLAH
++	exit 1
++fi
++
++################################
++# Setup derived variables
++################################
++PGM_VERSION=$(echo ${BUNDLE_DIR} | awk 'BEGIN { FS = "-" } ; { print $2 }' | awk 'BEGIN { FS = "_"} ; { print $1}')
++PGM_BUILD=$(echo ${BUNDLE_DIR} | awk 'BEGIN { FS = "-" } ; { print $2 }' | awk 'BEGIN { FS = "_"} ; { print $2}')
++PGM_FULL_NAME="${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}"
++
++ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}"			#no dash since it seperates vendor from program
++MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}.desktop"	#no dash since it seperates vendor from program
++DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}.desktop"
++
++PGM_EXEC_PATH="${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/bin/${PGM_EXEC_FILE}"
++ICON_PATH="${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/etc/icons"
++MENU_FILE_PATH="${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/share"
++
++	
++
++################################
++# Install bundle and Menu/Link
++################################
++
++if [ ! -d ${INSTALL_DEST_BASE} ];
++then
++	echo ""
++	echo "!!! ERROR !!! - Installation location ${INSTALL_DEST_BASE} does not exist!"
++	echo "Installation will not complete."
++	echo ""
++	read -p "Press ENTER to exit installer:" BLAH
++	exit 1
++fi
++
++# uninstall any older versions
++UNINSTALLERS=$(find ${INSTALL_DEST_BASE} -maxdepth 1 -type f -name "${PGM_NAME}*.uninstall.sh")
++if [ ! -z "$UNINSTALLERS" ];
++then
++	for i in $UNINSTALLERS; do
++		echo ""
++		echo "Found existing ${PGM_NAME} installation."
++		
++		ANSWER=$(VaildateYesNoQuestion "Do you want to run the uninstaller ${i} ?")
++
++		if test "y" = $ANSWER;
++		then
++			echo ""
++			echo "Running uninstaller $i"
++			
++			${i}
++			sudo rm -f ${i}
++		fi
++	done
++fi
++
++
++# install 
++
++echo ""
++echo "Installing ${PGM_NAME} ${PGM_VERSION} built from ${PGM_BUILD} in ${INSTALL_DEST_BASE}"
++echo ""
++
++# Copy the new version in the install directory
++sudo mkdir ${INSTALL_DEST_BASE}/${PGM_FULL_NAME} 
++sudo cp -Rf	${BUNDLE_DIR}/* ${INSTALL_DEST_BASE}/${PGM_FULL_NAME}/
++
++# write the desktop/menu file
++echo "[Desktop Entry]" > /tmp/${MENU_FILE}
++echo "Encoding=UTF-8" >> /tmp/${MENU_FILE}
++echo "Version=1.0" >> /tmp/${MENU_FILE}
++echo "Type=Application" >> /tmp/${MENU_FILE}
++echo "Terminal=false" >> /tmp/${MENU_FILE}
++echo "Exec=${PGM_EXEC_PATH}" >> /tmp/${MENU_FILE}
++echo "Name=${PGM_NAME}-${PGM_VERSION}" >> /tmp/${MENU_FILE}
++echo "Icon=${ICON_NAME}" >> /tmp/${MENU_FILE}
++echo "Comment=Digital Audio Workstation" >> /tmp/${MENU_FILE}
++echo "Categories=AudioVideo;AudioEditing;Audio;Recorder;" >> /tmp/${MENU_FILE}
++
++chmod ugo+rx /tmp/${MENU_FILE}
++sudo mv /tmp/${MENU_FILE} ${MENU_FILE_PATH}/.
++
++# install the Menu, Link, and Icon(s)
++if [ "T" = ${HAS_XDG} ];
++then
++	echo "Adding ${PGM_NAME} to the applications menu"
++	sudo xdg-icon-resource install --context apps --size 16 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_16px.png ${ICON_NAME}
++	sudo xdg-icon-resource install --context apps --size 22 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_22px.png ${ICON_NAME}
++	sudo xdg-icon-resource install --context apps --size 32 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_32px.png ${ICON_NAME}
++	sudo xdg-icon-resource install --context apps --size 48 ${ICON_PATH}/${PGM_NAME_LOWER}_icon_48px.png ${ICON_NAME}
++
++	if [ -e ${ICON_PATH}/${PGM_NAME_LOWER}_icon.svg -a -d /usr/share/icons/hicolor/scalable/apps ]; 
++	then
++		sudo cp -f ${ICON_PATH}/${PGM_NAME_LOWER}_icon.svg  /usr/share/icons/hicolor/scalable/apps/${ICON_NAME}.svg
++	fi
++
++	sudo xdg-desktop-menu install ${MENU_FILE_PATH}/${MENU_FILE}
++	sudo xdg-desktop-menu forceupdate --mode system			# Some systems need an extra kick
++	
++	echo ""
++	echo "Creating a desktop link for ${PGM_NAME}"
++	cp ${MENU_FILE_PATH}/${MENU_FILE} ~/Desktop/${DESKTOP_LINK_FILE}
++	chmod ugo+rx ~/Desktop/${DESKTOP_LINK_FILE}
++else
++	echo ""
++	echo "Creating a desktop link for ${PGM_NAME}"
++	cp ${MENU_FILE_PATH}/${MENU_FILE} ~/Desktop/${DESKTOP_LINK_FILE}
++	chmod ugo+rx ~/Desktop/${DESKTOP_LINK_FILE}
++fi
++
++echo ""
++echo "Copying uninstall script to ${INSTALL_DEST_BASE}"
++echo ""
++
++sudo cp -f ${BUNDLE_DIR}/bin/*.uninstall.sh ${INSTALL_DEST_BASE}/.
++
++###########################
++# Check Jack and qjackctl
++###########################
++
++echo ""
++echo "Checking to see if Jack is installed"
++echo ""
++
++if ! which jackd > /dev/null;
++then
++	echo ""
++	echo "The program Jack is missing from this system. Jack is a required component of $PGM_NAME."
++	echo ""
++
++	ANSWER=$(VaildateYesNoQuestion "Install jack using system software repository?")
++
++	if test "y" = $ANSWER;
++	then
++		echo "Attempting to install Jack"
++		SystemInstall "jackd"
++
++		if [ $? -ne 0 ];
++		then
++			echo ""
++			read -p "Press ENTER to continue:" BLAH
++		fi
++	fi
++else
++	echo "Jack OK"
++fi
++
++
++if ! which qjackctl > /dev/null;
++then
++	echo ""
++	echo "The program QjackCtl is missing from this system."
++	echo "QjackCtl is an extremely useful tool for any system that runs JACK applications like $PGM_NAME."
++	echo "We recommend that you install it."
++	echo ""
++
++	ANSWER=$(VaildateYesNoQuestion "Install QjackCtl using system software repository?")
++
++	if test "y" = $ANSWER;
++	then
++		echo "Attempting to install QjackCtl"
++		SystemInstall "qjackctl"
++
++		if [ $? -ne 0 ];
++		then
++			echo ""
++			read -p "Press ENTER to continue:" BLAH
++		fi
++	fi
++fi
++
++
++########################
++# Run Sanity Check
++########################
++
++USER_GROUP_ADJUSTED="f"
++
++if ! ./${BUNDLE_DIR}/bin/sanityCheck -a > /dev/null;
++then
++	echo ""
++	echo "System failed the quick sanity check... Looking for the cause"
++
++	if ! ./${BUNDLE_DIR}/bin/sanityCheck -rt > /dev/null;
++	then
++		echo ""
++		echo "System does not allow realtime for the current user... Looking for a solution"		
++		
++		if ./${BUNDLE_DIR}/bin/sanityCheck -hasaudiogroup > /dev/null;
++		then
++			if ./${BUNDLE_DIR}/bin/sanityCheck -memberaudiogroup > /dev/null 2>&1;
++			then
++				## This is an odd case. We have an audio group and are a member.
++				echo ""
++				echo "!!! WARNING !!! - The current user can not execute realtime processes."
++				echo "This will adversely affect audio latency."
++				echo "This system has an audio group and the user is a member. If jack was"
++				echo "just installed, a simple log out/in may fix this."
++				echo ""
++				echo "For best results, please correct this on your system."
++				echo "(Hint: check /etc/security/limits.conf or /etc/security/limits.d/)" 
++				echo ""
++				read -p "Press ENTER to continue:" BLAH
++			else
++				# Not a member of an audio group. Try to fix it.
++				
++				if ./${BUNDLE_DIR}/bin/sanityCheck -hasgroup audio > /dev/null && find /etc/security -type f -name "*.conf" | xargs grep -q "^@audio.*rtprio";
++				then
++					# add user to audio group
++					echo ""
++					echo "Adding user `whoami` to the audio group."
++					echo "This should allow you to run realtime tasks. Please re-login for this change to take affect."
++					echo ""
++					read -p "Press ENTER to continue:" BLAH
++
++					user=`whoami`
++					if sudo usermod -a -G audio $user;
++					then
++						USER_GROUP_ADJUSTED="t"
++					else
++						echo ""
++						echo "!!! ERROR !!! - Not able to add user to the audio group (usermod failed)!"
++						echo ""
++						echo "Please add yourself to the audio group and re-login"
++						echo ""
++						read -p "Press ENTER to continue:" BLAH
++					fi
++
++				elif ./${BUNDLE_DIR}/bin/sanityCheck -hasgroup jackuser > /dev/null && find /etc/security -type f -name "*.conf" | xargs grep -q "^@jackuser.*rtprio";
++				then
++					# add user to jackuser group
++					echo ""
++					echo "Adding user `whoami` to the jackuser group."
++					echo "This should allow you to run realtime tasks. Please re-login for this change to take affect."
++					echo ""
++					read -p "Press ENTER to continue:" BLAH
++
++					user=`whoami`
++					if sudo usermod -a -G jackuser $user;
++					then
++						USER_GROUP_ADJUSTED="t"
++					else
++						echo ""
++						echo "!!! ERROR !!! - Not able to add user to the jackuser group."
++						echo ""
++						echo "Please add yourself to the audio group and re-login"
++						echo ""
++						read -p "Press ENTER to continue:" BLAH
++					fi
++					
++
++				fi
++			fi
++		else
++			# No audio group found on this system!
++			echo ""
++			echo "!!! WARNING !!! - The system does not seem to have an audio group (audio or jackuser)."
++			echo ""
++			echo "We will not attempt to fix this. Please configure your system to allow"
++			echo "non-root users to execute realtime tasks."
++			echo ""
++			read -p "Press ENTER to continue:" BLAH
++		fi
++	fi
++
++	if ! ./${BUNDLE_DIR}/bin/sanityCheck -freqscaling > /dev/null;
++	then
++		echo ""
++		echo "!!! WARNING !!! - Your system seems to use frequency scaling."
++		echo "This can have a serious impact on audio latency. You have two choices:"
++		echo "(1) turn it off, e.g. by chosing the 'performance' governor."
++		echo "(2) Use the HPET clocksource by passing \"-c h\" to JACK"
++		echo "(this second option only works on relatively recent computers)"
++		echo ""
++		read -p "Press ENTER to continue:" BLAH
++	fi
++
++	if [ "f" = $USER_GROUP_ADJUSTED ];
++	then
++		if ! ./${BUNDLE_DIR}/bin/sanityCheck -memlock > /dev/null;
++		then
++			echo ""
++			echo "!!! WARNING !!! - You are not allowed to lock memory."
++			echo ""
++			echo "We will not attempt to fix this. Please configure your system to allow"
++			echo "non-root users to execute lock memory."
++			echo ""
++			read -p "Press ENTER to continue:" BLAH
++		fi
++	fi
++fi
++
++
++########################
++# Install Complete
++########################
++
++echo ""
++echo "Cleaning up"
++rm -rf ${BUNDLE_DIR}/
++
++echo ""
++echo "!!! Install Complete !!!"
++
++if [ "t" = $USER_GROUP_ADJUSTED ];
++then
++	echo "You will need to logout and then login again for all changes to be complete"
++fi
++
++echo ""
++read -p "Press ENTER to exit installer:" BLAH
++
++
+--- /dev/null
++++ b/tools/linux_packaging/uninstall.sh.in
+@@ -0,0 +1,84 @@
++#!/bin/sh
++
++######################################
++#
++#	Ardour/Mixbus bundle uninstaller
++#	Todd Naugle
++#
++#####################################
++
++
++PGM_NAME="%REPLACE_PGM%"
++PGM_VENDOR="%REPLACE_VENDOR%"
++PGM_VERSION="%REPLACE_VERSION%"
++PGM_BUILD="%REPLACE_BUILD%"
++
++INSTALL_DEST_BASE=/opt
++
++
++#### Derived Variables ####
++PGM_PATH=${INSTALL_DEST_BASE}/${PGM_NAME}-${PGM_VERSION}_${PGM_BUILD}
++
++ICON_NAME="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}"			#no dash between name and version since seperates vendor from program
++MENU_FILE="${PGM_VENDOR}-${PGM_NAME}_${PGM_VERSION}.desktop"	#no dash between name and version since seperates vendor from program
++DESKTOP_LINK_FILE="${PGM_NAME}_${PGM_VERSION}.desktop"
++MENU_FILE_PATH="${PGM_PATH}/share/${MENU_FILE}"
++
++
++#######################
++# Check for xdg utils
++#######################
++HAS_XDG="T"
++
++XDG_MENU_VER=$(xdg-desktop-menu --version 2> /dev/null)
++if [ -z "$XDG_MENU_VER" ];
++then
++	echo "System does not have xdg-desktop-menu installed"
++	HAS_XDG="F"
++fi
++
++XDG_ICON_VER=$(xdg-icon-resource --version 2> /dev/null)
++if [ -z "$XDG_ICON_VER" ];
++then
++	echo "System does not have xdg-icon-resource installed"
++	HAS_XDG="F"
++fi
++
++
++#############
++# Uninstall
++#############
++
++if [ -d ${PGM_PATH} ];
++then
++	echo ""
++	echo "Removing existing ${PGM_NAME} installation at ${PGM_PATH}"
++	echo ""
++
++	if [ "T" = ${HAS_XDG} ];
++	then
++		sudo xdg-desktop-menu uninstall ${MENU_FILE_PATH}
++		sudo xdg-icon-resource uninstall --size 16 ${ICON_NAME}
++		sudo xdg-icon-resource uninstall --size 22 ${ICON_NAME}
++		sudo xdg-icon-resource uninstall --size 32 ${ICON_NAME}
++		sudo xdg-icon-resource uninstall --size 48 ${ICON_NAME}
++
++		if [ -e /usr/share/icons/hicolor/scalable/apps/${ICON_NAME}.svg ]; 
++		then
++			sudo rm -f /usr/share/icons/hicolor/scalable/apps/${ICON_NAME}.svg
++		fi
++	fi
++
++	if [ -e ~/Desktop/${DESKTOP_LINK_FILE} ];
++	then
++		sudo rm -f ~/Desktop/${DESKTOP_LINK_FILE}
++	fi
++
++	# delete the old package
++	sudo rm -rf ${PGM_PATH}
++	sudo rm -f $0
++else
++	echo ""
++	echo "!!! FAILURE !!! - install path ${PGM_PATH} does not exist."
++	echo ""
++fi
+--- /dev/null
++++ b/tools/sanity_check/main.cpp
+@@ -0,0 +1,359 @@
++/*
++ * 
++ *   program:  sanityCheck 
++ *   file:     main.c
++ *   author:   Todd Naugle
++ *   date:     11/17/2010
++ * 
++ *   Desc:  Command line version of the sanity check functions found in jack
++*/ 
++
++#include <algorithm>
++#include <stdio.h>
++#include <string>
++#include <vector>
++
++#include "systemtest.h"
++
++
++using namespace std;
++
++typedef int (*testfuncPtr) ();
++typedef int (*testfuncOpPtr) (string);
++
++typedef struct
++{
++	string			switchText;			// ie -option
++	string			swOptionText;       // option arguments for just this swtich.
++	string			descriptionText;	// Help Text on what this does
++	string			failureText;		// What to say when this test fails
++	bool			hasOption;			// Set true if this switch has option paramters
++	testfuncPtr		functionPtr;		// Function to call
++	testfuncOpPtr	opFunctionPtr;		// Function with option string to call
++	string			optionArg;			// Storage used to hold any options passed in by the user
++} testRecord;
++
++static vector<testRecord>	gTestSet;
++	
++static vector<string>		gValidSwitchList;
++static vector<string>		gSwitchDescriptionList;
++
++static vector<string>		gSwitchesReceived;
++
++int
++ExecuteAll()
++{
++	bool OK = true;
++
++	OK &= system_user_can_rtprio();
++
++	if (system_has_frequencyscaling()) {
++		OK &= !system_uses_frequencyscaling();
++	}
++
++	OK &= !(system_memlock_amount() == 0);
++	
++	return OK;
++}
++
++int
++HasGroup(string name)
++{
++	return system_has_group(name.c_str());
++}
++
++int
++IsMemberOfGroup(string name)
++{
++	return system_user_in_group(name.c_str());
++}
++
++int
++CheckFreqScaling()
++{
++	bool OK = true;
++
++	if (system_has_frequencyscaling()) {
++		OK &= !system_uses_frequencyscaling();
++	}
++
++	return OK;
++}
++
++int
++CheckMemoryLocking()
++{
++	return !(system_memlock_amount() == 0);
++}
++
++int
++PrintUsage()
++{
++	printf("\n");
++	printf("  sanityCheck - A program to verify proper system settings for use with audio applications (Ardour/Jack/Mixbus).\n");
++	printf("\n");
++	printf("  Usage:  sanityCheck [OPTIONS]\n");
++	printf("\n");
++	printf("  Options are as follows:\n");
++	printf("\n");
++	printf("\n");
++	
++	vector<testRecord>::iterator		itr;
++	
++	for (itr = gTestSet.begin(); itr != gTestSet.end(); ++itr) {
++		printf("%20s %s :\t%s\n", (*itr).switchText.c_str(), (*itr).swOptionText.c_str(), (*itr).descriptionText.c_str());
++	}
++
++	printf("\n");
++	
++	return true;
++}
++
++void
++DefineSwitches()
++{
++	testRecord rec;
++	
++	// Global switches
++	rec.switchText = "-a";
++	rec.swOptionText = "";
++	rec.descriptionText = "Checks for a working RT system. Same as -rt -freqscaling -memlock";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &ExecuteAll;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-h";
++	rec.swOptionText = "";
++	rec.descriptionText = "Print usage";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &PrintUsage;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	// Switches for various tests that can be performed.
++	rec.switchText = "-rt";
++	rec.swOptionText = "";
++	rec.descriptionText = "Verfiy that the user can run tasks with realtime priority";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &system_user_can_rtprio;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-hasrtlimits";
++	rec.swOptionText = "";
++	rec.descriptionText = "Verfiy the system has a limits.conf and the audio group can use realtime";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &system_has_rtprio_limits_conf;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-hasgroup";
++	rec.swOptionText = "<groupname>";
++	rec.descriptionText = "Verfiy that the system has a group named <groupname>";
++	rec.failureText = "";
++	rec.hasOption = true;
++	rec.opFunctionPtr = &HasGroup;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-hasaudiogroup";
++	rec.swOptionText = "";
++	rec.descriptionText = "Verfiy that the system has an audio group (audio or jackuser) defined";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &system_has_audiogroup;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-memberofgroup";
++	rec.swOptionText = "<groupname>";
++	rec.descriptionText = "Verfiy that the user is a member of the group named <groupname>";
++	rec.failureText = "";
++	rec.hasOption = true;
++	rec.opFunctionPtr = &IsMemberOfGroup;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-memberaudiogroup";
++	rec.swOptionText = "";
++	rec.descriptionText = "Verfiy that the user is a member of the audio group (audio or jackuser)";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &system_user_in_audiogroup;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-freqscaling";
++	rec.swOptionText = "";
++	rec.descriptionText = "Check to see if frequency scaling is being used by the CPU";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &CheckFreqScaling;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++	rec.switchText = "-memlock";
++	rec.swOptionText = "";
++	rec.descriptionText = "Check to see if the user is able to lock memory";
++	rec.failureText = "";
++	rec.hasOption = false;
++	rec.functionPtr = &CheckMemoryLocking;
++	rec.optionArg = "";
++	gTestSet.push_back(rec);
++
++}
++
++bool
++ParseSwitches(
++	int		argc,
++	char	**argv)
++{
++	string	tmp;
++	vector<testRecord>::iterator	itr;
++	bool	OK = true;
++	int	i;
++	
++	if (argc == 1) {
++		gSwitchesReceived.push_back("-a");
++	}
++	else {
++		for (i = 1; i < argc && OK == true; i++) {
++			tmp = argv[i];
++
++			for (itr = gTestSet.begin(); itr != gTestSet.end(); ++itr) {
++				if (tmp == (*itr).switchText) {
++					if ((*itr).hasOption == true) {
++						if (++i < argc) {
++							string	op = argv[i];
++							if (op[0] == '-') {
++								// reqiured option for this switch is missing
++								--i;
++								OK = false;
++								break;
++							}
++							(*itr).optionArg = op;
++							break;
++						}
++						else {
++							// reqiured option for this switch is missing
++							--i;
++							OK = false;
++							break;
++						}
++					}
++					break;
++				}
++			}
++			
++			if (OK && itr != gTestSet.end()) {
++				// Known option switch found
++				gSwitchesReceived.push_back(tmp);
++			}
++			else {
++				// Unknown option
++				OK = false;
++			}
++		}
++	}
++
++	if (OK) {
++		// All switches are at least valid, now check to make sure they are all valid to 
++		// be used together.
++		
++		if (gSwitchesReceived.size() > 1) {
++			// make sure help is not mixed with other options
++			vector<string>::iterator	swItr;
++			tmp = "-h";
++
++			swItr = find(gSwitchesReceived.begin(), gSwitchesReceived.end(), tmp);
++
++			if (swItr != gSwitchesReceived.end()) {
++				gSwitchesReceived.clear();
++				gSwitchesReceived.push_back("-h");
++			}
++
++			// make sure -a is only used by itself
++			tmp = "-a";
++			swItr = find(gSwitchesReceived.begin(), gSwitchesReceived.end(), tmp);
++
++			if (swItr != gSwitchesReceived.end()) {
++				gSwitchesReceived.clear();
++				gSwitchesReceived.push_back("-a");
++			}
++		}
++
++		return true;
++	}
++	else {
++		fprintf(stderr, "\n");
++		fprintf(stderr, "ERROR - Invalid Option: %s\n", (const char *) argv[--i]); 
++		fprintf(stderr, "Check syntax\n");
++		PrintUsage();
++		return false;
++	}
++}
++
++bool
++Execute()
++{
++	bool OK = true;
++	vector<string>::iterator	itr;
++	vector<testRecord>::iterator	testItr;
++	
++	for (itr = gSwitchesReceived.begin(); itr != gSwitchesReceived.end(); ++itr) {
++		for (testItr = gTestSet.begin(); testItr != gTestSet.end(); ++testItr) {
++			if ((*itr) == (*testItr).switchText) {
++				break;
++			}
++		}
++		
++		bool result;
++		if ((*testItr).hasOption) {
++			result = ((*testItr).opFunctionPtr((*testItr).optionArg) != 0);
++		}
++		else {
++			result = ((*testItr).functionPtr() != 0);
++		}
++
++		if (result == 0) {
++			// Check for a Failure message and print it if found.
++			if (!(*testItr).failureText.empty()) {
++				printf("\n%s\n", (*testItr).failureText.c_str());
++			}
++		}
++
++		OK &= result;
++	}
++	
++	return OK;
++}
++
++int
++main(
++	int		 argc,
++	char 	**argv)
++{
++	int status = 0;
++	
++	DefineSwitches();
++
++	if (ParseSwitches(argc, argv)) {
++		if (Execute() == false) {
++			printf("\nSanity Check Failed!\n\n");
++			status = -1;
++		}
++		else {
++			printf("\nSanity Check OK!\n\n");
++		}
++	}
++	else {
++		status = -1;
++	}
++
++	return status;
++}
+--- /dev/null
++++ b/tools/sanity_check/SConscript
+@@ -0,0 +1,12 @@
++# -*- python -*-
++
++import os
++import os.path
++import glob
++
++Import('env')
++sanitycheck = env.Clone()
++sc = sanitycheck.Program('sanityCheck', ['main.cpp', 'systemtest.cpp'])
++
++Default(sc)
++
+--- /dev/null
++++ b/tools/sanity_check/systemtest.cpp
+@@ -0,0 +1,333 @@
++/**
++ * 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.
++ *
++ * Set of functions to gather system information for the jack setup wizard.
++ * 
++ * TODO: Test for rt prio availability
++ *
++ * @author Florian Faber, faber at faberman.de
++ *
++ **/
++
++/** maximum number of groups a user can be a member of **/
++#define MAX_GROUPS 100
++
++#include <fcntl.h>
++
++#include <stdlib.h>
++#include <sys/types.h>
++#include <unistd.h>
++#include <grp.h>
++
++#include <sched.h>
++#include <string.h>
++
++#include <sys/time.h>
++#include <sys/resource.h>
++
++#include <stdio.h>
++#include <errno.h>
++
++#include "systemtest.h"
++
++/**
++ * This function checks for the existence of known frequency scaling mechanisms 
++ * in this system by testing for the availability of scaling governors/
++ *
++ * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise.
++ **/
++int system_has_frequencyscaling() {
++  int fd;
++
++  fd = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", O_RDONLY);
++
++  if (-1==fd) {
++    return 0;
++  }
++
++  (void) close(fd);
++
++  return 1;
++}
++
++
++static int read_string(char* filename, char* buf, size_t buflen) {
++  int fd;
++  ssize_t r=-1;
++
++  memset (buf, 0, buflen);
++
++  fd = open (filename, O_RDONLY);
++  if (-1<fd) {
++    r = read (fd, buf, buflen-1);
++    (void) close(fd);
++    
++    if (-1==r) {
++      fprintf(stderr, "Error while reading \"%s\": %s\n", filename, strerror(errno));
++      exit(EXIT_FAILURE);
++    }
++  }
++  
++  return (int) r;
++}
++
++
++static int read_int(char* filename, int* value) {
++  char buf[20];
++
++  if (0<read_string(filename, buf, 20)) {
++		return (1==sscanf(buf, "%d", value));
++  }
++
++  return 0;
++}
++
++
++/**
++ * This function determines wether any CPU core uses a variable clock speed if frequency 
++ * scaling is available. If the governor for all cores is either "powersave" or
++ * "performance", the CPU frequency can be assumed to be static. This is also the case
++ * if scaling_min_freq and scaling_max_freq are set to the same value.
++ *
++ * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise
++ **/
++int system_uses_frequencyscaling() {
++  int cpu=0, done=0, min, max;
++  char filename[256], buf[256];
++
++  while (!done) {
++          (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
++          if (0<read_string(filename, buf, 256)) {
++                  if ((0!=strncmp("performance", buf, 11)) && 
++                      (0!=strncmp("powersafe", buf, 9))) {
++                          // So it's neither the "performance" nor the "powersafe" governor
++                          (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
++                          if (read_int(filename, &min)) {
++                                  (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
++                                  if (read_int(filename, &max)) {
++                                          if (min!=max) {
++                                                  // wrong governor AND different frequency limits -> scaling
++                                                  return 1;
++                                          }
++                                  } 
++                          }
++                  }
++          } else {
++                  // couldn't open file -> no more cores
++                  done = 1;
++          }
++          cpu++;
++  }
++  
++  // couldn't find anything that points to scaling
++  return 0;
++}
++
++
++static gid_t get_group_by_name(const char* name) {
++  struct group* grp;
++	gid_t res = 0;
++
++  while ((0==res) && (NULL != (grp = getgrent()))) {
++    if (0==strcmp(name, grp->gr_name)) {
++      res = grp->gr_gid;
++    }
++  }
++
++	endgrent();
++
++  return res;
++}
++
++/**
++ * Tests wether the owner of this process is in the group 'name'.
++ *
++ * @returns 0 if the owner of this process is not in the group, non-0 otherwise
++ **/
++int system_user_in_group(const char *name) {
++  gid_t* list = (gid_t*) malloc(MAX_GROUPS * sizeof(gid_t));
++  int num_groups, i=0, found=0;
++	unsigned int gid;
++
++  if (NULL==list) {
++    perror("Cannot allocate group list structure");
++    exit(EXIT_FAILURE);
++  }
++
++  gid = get_group_by_name(name);
++  if (0==gid) {
++    fprintf(stderr, "No %s group found\n", name);
++    return 0;
++  }
++  
++  num_groups = getgroups(MAX_GROUPS, list);
++  
++  while (i<num_groups) {
++    if (list[i]==gid) {
++      found = 1;
++      i = num_groups;
++    }
++    
++    i++;
++  }
++  
++  free(list);
++
++  return found;
++}
++
++
++/***
++ * Checks for a definition in /etc/security/limits.conf that looks
++ * as if it allows RT scheduling priority.
++ *
++ * @returns 1 if there appears to be such a line
++ **/
++int system_has_rtprio_limits_conf ()
++{
++	const char* limits = "/etc/security/limits.conf";
++	char cmd[100];
++
++	snprintf (cmd, sizeof (cmd), "grep -q 'rtprio *[0-9][0-9]*' %s", limits);
++	if (system (cmd) == 0) {
++		return 1;
++	}
++	return 0;
++}
++
++
++/**
++ * Checks for the existence of the 'audio' group on this system
++ *
++ * @returns 0 if there is no 'audio' group, the group id otherwise
++ **/
++int system_has_audiogroup() {
++	return get_group_by_name("audio") || get_group_by_name ("jackuser");
++}
++
++
++/**
++ * Checks for the existence of 'groupname' on this system
++ *
++ * @returns 0 if there is no group, the group id otherwise
++ **/
++int system_has_group(const char * name) {
++	return get_group_by_name(name);
++}
++
++
++/**
++ * Tests wether the owner of this process is in the 'audio' group.
++ *
++ * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise
++ **/
++int system_user_in_audiogroup() {
++	return system_user_in_group("audio") || system_user_in_group("jackuser");
++}
++
++
++/**
++ * Determines wether the owner of this process can enable rt priority.
++ *
++ * @returns 0 if this process can not be switched to rt prio, non-0 otherwise
++ **/
++int system_user_can_rtprio() {
++  int min_prio;
++  struct sched_param schparam;
++
++  memset(&schparam, 0, sizeof(struct sched_param));
++
++  if (-1 == (min_prio = sched_get_priority_min(SCHED_FIFO))) {
++    perror("sched_get_priority");
++    exit(EXIT_FAILURE);
++  }
++  schparam.sched_priority = min_prio;  
++
++  if (0 == sched_setscheduler(0, SCHED_FIFO, &schparam)) {
++    // TODO: restore previous state
++    schparam.sched_priority = 0;
++    if (0 != sched_setscheduler(0, SCHED_OTHER, &schparam)) {
++      perror("sched_setscheduler");
++      exit(EXIT_FAILURE);
++    }
++    return 1;
++  }  
++
++  return 0;
++}
++
++
++long long unsigned int system_memlock_amount() {
++	struct rlimit limits;
++
++	if (-1==getrlimit(RLIMIT_MEMLOCK, &limits)) {
++		perror("getrlimit on RLIMIT_MEMLOCK");
++		exit(EXIT_FAILURE);
++	}
++
++	return limits.rlim_max;
++}
++
++
++/**
++ * Checks wether the memlock limit is unlimited
++ *
++ * @returns - 0 if the memlock limit is limited, non-0 otherwise
++ **/
++int system_memlock_is_unlimited() {
++	return ((RLIM_INFINITY==system_memlock_amount())?1:0);
++}
++
++
++long long unsigned int system_available_physical_mem() {
++	char buf[256];
++	long long unsigned int res = 0;
++
++	if (0<read_string((char*)"/proc/meminfo", buf, sizeof (buf))) {
++		if (strncmp (buf, "MemTotal:", 9) == 0) {
++			if (sscanf (buf, "%*s %llu", &res) != 1) {
++				perror ("parse error in /proc/meminfo");
++			} 
++		}
++	} else {
++		perror("read from /proc/meminfo");
++	}
++
++	return res*1024;
++}
++
++
++/**
++ * Gets the version of the currently running kernel. The string
++ * returned has to be freed by the caller.
++ *
++ * @returns String with the full version of the kernel
++ **/
++char* system_kernel_version() {
++  return NULL;
++}
++
++
++
++char* system_get_username() {
++  char* res = NULL;
++  char* name = NULL;
++
++  if ((name = getlogin())) {
++    res = strdup(name);
++  }
++
++  return res;
++}
+--- /dev/null
++++ b/tools/sanity_check/systemtest.h
+@@ -0,0 +1,109 @@
++#ifndef __systemtest_h__
++#define __systemtest_h__
++
++/**
++ * GPL, yabbadabba
++ *
++ * Set of functions to gather system information for the jack setup wizard.
++ * 
++ * @author Florian Faber, faber at faberman.de
++ * 
++ * @version 0.1 (2009-01-15) [FF]
++ *              - initial version
++ *
++ **/
++
++
++/**
++ * This function checks for the existence of known frequency scaling mechanisms 
++ * in this system.
++ *
++ * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise.
++ **/
++int system_has_frequencyscaling();
++
++
++/**
++ * This function determines wether the CPU has a variable clock speed if frequency 
++ * scaling is available. 
++ *
++ * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise
++ **/
++int system_uses_frequencyscaling();
++
++/**
++ * Tests wether the owner of this process is in the group 'name'.
++ *
++ * @returns 0 if the owner of this process is not in the group, non-0 otherwise
++ **/
++int system_user_in_group(const char *name);
++
++/***
++ * Checks for a definition in /etc/security/limits.conf that looks
++ * as if it allows RT scheduling priority.
++ *
++ * @returns 1 if there appears to be such a line
++ **/
++int system_has_rtprio_limits_conf ();
++
++/**
++ * Checks for the existence of the 'audio' group on this system
++ *
++ * @returns 0 is there is no 'audio' group, non-0 otherwise
++ **/
++int system_has_audiogroup();
++
++/**
++ * Checks for the existence of a group named 'name' on this system
++ *
++ * @returns 0 if not found, non-0 otherwise
++ **/
++int system_has_group(const char * name);
++
++/**
++ * Tests wether the owner of this process is in the 'audio' group.
++ *
++ * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise
++ **/
++int system_user_in_audiogroup();
++
++
++/**
++ * Determines wether the owner of this process can enable rt priority.
++ *
++ * @returns 0 if this process can not be switched to rt prio, non-0 otherwise
++ **/
++int system_user_can_rtprio();
++
++
++long long unsigned int system_memlock_amount();
++
++
++/**
++ * Checks wether the memlock limit is unlimited
++ *
++ * @returns 0 if the memlock limit is limited, non-0 otherwise
++ **/
++int system_memlock_is_unlimited();
++
++
++long long unsigned int system_available_physical_mem();
++
++
++/**
++ * Gets the version of the currently running kernel
++ *
++ * @returns String with the full version of the kernel
++ **/
++char* system_kernel_version();
++
++
++/**
++ * Returns the username. The caller is in charge of disposal of
++ * the returned name.
++ *
++ * @returns Pointer to a username or NULL
++ **/
++char* system_get_username();
++
++#endif /* __jack_systemtest_h__ */
diff --git a/debian/patches/series b/debian/patches/series
index dbcfbc3..2c44822 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
+000_sync_vcs.patch
 60-libdir.patch
 80_ardourino.patch
 90_ardour-x-change.patch

-- 
ardour Debian packaging



More information about the pkg-multimedia-commits mailing list