0944686f4efc10290014846aa953e86276eeac38
[ardour.git] / gtk2_ardour / ardour_ui.cc
1 /*
2     Copyright (C) 1999-2007 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #define __STDC_FORMAT_MACROS 1
21 #include <stdint.h>
22
23 #include <algorithm>
24 #include <cmath>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <time.h>
29 #include <cerrno>
30 #include <fstream>
31
32 #include <iostream>
33
34 #include <sys/resource.h>
35
36 #include <gtkmm/messagedialog.h>
37 #include <gtkmm/accelmap.h>
38
39 #include "pbd/error.h"
40 #include "pbd/basename.h"
41 #include "pbd/compose.h"
42 #include "pbd/failed_constructor.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/openuri.h"
46 #include "pbd/file_utils.h"
47
48 #include "gtkmm2ext/gtk_ui.h"
49 #include "gtkmm2ext/utils.h"
50 #include "gtkmm2ext/click_box.h"
51 #include "gtkmm2ext/fastmeter.h"
52 #include "gtkmm2ext/stop_signal.h"
53 #include "gtkmm2ext/popup.h"
54 #include "gtkmm2ext/window_title.h"
55
56 #include "midi++/manager.h"
57
58 #include "ardour/ardour.h"
59 #include "ardour/profile.h"
60 #include "ardour/session_directory.h"
61 #include "ardour/session_route.h"
62 #include "ardour/session_state_utils.h"
63 #include "ardour/session_utils.h"
64 #include "ardour/port.h"
65 #include "ardour/audioengine.h"
66 #include "ardour/playlist.h"
67 #include "ardour/utils.h"
68 #include "ardour/audio_diskstream.h"
69 #include "ardour/audiofilesource.h"
70 #include "ardour/recent_sessions.h"
71 #include "ardour/port.h"
72 #include "ardour/audio_track.h"
73 #include "ardour/midi_track.h"
74 #include "ardour/filesystem_paths.h"
75 #include "ardour/filename_extensions.h"
76
77 typedef uint64_t microseconds_t;
78
79 #include "actions.h"
80 #include "ardour_ui.h"
81 #include "public_editor.h"
82 #include "audio_clock.h"
83 #include "keyboard.h"
84 #include "mixer_ui.h"
85 #include "prompter.h"
86 #include "opts.h"
87 #include "add_route_dialog.h"
88 #include "about.h"
89 #include "splash.h"
90 #include "utils.h"
91 #include "gui_thread.h"
92 #include "theme_manager.h"
93 #include "bundle_manager.h"
94 #include "session_metadata_dialog.h"
95 #include "gain_meter.h"
96 #include "route_time_axis.h"
97 #include "startup.h"
98 #include "engine_dialog.h"
99 #include "processor_box.h"
100
101 #include "i18n.h"
102
103 using namespace ARDOUR;
104 using namespace PBD;
105 using namespace Gtkmm2ext;
106 using namespace Gtk;
107
108 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
109 UIConfiguration *ARDOUR_UI::ui_config = 0;
110
111 sigc::signal<void,bool> ARDOUR_UI::Blink;
112 sigc::signal<void>      ARDOUR_UI::RapidScreenUpdate;
113 sigc::signal<void>      ARDOUR_UI::SuperRapidScreenUpdate;
114 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
115
116 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
117
118         : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
119
120           primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
121           secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
122           preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
123           postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
124
125           /* preroll stuff */
126
127           preroll_button (_("pre\nroll")),
128           postroll_button (_("post\nroll")),
129
130           /* big clock */
131
132           big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
133
134           /* transport */
135
136           roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
137           stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
138           goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
139           goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
140           auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
141           play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
142           rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
143           shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
144           shuttle_controller_binding_proxy (shuttle_controllable),
145
146           roll_button (roll_controllable),
147           stop_button (stop_controllable),
148           goto_start_button (goto_start_controllable),
149           goto_end_button (goto_end_controllable),
150           auto_loop_button (auto_loop_controllable),
151           play_selection_button (play_selection_controllable),
152           rec_button (rec_controllable),
153
154           shuttle_units_button (_("% ")),
155
156           punch_in_button (_("Punch In")),
157           punch_out_button (_("Punch Out")),
158           auto_return_button (_("Auto Return")),
159           auto_play_button (_("Auto Play")),
160           auto_input_button (_("Auto Input")),
161           click_button (_("Click")),
162           time_master_button (_("time\nmaster")),
163
164           auditioning_alert_button (_("AUDITION")),
165           solo_alert_button (_("SOLO")),
166           shown_flag (false),
167           error_log_button (_("Errors"))
168
169 {
170         using namespace Gtk::Menu_Helpers;
171
172         Gtkmm2ext::init();
173
174
175 #ifdef TOP_MENUBAR
176         // _auto_display_errors = false;
177         /*
178          * This was commented out as it wasn't defined
179          * in A3 IIRC.  If this is not needed it should
180          * be completely removed.
181          */
182 #endif
183
184         about = 0;
185         splash = 0;
186         _startup = 0;
187
188         if (theArdourUI == 0) {
189                 theArdourUI = this;
190         }
191
192         ui_config = new UIConfiguration();
193         theme_manager = new ThemeManager();
194
195         editor = 0;
196         mixer = 0;
197         editor = 0;
198         engine = 0;
199         _session_is_new = false;
200         big_clock_window = 0;
201         big_clock_height = 0;
202         big_clock_resize_in_progress = false;
203         session_selector_window = 0;
204         last_key_press_time = 0;
205         _will_create_new_session_automatically = false;
206         add_route_dialog = 0;
207         route_params = 0;
208         rc_option_editor = 0;
209         session_option_editor = 0;
210         location_ui = 0;
211         open_session_selector = 0;
212         have_configure_timeout = false;
213         have_disk_speed_dialog_displayed = false;
214         session_loaded = false;
215         last_speed_displayed = -1.0f;
216         ignore_dual_punch = false;
217         _mixer_on_top = false;
218         original_big_clock_width = -1;
219         original_big_clock_height = -1;
220         original_big_clock_font_size = 0;
221
222         roll_button.unset_flags (Gtk::CAN_FOCUS);
223         stop_button.unset_flags (Gtk::CAN_FOCUS);
224         goto_start_button.unset_flags (Gtk::CAN_FOCUS);
225         goto_end_button.unset_flags (Gtk::CAN_FOCUS);
226         auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
227         play_selection_button.unset_flags (Gtk::CAN_FOCUS);
228         rec_button.unset_flags (Gtk::CAN_FOCUS);
229
230         last_configure_time= 0;
231
232         shuttle_grabbed = false;
233         shuttle_fract = 0.0;
234         shuttle_max_speed = 8.0f;
235
236         shuttle_style_menu = 0;
237         shuttle_unit_menu = 0;
238
239         // We do not have jack linked in yet so;
240
241         last_shuttle_request = last_peak_grab = 0; //  get_microseconds();
242
243         ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244         ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
245
246         /* handle dialog requests */
247
248         ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
249
250         /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
251
252         ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
253
254         /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255
256         ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
257
258         /* lets get this party started */
259
260         try {
261                 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
262                         throw failed_constructor ();
263                 }
264
265                 setup_gtk_ardour_enums ();
266                 setup_profile ();
267
268                 GainMeter::setup_slider_pix ();
269                 RouteTimeAxisView::setup_slider_pix ();
270                 SendProcessorEntry::setup_slider_pix ();
271                 SessionEvent::create_per_thread_pool ("GUI", 512);
272
273         } catch (failed_constructor& err) {
274                 error << _("could not initialize Ardour.") << endmsg;
275                 // pass it on up
276                 throw;
277         }
278
279         /* we like keyboards */
280
281         keyboard = new ArdourKeyboard(*this);
282
283         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
284         if (node) {
285                 keyboard->set_state (*node, Stateful::loading_state_version);
286         }
287
288         reset_dpi();
289
290         starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
291         stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
292
293         platform_setup ();
294 }
295
296 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
297 bool
298 ARDOUR_UI::run_startup (bool should_be_new)
299 {
300         if (_startup == 0) {
301                 _startup = new ArdourStartup ();
302         }
303         
304         XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
305
306         if (audio_setup && _startup->engine_control()) {
307                 _startup->engine_control()->set_state (*audio_setup);
308         }
309
310         _startup->set_new_only (should_be_new);
311         _startup->present ();
312
313         main().run();
314
315         _startup->hide ();
316
317         switch (_startup->response()) {
318         case RESPONSE_OK:
319                 return true;
320         default:
321                 return false;
322         }
323 }
324
325 int
326 ARDOUR_UI::create_engine ()
327 {
328         // this gets called every time by new_session()
329
330         if (engine) {
331                 return 0;
332         }
333
334         loading_message (_("Starting audio engine"));
335
336         try {
337                 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
338
339         } catch (...) {
340
341                 return -1;
342         }
343
344         engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
345         engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
346         engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
347
348         engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
349
350         post_engine ();
351
352         return 0;
353 }
354
355 void
356 ARDOUR_UI::post_engine ()
357 {
358         /* Things to be done once we create the AudioEngine
359          */
360
361         MIDI::Manager::instance()->set_api_data (engine->jack());
362         setup_midi ();
363         
364         ARDOUR::init_post_engine ();
365
366         ActionManager::init ();
367         _tooltips.enable();
368
369         if (setup_windows ()) {
370                 throw failed_constructor ();
371         }
372         
373         check_memory_locking();
374
375         /* this is the first point at which all the keybindings are available */
376
377         if (ARDOUR_COMMAND_LINE::show_key_actions) {
378                 vector<string> names;
379                 vector<string> paths;
380                 vector<string> keys;
381                 vector<AccelKey> bindings;
382
383                 ActionManager::get_all_actions (names, paths, keys, bindings);
384
385                 vector<string>::iterator n;
386                 vector<string>::iterator k;
387                 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
388                         cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
389                 }
390
391                 exit (0);
392         }
393
394         blink_timeout_tag = -1;
395
396         /* this being a GUI and all, we want peakfiles */
397
398         AudioFileSource::set_build_peakfiles (true);
399         AudioFileSource::set_build_missing_peakfiles (true);
400
401         /* set default clock modes */
402
403         if (Profile->get_sae()) {
404                 primary_clock.set_mode (AudioClock::BBT);
405                 secondary_clock.set_mode (AudioClock::MinSec);
406         }  else {
407                 primary_clock.set_mode (AudioClock::Timecode);
408                 secondary_clock.set_mode (AudioClock::BBT);
409         }
410
411         /* start the time-of-day-clock */
412
413 #ifndef GTKOSX
414         /* OS X provides a nearly-always visible wallclock, so don't be stupid */
415         update_wall_clock ();
416         Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
417 #endif
418
419         update_disk_space ();
420         update_cpu_load ();
421         update_sample_rate (engine->frame_rate());
422
423         Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
424         boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
425         Config->map_parameters (pc);
426
427         /* now start and maybe save state */
428
429         if (do_engine_start () == 0) {
430                 if (_session && _session_is_new) {
431                         /* we need to retain initial visual
432                            settings for a new session
433                         */
434                         _session->save_state ("");
435                 }
436         }
437 }
438
439 ARDOUR_UI::~ARDOUR_UI ()
440 {
441         delete keyboard;
442         delete editor;
443         delete mixer;
444         delete add_route_dialog;
445 }
446
447 void
448 ARDOUR_UI::pop_back_splash ()
449 {
450         if (Splash::instance()) {
451                 // Splash::instance()->pop_back();
452                 Splash::instance()->hide ();
453         }
454 }
455
456 gint
457 ARDOUR_UI::configure_timeout ()
458 {
459         if (last_configure_time == 0) {
460                 /* no configure events yet */
461                 return true;
462         }
463
464         /* force a gap of 0.5 seconds since the last configure event
465          */
466
467         if (get_microseconds() - last_configure_time < 500000) {
468                 return true;
469         } else {
470                 have_configure_timeout = false;
471                 cerr << "config event-driven save\n";
472                 save_ardour_state ();
473                 return false;
474         }
475 }
476
477 gboolean
478 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
479 {
480         if (have_configure_timeout) {
481                 last_configure_time = get_microseconds();
482         } else {
483                 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
484                 have_configure_timeout = true;
485         }
486
487         return FALSE;
488 }
489
490 void
491 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
492 {
493         const XMLProperty* prop;
494
495         if ((prop = node.property ("roll")) != 0) {
496                 roll_controllable->set_id (prop->value());
497         }
498         if ((prop = node.property ("stop")) != 0) {
499                 stop_controllable->set_id (prop->value());
500         }
501         if ((prop = node.property ("goto-start")) != 0) {
502                 goto_start_controllable->set_id (prop->value());
503         }
504         if ((prop = node.property ("goto-end")) != 0) {
505                 goto_end_controllable->set_id (prop->value());
506         }
507         if ((prop = node.property ("auto-loop")) != 0) {
508                 auto_loop_controllable->set_id (prop->value());
509         }
510         if ((prop = node.property ("play-selection")) != 0) {
511                 play_selection_controllable->set_id (prop->value());
512         }
513         if ((prop = node.property ("rec")) != 0) {
514                 rec_controllable->set_id (prop->value());
515         }
516         if ((prop = node.property ("shuttle")) != 0) {
517                 shuttle_controllable->set_id (prop->value());
518         }
519 }
520
521 XMLNode&
522 ARDOUR_UI::get_transport_controllable_state ()
523 {
524         XMLNode* node = new XMLNode(X_("TransportControllables"));
525         char buf[64];
526
527         roll_controllable->id().print (buf, sizeof (buf));
528         node->add_property (X_("roll"), buf);
529         stop_controllable->id().print (buf, sizeof (buf));
530         node->add_property (X_("stop"), buf);
531         goto_start_controllable->id().print (buf, sizeof (buf));
532         node->add_property (X_("goto_start"), buf);
533         goto_end_controllable->id().print (buf, sizeof (buf));
534         node->add_property (X_("goto_end"), buf);
535         auto_loop_controllable->id().print (buf, sizeof (buf));
536         node->add_property (X_("auto_loop"), buf);
537         play_selection_controllable->id().print (buf, sizeof (buf));
538         node->add_property (X_("play_selection"), buf);
539         rec_controllable->id().print (buf, sizeof (buf));
540         node->add_property (X_("rec"), buf);
541         shuttle_controllable->id().print (buf, sizeof (buf));
542         node->add_property (X_("shuttle"), buf);
543
544         return *node;
545 }
546
547
548 gint
549 ARDOUR_UI::autosave_session ()
550 {
551         if (g_main_depth() > 1) {
552                 /* inside a recursive main loop,
553                    give up because we may not be able to
554                    take a lock.
555                 */
556                 return 1;
557         }
558
559         if (!Config->get_periodic_safety_backups()) {
560                 return 1;
561         }
562
563         if (_session) {
564                 _session->maybe_write_autosave();
565         }
566
567         return 1;
568 }
569
570 void
571 ARDOUR_UI::update_autosave ()
572 {
573         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
574
575         if (_session && _session->dirty()) {
576                 if (_autosave_connection.connected()) {
577                         _autosave_connection.disconnect();
578                 }
579
580                 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
581                                 Config->get_periodic_safety_backup_interval() * 1000);
582
583         } else {
584                 if (_autosave_connection.connected()) {
585                         _autosave_connection.disconnect();
586                 }
587         }
588 }
589
590 void
591 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
592 {
593         string title;
594         if (we_set_params) {
595                 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
596         } else {
597                 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
598         }
599
600         MessageDialog win (title,
601                            false,
602                            Gtk::MESSAGE_INFO,
603                            Gtk::BUTTONS_NONE);
604
605         if (we_set_params) {
606                 win.set_secondary_text(_("There are several possible reasons:\n\
607 \n\
608 1) You requested audio parameters that are not supported..\n\
609 2) JACK is running as another user.\n\
610 \n\
611 Please consider the possibilities, and perhaps try different parameters."));
612         } else {
613                 win.set_secondary_text(_("There are several possible reasons:\n\
614 \n\
615 1) JACK is not running.\n\
616 2) JACK is running as another user, perhaps root.\n\
617 3) There is already another client called \"ardour\".\n\
618 \n\
619 Please consider the possibilities, and perhaps (re)start JACK."));
620         }
621
622         if (toplevel) {
623                 win.set_transient_for (*toplevel);
624         }
625
626         if (we_set_params) {
627                 win.add_button (Stock::OK, RESPONSE_CLOSE);
628         } else {
629                 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
630         }
631
632         win.set_default_response (RESPONSE_CLOSE);
633
634         win.show_all ();
635         win.set_position (Gtk::WIN_POS_CENTER);
636         pop_back_splash ();
637
638         /* we just don't care about the result, but we want to block */
639
640         win.run ();
641 }
642
643 void
644 ARDOUR_UI::startup ()
645 {
646         if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session)) {
647                 exit (1);
648         }
649
650         use_config ();
651
652         goto_editor_window ();
653
654         BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
655         show ();
656 }
657
658 void
659 ARDOUR_UI::no_memory_warning ()
660 {
661         XMLNode node (X_("no-memory-warning"));
662         Config->add_instant_xml (node);
663 }
664
665 void
666 ARDOUR_UI::check_memory_locking ()
667 {
668 #ifdef __APPLE__
669         /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
670         return;
671 #else // !__APPLE__
672
673         XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
674
675         if (engine->is_realtime() && memory_warning_node == 0) {
676
677                 struct rlimit limits;
678                 int64_t ram;
679                 long pages, page_size;
680
681                 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
682                         ram = 0;
683                 } else {
684                         ram = (int64_t) pages * (int64_t) page_size;
685                 }
686
687                 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
688                         return;
689                 }
690
691                 if (limits.rlim_cur != RLIM_INFINITY) {
692
693                         if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
694
695
696                                 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
697                                                                      "This might cause %1 to run out of memory before your system "
698                                                                      "runs out of memory. \n\n"
699                                                                      "You can view the memory limit with 'ulimit -l', "
700                                                                      "and it is normally controlled by /etc/security/limits.conf"),
701                                                                    PROGRAM_NAME).c_str());
702                                                    
703                                 VBox* vbox = msg.get_vbox();
704                                 HBox hbox;
705                                 CheckButton cb (_("Do not show this window again"));
706
707                                 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
708
709                                 hbox.pack_start (cb, true, false);
710                                 vbox->pack_start (hbox);
711                                 cb.show();
712                                 vbox->show();
713                                 hbox.show ();
714
715                                 pop_back_splash ();
716
717                                 editor->ensure_float (msg);
718                                 msg.run ();
719                         }
720                 }
721         }
722 #endif // !__APPLE__
723 }
724
725
726 void
727 ARDOUR_UI::finish()
728 {
729         if (_session) {
730                 int tries = 0;
731
732                 if (_session->transport_rolling() && (++tries < 8)) {
733                         _session->request_stop (false, true);
734                         usleep (10000);
735                 }
736
737                 if (_session->dirty()) {
738                         switch (ask_about_saving_session(_("quit"))) {
739                         case -1:
740                                 return;
741                                 break;
742                         case 1:
743                                 /* use the default name */
744                                 if (save_state_canfail ("")) {
745                                         /* failed - don't quit */
746                                         MessageDialog msg (*editor,
747                                                            _("\
748 Ardour was unable to save your session.\n\n\
749 If you still wish to quit, please use the\n\n\
750 \"Just quit\" option."));
751                                         pop_back_splash();
752                                         msg.run ();
753                                         return;
754                                 }
755                                 break;
756                         case 0:
757                                 break;
758                         }
759                 }
760
761                 second_connection.disconnect ();
762                 point_one_second_connection.disconnect ();
763                 point_oh_five_second_connection.disconnect ();
764                 point_zero_one_second_connection.disconnect();
765                 
766                 // _session->set_deletion_in_progress ();
767                 _session->remove_pending_capture_state ();
768                 delete _session;
769                 _session = 0;
770         }
771
772         ArdourDialog::close_all_dialogs ();
773         engine->stop (true);
774         cerr << "Save before quit\n";
775         save_ardour_state ();
776         quit ();
777 }
778
779 int
780 ARDOUR_UI::ask_about_saving_session (const string & what)
781 {
782         ArdourDialog window (_("ardour: save session?"));
783         Gtk::HBox dhbox;  // the hbox for the image and text
784         Gtk::Label  prompt_label;
785         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING,  Gtk::ICON_SIZE_DIALOG));
786
787         string msg;
788
789         msg = string_compose(_("Don't %1"), what);
790         window.add_button (msg, RESPONSE_REJECT);
791         msg = string_compose(_("Just %1"), what);
792         window.add_button (msg, RESPONSE_APPLY);
793         msg = string_compose(_("Save and %1"), what);
794         window.add_button (msg, RESPONSE_ACCEPT);
795
796         window.set_default_response (RESPONSE_ACCEPT);
797
798         Gtk::Button noquit_button (msg);
799         noquit_button.set_name ("EditorGTKButton");
800
801         string prompt;
802         string type;
803
804         if (_session->snap_name() == _session->name()) {
805                 type = _("session");
806         } else {
807                 type = _("snapshot");
808         }
809         prompt = string_compose(_("The %1 \"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
810                          type, _session->snap_name());
811
812         prompt_label.set_text (prompt);
813         prompt_label.set_name (X_("PrompterLabel"));
814         prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
815
816         dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
817         dhbox.set_homogeneous (false);
818         dhbox.pack_start (*dimage, false, false, 5);
819         dhbox.pack_start (prompt_label, true, false, 5);
820         window.get_vbox()->pack_start (dhbox);
821
822         window.set_name (_("Prompter"));
823         window.set_position (Gtk::WIN_POS_MOUSE);
824         window.set_modal (true);
825         window.set_resizable (false);
826
827         dhbox.show();
828         prompt_label.show();
829         dimage->show();
830         window.show();
831         window.set_keep_above (true);
832         window.present ();
833
834         ResponseType r = (ResponseType) window.run();
835
836         window.hide ();
837
838         switch (r) {
839         case RESPONSE_ACCEPT: // save and get out of here
840                 return 1;
841         case RESPONSE_APPLY:  // get out of here
842                 return 0;
843         default:
844                 break;
845         }
846
847         return -1;
848 }
849
850 gint
851 ARDOUR_UI::every_second ()
852 {
853         update_cpu_load ();
854         update_buffer_load ();
855         update_disk_space ();
856         return TRUE;
857 }
858
859 gint
860 ARDOUR_UI::every_point_one_seconds ()
861 {
862         update_speed_display ();
863         RapidScreenUpdate(); /* EMIT_SIGNAL */
864         return TRUE;
865 }
866
867 gint
868 ARDOUR_UI::every_point_zero_one_seconds ()
869 {
870         // august 2007: actual update frequency: 40Hz, not 100Hz
871
872         SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
873         return TRUE;
874 }
875
876 void
877 ARDOUR_UI::update_sample_rate (nframes_t)
878 {
879         char buf[32];
880
881         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
882
883         if (!engine->connected()) {
884
885                 snprintf (buf, sizeof (buf), _("disconnected"));
886
887         } else {
888
889                 nframes_t rate = engine->frame_rate();
890
891                 if (fmod (rate, 1000.0) != 0.0) {
892                         snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
893                                   (float) rate/1000.0f,
894                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
895                 } else {
896                         snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
897                                   rate/1000,
898                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
899                 }
900         }
901
902         sample_rate_label.set_text (buf);
903 }
904
905 void
906 ARDOUR_UI::update_cpu_load ()
907 {
908         char buf[32];
909         snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
910         cpu_load_label.set_text (buf);
911 }
912
913 void
914 ARDOUR_UI::update_buffer_load ()
915 {
916         char buf[64];
917         uint32_t c, p;
918
919         if (_session) {
920                 c = _session->capture_load ();
921                 p = _session->playback_load ();
922
923                 push_buffer_stats (c, p);
924
925                 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
926                           _session->playback_load(), _session->capture_load());
927                 buffer_load_label.set_text (buf);
928         } else {
929                 buffer_load_label.set_text ("");
930         }
931 }
932
933 void
934 ARDOUR_UI::count_recenabled_streams (Route& route)
935 {
936         Track* track = dynamic_cast<Track*>(&route);
937         if (track && track->diskstream()->record_enabled()) {
938                 rec_enabled_streams += track->n_inputs().n_total();
939         }
940 }
941
942 void
943 ARDOUR_UI::update_disk_space()
944 {
945         if (_session == 0) {
946                 return;
947         }
948
949         nframes_t frames = _session->available_capture_duration();
950         char buf[64];
951         nframes_t fr = _session->frame_rate();
952
953         if (frames == max_frames) {
954                 strcpy (buf, _("Disk: 24hrs+"));
955         } else {
956                 rec_enabled_streams = 0;
957                 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
958
959                 if (rec_enabled_streams) {
960                         frames /= rec_enabled_streams;
961                 }
962
963                 int hrs;
964                 int mins;
965                 int secs;
966
967                 hrs  = frames / (fr * 3600);
968                 frames -= hrs * fr * 3600;
969                 mins = frames / (fr * 60);
970                 frames -= mins * fr * 60;
971                 secs = frames / fr;
972
973                 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
974         }
975
976         disk_space_label.set_text (buf);
977
978         // An attempt to make the disk space label flash red when space has run out.
979
980         if (frames < fr * 60 * 5) {
981         /*      disk_space_box.style ("disk_space_label_empty"); */
982         } else {
983         /*      disk_space_box.style ("disk_space_label"); */
984         }
985
986 }
987
988 gint
989 ARDOUR_UI::update_wall_clock ()
990 {
991         time_t now;
992         struct tm *tm_now;
993         char buf[16];
994
995         time (&now);
996         tm_now = localtime (&now);
997
998         sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
999         wall_clock_label.set_text (buf);
1000
1001         return TRUE;
1002 }
1003
1004 gint
1005 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1006 {
1007         session_popup_menu->popup (0, 0);
1008         return TRUE;
1009 }
1010
1011 void
1012 ARDOUR_UI::redisplay_recent_sessions ()
1013 {
1014         std::vector<sys::path> session_directories;
1015         RecentSessionsSorter cmp;
1016
1017         recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1018         recent_session_model->clear ();
1019
1020         ARDOUR::RecentSessions rs;
1021         ARDOUR::read_recent_sessions (rs);
1022
1023         if (rs.empty()) {
1024                 recent_session_display.set_model (recent_session_model);
1025                 return;
1026         }
1027         //
1028         // sort them alphabetically
1029         sort (rs.begin(), rs.end(), cmp);
1030
1031         for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1032                 session_directories.push_back ((*i).second);
1033         }
1034
1035         for (vector<sys::path>::const_iterator i = session_directories.begin();
1036                         i != session_directories.end(); ++i)
1037         {
1038                 std::vector<sys::path> state_file_paths;
1039
1040                 // now get available states for this session
1041
1042                 get_state_files_in_directory (*i, state_file_paths);
1043
1044                 vector<string*>* states;
1045                 vector<const gchar*> item;
1046                 string fullpath = (*i).to_string();
1047
1048                 /* remove any trailing / */
1049
1050                 if (fullpath[fullpath.length()-1] == '/') {
1051                         fullpath = fullpath.substr (0, fullpath.length()-1);
1052                 }
1053
1054                 /* check whether session still exists */
1055                 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1056                         /* session doesn't exist */
1057                         cerr << "skipping non-existent session " << fullpath << endl;
1058                         continue;
1059                 }
1060
1061                 /* now get available states for this session */
1062
1063                 if ((states = Session::possible_states (fullpath)) == 0) {
1064                         /* no state file? */
1065                         continue;
1066                 }
1067
1068                 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1069
1070                 Gtk::TreeModel::Row row = *(recent_session_model->append());
1071
1072                 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1073                 row[recent_session_columns.fullpath] = fullpath;
1074
1075                 if (state_file_names.size() > 1) {
1076
1077                         // add the children
1078
1079                         for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1080                                         i2 != state_file_names.end(); ++i2)
1081                         {
1082
1083                                 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1084
1085                                 child_row[recent_session_columns.visible_name] = *i2;
1086                                 child_row[recent_session_columns.fullpath] = fullpath;
1087                         }
1088                 }
1089         }
1090
1091         recent_session_display.set_model (recent_session_model);
1092 }
1093
1094 void
1095 ARDOUR_UI::build_session_selector ()
1096 {
1097         session_selector_window = new ArdourDialog (_("Recent Sessions"));
1098
1099         Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1100
1101         session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1102         session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1103         session_selector_window->set_default_response (RESPONSE_ACCEPT);
1104         recent_session_model = TreeStore::create (recent_session_columns);
1105         recent_session_display.set_model (recent_session_model);
1106         recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1107         recent_session_display.set_headers_visible (false);
1108         recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1109         recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1110
1111         scroller->add (recent_session_display);
1112         scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1113
1114         session_selector_window->set_name ("SessionSelectorWindow");
1115         session_selector_window->set_size_request (200, 400);
1116         session_selector_window->get_vbox()->pack_start (*scroller);
1117
1118         recent_session_display.show();
1119         scroller->show();
1120         //session_selector_window->get_vbox()->show();
1121 }
1122
1123 void
1124 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1125 {
1126         session_selector_window->response (RESPONSE_ACCEPT);
1127 }
1128
1129 void
1130 ARDOUR_UI::open_recent_session ()
1131 {
1132         bool can_return = (_session != 0);
1133
1134         if (session_selector_window == 0) {
1135                 build_session_selector ();
1136         }
1137
1138         redisplay_recent_sessions ();
1139
1140         while (true) {
1141
1142                 session_selector_window->set_position (WIN_POS_MOUSE);
1143
1144                 ResponseType r = (ResponseType) session_selector_window->run ();
1145
1146                 switch (r) {
1147                 case RESPONSE_ACCEPT:
1148                         break;
1149                 default:
1150                         if (can_return) {
1151                                 session_selector_window->hide();
1152                                 return;
1153                         } else {
1154                                 exit (1);
1155                         }
1156                 }
1157
1158                 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1159                         continue;
1160                 }
1161
1162                 session_selector_window->hide();
1163
1164                 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1165
1166                 if (i == recent_session_model->children().end()) {
1167                         return;
1168                 }
1169
1170                 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1171                 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1172
1173                 _session_is_new = false;
1174
1175                 if (load_session (path, state) == 0) {
1176                         break;
1177                 }
1178
1179                 can_return = false;
1180         }
1181 }
1182
1183 bool
1184 ARDOUR_UI::check_audioengine ()
1185 {
1186         if (engine) {
1187                 if (!engine->connected()) {
1188                         MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1189                                                              "You cannot open or close sessions in this condition"),
1190                                                            PROGRAM_NAME));
1191                         pop_back_splash ();
1192                         msg.run ();
1193                         return false;
1194                 }
1195                 return true;
1196         } else {
1197                 return false;
1198         }
1199 }
1200
1201 void
1202 ARDOUR_UI::open_session ()
1203 {
1204         if (!check_audioengine()) {
1205                 return;
1206
1207         }
1208
1209         /* popup selector window */
1210
1211         if (open_session_selector == 0) {
1212
1213                 /* ardour sessions are folders */
1214
1215                 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1216                 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1217                 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1218                 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1219
1220                 FileFilter session_filter;
1221                 session_filter.add_pattern ("*.ardour");
1222                 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1223                 open_session_selector->add_filter (session_filter);
1224                 open_session_selector->set_filter (session_filter);
1225         }
1226
1227         int response = open_session_selector->run();
1228         open_session_selector->hide ();
1229
1230         switch (response) {
1231         case RESPONSE_ACCEPT:
1232                 break;
1233         default:
1234                 open_session_selector->hide();
1235                 return;
1236         }
1237
1238         open_session_selector->hide();
1239         string session_path = open_session_selector->get_filename();
1240         string path, name;
1241         bool isnew;
1242
1243         if (session_path.length() > 0) {
1244                 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1245                         _session_is_new = isnew;
1246                         load_session (path, name);
1247                 }
1248         }
1249 }
1250
1251
1252 void
1253 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1254 {
1255         list<boost::shared_ptr<MidiTrack> > tracks;
1256
1257         if (_session == 0) {
1258                 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1259                 return;
1260         }
1261
1262         try {
1263                 if (disk) {
1264
1265                         tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1266
1267                         if (tracks.size() != how_many) {
1268                                 if (how_many == 1) {
1269                                         error << _("could not create a new midi track") << endmsg;
1270                                 } else {
1271                                         error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1272                                 }
1273                         }
1274                 } /*else {
1275                         if ((route = _session->new_midi_route ()) == 0) {
1276                                 error << _("could not create new midi bus") << endmsg;
1277                         }
1278                 }*/
1279         }
1280
1281         catch (...) {
1282                 MessageDialog msg (*editor,
1283                                    _("There are insufficient JACK ports available\n\
1284 to create a new track or bus.\n\
1285 You should save Ardour, exit and\n\
1286 restart JACK with more ports."));
1287                 msg.run ();
1288         }
1289 }
1290
1291
1292 void
1293 ARDOUR_UI::session_add_audio_route (bool track, bool aux, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1294 {
1295         list<boost::shared_ptr<AudioTrack> > tracks;
1296         RouteList routes;
1297
1298         if (_session == 0) {
1299                 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1300                 return;
1301         }
1302
1303         try {
1304                 if (track) {
1305                         tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1306
1307                         if (tracks.size() != how_many) {
1308                                 if (how_many == 1) {
1309                                         error << _("could not create a new audio track") << endmsg;
1310                                 } else {
1311                                         error << string_compose (_("could only create %1 of %2 new audio %3"),
1312                                                                  tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1313                                 }
1314                         }
1315
1316                 } else {
1317
1318                         routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1319
1320                         if (routes.size() != how_many) {
1321                                 if (how_many == 1) {
1322                                         error << _("could not create a new audio track") << endmsg;
1323                                 } else {
1324                                         error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1325                                 }
1326                         }
1327                 }
1328         }
1329
1330         catch (...) {
1331                 MessageDialog msg (*editor,
1332                                    _("There are insufficient JACK ports available\n\
1333 to create a new track or bus.\n\
1334 You should save Ardour, exit and\n\
1335 restart JACK with more ports."));
1336                 pop_back_splash ();
1337                 msg.run ();
1338         }
1339 }
1340
1341 void
1342 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1343 {
1344         nframes_t _preroll = 0;
1345
1346         if (_session) {
1347                 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1348                 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1349
1350                 if (new_position > _preroll) {
1351                         new_position -= _preroll;
1352                 } else {
1353                         new_position = 0;
1354                 }
1355
1356                 _session->request_locate (new_position);
1357         }
1358 }
1359
1360 void
1361 ARDOUR_UI::transport_goto_start ()
1362 {
1363         if (_session) {
1364                 _session->goto_start();
1365
1366                 /* force displayed area in editor to start no matter
1367                    what "follow playhead" setting is.
1368                 */
1369
1370                 if (editor) {
1371                         editor->center_screen (_session->current_start_frame ());
1372                 }
1373         }
1374 }
1375
1376 void
1377 ARDOUR_UI::transport_goto_zero ()
1378 {
1379         if (_session) {
1380                 _session->request_locate (0);
1381
1382                 /* force displayed area in editor to start no matter
1383                    what "follow playhead" setting is.
1384                 */
1385
1386                 if (editor) {
1387                         editor->reset_x_origin (0);
1388                 }
1389         }
1390 }
1391
1392 void
1393 ARDOUR_UI::transport_goto_wallclock ()
1394 {
1395         if (_session && editor) {
1396
1397                 time_t now;
1398                 struct tm tmnow;
1399                 nframes64_t frames;
1400
1401                 time (&now);
1402                 localtime_r (&now, &tmnow);
1403
1404                 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1405                 frames += tmnow.tm_min * (60 * _session->frame_rate());
1406                 frames += tmnow.tm_sec * _session->frame_rate();
1407
1408                 _session->request_locate (frames);
1409
1410                 /* force displayed area in editor to start no matter
1411                    what "follow playhead" setting is.
1412                 */
1413
1414                 if (editor) {
1415                         editor->center_screen (frames);
1416                 }
1417         }
1418 }
1419
1420 void
1421 ARDOUR_UI::transport_goto_end ()
1422 {
1423         if (_session) {
1424                 nframes_t const frame = _session->current_end_frame();
1425                 _session->request_locate (frame);
1426
1427                 /* force displayed area in editor to start no matter
1428                    what "follow playhead" setting is.
1429                 */
1430
1431                 if (editor) {
1432                         editor->center_screen (frame);
1433                 }
1434         }
1435 }
1436
1437 void
1438 ARDOUR_UI::transport_stop ()
1439 {
1440         if (!_session) {
1441                 return;
1442         }
1443
1444         if (_session->is_auditioning()) {
1445                 _session->cancel_audition ();
1446                 return;
1447         }
1448
1449         _session->request_stop (false, true);
1450 }
1451
1452 void
1453 ARDOUR_UI::transport_stop_and_forget_capture ()
1454 {
1455         if (_session) {
1456                 _session->request_stop (true, true);
1457         }
1458 }
1459
1460 void
1461 ARDOUR_UI::remove_last_capture()
1462 {
1463         if (editor) {
1464                 editor->remove_last_capture();
1465         }
1466 }
1467
1468 void
1469 ARDOUR_UI::transport_record (bool roll)
1470 {
1471
1472         if (_session) {
1473                 switch (_session->record_status()) {
1474                 case Session::Disabled:
1475                         if (_session->ntracks() == 0) {
1476                                 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1477                                 msg.run ();
1478                                 return;
1479                         }
1480                         _session->maybe_enable_record ();
1481                         if (roll) {
1482                                 transport_roll ();
1483                         }
1484                         break;
1485                 case Session::Recording:
1486                         if (roll) {
1487                                 _session->request_stop();
1488                         } else {
1489                                 _session->disable_record (false, true);
1490                         }
1491                         break;
1492
1493                 case Session::Enabled:
1494                         _session->disable_record (false, true);
1495                 }
1496         }
1497         //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1498 }
1499
1500 void 
1501 ARDOUR_UI::transport_roll ()
1502 {
1503         if (!_session) {
1504                 return;
1505         }
1506
1507         if (_session->is_auditioning()) {
1508                 return;
1509         }
1510         
1511         if (_session->config.get_external_sync()) {
1512                 switch (_session->config.get_sync_source()) {
1513                 case JACK:
1514                         break;
1515                 default:
1516                         /* transport controlled by the master */
1517                         return;
1518                 }
1519         }
1520
1521         bool rolling = _session->transport_rolling();
1522
1523         if (_session->get_play_loop()) {
1524                 /* XXX it is not possible to just leave seamless loop and keep
1525                    playing at present (nov 4th 2009)
1526                 */
1527                 if (!Config->get_seamless_loop()) {
1528                         _session->request_play_loop (false, true);
1529                 }
1530         } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1531                 /* stop playing a range if we currently are */
1532                 _session->request_play_range (0, true);
1533         }
1534
1535         if (join_play_range_button.get_active()) {
1536                 _session->request_play_range (&editor->get_selection().time, true);
1537         }
1538
1539         if (!rolling) {
1540                 _session->request_transport_speed (1.0f);
1541         }
1542 }
1543
1544 void
1545 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1546 {
1547         
1548         if (!_session) {
1549                 return;
1550         }
1551
1552         if (_session->is_auditioning()) {
1553                 _session->cancel_audition ();
1554                 return;
1555         }
1556         
1557         if (_session->config.get_external_sync()) {
1558                 switch (_session->config.get_sync_source()) {
1559                 case JACK:
1560                         break;
1561                 default:
1562                         /* transport controlled by the master */
1563                         return;
1564                 }
1565         }
1566
1567         bool rolling = _session->transport_rolling();
1568         bool affect_transport = true;
1569
1570         if (rolling && roll_out_of_bounded_mode) {
1571                 /* drop out of loop/range playback but leave transport rolling */
1572                 if (_session->get_play_loop()) {
1573                         if (Config->get_seamless_loop()) {
1574                                 /* the disk buffers contain copies of the loop - we can't 
1575                                    just keep playing, so stop the transport. the user
1576                                    can restart as they wish.
1577                                 */
1578                                 affect_transport = true;
1579                         } else {
1580                                 /* disk buffers are normal, so we can keep playing */
1581                                 affect_transport = false;
1582                         }
1583                         _session->request_play_loop (false, true);
1584                 } else if (_session->get_play_range ()) {
1585                         affect_transport = false;
1586                         _session->request_play_range (0, true);
1587                 } 
1588         } 
1589
1590         if (affect_transport) {
1591                 if (rolling) {
1592                         _session->request_stop (with_abort, true);
1593                 } else {
1594                         if (join_play_range_button.get_active()) {
1595                                 _session->request_play_range (&editor->get_selection().time, true);
1596                         }
1597                         
1598                         _session->request_transport_speed (1.0f);
1599                 }
1600         }
1601 }
1602
1603 void
1604 ARDOUR_UI::toggle_session_auto_loop ()
1605 {
1606         if (_session) {
1607                 if (_session->get_play_loop()) {
1608                         if (_session->transport_rolling()) {
1609                                 Location * looploc = _session->locations()->auto_loop_location();
1610                                 if (looploc) {
1611                                         _session->request_locate (looploc->start(), true);
1612                                 }
1613                         } else {
1614                                 _session->request_play_loop (false);
1615                         }
1616                 } else {
1617                         Location * looploc = _session->locations()->auto_loop_location();
1618                         if (looploc) {
1619                                 _session->request_play_loop (true);
1620                         }
1621                 }
1622         }
1623 }
1624
1625 void
1626 ARDOUR_UI::transport_play_selection ()
1627 {
1628         if (!_session) {
1629                 return;
1630         }
1631
1632         editor->play_selection ();
1633 }
1634
1635 void
1636 ARDOUR_UI::transport_rewind (int option)
1637 {
1638         float current_transport_speed;
1639
1640         if (_session) {
1641                 current_transport_speed = _session->transport_speed();
1642
1643                 if (current_transport_speed >= 0.0f) {
1644                         switch (option) {
1645                         case 0:
1646                                 _session->request_transport_speed (-1.0f);
1647                                 break;
1648                         case 1:
1649                                 _session->request_transport_speed (-4.0f);
1650                                 break;
1651                         case -1:
1652                                 _session->request_transport_speed (-0.5f);
1653                                 break;
1654                         }
1655                 } else {
1656                         /* speed up */
1657                         _session->request_transport_speed (current_transport_speed * 1.5f);
1658                 }
1659         }
1660 }
1661
1662 void
1663 ARDOUR_UI::transport_forward (int option)
1664 {
1665         float current_transport_speed;
1666
1667         if (_session) {
1668                 current_transport_speed = _session->transport_speed();
1669
1670                 if (current_transport_speed <= 0.0f) {
1671                         switch (option) {
1672                         case 0:
1673                                 _session->request_transport_speed (1.0f);
1674                                 break;
1675                         case 1:
1676                                 _session->request_transport_speed (4.0f);
1677                                 break;
1678                         case -1:
1679                                 _session->request_transport_speed (0.5f);
1680                                 break;
1681                         }
1682                 } else {
1683                         /* speed up */
1684                         _session->request_transport_speed (current_transport_speed * 1.5f);
1685                 }
1686
1687         }
1688 }
1689
1690 void
1691 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1692 {
1693         if (_session == 0) {
1694                 return;
1695         }
1696
1697         boost::shared_ptr<Route> r;
1698
1699         if ((r = _session->route_by_remote_id (dstream)) != 0) {
1700
1701                 Track* t;
1702
1703                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1704                         t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1705                 }
1706         }
1707         if (_session == 0) {
1708                 return;
1709         }
1710 }
1711
1712 void
1713 ARDOUR_UI::map_transport_state ()
1714 {
1715         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1716
1717         if (!_session) {
1718                 auto_loop_button.set_visual_state (0);
1719                 play_selection_button.set_visual_state (0);
1720                 roll_button.set_visual_state (0);
1721                 stop_button.set_visual_state (1);
1722                 return;
1723         }
1724
1725         float sp = _session->transport_speed();
1726
1727         if (sp == 1.0f) {
1728                 shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
1729                 shuttle_box.queue_draw ();
1730         } else if (sp == 0.0f) {
1731                 shuttle_fract = 0;
1732                 shuttle_box.queue_draw ();
1733                 update_disk_space ();
1734         }
1735
1736         if (sp != 0.0) {
1737
1738                 /* we're rolling */
1739
1740                 if (_session->get_play_range()) {
1741
1742                         play_selection_button.set_visual_state (1);
1743                         roll_button.set_visual_state (0);
1744                         auto_loop_button.set_visual_state (0);
1745
1746                 } else if (_session->get_play_loop ()) {
1747                         
1748                         auto_loop_button.set_visual_state (1);
1749                         play_selection_button.set_visual_state (0);
1750                         roll_button.set_visual_state (0);
1751
1752                 } else {
1753                         
1754                         roll_button.set_visual_state (1);
1755                         play_selection_button.set_visual_state (0);
1756                         auto_loop_button.set_visual_state (0);
1757                 }
1758
1759                 if (join_play_range_button.get_active()) {
1760                         /* light up both roll and play-selection if they are joined */
1761                         roll_button.set_visual_state (1);
1762                         play_selection_button.set_visual_state (1);
1763                 }
1764
1765                 stop_button.set_visual_state (0);
1766
1767         } else {
1768
1769                 stop_button.set_visual_state (1);
1770                 roll_button.set_visual_state (0);
1771                 play_selection_button.set_visual_state (0);
1772                 auto_loop_button.set_visual_state (0);
1773         }
1774 }
1775
1776 void
1777 ARDOUR_UI::engine_stopped ()
1778 {
1779         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1780         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1781         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1782 }
1783
1784 void
1785 ARDOUR_UI::engine_running ()
1786 {
1787         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1788         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1789         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1790
1791         Glib::RefPtr<Action> action;
1792         const char* action_name = 0;
1793
1794         switch (engine->frames_per_cycle()) {
1795         case 32:
1796                 action_name = X_("JACKLatency32");
1797                 break;
1798         case 64:
1799                 action_name = X_("JACKLatency64");
1800                 break;
1801         case 128:
1802                 action_name = X_("JACKLatency128");
1803                 break;
1804         case 512:
1805                 action_name = X_("JACKLatency512");
1806                 break;
1807         case 1024:
1808                 action_name = X_("JACKLatency1024");
1809                 break;
1810         case 2048:
1811                 action_name = X_("JACKLatency2048");
1812                 break;
1813         case 4096:
1814                 action_name = X_("JACKLatency4096");
1815                 break;
1816         case 8192:
1817                 action_name = X_("JACKLatency8192");
1818                 break;
1819         default:
1820                 /* XXX can we do anything useful ? */
1821                 break;
1822         }
1823
1824         if (action_name) {
1825
1826                 action = ActionManager::get_action (X_("JACK"), action_name);
1827
1828                 if (action) {
1829                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1830                         ract->set_active ();
1831                 }
1832         }
1833 }
1834
1835 void
1836 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1837 {
1838        if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1839                /* we can't rely on the original string continuing to exist when we are called
1840                   again in the GUI thread, so make a copy and note that we need to
1841                   free it later.
1842                */
1843                char *copy = strdup (reason);
1844                Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1845                return;
1846        }
1847
1848         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1849         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1850
1851         update_sample_rate (0);
1852
1853         string msgstr;
1854
1855         /* if the reason is a non-empty string, it means that the backend was shutdown
1856            rather than just Ardour.
1857         */
1858
1859         if (strlen (reason)) {
1860                 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1861         } else {
1862                 msgstr = _("\
1863 JACK has either been shutdown or it\n\
1864 disconnected Ardour because Ardour\n\
1865 was not fast enough. Try to restart\n\
1866 JACK, reconnect and save the session.");
1867         }
1868
1869         MessageDialog msg (*editor, msgstr);
1870         pop_back_splash ();
1871         msg.run ();
1872
1873         if (free_reason) {
1874                 free ((char*) reason);
1875         }
1876 }
1877
1878 int32_t
1879 ARDOUR_UI::do_engine_start ()
1880 {
1881         try {
1882                 engine->start();
1883         }
1884
1885         catch (...) {
1886                 engine->stop ();
1887                 error << _("Unable to start the session running")
1888                       << endmsg;
1889                 unload_session ();
1890                 return -2;
1891         }
1892
1893         return 0;
1894 }
1895
1896 void
1897 ARDOUR_UI::setup_theme ()
1898 {
1899         theme_manager->setup_theme();
1900 }
1901
1902 void
1903 ARDOUR_UI::update_clocks ()
1904 {
1905         if (!editor || !editor->dragging_playhead()) {
1906                 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1907         }
1908 }
1909
1910 void
1911 ARDOUR_UI::start_clocking ()
1912 {
1913         clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1914 }
1915
1916 void
1917 ARDOUR_UI::stop_clocking ()
1918 {
1919         clock_signal_connection.disconnect ();
1920 }
1921
1922 void
1923 ARDOUR_UI::toggle_clocking ()
1924 {
1925 #if 0
1926         if (clock_button.get_active()) {
1927                 start_clocking ();
1928         } else {
1929                 stop_clocking ();
1930         }
1931 #endif
1932 }
1933
1934 gint
1935 ARDOUR_UI::_blink (void *arg)
1936
1937 {
1938         ((ARDOUR_UI *) arg)->blink ();
1939         return TRUE;
1940 }
1941
1942 void
1943 ARDOUR_UI::blink ()
1944 {
1945         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1946 }
1947
1948 void
1949 ARDOUR_UI::start_blinking ()
1950 {
1951         /* Start the blink signal. Everybody with a blinking widget
1952            uses Blink to drive the widget's state.
1953         */
1954
1955         if (blink_timeout_tag < 0) {
1956                 blink_on = false;
1957                 blink_timeout_tag = g_timeout_add (240, _blink, this);
1958         }
1959 }
1960
1961 void
1962 ARDOUR_UI::stop_blinking ()
1963 {
1964         if (blink_timeout_tag >= 0) {
1965                 g_source_remove (blink_timeout_tag);
1966                 blink_timeout_tag = -1;
1967         }
1968 }
1969
1970
1971 /** Ask the user for the name of a new shapshot and then take it.
1972  */
1973
1974 void
1975 ARDOUR_UI::snapshot_session (bool switch_to_it)
1976 {
1977         ArdourPrompter prompter (true);
1978         string snapname;
1979
1980         prompter.set_name ("Prompter");
1981         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1982         prompter.set_title (_("Take Snapshot"));
1983         prompter.set_title (_("Take Snapshot"));
1984         prompter.set_prompt (_("Name of New Snapshot"));
1985
1986         if (!switch_to_it) {
1987                 char timebuf[128];
1988                 time_t n;
1989                 struct tm local_time;
1990                 
1991                 time (&n);
1992                 localtime_r (&n, &local_time);
1993                 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1994                 prompter.set_initial_text (timebuf);
1995         }
1996
1997   again:
1998         switch (prompter.run()) {
1999         case RESPONSE_ACCEPT:
2000         {
2001                 prompter.get_result (snapname);
2002
2003                 bool do_save = (snapname.length() != 0);
2004
2005                 if (do_save) {
2006                         if (snapname.find ('/') != string::npos) {
2007                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2008                                                      "snapshot names may not contain a '/' character"));
2009                                 msg.run ();
2010                                 goto again;
2011                         }
2012                         if (snapname.find ('\\') != string::npos) {
2013                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2014                                                      "snapshot names may not contain a '\\' character"));
2015                                 msg.run ();
2016                                 goto again;
2017                         }
2018                 }
2019
2020                 vector<sys::path> p;
2021                 get_state_files_in_directory (_session->session_directory().root_path(), p);
2022                 vector<string> n = get_file_names_no_extension (p);
2023                 if (find (n.begin(), n.end(), snapname) != n.end()) {
2024
2025                         ArdourDialog confirm (_("Confirm snapshot overwrite"), true);
2026                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
2027                         confirm.get_vbox()->pack_start (m, true, true);
2028                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2029                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2030                         confirm.show_all ();
2031                         switch (confirm.run()) {
2032                         case RESPONSE_CANCEL:
2033                                 do_save = false;
2034                         }
2035                 }
2036
2037                 if (do_save) {
2038                         save_state (snapname, switch_to_it);
2039                 }
2040                 break;
2041         }
2042
2043         default:
2044                 break;
2045         }
2046 }
2047
2048 void
2049 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2050 {
2051         save_state_canfail (name, switch_to_it);
2052 }
2053
2054 int
2055 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2056 {
2057         if (_session) {
2058                 int ret;
2059
2060                 if (name.length() == 0) {
2061                         name = _session->snap_name();
2062                 }
2063
2064                 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2065                         return ret;
2066                 }
2067         }
2068         cerr << "SS canfail\n";
2069         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2070         return 0;
2071 }
2072
2073 void
2074 ARDOUR_UI::primary_clock_value_changed ()
2075 {
2076         if (_session) {
2077                 _session->request_locate (primary_clock.current_time ());
2078         }
2079 }
2080
2081 void
2082 ARDOUR_UI::big_clock_value_changed ()
2083 {
2084         if (_session) {
2085                 _session->request_locate (big_clock.current_time ());
2086         }
2087 }
2088
2089 void
2090 ARDOUR_UI::secondary_clock_value_changed ()
2091 {
2092         if (_session) {
2093                 _session->request_locate (secondary_clock.current_time ());
2094         }
2095 }
2096
2097 void
2098 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2099 {
2100         if (_session == 0) {
2101                 return;
2102         }
2103
2104         Session::RecordState const r = _session->record_status ();
2105         bool const h = _session->have_rec_enabled_diskstream ();
2106
2107         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2108                 if (onoff) {
2109                         rec_button.set_visual_state (2);
2110                 } else {
2111                         rec_button.set_visual_state (0);
2112                 }
2113         } else if (r == Session::Recording && h) {
2114                 rec_button.set_visual_state (1);
2115         } else {
2116                 rec_button.set_visual_state (0);
2117         }
2118 }
2119
2120 void
2121 ARDOUR_UI::save_template ()
2122 {
2123         ArdourPrompter prompter (true);
2124         string name;
2125
2126         if (!check_audioengine()) {
2127                 return;
2128         }
2129
2130         prompter.set_name (X_("Prompter"));
2131         prompter.set_title (_("Save Mix Template"));
2132         prompter.set_prompt (_("Name for mix template:"));
2133         prompter.set_initial_text(_session->name() + _("-template"));
2134         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2135
2136         switch (prompter.run()) {
2137         case RESPONSE_ACCEPT:
2138                 prompter.get_result (name);
2139
2140                 if (name.length()) {
2141                         _session->save_template (name);
2142                 }
2143                 break;
2144
2145         default:
2146                 break;
2147         }
2148 }
2149
2150 void
2151 ARDOUR_UI::edit_metadata ()
2152 {
2153         SessionMetadataEditor dialog;
2154         dialog.set_session (_session);
2155         editor->ensure_float (dialog);
2156         dialog.run ();
2157 }
2158
2159 void
2160 ARDOUR_UI::import_metadata ()
2161 {
2162         SessionMetadataImporter dialog;
2163         dialog.set_session (_session);
2164         editor->ensure_float (dialog);
2165         dialog.run ();
2166 }
2167
2168 void
2169 ARDOUR_UI::fontconfig_dialog ()
2170 {
2171 #ifdef GTKOSX
2172         /* X11 users will always have fontconfig info around, but new GTK-OSX users
2173            may not and it can take a while to build it. Warn them.
2174         */
2175
2176         Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2177
2178         if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2179                 MessageDialog msg (*_startup,
2180                                    _("Welcome to Ardour.\n\n"
2181                                      "The program will take a bit longer to start up\n"
2182                                      "while the system fonts are checked.\n\n"
2183                                      "This will only be done once, and you will\n"
2184                                      "not see this message again\n"),
2185                                    true,
2186                                    Gtk::MESSAGE_INFO,
2187                                    Gtk::BUTTONS_OK);
2188                 pop_back_splash ();
2189                 msg.show_all ();
2190                 msg.present ();
2191                 msg.run ();
2192         }
2193 #endif
2194 }
2195
2196 void
2197 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2198 {
2199         existing_session = false;
2200
2201         if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2202                 session_path = cmdline_path;
2203                 existing_session = true;
2204         } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2205                 session_path = Glib::path_get_dirname (string (cmdline_path));
2206                 existing_session = true;
2207         } else {
2208                 /* it doesn't exist, assume the best */
2209                 session_path = Glib::path_get_dirname (string (cmdline_path));
2210         }
2211
2212         session_name = basename_nosuffix (string (cmdline_path));
2213 }
2214
2215 int
2216 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2217 {
2218         /* when this is called, the backend audio system must be running */
2219
2220         /* the main idea here is to deal with the fact that a cmdline argument for the session
2221            can be interpreted in different ways - it could be a directory or a file, and before
2222            we load, we need to know both the session directory and the snapshot (statefile) within it
2223            that we are supposed to use.
2224         */
2225
2226         if (session_name.length() == 0 || session_path.length() == 0) {
2227                 return false;
2228         }
2229
2230         if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2231
2232                 Glib::ustring predicted_session_file;
2233
2234                 predicted_session_file = session_path;
2235                 predicted_session_file += '/';
2236                 predicted_session_file += session_name;
2237                 predicted_session_file += ARDOUR::statefile_suffix;
2238
2239                 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2240                         existing_session = true;
2241                 }
2242
2243         } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2244
2245                 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2246                         /* existing .ardour file */
2247                         existing_session = true;
2248                 }
2249
2250         } else {
2251                 existing_session = false;
2252         }
2253
2254         /* lets just try to load it */
2255
2256         if (create_engine ()) {
2257                 backend_audio_error (false, _startup);
2258                 return -1;
2259         }
2260
2261         return load_session (session_path, session_name);
2262 }
2263
2264 bool
2265 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2266 {
2267         Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2268
2269         MessageDialog msg (str,
2270                            false,
2271                            Gtk::MESSAGE_WARNING,
2272                            Gtk::BUTTONS_YES_NO,
2273                            true);
2274
2275
2276         msg.set_name (X_("OpenExistingDialog"));
2277         msg.set_title (_("Open Existing Session"));
2278         msg.set_wmclass (X_("existing_session"), "Ardour");
2279         msg.set_position (Gtk::WIN_POS_MOUSE);
2280         pop_back_splash ();
2281
2282         switch (msg.run()) {
2283         case RESPONSE_YES:
2284                 return true;
2285                 break;
2286         }
2287         return false;
2288 }
2289
2290 int
2291 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2292 {
2293         BusProfile bus_profile;
2294
2295         if (Profile->get_sae()) {
2296
2297                 bus_profile.master_out_channels = 2;
2298                 bus_profile.input_ac = AutoConnectPhysical;
2299                 bus_profile.output_ac = AutoConnectMaster;
2300                 bus_profile.requested_physical_in = 0; // use all available
2301                 bus_profile.requested_physical_out = 0; // use all available
2302
2303         } else {
2304
2305                 /* get settings from advanced section of NSD */
2306
2307                 if (_startup->create_master_bus()) {
2308                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2309                 } else {
2310                         bus_profile.master_out_channels = 0;
2311                 }
2312
2313                 if (_startup->connect_inputs()) {
2314                         bus_profile.input_ac = AutoConnectPhysical;
2315                 } else {
2316                         bus_profile.input_ac = AutoConnectOption (0);
2317                 }
2318
2319                 /// @todo some minor tweaks.
2320                 
2321                 bus_profile.output_ac = AutoConnectOption (0);
2322
2323                 if (_startup->connect_outputs ()) {
2324                         if (_startup->connect_outs_to_master()) {
2325                                 bus_profile.output_ac = AutoConnectMaster;
2326                         } else if (_startup->connect_outs_to_physical()) {
2327                                 bus_profile.output_ac = AutoConnectPhysical;
2328                         }
2329                 }
2330
2331                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2332                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2333         }
2334
2335         if (build_session (session_path, session_name, bus_profile)) {
2336                 return -1;
2337         }
2338
2339         return 0;
2340 }
2341
2342 void
2343 ARDOUR_UI::idle_load (const Glib::ustring& path)
2344 {
2345         if (_session) {
2346                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2347                         /* /path/to/foo => /path/to/foo, foo */
2348                         load_session (path, basename_nosuffix (path));
2349                 } else {
2350                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2351                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2352                 }
2353         } else {
2354
2355                 ARDOUR_COMMAND_LINE::session_name = path;
2356
2357                 /*
2358                  * new_session_dialog doens't exist in A3
2359                  * Try to remove all references to it to
2360                  * see if it will compile.  NOTE: this will
2361                  * likely cause a runtime issue is my somewhat
2362                  * uneducated guess.
2363                  */
2364
2365                 //if (new_session_dialog) {
2366
2367
2368                         /* make it break out of Dialog::run() and
2369                            start again.
2370                          */
2371
2372                         //new_session_dialog->response (1);
2373                 //}
2374         }
2375 }
2376
2377 void
2378 ARDOUR_UI::end_loading_messages ()
2379 {
2380         // hide_splash ();
2381 }
2382
2383 void
2384 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2385 {
2386         // show_splash ();
2387         // splash->message (msg);
2388         flush_pending ();
2389 }
2390
2391 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2392 int
2393 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new)
2394 {
2395         Glib::ustring session_name;
2396         Glib::ustring session_path;
2397         Glib::ustring template_name;
2398         int ret = -1;
2399         bool likely_new = false;
2400
2401         while (ret != 0) {
2402
2403                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2404
2405                         /* if they named a specific statefile, use it, otherwise they are
2406                            just giving a session folder, and we want to use it as is
2407                            to find the session.
2408                         */
2409
2410                         if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2411                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2412                         } else {
2413                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2414                         }
2415
2416                         session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2417
2418                 } else {
2419
2420                         bool const apply = run_startup (should_be_new);
2421                         if (!apply) {
2422                                 if (quit_on_cancel) {
2423                                         exit (1);
2424                                 } else {
2425                                         return ret;
2426                                 }
2427                         }
2428
2429                         /* if we run the startup dialog again, offer more than just "new session" */
2430
2431                         should_be_new = false;
2432
2433                         session_name = _startup->session_name (likely_new);
2434
2435                         /* this shouldn't happen, but we catch it just in case it does */
2436
2437                         if (session_name.empty()) {
2438                                 break;
2439                         }
2440                         if (_startup->use_session_template()) {
2441                                 template_name = _startup->session_template_name();
2442                                 _session_is_new = true;
2443                         }
2444
2445                         if (session_name[0] == '/' ||
2446                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2447                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2448
2449                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2450                                    from what was given.
2451                                 */
2452                                 
2453                                 session_path = Glib::path_get_dirname (session_name);
2454                                 session_name = Glib::path_get_basename (session_name);
2455
2456                         } else {
2457
2458                                 session_path = _startup->session_folder();
2459                         }
2460                 }
2461
2462                 if (create_engine ()) {
2463                         break;
2464                 }
2465
2466                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2467
2468                         if (likely_new) {
2469
2470                                 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2471
2472                                 if (!ask_about_loading_existing_session (existing)) {
2473                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2474                                         continue;
2475                                 }
2476                         }
2477
2478                         _session_is_new = false;
2479
2480                 } else {
2481
2482                         if (!likely_new) {
2483                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2484                                 msg.run ();
2485                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2486                                 continue;
2487                         }
2488
2489                         if (session_name.find ('/') != Glib::ustring::npos) {
2490                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2491                                                                           "session names may not contain a '/' character"));
2492                                 msg.run ();
2493                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2494                                 continue;
2495                         }
2496
2497                         if (session_name.find ('\\') != Glib::ustring::npos) {
2498                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2499                                                                           "session names may not contain a '\\' character"));
2500                                 msg.run ();
2501                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2502                                 continue;
2503                         }
2504
2505                         _session_is_new = true;
2506                 }
2507
2508                 if (likely_new && template_name.empty()) {
2509
2510                         ret = build_session_from_nsd (session_path, session_name);
2511
2512                 } else {
2513
2514                         ret = load_session (session_path, session_name, template_name);
2515                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2516                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2517                                 exit (1);
2518                         }
2519                 }
2520         }
2521
2522         return ret;
2523 }
2524
2525 void
2526 ARDOUR_UI::close_session()
2527 {
2528         if (!check_audioengine()) {
2529                 return;
2530         }
2531
2532         if (unload_session (true)) {
2533                 return;
2534         }
2535
2536         ARDOUR_COMMAND_LINE::session_name = "";
2537         get_session_parameters (true, false);
2538 }
2539
2540 int
2541 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2542 {
2543         Session *new_session;
2544         int unload_status;
2545         int retval = -1;
2546
2547         session_loaded = false;
2548
2549         if (!check_audioengine()) {
2550                 return -1;
2551         }
2552
2553         unload_status = unload_session ();
2554
2555         if (unload_status < 0) {
2556                 goto out;
2557         } else if (unload_status > 0) {
2558                 retval = 0;
2559                 goto out;
2560         }
2561
2562         loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2563
2564         try {
2565                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2566         }
2567
2568         /* this one is special */
2569
2570         catch (AudioEngine::PortRegistrationFailure& err) {
2571
2572                 MessageDialog msg (err.what(),
2573                                    true,
2574                                    Gtk::MESSAGE_INFO,
2575                                    Gtk::BUTTONS_CLOSE);
2576
2577                 msg.set_title (_("Port Registration Error"));
2578                 msg.set_secondary_text (_("Click the Close button to try again."));
2579                 msg.set_position (Gtk::WIN_POS_CENTER);
2580                 pop_back_splash ();
2581                 msg.present ();
2582
2583                 int response = msg.run ();
2584
2585                 msg.hide ();
2586
2587                 switch (response) {
2588                 case RESPONSE_CANCEL:
2589                         exit (1);
2590                 default:
2591                         break;
2592                 }
2593                 goto out;
2594         }
2595
2596         catch (...) {
2597
2598                 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2599                                    true,
2600                                    Gtk::MESSAGE_INFO,
2601                                    Gtk::BUTTONS_CLOSE);
2602
2603                 msg.set_title (_("Loading Error"));
2604                 msg.set_secondary_text (_("Click the Close button to try again."));
2605                 msg.set_position (Gtk::WIN_POS_CENTER);
2606                 pop_back_splash ();
2607                 msg.present ();
2608
2609                 int response = msg.run ();
2610
2611                 msg.hide ();
2612
2613                 switch (response) {
2614                 case RESPONSE_CANCEL:
2615                         exit (1);
2616                 default:
2617                         break;
2618                 }
2619                 goto out;
2620         }
2621
2622         set_session (new_session);
2623
2624         session_loaded = true;
2625
2626         goto_editor_window ();
2627
2628         if (_session) {
2629                 _session->set_clean ();
2630         }
2631
2632         flush_pending ();
2633         retval = 0;
2634
2635   out:
2636         return retval;
2637 }
2638
2639 int
2640 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2641 {
2642         Session *new_session;
2643         int x;
2644
2645         if (!check_audioengine()) {
2646                 return -1;
2647         }
2648
2649         session_loaded = false;
2650
2651         x = unload_session ();
2652
2653         if (x < 0) {
2654                 return -1;
2655         } else if (x > 0) {
2656                 return 0;
2657         }
2658
2659         _session_is_new = true;
2660
2661         try {
2662                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2663         }
2664
2665         catch (...) {
2666
2667                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2668                 pop_back_splash ();
2669                 msg.run ();
2670                 return -1;
2671         }
2672
2673         set_session (new_session);
2674
2675         session_loaded = true;
2676
2677         new_session->save_state(new_session->name());
2678
2679         return 0;
2680 }
2681
2682 void
2683 ARDOUR_UI::show ()
2684 {
2685         if (editor) {
2686                 editor->show_window ();
2687
2688                 if (!shown_flag) {
2689                         editor->present ();
2690                 }
2691
2692                 shown_flag = true;
2693         }
2694 }
2695
2696 void
2697 ARDOUR_UI::launch_chat ()
2698 {
2699 #ifdef __APPLE__
2700         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2701 #else
2702         open_uri("http://webchat.freenode.net/?channels=ardour");
2703 #endif
2704 }
2705
2706 void
2707 ARDOUR_UI::show_about ()
2708 {
2709         if (about == 0) {
2710                 about = new About;
2711                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2712         }
2713
2714         about->set_transient_for(*editor);
2715         about->show_all ();
2716 }
2717
2718 void
2719 ARDOUR_UI::hide_about ()
2720 {
2721         if (about) {
2722                 about->get_window()->set_cursor ();
2723                 about->hide ();
2724         }
2725 }
2726
2727 void
2728 ARDOUR_UI::about_signal_response (int /*response*/)
2729 {
2730         hide_about();
2731 }
2732
2733 void
2734 ARDOUR_UI::show_splash ()
2735 {
2736         if (splash == 0) {
2737                 try {
2738                         splash = new Splash;
2739                 } catch (...) {
2740                         return;
2741                 }
2742         }
2743
2744         splash->show ();
2745         splash->present ();
2746         splash->queue_draw ();
2747         splash->get_window()->process_updates (true);
2748         flush_pending ();
2749 }
2750
2751 void
2752 ARDOUR_UI::hide_splash ()
2753 {
2754         if (splash) {
2755                 splash->hide();
2756         }
2757 }
2758
2759 void
2760 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2761                                     const string& plural_msg, const string& singular_msg)
2762 {
2763         size_t removed;
2764
2765         removed = rep.paths.size();
2766
2767         if (removed == 0) {
2768                 MessageDialog msgd (*editor,
2769                                     _("No audio files were ready for cleanup"),
2770                                     true,
2771                                     Gtk::MESSAGE_INFO,
2772                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2773                 msgd.set_secondary_text (_("If this seems suprising, \n\
2774 check for any existing snapshots.\n\
2775 These may still include regions that\n\
2776 require some unused files to continue to exist."));
2777
2778                 msgd.run ();
2779                 return;
2780         }
2781
2782         ArdourDialog results (_("ardour: cleanup"), true, false);
2783
2784         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2785             CleanupResultsModelColumns() {
2786                     add (visible_name);
2787                     add (fullpath);
2788             }
2789             Gtk::TreeModelColumn<Glib::ustring> visible_name;
2790             Gtk::TreeModelColumn<Glib::ustring> fullpath;
2791         };
2792
2793
2794         CleanupResultsModelColumns results_columns;
2795         Glib::RefPtr<Gtk::ListStore> results_model;
2796         Gtk::TreeView results_display;
2797
2798         results_model = ListStore::create (results_columns);
2799         results_display.set_model (results_model);
2800         results_display.append_column (list_title, results_columns.visible_name);
2801
2802         results_display.set_name ("CleanupResultsList");
2803         results_display.set_headers_visible (true);
2804         results_display.set_headers_clickable (false);
2805         results_display.set_reorderable (false);
2806
2807         Gtk::ScrolledWindow list_scroller;
2808         Gtk::Label txt;
2809         Gtk::VBox dvbox;
2810         Gtk::HBox dhbox;  // the hbox for the image and text
2811         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2812         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2813
2814         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2815
2816         const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2817
2818         /* subst:
2819            %1 - number of files removed
2820            %2 - location of "dead_sounds"
2821            %3 - size of files affected
2822            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2823         */
2824
2825         const char* bprefix;
2826         double space_adjusted = 0;
2827
2828         if (rep.space < 100000.0f) {
2829                 bprefix = X_("kilo");
2830         } else if (rep.space < 1000000.0f * 1000) {
2831                 bprefix = X_("mega");
2832                 space_adjusted = truncf((float)rep.space / 1000.0);
2833         } else {
2834                 bprefix = X_("giga");
2835                 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2836         }
2837
2838         if (removed > 1) {
2839                 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2840         } else {
2841                 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2842         }
2843
2844         dhbox.pack_start (*dimage, true, false, 5);
2845         dhbox.pack_start (txt, true, false, 5);
2846
2847         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2848                 TreeModel::Row row = *(results_model->append());
2849                 row[results_columns.visible_name] = *i;
2850                 row[results_columns.fullpath] = *i;
2851         }
2852
2853         list_scroller.add (results_display);
2854         list_scroller.set_size_request (-1, 150);
2855         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2856
2857         dvbox.pack_start (dhbox, true, false, 5);
2858         dvbox.pack_start (list_scroller, true, false, 5);
2859         ddhbox.pack_start (dvbox, true, false, 5);
2860
2861         results.get_vbox()->pack_start (ddhbox, true, false, 5);
2862         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2863         results.set_default_response (RESPONSE_CLOSE);
2864         results.set_position (Gtk::WIN_POS_MOUSE);
2865
2866         results_display.show();
2867         list_scroller.show();
2868         txt.show();
2869         dvbox.show();
2870         dhbox.show();
2871         ddhbox.show();
2872         dimage->show();
2873
2874         //results.get_vbox()->show();
2875         results.set_resizable (false);
2876
2877         results.run ();
2878
2879 }
2880
2881 void
2882 ARDOUR_UI::cleanup ()
2883 {
2884         if (_session == 0) {
2885                 /* shouldn't happen: menu item is insensitive */
2886                 return;
2887         }
2888
2889
2890         MessageDialog  checker (_("Are you sure you want to cleanup?"),
2891                                 true,
2892                                 Gtk::MESSAGE_QUESTION,
2893                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2894
2895         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2896 ALL undo/redo information will be lost if you cleanup.\n\
2897 After cleanup, unused audio files will be moved to a \
2898 \"dead sounds\" location."));
2899
2900         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2901         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2902         checker.set_default_response (RESPONSE_CANCEL);
2903
2904         checker.set_name (_("CleanupDialog"));
2905         checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2906         checker.set_position (Gtk::WIN_POS_MOUSE);
2907
2908         switch (checker.run()) {
2909         case RESPONSE_ACCEPT:
2910                 break;
2911         default:
2912                 return;
2913         }
2914
2915         ARDOUR::CleanupReport rep;
2916
2917         editor->prepare_for_cleanup ();
2918
2919         /* do not allow flush until a session is reloaded */
2920
2921         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2922         if (act) {
2923                 act->set_sensitive (false);
2924         }
2925
2926         if (_session->cleanup_sources (rep)) {
2927                 editor->finish_cleanup ();
2928                 return;
2929         }
2930
2931         editor->finish_cleanup ();
2932
2933         checker.hide();
2934         display_cleanup_results (rep,
2935                                  _("cleaned files"),
2936                                  _("\
2937 The following %1 files were not in use and \n\
2938 have been moved to:\n\
2939 %2. \n\n\
2940 Flushing the wastebasket will \n\
2941 release an additional\n\
2942 %3 %4bytes of disk space.\n"),
2943                                  _("\
2944 The following file was not in use and \n        \
2945 has been moved to:\n                            \
2946 %2. \n\n\
2947 Flushing the wastebasket will \n\
2948 release an additional\n\
2949 %3 %4bytes of disk space.\n"
2950                                          ));
2951
2952 }
2953
2954 void
2955 ARDOUR_UI::flush_trash ()
2956 {
2957         if (_session == 0) {
2958                 /* shouldn't happen: menu item is insensitive */
2959                 return;
2960         }
2961
2962         ARDOUR::CleanupReport rep;
2963
2964         if (_session->cleanup_trash_sources (rep)) {
2965                 return;
2966         }
2967
2968         display_cleanup_results (rep,
2969                                  _("deleted file"),
2970                                  _("The following %1 files were deleted from\n\
2971 %2,\n\
2972 releasing %3 %4bytes of disk space"),
2973                                  _("The following file was deleted from\n\
2974 %2,\n\
2975 releasing %3 %4bytes of disk space"));
2976 }
2977
2978 void
2979 ARDOUR_UI::add_route (Gtk::Window* float_window)
2980 {
2981         int count;
2982
2983         if (!_session) {
2984                 return;
2985         }
2986
2987         if (add_route_dialog == 0) {
2988                 add_route_dialog = new AddRouteDialog (_session);
2989                 if (float_window) {
2990                         add_route_dialog->set_transient_for (*float_window);
2991                 }
2992         }
2993
2994         if (add_route_dialog->is_visible()) {
2995                 /* we're already doing this */
2996                 return;
2997         }
2998
2999         ResponseType r = (ResponseType) add_route_dialog->run ();
3000
3001         add_route_dialog->hide();
3002
3003         switch (r) {
3004                 case RESPONSE_ACCEPT:
3005                         break;
3006                 default:
3007                         return;
3008                         break;
3009         }
3010
3011         if ((count = add_route_dialog->count()) <= 0) {
3012                 return;
3013         }
3014
3015         string template_path = add_route_dialog->track_template();
3016
3017         if (!template_path.empty()) {
3018                 _session->new_route_from_template (count, template_path);
3019                 return;
3020         }
3021
3022         uint32_t input_chan = add_route_dialog->channels ();
3023         uint32_t output_chan;
3024         string name_template = add_route_dialog->name_template ();
3025         bool track = add_route_dialog->track ();
3026         bool aux = !track && add_route_dialog->aux();
3027         RouteGroup* route_group = add_route_dialog->route_group ();
3028
3029         AutoConnectOption oac = Config->get_output_auto_connect();
3030
3031         if (oac & AutoConnectMaster) {
3032                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3033         } else {
3034                 output_chan = input_chan;
3035         }
3036
3037         /* XXX do something with name template */
3038
3039         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3040                 if (track) {
3041                         session_add_midi_track (route_group, count);
3042                 } else  {
3043                         MessageDialog msg (*editor,
3044                                         _("Sorry, MIDI Busses are not supported at this time."));
3045                         msg.run ();
3046                         //session_add_midi_bus();
3047                 }
3048         } else {
3049                 if (track) {
3050                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3051                 } else {
3052                         session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3053                 }
3054         }
3055 }
3056
3057 XMLNode*
3058 ARDOUR_UI::mixer_settings () const
3059 {
3060         XMLNode* node = 0;
3061
3062         if (_session) {
3063                 node = _session->instant_xml(X_("Mixer"));
3064         } else {
3065                 node = Config->instant_xml(X_("Mixer"));
3066         }
3067
3068         if (!node) {
3069                 node = new XMLNode (X_("Mixer"));
3070         }
3071
3072         return node;
3073 }
3074
3075 XMLNode*
3076 ARDOUR_UI::editor_settings () const
3077 {
3078         XMLNode* node = 0;
3079
3080         if (_session) {
3081                 node = _session->instant_xml(X_("Editor"));
3082         } else {
3083                 node = Config->instant_xml(X_("Editor"));
3084         }
3085
3086         if (!node) {
3087                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3088                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3089                 }
3090         }
3091
3092         if (!node) {
3093                 node = new XMLNode (X_("Editor"));
3094         }
3095
3096         return node;
3097 }
3098
3099 XMLNode*
3100 ARDOUR_UI::keyboard_settings () const
3101 {
3102         XMLNode* node = 0;
3103
3104         node = Config->extra_xml(X_("Keyboard"));
3105
3106         if (!node) {
3107                 node = new XMLNode (X_("Keyboard"));
3108         }
3109         return node;
3110 }
3111
3112 void
3113 ARDOUR_UI::create_xrun_marker(nframes_t where)
3114 {
3115         editor->mouse_add_new_marker (where, false, true);
3116 }
3117
3118 void
3119 ARDOUR_UI::halt_on_xrun_message ()
3120 {
3121         MessageDialog msg (*editor,
3122                            _("Recording was stopped because your system could not keep up."));
3123         msg.run ();
3124 }
3125
3126 void
3127 ARDOUR_UI::xrun_handler(nframes_t where)
3128 {
3129         if (!_session) {
3130                 return;
3131         }
3132
3133         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3134
3135         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3136                 create_xrun_marker(where);
3137         }
3138
3139         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3140                 halt_on_xrun_message ();
3141         }
3142 }
3143
3144 void
3145 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3146 {
3147         time_t now;
3148         time (&now);
3149
3150         while (disk_buffer_stats.size() > 60) {
3151                 disk_buffer_stats.pop_front ();
3152         }
3153
3154         disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3155 }
3156
3157 void
3158 ARDOUR_UI::write_buffer_stats ()
3159 {
3160         std::ofstream fout;
3161         struct tm tm;
3162         char buf[64];
3163         char path[PATH_MAX+1];  int fd;
3164
3165         strcpy (path, "ardourBufferingXXXXXX");
3166
3167         if ((fd = mkstemp (path )) < 0) {
3168                 cerr << X_("cannot find temporary name for buffer stats") << endl;
3169                 return;
3170         }
3171         
3172         fout.open (path);
3173         close (fd);
3174
3175         if (!fout) {
3176                 cerr << string_compose (X_("cannot open file %1 for buffer stats"), path) << endl;
3177                 return;
3178         }
3179
3180         for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3181                 localtime_r (&(*i).when, &tm);
3182                 strftime (buf, sizeof (buf), "%T", &tm);
3183                 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3184         }
3185         
3186         disk_buffer_stats.clear ();
3187
3188         fout.close ();
3189
3190         cerr << "buffering statistics can be found in: " << path << endl;
3191 }
3192
3193 void
3194 ARDOUR_UI::disk_overrun_handler ()
3195 {
3196         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3197
3198         write_buffer_stats ();
3199
3200         if (!have_disk_speed_dialog_displayed) {
3201                 have_disk_speed_dialog_displayed = true;
3202                 MessageDialog* msg = new MessageDialog (*editor, _("\
3203 The disk system on your computer\n\
3204 was not able to keep up with Ardour.\n\
3205 \n\
3206 Specifically, it failed to write data to disk\n\
3207 quickly enough to keep up with recording.\n"));
3208                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3209                 msg->show ();
3210         }
3211 }
3212
3213 void
3214 ARDOUR_UI::disk_underrun_handler ()
3215 {
3216         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3217
3218         write_buffer_stats ();
3219
3220         if (!have_disk_speed_dialog_displayed) {
3221                 have_disk_speed_dialog_displayed = true;
3222                 MessageDialog* msg = new MessageDialog (*editor,
3223                                    _("The disk system on your computer\n\
3224 was not able to keep up with Ardour.\n\
3225 \n\
3226 Specifically, it failed to read data from disk\n\
3227 quickly enough to keep up with playback.\n"));
3228                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3229                 msg->show ();
3230         }
3231 }
3232
3233 void
3234 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3235 {
3236         have_disk_speed_dialog_displayed = false;
3237         delete msg;
3238 }
3239
3240 void
3241 ARDOUR_UI::session_dialog (std::string msg)
3242 {
3243         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3244
3245         MessageDialog* d;
3246
3247         if (editor) {
3248                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3249         } else {
3250                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3251         }
3252
3253         d->show_all ();
3254         d->run ();
3255         delete d;
3256 }
3257
3258 int
3259 ARDOUR_UI::pending_state_dialog ()
3260 {
3261         HBox* hbox = new HBox();
3262         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3263         ArdourDialog dialog (_("Crash Recovery"), true);
3264         Label  message (_("\
3265 This session appears to have been in\n\
3266 middle of recording when ardour or\n\
3267 the computer was shutdown.\n\
3268 \n\
3269 Ardour can recover any captured audio for\n\
3270 you, or it can ignore it. Please decide\n\
3271 what you would like to do.\n"));
3272         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3273         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3274         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3275         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3276         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3277         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3278         dialog.set_default_response (RESPONSE_ACCEPT);
3279         dialog.set_position (WIN_POS_CENTER);
3280         message.show();
3281         image->show();
3282         hbox->show();
3283
3284         switch (dialog.run ()) {
3285         case RESPONSE_ACCEPT:
3286                 return 1;
3287         default:
3288                 return 0;
3289         }
3290 }
3291
3292 int
3293 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3294 {
3295         HBox* hbox = new HBox();
3296         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3297         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3298         Label  message (string_compose (_("\
3299 This session was created with a sample rate of %1 Hz\n\
3300 \n\
3301 The audioengine is currently running at %2 Hz\n"), desired, actual));
3302
3303         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3304         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3305         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3306         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3307         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3308         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3309         dialog.set_default_response (RESPONSE_ACCEPT);
3310         dialog.set_position (WIN_POS_CENTER);
3311         message.show();
3312         image->show();
3313         hbox->show();
3314
3315         switch (dialog.run ()) {
3316         case RESPONSE_ACCEPT:
3317                 return 0;
3318         default:
3319                 return 1;
3320         }
3321 }
3322
3323
3324 void
3325 ARDOUR_UI::disconnect_from_jack ()
3326 {
3327         if (engine) {
3328                 if( engine->disconnect_from_jack ()) {
3329                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3330                         msg.run ();
3331                 }
3332
3333                 update_sample_rate (0);
3334         }
3335 }
3336
3337 void
3338 ARDOUR_UI::reconnect_to_jack ()
3339 {
3340         if (engine) {
3341                 if (engine->reconnect_to_jack ()) {
3342                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3343                         msg.run ();
3344                 }
3345
3346                 update_sample_rate (0);
3347         }
3348 }
3349
3350 void
3351 ARDOUR_UI::use_config ()
3352 {
3353
3354         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3355         if (node) {
3356                 set_transport_controllable_state (*node);
3357         }
3358
3359         node = Config->extra_xml (X_("UI"));
3360
3361         if (node) {
3362                 const XMLProperty* prop = node->property (X_("show-big-clock"));
3363                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3364                 if (act) {
3365                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3366                         tact->set_active (string_is_affirmative (prop->value()));
3367                 }
3368         }
3369 }
3370
3371 void
3372 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3373 {
3374         if (Config->get_primary_clock_delta_edit_cursor()) {
3375                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3376         } else {
3377                 primary_clock.set (pos, 0, true);
3378         }
3379
3380         if (Config->get_secondary_clock_delta_edit_cursor()) {
3381                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3382         } else {
3383                 secondary_clock.set (pos);
3384         }
3385
3386         if (big_clock_window) {
3387                 big_clock.set (pos);
3388         }
3389 }
3390
3391 void
3392 ARDOUR_UI::record_state_changed ()
3393 {
3394         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3395
3396         if (!_session || !big_clock_window) {
3397                 /* why bother - the clock isn't visible */
3398                 return;
3399         }
3400
3401         Session::RecordState const r = _session->record_status ();
3402         bool const h = _session->have_rec_enabled_diskstream ();
3403
3404         if (r == Session::Recording && h)  {
3405                 big_clock.set_widget_name ("BigClockRecording");
3406         } else {
3407                 big_clock.set_widget_name ("BigClockNonRecording");
3408         }
3409 }
3410
3411 bool
3412 ARDOUR_UI::first_idle ()
3413 {
3414         if (_session) {
3415                 _session->allow_auto_play (true);
3416         }
3417
3418         if (editor) {
3419                 editor->first_idle();
3420         }
3421
3422         Keyboard::set_can_save_keybindings (true);
3423         return false;
3424 }
3425
3426 void
3427 ARDOUR_UI::store_clock_modes ()
3428 {
3429         XMLNode* node = new XMLNode(X_("ClockModes"));
3430
3431         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3432                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3433         }
3434
3435         _session->add_extra_xml (*node);
3436         _session->set_dirty ();
3437 }
3438
3439
3440
3441 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3442         : Controllable (name), ui (u), type(tp)
3443 {
3444
3445 }
3446
3447 void
3448 ARDOUR_UI::TransportControllable::set_value (float val)
3449 {
3450         if (type == ShuttleControl) {
3451                 double fract;
3452
3453                 if (val == 0.5f) {
3454                         fract = 0.0;
3455                 } else {
3456                         if (val < 0.5f) {
3457                                 fract = -((0.5f - val)/0.5f);
3458                         } else {
3459                                 fract = ((val - 0.5f)/0.5f);
3460                         }
3461                 }
3462
3463                 ui.set_shuttle_fract (fract);
3464                 return;
3465         }
3466
3467         if (val < 0.5f) {
3468                 /* do nothing: these are radio-style actions */
3469                 return;
3470         }
3471
3472         const char *action = 0;
3473
3474         switch (type) {
3475         case Roll:
3476                 action = X_("Roll");
3477                 break;
3478         case Stop:
3479                 action = X_("Stop");
3480                 break;
3481         case GotoStart:
3482                 action = X_("Goto Start");
3483                 break;
3484         case GotoEnd:
3485                 action = X_("Goto End");
3486                 break;
3487         case AutoLoop:
3488                 action = X_("Loop");
3489                 break;
3490         case PlaySelection:
3491                 action = X_("Play Selection");
3492                 break;
3493         case RecordEnable:
3494                 action = X_("Record");
3495                 break;
3496         default:
3497                 break;
3498         }
3499
3500         if (action == 0) {
3501                 return;
3502         }
3503
3504         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3505
3506         if (act) {
3507                 act->activate ();
3508         }
3509 }
3510
3511 float
3512 ARDOUR_UI::TransportControllable::get_value (void) const
3513 {
3514         float val = 0.0f;
3515
3516         switch (type) {
3517         case Roll:
3518                 break;
3519         case Stop:
3520                 break;
3521         case GotoStart:
3522                 break;
3523         case GotoEnd:
3524                 break;
3525         case AutoLoop:
3526                 break;
3527         case PlaySelection:
3528                 break;
3529         case RecordEnable:
3530                 break;
3531         case ShuttleControl:
3532                 break;
3533         default:
3534                 break;
3535         }
3536
3537         return val;
3538 }
3539
3540 void
3541 ARDOUR_UI::TransportControllable::set_id (const string& str)
3542 {
3543         _id = str;
3544 }
3545
3546 void
3547 ARDOUR_UI::setup_profile ()
3548 {
3549         if (gdk_screen_width() < 1200) {
3550                 Profile->set_small_screen ();
3551         }
3552
3553
3554         if (getenv ("ARDOUR_SAE")) {
3555                 Profile->set_sae ();
3556                 Profile->set_single_package ();
3557         }
3558 }
3559