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