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