basic adoption of new mouse binding facility
[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
766                                 MessageDialog msg (
767                                         string_compose (_("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 (_("%1 is not connected to JACK\n"
1278                                                              "You cannot open or close sessions in this condition"),
1279                                                            PROGRAM_NAME));
1280                         pop_back_splash ();
1281                         msg.run ();
1282                         return false;
1283                 }
1284                 return true;
1285         } else {
1286                 return false;
1287         }
1288 }
1289
1290 void
1291 ARDOUR_UI::open_session ()
1292 {
1293         if (!check_audioengine()) {
1294                 return;
1295
1296         }
1297
1298         /* popup selector window */
1299
1300         if (open_session_selector == 0) {
1301
1302                 /* ardour sessions are folders */
1303
1304                 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1305                 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1306                 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1307                 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1308
1309                 FileFilter session_filter;
1310                 session_filter.add_pattern ("*.ardour");
1311                 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1312                 open_session_selector->add_filter (session_filter);
1313                 open_session_selector->set_filter (session_filter);
1314         }
1315
1316         int response = open_session_selector->run();
1317         open_session_selector->hide ();
1318
1319         switch (response) {
1320         case RESPONSE_ACCEPT:
1321                 break;
1322         default:
1323                 open_session_selector->hide();
1324                 return;
1325         }
1326
1327         open_session_selector->hide();
1328         string session_path = open_session_selector->get_filename();
1329         string path, name;
1330         bool isnew;
1331
1332         if (session_path.length() > 0) {
1333                 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1334                         _session_is_new = isnew;
1335                         load_session (path, name);
1336                 }
1337         }
1338 }
1339
1340
1341 void
1342 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1343 {
1344         list<boost::shared_ptr<MidiTrack> > tracks;
1345
1346         if (_session == 0) {
1347                 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1348                 return;
1349         }
1350
1351         try {
1352                 if (disk) {
1353
1354                         tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1355
1356                         if (tracks.size() != how_many) {
1357                                 if (how_many == 1) {
1358                                         error << _("could not create a new midi track") << endmsg;
1359                                 } else {
1360                                         error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1361                                 }
1362                         }
1363                 } /*else {
1364                         if ((route = _session->new_midi_route ()) == 0) {
1365                                 error << _("could not create new midi bus") << endmsg;
1366                         }
1367                 }*/
1368         }
1369
1370         catch (...) {
1371                 MessageDialog msg (*editor,
1372                                    string_compose (_("There are insufficient JACK ports available\n\
1373 to create a new track or bus.\n\
1374 You should save %1, exit and\n\
1375 restart JACK with more ports."), PROGRAM_NAME));
1376                 msg.run ();
1377         }
1378 }
1379
1380
1381 void
1382 ARDOUR_UI::session_add_audio_route (
1383         bool track,
1384         int32_t input_channels,
1385         int32_t output_channels,
1386         ARDOUR::TrackMode mode,
1387         RouteGroup* route_group,
1388         uint32_t how_many,
1389         string const & name_template
1390         )
1391 {
1392         list<boost::shared_ptr<AudioTrack> > tracks;
1393         RouteList routes;
1394
1395         if (_session == 0) {
1396                 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1397                 return;
1398         }
1399
1400         try {
1401                 if (track) {
1402                         tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1403
1404                         if (tracks.size() != how_many) {
1405                                 if (how_many == 1) {
1406                                         error << _("could not create a new audio track") << endmsg;
1407                                 } else {
1408                                         error << string_compose (_("could only create %1 of %2 new audio %3"),
1409                                                                  tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1410                                 }
1411                         }
1412
1413                 } else {
1414
1415                         routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1416
1417                         if (routes.size() != how_many) {
1418                                 if (how_many == 1) {
1419                                         error << _("could not create a new audio track") << endmsg;
1420                                 } else {
1421                                         error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1422                                 }
1423                         }
1424                 }
1425         }
1426
1427         catch (...) {
1428                 MessageDialog msg (*editor,
1429                                    string_compose (_("There are insufficient JACK ports available\n\
1430 to create a new track or bus.\n\
1431 You should save %1, exit and\n\
1432 restart JACK with more ports."), PROGRAM_NAME));
1433                 pop_back_splash ();
1434                 msg.run ();
1435         }
1436 }
1437
1438 void
1439 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1440 {
1441         framecnt_t _preroll = 0;
1442
1443         if (_session) {
1444                 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1445                 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1446
1447                 if (new_position > _preroll) {
1448                         new_position -= _preroll;
1449                 } else {
1450                         new_position = 0;
1451                 }
1452
1453                 _session->request_locate (new_position, with_roll);
1454         }
1455 }
1456
1457 void
1458 ARDOUR_UI::transport_goto_start ()
1459 {
1460         if (_session) {
1461                 _session->goto_start();
1462
1463                 /* force displayed area in editor to start no matter
1464                    what "follow playhead" setting is.
1465                 */
1466
1467                 if (editor) {
1468                         editor->center_screen (_session->current_start_frame ());
1469                 }
1470         }
1471 }
1472
1473 void
1474 ARDOUR_UI::transport_goto_zero ()
1475 {
1476         if (_session) {
1477                 _session->request_locate (0);
1478
1479                 /* force displayed area in editor to start no matter
1480                    what "follow playhead" setting is.
1481                 */
1482
1483                 if (editor) {
1484                         editor->reset_x_origin (0);
1485                 }
1486         }
1487 }
1488
1489 void
1490 ARDOUR_UI::transport_goto_wallclock ()
1491 {
1492         if (_session && editor) {
1493
1494                 time_t now;
1495                 struct tm tmnow;
1496                 framepos_t frames;
1497
1498                 time (&now);
1499                 localtime_r (&now, &tmnow);
1500
1501                 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1502                 frames += tmnow.tm_min * (60 * _session->frame_rate());
1503                 frames += tmnow.tm_sec * _session->frame_rate();
1504
1505                 _session->request_locate (frames, _session->transport_rolling ());
1506
1507                 /* force displayed area in editor to start no matter
1508                    what "follow playhead" setting is.
1509                 */
1510
1511                 if (editor) {
1512                         editor->center_screen (frames);
1513                 }
1514         }
1515 }
1516
1517 void
1518 ARDOUR_UI::transport_goto_end ()
1519 {
1520         if (_session) {
1521                 framepos_t const frame = _session->current_end_frame();
1522                 _session->request_locate (frame);
1523
1524                 /* force displayed area in editor to start no matter
1525                    what "follow playhead" setting is.
1526                 */
1527
1528                 if (editor) {
1529                         editor->center_screen (frame);
1530                 }
1531         }
1532 }
1533
1534 void
1535 ARDOUR_UI::transport_stop ()
1536 {
1537         if (!_session) {
1538                 return;
1539         }
1540
1541         if (_session->is_auditioning()) {
1542                 _session->cancel_audition ();
1543                 return;
1544         }
1545
1546         _session->request_stop (false, true);
1547 }
1548
1549 void
1550 ARDOUR_UI::transport_stop_and_forget_capture ()
1551 {
1552         if (_session) {
1553                 _session->request_stop (true, true);
1554         }
1555 }
1556
1557 void
1558 ARDOUR_UI::remove_last_capture()
1559 {
1560         if (editor) {
1561                 editor->remove_last_capture();
1562         }
1563 }
1564
1565 void
1566 ARDOUR_UI::transport_record (bool roll)
1567 {
1568
1569         if (_session) {
1570                 switch (_session->record_status()) {
1571                 case Session::Disabled:
1572                         if (_session->ntracks() == 0) {
1573                                 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1574                                 msg.run ();
1575                                 return;
1576                         }
1577                         _session->maybe_enable_record ();
1578                         if (roll) {
1579                                 transport_roll ();
1580                         }
1581                         break;
1582                 case Session::Recording:
1583                         if (roll) {
1584                                 _session->request_stop();
1585                         } else {
1586                                 _session->disable_record (false, true);
1587                         }
1588                         break;
1589
1590                 case Session::Enabled:
1591                         _session->disable_record (false, true);
1592                 }
1593         }
1594         //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1595 }
1596
1597 void 
1598 ARDOUR_UI::transport_roll ()
1599 {
1600         if (!_session) {
1601                 return;
1602         }
1603
1604         if (_session->is_auditioning()) {
1605                 return;
1606         }
1607
1608 #if 0
1609         if (_session->config.get_external_sync()) {
1610                 switch (_session->config.get_sync_source()) {
1611                 case JACK:
1612                         break;
1613                 default:
1614                         /* transport controlled by the master */
1615                         return;
1616                 }
1617         }
1618 #endif
1619
1620         bool rolling = _session->transport_rolling();
1621
1622         if (_session->get_play_loop()) {
1623                 /* XXX it is not possible to just leave seamless loop and keep
1624                    playing at present (nov 4th 2009)
1625                 */
1626                 if (!Config->get_seamless_loop()) {
1627                         _session->request_play_loop (false, true);
1628                 }
1629         } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1630                 /* stop playing a range if we currently are */
1631                 _session->request_play_range (0, true);
1632         }
1633
1634         if (join_play_range_button.get_active()) {
1635                 _session->request_play_range (&editor->get_selection().time, true);
1636         }
1637
1638         if (!rolling) {
1639                 _session->request_transport_speed (1.0f);
1640         }
1641 }
1642
1643 void
1644 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1645 {
1646         
1647         if (!_session) {
1648                 return;
1649         }
1650
1651         if (_session->is_auditioning()) {
1652                 _session->cancel_audition ();
1653                 return;
1654         }
1655
1656 #if 0
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 #endif
1667
1668         bool rolling = _session->transport_rolling();
1669         bool affect_transport = true;
1670
1671         if (rolling && roll_out_of_bounded_mode) {
1672                 /* drop out of loop/range playback but leave transport rolling */
1673                 if (_session->get_play_loop()) {
1674                         if (Config->get_seamless_loop()) {
1675                                 /* the disk buffers contain copies of the loop - we can't 
1676                                    just keep playing, so stop the transport. the user
1677                                    can restart as they wish.
1678                                 */
1679                                 affect_transport = true;
1680                         } else {
1681                                 /* disk buffers are normal, so we can keep playing */
1682                                 affect_transport = false;
1683                         }
1684                         _session->request_play_loop (false, true);
1685                 } else if (_session->get_play_range ()) {
1686                         affect_transport = false;
1687                         _session->request_play_range (0, true);
1688                 } 
1689         } 
1690
1691         if (affect_transport) {
1692                 if (rolling) {
1693                         _session->request_stop (with_abort, true);
1694                 } else {
1695                         if (join_play_range_button.get_active()) {
1696                                 _session->request_play_range (&editor->get_selection().time, true);
1697                         }
1698                         
1699                         _session->request_transport_speed (1.0f);
1700                 }
1701         }
1702 }
1703
1704 void
1705 ARDOUR_UI::toggle_session_auto_loop ()
1706 {
1707         if (!_session) {
1708                 return;
1709         }
1710         
1711         if (_session->get_play_loop()) {
1712
1713                 if (_session->transport_rolling()) {
1714                   
1715                         Location * looploc = _session->locations()->auto_loop_location();
1716                         
1717                         if (looploc) {
1718                                 _session->request_locate (looploc->start(), true);
1719                                 _session->request_play_loop (false);
1720                         }
1721                         
1722                 } else {
1723                         _session->request_play_loop (false);
1724                 }
1725         } else {
1726                 
1727           Location * looploc = _session->locations()->auto_loop_location();
1728                 
1729                 if (looploc) {
1730                         _session->request_play_loop (true);
1731                 }
1732         }
1733 }
1734
1735 void
1736 ARDOUR_UI::transport_play_selection ()
1737 {
1738         if (!_session) {
1739                 return;
1740         }
1741
1742         editor->play_selection ();
1743 }
1744
1745 void
1746 ARDOUR_UI::transport_rewind (int option)
1747 {
1748         float current_transport_speed;
1749
1750         if (_session) {
1751                 current_transport_speed = _session->transport_speed();
1752
1753                 if (current_transport_speed >= 0.0f) {
1754                         switch (option) {
1755                         case 0:
1756                                 _session->request_transport_speed (-1.0f);
1757                                 break;
1758                         case 1:
1759                                 _session->request_transport_speed (-4.0f);
1760                                 break;
1761                         case -1:
1762                                 _session->request_transport_speed (-0.5f);
1763                                 break;
1764                         }
1765                 } else {
1766                         /* speed up */
1767                         _session->request_transport_speed (current_transport_speed * 1.5f);
1768                 }
1769         }
1770 }
1771
1772 void
1773 ARDOUR_UI::transport_forward (int option)
1774 {
1775         float current_transport_speed;
1776
1777         if (_session) {
1778                 current_transport_speed = _session->transport_speed();
1779
1780                 if (current_transport_speed <= 0.0f) {
1781                         switch (option) {
1782                         case 0:
1783                                 _session->request_transport_speed (1.0f);
1784                                 break;
1785                         case 1:
1786                                 _session->request_transport_speed (4.0f);
1787                                 break;
1788                         case -1:
1789                                 _session->request_transport_speed (0.5f);
1790                                 break;
1791                         }
1792                 } else {
1793                         /* speed up */
1794                         _session->request_transport_speed (current_transport_speed * 1.5f);
1795                 }
1796
1797         }
1798 }
1799
1800 void
1801 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1802 {
1803         if (_session == 0) {
1804                 return;
1805         }
1806
1807         boost::shared_ptr<Route> r;
1808
1809         if ((r = _session->route_by_remote_id (rid)) != 0) {
1810
1811                 Track* t;
1812
1813                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1814                         t->set_record_enabled (!t->record_enabled(), this);
1815                 }
1816         }
1817         if (_session == 0) {
1818                 return;
1819         }
1820 }
1821
1822 void
1823 ARDOUR_UI::map_transport_state ()
1824 {
1825         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1826
1827         if (!_session) {
1828                 auto_loop_button.set_visual_state (0);
1829                 play_selection_button.set_visual_state (0);
1830                 roll_button.set_visual_state (0);
1831                 stop_button.set_visual_state (1);
1832                 return;
1833         }
1834
1835         float sp = _session->transport_speed();
1836
1837         if (sp == 1.0f) {
1838                 shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
1839                 shuttle_box.queue_draw ();
1840         } else if (sp == 0.0f) {
1841                 shuttle_fract = 0;
1842                 shuttle_box.queue_draw ();
1843                 update_disk_space ();
1844         }
1845
1846         if (sp != 0.0) {
1847
1848                 /* we're rolling */
1849
1850                 if (_session->get_play_range()) {
1851
1852                         play_selection_button.set_visual_state (1);
1853                         roll_button.set_visual_state (0);
1854                         auto_loop_button.set_visual_state (0);
1855
1856                 } else if (_session->get_play_loop ()) {
1857                         
1858                         auto_loop_button.set_visual_state (1);
1859                         play_selection_button.set_visual_state (0);
1860                         roll_button.set_visual_state (0);
1861
1862                 } else {
1863                         
1864                         roll_button.set_visual_state (1);
1865                         play_selection_button.set_visual_state (0);
1866                         auto_loop_button.set_visual_state (0);
1867                 }
1868
1869                 if (join_play_range_button.get_active()) {
1870                         /* light up both roll and play-selection if they are joined */
1871                         roll_button.set_visual_state (1);
1872                         play_selection_button.set_visual_state (1);
1873                 }
1874
1875                 stop_button.set_visual_state (0);
1876
1877         } else {
1878
1879                 stop_button.set_visual_state (1);
1880                 roll_button.set_visual_state (0);
1881                 play_selection_button.set_visual_state (0);
1882                 auto_loop_button.set_visual_state (0);
1883         }
1884 }
1885
1886 void
1887 ARDOUR_UI::engine_stopped ()
1888 {
1889         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1890         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1891         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1892 }
1893
1894 void
1895 ARDOUR_UI::engine_running ()
1896 {
1897         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1898         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1899         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1900
1901         Glib::RefPtr<Action> action;
1902         const char* action_name = 0;
1903
1904         switch (engine->frames_per_cycle()) {
1905         case 32:
1906                 action_name = X_("JACKLatency32");
1907                 break;
1908         case 64:
1909                 action_name = X_("JACKLatency64");
1910                 break;
1911         case 128:
1912                 action_name = X_("JACKLatency128");
1913                 break;
1914         case 512:
1915                 action_name = X_("JACKLatency512");
1916                 break;
1917         case 1024:
1918                 action_name = X_("JACKLatency1024");
1919                 break;
1920         case 2048:
1921                 action_name = X_("JACKLatency2048");
1922                 break;
1923         case 4096:
1924                 action_name = X_("JACKLatency4096");
1925                 break;
1926         case 8192:
1927                 action_name = X_("JACKLatency8192");
1928                 break;
1929         default:
1930                 /* XXX can we do anything useful ? */
1931                 break;
1932         }
1933
1934         if (action_name) {
1935
1936                 action = ActionManager::get_action (X_("JACK"), action_name);
1937
1938                 if (action) {
1939                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1940                         ract->set_active ();
1941                 }
1942         }
1943 }
1944
1945 void
1946 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1947 {
1948         if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1949                 /* we can't rely on the original string continuing to exist when we are called
1950                    again in the GUI thread, so make a copy and note that we need to
1951                    free it later.
1952                 */
1953                 char *copy = strdup (reason);
1954                 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1955                 return;
1956         }
1957
1958         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1959         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1960
1961         update_sample_rate (0);
1962
1963         string msgstr;
1964
1965         /* if the reason is a non-empty string, it means that the backend was shutdown
1966            rather than just Ardour.
1967         */
1968
1969         if (strlen (reason)) {
1970                 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1971         } else {
1972                 msgstr = string_compose (_("\
1973 JACK has either been shutdown or it\n\
1974 disconnected %1 because %1\n\
1975 was not fast enough. Try to restart\n\
1976 JACK, reconnect and save the session."), PROGRAM_NAME);
1977         }
1978
1979         MessageDialog msg (*editor, msgstr);
1980         pop_back_splash ();
1981         msg.run ();
1982
1983         if (free_reason) {
1984                 free ((char*) reason);
1985         }
1986 }
1987
1988 int32_t
1989 ARDOUR_UI::do_engine_start ()
1990 {
1991         try {
1992                 engine->start();
1993         }
1994
1995         catch (...) {
1996                 engine->stop ();
1997                 error << _("Unable to start the session running")
1998                       << endmsg;
1999                 unload_session ();
2000                 return -2;
2001         }
2002
2003         return 0;
2004 }
2005
2006 void
2007 ARDOUR_UI::setup_theme ()
2008 {
2009         theme_manager->setup_theme();
2010 }
2011
2012 void
2013 ARDOUR_UI::update_clocks ()
2014 {
2015         if (!editor || !editor->dragging_playhead()) {
2016                 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2017         }
2018 }
2019
2020 void
2021 ARDOUR_UI::start_clocking ()
2022 {
2023         clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2024 }
2025
2026 void
2027 ARDOUR_UI::stop_clocking ()
2028 {
2029         clock_signal_connection.disconnect ();
2030 }
2031
2032 void
2033 ARDOUR_UI::toggle_clocking ()
2034 {
2035 #if 0
2036         if (clock_button.get_active()) {
2037                 start_clocking ();
2038         } else {
2039                 stop_clocking ();
2040         }
2041 #endif
2042 }
2043
2044 gint
2045 ARDOUR_UI::_blink (void *arg)
2046
2047 {
2048         ((ARDOUR_UI *) arg)->blink ();
2049         return TRUE;
2050 }
2051
2052 void
2053 ARDOUR_UI::blink ()
2054 {
2055         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2056 }
2057
2058 void
2059 ARDOUR_UI::start_blinking ()
2060 {
2061         /* Start the blink signal. Everybody with a blinking widget
2062            uses Blink to drive the widget's state.
2063         */
2064
2065         if (blink_timeout_tag < 0) {
2066                 blink_on = false;
2067                 blink_timeout_tag = g_timeout_add (240, _blink, this);
2068         }
2069 }
2070
2071 void
2072 ARDOUR_UI::stop_blinking ()
2073 {
2074         if (blink_timeout_tag >= 0) {
2075                 g_source_remove (blink_timeout_tag);
2076                 blink_timeout_tag = -1;
2077         }
2078 }
2079
2080
2081 /** Ask the user for the name of a new shapshot and then take it.
2082  */
2083
2084 void
2085 ARDOUR_UI::snapshot_session (bool switch_to_it)
2086 {
2087         ArdourPrompter prompter (true);
2088         string snapname;
2089
2090         prompter.set_name ("Prompter");
2091         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2092         prompter.set_title (_("Take Snapshot"));
2093         prompter.set_title (_("Take Snapshot"));
2094         prompter.set_prompt (_("Name of new snapshot"));
2095
2096         if (!switch_to_it) {
2097                 char timebuf[128];
2098                 time_t n;
2099                 struct tm local_time;
2100                 
2101                 time (&n);
2102                 localtime_r (&n, &local_time);
2103                 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2104                 prompter.set_initial_text (timebuf);
2105         }
2106
2107   again:
2108         switch (prompter.run()) {
2109         case RESPONSE_ACCEPT:
2110         {
2111                 prompter.get_result (snapname);
2112
2113                 bool do_save = (snapname.length() != 0);
2114
2115                 if (do_save) {
2116                         if (snapname.find ('/') != string::npos) {
2117                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2118                                                      "snapshot names may not contain a '/' character"));
2119                                 msg.run ();
2120                                 goto again;
2121                         }
2122                         if (snapname.find ('\\') != string::npos) {
2123                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2124                                                      "snapshot names may not contain a '\\' character"));
2125                                 msg.run ();
2126                                 goto again;
2127                         }
2128                 }
2129
2130                 vector<sys::path> p;
2131                 get_state_files_in_directory (_session->session_directory().root_path(), p);
2132                 vector<string> n = get_file_names_no_extension (p);
2133                 if (find (n.begin(), n.end(), snapname) != n.end()) {
2134
2135                         ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2136                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
2137                         confirm.get_vbox()->pack_start (m, true, true);
2138                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2139                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2140                         confirm.show_all ();
2141                         switch (confirm.run()) {
2142                         case RESPONSE_CANCEL:
2143                                 do_save = false;
2144                         }
2145                 }
2146
2147                 if (do_save) {
2148                         save_state (snapname, switch_to_it);
2149                 }
2150                 break;
2151         }
2152
2153         default:
2154                 break;
2155         }
2156 }
2157
2158 void
2159 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2160 {
2161         XMLNode* node = new XMLNode (X_("UI"));
2162
2163         for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2164                 if (!(*i)->rc_configured()) {
2165                         node->add_child_nocopy (*((*i)->get_state ()));
2166                 }
2167         }
2168
2169         _session->add_extra_xml (*node);
2170         
2171         save_state_canfail (name, switch_to_it);
2172 }
2173
2174 int
2175 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2176 {
2177         if (_session) {
2178                 int ret;
2179
2180                 if (name.length() == 0) {
2181                         name = _session->snap_name();
2182                 }
2183
2184                 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2185                         return ret;
2186                 }
2187         }
2188         cerr << "SS canfail\n";
2189         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2190         return 0;
2191 }
2192
2193 void
2194 ARDOUR_UI::primary_clock_value_changed ()
2195 {
2196         if (_session) {
2197                 _session->request_locate (primary_clock.current_time ());
2198         }
2199 }
2200
2201 void
2202 ARDOUR_UI::big_clock_value_changed ()
2203 {
2204         if (_session) {
2205                 _session->request_locate (big_clock.current_time ());
2206         }
2207 }
2208
2209 void
2210 ARDOUR_UI::secondary_clock_value_changed ()
2211 {
2212         if (_session) {
2213                 _session->request_locate (secondary_clock.current_time ());
2214         }
2215 }
2216
2217 void
2218 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2219 {
2220         if (_session == 0) {
2221                 return;
2222         }
2223
2224         if (_session->step_editing()) {
2225                 return;
2226         }
2227
2228         Session::RecordState const r = _session->record_status ();
2229         bool const h = _session->have_rec_enabled_track ();
2230
2231         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2232                 if (onoff) {
2233                         rec_button.set_visual_state (2);
2234                 } else {
2235                         rec_button.set_visual_state (0);
2236                 }
2237         } else if (r == Session::Recording && h) {
2238                 rec_button.set_visual_state (1);
2239         } else {
2240                 rec_button.set_visual_state (0);
2241         }
2242 }
2243
2244 void
2245 ARDOUR_UI::save_template ()
2246 {
2247         ArdourPrompter prompter (true);
2248         string name;
2249
2250         if (!check_audioengine()) {
2251                 return;
2252         }
2253
2254         prompter.set_name (X_("Prompter"));
2255         prompter.set_title (_("Save Template"));
2256         prompter.set_prompt (_("Name for template:"));
2257         prompter.set_initial_text(_session->name() + _("-template"));
2258         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2259
2260         switch (prompter.run()) {
2261         case RESPONSE_ACCEPT:
2262                 prompter.get_result (name);
2263
2264                 if (name.length()) {
2265                         _session->save_template (name);
2266                 }
2267                 break;
2268
2269         default:
2270                 break;
2271         }
2272 }
2273
2274 void
2275 ARDOUR_UI::edit_metadata ()
2276 {
2277         SessionMetadataEditor dialog;
2278         dialog.set_session (_session);
2279         editor->ensure_float (dialog);
2280         dialog.run ();
2281 }
2282
2283 void
2284 ARDOUR_UI::import_metadata ()
2285 {
2286         SessionMetadataImporter dialog;
2287         dialog.set_session (_session);
2288         editor->ensure_float (dialog);
2289         dialog.run ();
2290 }
2291
2292 void
2293 ARDOUR_UI::fontconfig_dialog ()
2294 {
2295 #ifdef GTKOSX
2296         /* X11 users will always have fontconfig info around, but new GTK-OSX users
2297            may not and it can take a while to build it. Warn them.
2298         */
2299
2300         std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2301
2302         if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2303                 MessageDialog msg (*_startup,
2304                                    string_compose (_("Welcome to %1.\n\n"
2305                                                      "The program will take a bit longer to start up\n"
2306                                                      "while the system fonts are checked.\n\n"
2307                                                      "This will only be done once, and you will\n"
2308                                                      "not see this message again\n"), PROGRAM_NAME),
2309                                    true,
2310                                    Gtk::MESSAGE_INFO,
2311                                    Gtk::BUTTONS_OK);
2312                 pop_back_splash ();
2313                 msg.show_all ();
2314                 msg.present ();
2315                 msg.run ();
2316         }
2317 #endif
2318 }
2319
2320 void
2321 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2322 {
2323         existing_session = false;
2324
2325         if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2326                 session_path = cmdline_path;
2327                 existing_session = true;
2328         } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2329                 session_path = Glib::path_get_dirname (string (cmdline_path));
2330                 existing_session = true;
2331         } else {
2332                 /* it doesn't exist, assume the best */
2333                 session_path = Glib::path_get_dirname (string (cmdline_path));
2334         }
2335
2336         session_name = basename_nosuffix (string (cmdline_path));
2337 }
2338
2339 int
2340 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2341 {
2342         /* when this is called, the backend audio system must be running */
2343
2344         /* the main idea here is to deal with the fact that a cmdline argument for the session
2345            can be interpreted in different ways - it could be a directory or a file, and before
2346            we load, we need to know both the session directory and the snapshot (statefile) within it
2347            that we are supposed to use.
2348         */
2349
2350         if (session_name.length() == 0 || session_path.length() == 0) {
2351                 return false;
2352         }
2353
2354         if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2355
2356                 std::string predicted_session_file;
2357
2358                 predicted_session_file = session_path;
2359                 predicted_session_file += '/';
2360                 predicted_session_file += session_name;
2361                 predicted_session_file += ARDOUR::statefile_suffix;
2362
2363                 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2364                         existing_session = true;
2365                 }
2366
2367         } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2368
2369                 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2370                         /* existing .ardour file */
2371                         existing_session = true;
2372                 }
2373
2374         } else {
2375                 existing_session = false;
2376         }
2377
2378         /* lets just try to load it */
2379
2380         if (create_engine ()) {
2381                 backend_audio_error (false, _startup);
2382                 return -1;
2383         }
2384
2385         return load_session (session_path, session_name);
2386 }
2387
2388 bool
2389 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2390 {
2391         std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2392
2393         MessageDialog msg (str,
2394                            false,
2395                            Gtk::MESSAGE_WARNING,
2396                            Gtk::BUTTONS_YES_NO,
2397                            true);
2398
2399
2400         msg.set_name (X_("OpenExistingDialog"));
2401         msg.set_title (_("Open Existing Session"));
2402         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2403         msg.set_position (Gtk::WIN_POS_MOUSE);
2404         pop_back_splash ();
2405
2406         switch (msg.run()) {
2407         case RESPONSE_YES:
2408                 return true;
2409                 break;
2410         }
2411         return false;
2412 }
2413
2414 int
2415 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2416 {
2417         BusProfile bus_profile;
2418
2419         if (Profile->get_sae()) {
2420
2421                 bus_profile.master_out_channels = 2;
2422                 bus_profile.input_ac = AutoConnectPhysical;
2423                 bus_profile.output_ac = AutoConnectMaster;
2424                 bus_profile.requested_physical_in = 0; // use all available
2425                 bus_profile.requested_physical_out = 0; // use all available
2426
2427         } else {
2428
2429                 /* get settings from advanced section of NSD */
2430
2431                 if (_startup->create_master_bus()) {
2432                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2433                 } else {
2434                         bus_profile.master_out_channels = 0;
2435                 }
2436
2437                 if (_startup->connect_inputs()) {
2438                         bus_profile.input_ac = AutoConnectPhysical;
2439                 } else {
2440                         bus_profile.input_ac = AutoConnectOption (0);
2441                 }
2442
2443                 /// @todo some minor tweaks.
2444                 
2445                 bus_profile.output_ac = AutoConnectOption (0);
2446
2447                 if (_startup->connect_outputs ()) {
2448                         if (_startup->connect_outs_to_master()) {
2449                                 bus_profile.output_ac = AutoConnectMaster;
2450                         } else if (_startup->connect_outs_to_physical()) {
2451                                 bus_profile.output_ac = AutoConnectPhysical;
2452                         }
2453                 }
2454
2455                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2456                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2457         }
2458
2459         if (build_session (session_path, session_name, bus_profile)) {
2460                 return -1;
2461         }
2462
2463         return 0;
2464 }
2465
2466 void
2467 ARDOUR_UI::idle_load (const std::string& path)
2468 {
2469         if (_session) {
2470                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2471                         /* /path/to/foo => /path/to/foo, foo */
2472                         load_session (path, basename_nosuffix (path));
2473                 } else {
2474                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2475                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2476                 }
2477         } else {
2478
2479                 ARDOUR_COMMAND_LINE::session_name = path;
2480
2481                 /*
2482                  * new_session_dialog doens't exist in A3
2483                  * Try to remove all references to it to
2484                  * see if it will compile.  NOTE: this will
2485                  * likely cause a runtime issue is my somewhat
2486                  * uneducated guess.
2487                  */
2488
2489                 //if (new_session_dialog) {
2490
2491
2492                         /* make it break out of Dialog::run() and
2493                            start again.
2494                          */
2495
2496                         //new_session_dialog->response (1);
2497                 //}
2498         }
2499 }
2500
2501 void
2502 ARDOUR_UI::end_loading_messages ()
2503 {
2504         // hide_splash ();
2505 }
2506
2507 void
2508 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2509 {
2510         // show_splash ();
2511         // splash->message (msg);
2512         flush_pending ();
2513 }
2514
2515 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2516 int
2517 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2518 {
2519         string session_name;
2520         string session_path;
2521         string template_name;
2522         int ret = -1;
2523         bool likely_new = false;
2524
2525         if (! load_template.empty()) {
2526                 should_be_new = true;
2527                 template_name = load_template;
2528         }
2529
2530         while (ret != 0) {
2531
2532                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2533
2534                         /* if they named a specific statefile, use it, otherwise they are
2535                            just giving a session folder, and we want to use it as is
2536                            to find the session.
2537                         */
2538
2539                         if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2540                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2541                         } else {
2542                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2543                         }
2544
2545                         session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2546
2547                 } else {
2548
2549                         bool const apply = run_startup (should_be_new, load_template);
2550
2551                         if (!apply) {
2552                                 if (quit_on_cancel) {
2553                                         exit (1);
2554                                 } else {
2555                                         return ret;
2556                                 }
2557                         }
2558
2559                         /* if we run the startup dialog again, offer more than just "new session" */
2560
2561                         should_be_new = false;
2562
2563                         session_name = _startup->session_name (likely_new);
2564
2565                         /* this shouldn't happen, but we catch it just in case it does */
2566
2567                         if (session_name.empty()) {
2568                                 continue;
2569                         }
2570
2571                         if (_startup->use_session_template()) {
2572                                 template_name = _startup->session_template_name();
2573                                 _session_is_new = true;
2574                         }
2575
2576                         if (session_name[0] == G_DIR_SEPARATOR ||
2577                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2578                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2579
2580                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2581                                    from what was given.
2582                                 */
2583                                 
2584                                 session_path = Glib::path_get_dirname (session_name);
2585                                 session_name = Glib::path_get_basename (session_name);
2586
2587                         } else {
2588
2589                                 session_path = _startup->session_folder();
2590
2591                                 if (session_name.find ('/') != string::npos) {
2592                                         MessageDialog msg (*_startup, _("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, _("To ensure compatibility with various systems\n"
2601                                                                         "session names may not contain a '\\' character"));
2602                                         msg.run ();
2603                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2604                                         continue;
2605                                 }
2606                         }
2607                 }
2608
2609                 if (create_engine ()) {
2610                         break;
2611                 }
2612
2613                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2614
2615                         if (likely_new) {
2616
2617                                 std::string existing = Glib::build_filename (session_path, session_name);
2618
2619                                 if (!ask_about_loading_existing_session (existing)) {
2620                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2621                                         continue;
2622                                 }
2623                         }
2624
2625                         _session_is_new = false;
2626
2627                 } else {
2628
2629                         if (!likely_new) {
2630                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2631                                 msg.run ();
2632                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2633                                 continue;
2634                         }
2635
2636                         if (session_name.find ('/') != std::string::npos) {
2637                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2638                                                                 "session names may not contain a '/' character"));
2639                                 msg.run ();
2640                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2641                                 continue;
2642                         }
2643
2644                         if (session_name.find ('\\') != std::string::npos) {
2645                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2646                                                                 "session names may not contain a '\\' character"));
2647                                 msg.run ();
2648                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2649                                 continue;
2650                         }
2651
2652                         _session_is_new = true;
2653                 }
2654
2655                 if (likely_new && template_name.empty()) {
2656
2657                         ret = build_session_from_nsd (session_path, session_name);
2658
2659                 } else {
2660
2661                         ret = load_session (session_path, session_name, template_name);
2662
2663                         if (ret == -2) {
2664                                 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2665                                 exit (1);
2666                         }
2667                         
2668                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2669                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2670                                 exit (1);
2671                         }
2672                 }
2673         }
2674
2675         return ret;
2676 }
2677
2678 void
2679 ARDOUR_UI::close_session()
2680 {
2681         if (!check_audioengine()) {
2682                 return;
2683         }
2684
2685         if (unload_session (true)) {
2686                 return;
2687         }
2688
2689         ARDOUR_COMMAND_LINE::session_name = "";
2690
2691         if (get_session_parameters (true, false)) {
2692                 exit (1);
2693         }
2694
2695         goto_editor_window ();
2696 }
2697
2698 /** @return -2 if the load failed because we are not connected to the AudioEngine */
2699 int
2700 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2701 {
2702         Session *new_session;
2703         int unload_status;
2704         int retval = -1;
2705
2706         session_loaded = false;
2707
2708         if (!check_audioengine()) {
2709                 return -2;
2710         }
2711
2712         unload_status = unload_session ();
2713
2714         if (unload_status < 0) {
2715                 goto out;
2716         } else if (unload_status > 0) {
2717                 retval = 0;
2718                 goto out;
2719         }
2720
2721         loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2722
2723         try {
2724                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2725         }
2726
2727         /* this one is special */
2728
2729         catch (AudioEngine::PortRegistrationFailure& err) {
2730
2731                 MessageDialog msg (err.what(),
2732                                    true,
2733                                    Gtk::MESSAGE_INFO,
2734                                    Gtk::BUTTONS_CLOSE);
2735
2736                 msg.set_title (_("Port Registration Error"));
2737                 msg.set_secondary_text (_("Click the Close button to try again."));
2738                 msg.set_position (Gtk::WIN_POS_CENTER);
2739                 pop_back_splash ();
2740                 msg.present ();
2741
2742                 int response = msg.run ();
2743
2744                 msg.hide ();
2745
2746                 switch (response) {
2747                 case RESPONSE_CANCEL:
2748                         exit (1);
2749                 default:
2750                         break;
2751                 }
2752                 goto out;
2753         }
2754
2755         catch (...) {
2756
2757                 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2758                                    true,
2759                                    Gtk::MESSAGE_INFO,
2760                                    BUTTONS_OK);
2761
2762                 msg.set_title (_("Loading Error"));
2763                 msg.set_secondary_text (_("Click the Refresh button to try again."));
2764                 msg.add_button (Stock::REFRESH, 1);
2765                 msg.set_position (Gtk::WIN_POS_CENTER);
2766                 pop_back_splash ();
2767                 msg.present ();
2768
2769                 int response = msg.run ();
2770
2771                 switch (response) {
2772                 case 1:
2773                         break;
2774                 default:
2775                         exit (1);
2776                 }
2777
2778                 msg.hide ();
2779
2780                 goto out;
2781         }
2782
2783         {
2784                 list<string> const u = new_session->unknown_processors ();
2785                 if (!u.empty()) {
2786                         MissingPluginDialog d (_session, u);
2787                         d.run ();
2788                 }
2789         }
2790
2791         /* Now the session been created, add the transport controls */
2792         new_session->add_controllable(roll_controllable);
2793         new_session->add_controllable(stop_controllable);
2794         new_session->add_controllable(goto_start_controllable);
2795         new_session->add_controllable(goto_end_controllable);
2796         new_session->add_controllable(auto_loop_controllable);
2797         new_session->add_controllable(play_selection_controllable);
2798         new_session->add_controllable(rec_controllable);
2799
2800         set_session (new_session);
2801
2802         session_loaded = true;
2803
2804         goto_editor_window ();
2805
2806         if (_session) {
2807                 _session->set_clean ();
2808         }
2809
2810         flush_pending ();
2811         retval = 0;
2812
2813   out:
2814         return retval;
2815 }
2816
2817 int
2818 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2819 {
2820         Session *new_session;
2821         int x;
2822
2823         if (!check_audioengine()) {
2824                 return -1;
2825         }
2826
2827         session_loaded = false;
2828
2829         x = unload_session ();
2830
2831         if (x < 0) {
2832                 return -1;
2833         } else if (x > 0) {
2834                 return 0;
2835         }
2836
2837         _session_is_new = true;
2838
2839         try {
2840                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2841         }
2842
2843         catch (...) {
2844
2845                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2846                 pop_back_splash ();
2847                 msg.run ();
2848                 return -1;
2849         }
2850
2851         /* Give the new session the default GUI state, if such things exist */
2852
2853         XMLNode* n;
2854         n = Config->instant_xml (X_("Editor"));
2855         if (n) {
2856                 new_session->add_instant_xml (*n, false);
2857         }
2858         n = Config->instant_xml (X_("Mixer"));
2859         if (n) {
2860                 new_session->add_instant_xml (*n, false);
2861         }
2862
2863         /* Put the playhead at 0 and scroll fully left */
2864         n = new_session->instant_xml (X_("Editor"));
2865         if (n) {
2866                 n->add_property (X_("playhead"), X_("0"));
2867                 n->add_property (X_("left-frame"), X_("0"));
2868         }
2869
2870         set_session (new_session);
2871
2872         session_loaded = true;
2873
2874         new_session->save_state(new_session->name());
2875
2876         return 0;
2877 }
2878
2879 void
2880 ARDOUR_UI::launch_chat ()
2881 {
2882 #ifdef __APPLE__
2883         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2884 #else
2885         open_uri("http://webchat.freenode.net/?channels=ardour");
2886 #endif
2887 }
2888
2889 void
2890 ARDOUR_UI::show_about ()
2891 {
2892         if (about == 0) {
2893                 about = new About;
2894                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2895         }
2896
2897         about->set_transient_for(*editor);
2898         about->show_all ();
2899 }
2900
2901 void
2902 ARDOUR_UI::launch_manual ()
2903 {
2904         PBD::open_uri("http://ardour.org/flossmanual");
2905 }
2906
2907 void
2908 ARDOUR_UI::launch_reference ()
2909 {
2910         PBD::open_uri("http://ardour.org/refmanual");
2911 }
2912
2913 void
2914 ARDOUR_UI::hide_about ()
2915 {
2916         if (about) {
2917                 about->get_window()->set_cursor ();
2918                 about->hide ();
2919         }
2920 }
2921
2922 void
2923 ARDOUR_UI::about_signal_response (int /*response*/)
2924 {
2925         hide_about();
2926 }
2927
2928 void
2929 ARDOUR_UI::show_splash ()
2930 {
2931         if (splash == 0) {
2932                 try {
2933                         splash = new Splash;
2934                 } catch (...) {
2935                         return;
2936                 }
2937         }
2938
2939         splash->show ();
2940         splash->present ();
2941         splash->queue_draw ();
2942         splash->get_window()->process_updates (true);
2943         flush_pending ();
2944 }
2945
2946 void
2947 ARDOUR_UI::hide_splash ()
2948 {
2949         if (splash) {
2950                 splash->hide();
2951         }
2952 }
2953
2954 void
2955 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2956                                     const string& plural_msg, const string& singular_msg)
2957 {
2958         size_t removed;
2959
2960         removed = rep.paths.size();
2961
2962         if (removed == 0) {
2963                 MessageDialog msgd (*editor,
2964                                     _("No files were ready for cleanup"),
2965                                     true,
2966                                     Gtk::MESSAGE_INFO,
2967                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2968                 msgd.set_secondary_text (_("If this seems suprising, \n\
2969 check for any existing snapshots.\n\
2970 These may still include regions that\n\
2971 require some unused files to continue to exist."));
2972
2973                 msgd.run ();
2974                 return;
2975         }
2976
2977         ArdourDialog results (_("Clean-up"), true, false);
2978
2979         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2980             CleanupResultsModelColumns() {
2981                     add (visible_name);
2982                     add (fullpath);
2983             }
2984             Gtk::TreeModelColumn<std::string> visible_name;
2985             Gtk::TreeModelColumn<std::string> fullpath;
2986         };
2987
2988
2989         CleanupResultsModelColumns results_columns;
2990         Glib::RefPtr<Gtk::ListStore> results_model;
2991         Gtk::TreeView results_display;
2992
2993         results_model = ListStore::create (results_columns);
2994         results_display.set_model (results_model);
2995         results_display.append_column (list_title, results_columns.visible_name);
2996
2997         results_display.set_name ("CleanupResultsList");
2998         results_display.set_headers_visible (true);
2999         results_display.set_headers_clickable (false);
3000         results_display.set_reorderable (false);
3001
3002         Gtk::ScrolledWindow list_scroller;
3003         Gtk::Label txt;
3004         Gtk::VBox dvbox;
3005         Gtk::HBox dhbox;  // the hbox for the image and text
3006         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3007         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
3008
3009         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3010
3011         const string dead_directory = _session->session_directory().dead_path().to_string();
3012
3013         /* subst:
3014            %1 - number of files removed
3015            %2 - location of "dead"
3016            %3 - size of files affected
3017            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3018         */
3019
3020         const char* bprefix;
3021         double space_adjusted = 0;
3022
3023         if (rep.space < 1000) {
3024                 bprefix = X_("");
3025                 space_adjusted = rep.space;
3026         } else if (rep.space < 1000000) {
3027                         bprefix = X_("kilo");
3028                 space_adjusted = truncf((float)rep.space / 1000.0);
3029         } else if (rep.space < 1000000 * 1000) {
3030                 bprefix = X_("mega");
3031                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3032         } else {
3033                 bprefix = X_("giga");
3034                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3035         }
3036
3037         if (removed > 1) {
3038                 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3039         } else {
3040                 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3041         }
3042
3043         dhbox.pack_start (*dimage, true, false, 5);
3044         dhbox.pack_start (txt, true, false, 5);
3045
3046         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3047                 TreeModel::Row row = *(results_model->append());
3048                 row[results_columns.visible_name] = *i;
3049                 row[results_columns.fullpath] = *i;
3050         }
3051
3052         list_scroller.add (results_display);
3053         list_scroller.set_size_request (-1, 150);
3054         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3055
3056         dvbox.pack_start (dhbox, true, false, 5);
3057         dvbox.pack_start (list_scroller, true, false, 5);
3058         ddhbox.pack_start (dvbox, true, false, 5);
3059
3060         results.get_vbox()->pack_start (ddhbox, true, false, 5);
3061         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3062         results.set_default_response (RESPONSE_CLOSE);
3063         results.set_position (Gtk::WIN_POS_MOUSE);
3064
3065         results_display.show();
3066         list_scroller.show();
3067         txt.show();
3068         dvbox.show();
3069         dhbox.show();
3070         ddhbox.show();
3071         dimage->show();
3072
3073         //results.get_vbox()->show();
3074         results.set_resizable (false);
3075
3076         results.run ();
3077
3078 }        
3079
3080 void
3081 ARDOUR_UI::cleanup ()
3082 {
3083         if (_session == 0) {
3084                 /* shouldn't happen: menu item is insensitive */
3085                 return;
3086         }
3087
3088
3089         MessageDialog  checker (_("Are you sure you want to cleanup?"),
3090                                 true,
3091                                 Gtk::MESSAGE_QUESTION,
3092                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3093
3094         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3095 ALL undo/redo information will be lost if you cleanup.\n\
3096 Cleanup will move all unused files to a \"dead\" location."));
3097
3098         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3099         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3100         checker.set_default_response (RESPONSE_CANCEL);
3101
3102         checker.set_name (_("CleanupDialog"));
3103         checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3104         checker.set_position (Gtk::WIN_POS_MOUSE);
3105
3106         switch (checker.run()) {
3107         case RESPONSE_ACCEPT:
3108                 break;
3109         default:
3110                 return;
3111         }
3112
3113         ARDOUR::CleanupReport rep;
3114
3115         editor->prepare_for_cleanup ();
3116
3117         /* do not allow flush until a session is reloaded */
3118
3119         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3120         if (act) {
3121                 act->set_sensitive (false);
3122         }
3123
3124         if (_session->cleanup_sources (rep)) {
3125                 editor->finish_cleanup ();
3126                 return;
3127         }
3128
3129         editor->finish_cleanup ();
3130
3131         checker.hide();
3132         display_cleanup_results (rep,
3133                                  _("cleaned files"),
3134                                  _("\
3135 The following %1 files were not in use and \n\
3136 have been moved to:\n\n\
3137 %2\n\n\
3138 After a restart of Ardour,\n\n\
3139 Session -> Cleanup -> Flush Wastebasket\n\n\
3140 will release an additional\n\
3141 %3 %4bytes of disk space.\n"),
3142                                  _("\
3143 The following file was not in use and \n        \
3144 has been moved to:\n                            \
3145 %2\n\n\
3146 After a restart of Ardour,\n\n\
3147 Session -> Cleanup -> Flush Wastebasket\n\n\
3148 will release an additional\n\
3149 %3 %4bytes of disk space.\n"
3150                                          ));
3151
3152 }
3153
3154 void
3155 ARDOUR_UI::flush_trash ()
3156 {
3157         if (_session == 0) {
3158                 /* shouldn't happen: menu item is insensitive */
3159                 return;
3160         }
3161
3162         ARDOUR::CleanupReport rep;
3163
3164         if (_session->cleanup_trash_sources (rep)) {
3165                 return;
3166         }
3167
3168         display_cleanup_results (rep,
3169                                  _("deleted file"),
3170                                  _("The following %1 files were deleted from\n\
3171 %2,\n\
3172 releasing %3 %4bytes of disk space"),
3173                                  _("The following file was deleted from\n\
3174 %2,\n\
3175 releasing %3 %4bytes of disk space"));
3176 }
3177
3178 void
3179 ARDOUR_UI::add_route (Gtk::Window* float_window)
3180 {
3181         int count;
3182
3183         if (!_session) {
3184                 return;
3185         }
3186
3187         if (add_route_dialog == 0) {
3188                 add_route_dialog = new AddRouteDialog (_session);
3189                 if (float_window) {
3190                         add_route_dialog->set_transient_for (*float_window);
3191                 }
3192         }
3193
3194         if (add_route_dialog->is_visible()) {
3195                 /* we're already doing this */
3196                 return;
3197         }
3198
3199         ResponseType r = (ResponseType) add_route_dialog->run ();
3200
3201         add_route_dialog->hide();
3202
3203         switch (r) {
3204                 case RESPONSE_ACCEPT:
3205                         break;
3206                 default:
3207                         return;
3208                         break;
3209         }
3210
3211         if ((count = add_route_dialog->count()) <= 0) {
3212                 return;
3213         }
3214
3215         string template_path = add_route_dialog->track_template();
3216
3217         if (!template_path.empty()) {
3218                 _session->new_route_from_template (count, template_path);
3219                 return;
3220         }
3221
3222         uint32_t input_chan = add_route_dialog->channels ();
3223         uint32_t output_chan;
3224         string name_template = add_route_dialog->name_template ();
3225         bool track = add_route_dialog->track ();
3226         RouteGroup* route_group = add_route_dialog->route_group ();
3227
3228         AutoConnectOption oac = Config->get_output_auto_connect();
3229
3230         if (oac & AutoConnectMaster) {
3231                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3232         } else {
3233                 output_chan = input_chan;
3234         }
3235
3236         /* XXX do something with name template */
3237
3238         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3239                 if (track) {
3240                         session_add_midi_track (route_group, count, name_template);
3241                 } else  {
3242                         MessageDialog msg (*editor,
3243                                         _("Sorry, MIDI Busses are not supported at this time."));
3244                         msg.run ();
3245                         //session_add_midi_bus();
3246                 }
3247         } else {
3248                 if (track) {
3249                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3250                 } else {
3251                         session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3252                 }
3253         }
3254 }
3255
3256 XMLNode*
3257 ARDOUR_UI::mixer_settings () const
3258 {
3259         XMLNode* node = 0;
3260
3261         if (_session) {
3262                 node = _session->instant_xml(X_("Mixer"));
3263         } else {
3264                 node = Config->instant_xml(X_("Mixer"));
3265         }
3266
3267         if (!node) {
3268                 node = new XMLNode (X_("Mixer"));
3269         }
3270
3271         return node;
3272 }
3273
3274 XMLNode*
3275 ARDOUR_UI::editor_settings () const
3276 {
3277         XMLNode* node = 0;
3278
3279         if (_session) {
3280                 node = _session->instant_xml(X_("Editor"));
3281         } else {
3282                 node = Config->instant_xml(X_("Editor"));
3283         }
3284         
3285         if (!node) {
3286                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3287                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3288                 }
3289         }
3290
3291         if (!node) {
3292                 node = new XMLNode (X_("Editor"));
3293         }
3294
3295         return node;
3296 }
3297
3298 XMLNode*
3299 ARDOUR_UI::keyboard_settings () const
3300 {
3301         XMLNode* node = 0;
3302
3303         node = Config->extra_xml(X_("Keyboard"));
3304
3305         if (!node) {
3306                 node = new XMLNode (X_("Keyboard"));
3307         }
3308
3309         return node;
3310 }
3311
3312 void
3313 ARDOUR_UI::create_xrun_marker (framepos_t where)
3314 {
3315         editor->mouse_add_new_marker (where, false, true);
3316 }
3317
3318 void
3319 ARDOUR_UI::halt_on_xrun_message ()
3320 {
3321         MessageDialog msg (*editor,
3322                            _("Recording was stopped because your system could not keep up."));
3323         msg.run ();
3324 }
3325
3326 void
3327 ARDOUR_UI::xrun_handler (framepos_t where)
3328 {
3329         if (!_session) {
3330                 return;
3331         }
3332
3333         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3334
3335         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3336                 create_xrun_marker(where);
3337         }
3338
3339         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3340                 halt_on_xrun_message ();
3341         }
3342 }
3343
3344 void
3345 ARDOUR_UI::disk_overrun_handler ()
3346 {
3347         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3348
3349         if (!have_disk_speed_dialog_displayed) {
3350                 have_disk_speed_dialog_displayed = true;
3351                 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3352 The disk system on your computer\n\
3353 was not able to keep up with %1.\n\
3354 \n\
3355 Specifically, it failed to write data to disk\n\
3356 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3357                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3358                 msg->show ();
3359         }
3360 }
3361
3362 void
3363 ARDOUR_UI::disk_underrun_handler ()
3364 {
3365         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3366
3367         if (!have_disk_speed_dialog_displayed) {
3368                 have_disk_speed_dialog_displayed = true;
3369                 MessageDialog* msg = new MessageDialog (*editor,
3370                                                         string_compose (_("The disk system on your computer\n\
3371 was not able to keep up with %1.\n\
3372 \n\
3373 Specifically, it failed to read data from disk\n\
3374 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3375                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3376                 msg->show ();
3377         }
3378 }
3379
3380 void
3381 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3382 {
3383         have_disk_speed_dialog_displayed = false;
3384         delete msg;
3385 }
3386
3387 void
3388 ARDOUR_UI::session_dialog (std::string msg)
3389 {
3390         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3391
3392         MessageDialog* d;
3393
3394         if (editor) {
3395                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3396         } else {
3397                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3398         }
3399
3400         d->show_all ();
3401         d->run ();
3402         delete d;
3403 }
3404
3405 int
3406 ARDOUR_UI::pending_state_dialog ()
3407 {
3408         HBox* hbox = new HBox();
3409         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3410         ArdourDialog dialog (_("Crash Recovery"), true);
3411         Label  message (_("\
3412 This session appears to have been in\n\
3413 middle of recording when ardour or\n\
3414 the computer was shutdown.\n\
3415 \n\
3416 Ardour can recover any captured audio for\n\
3417 you, or it can ignore it. Please decide\n\
3418 what you would like to do.\n"));
3419         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3420         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3421         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3422         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3423         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3424         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3425         dialog.set_default_response (RESPONSE_ACCEPT);
3426         dialog.set_position (WIN_POS_CENTER);
3427         message.show();
3428         image->show();
3429         hbox->show();
3430
3431         switch (dialog.run ()) {
3432         case RESPONSE_ACCEPT:
3433                 return 1;
3434         default:
3435                 return 0;
3436         }
3437 }
3438
3439 int
3440 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3441 {
3442         HBox* hbox = new HBox();
3443         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3444         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3445         Label  message (string_compose (_("\
3446 This session was created with a sample rate of %1 Hz\n\
3447 \n\
3448 The audioengine is currently running at %2 Hz\n"), desired, actual));
3449
3450         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3451         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3452         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3453         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3454         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3455         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3456         dialog.set_default_response (RESPONSE_ACCEPT);
3457         dialog.set_position (WIN_POS_CENTER);
3458         message.show();
3459         image->show();
3460         hbox->show();
3461
3462         switch (dialog.run ()) {
3463         case RESPONSE_ACCEPT:
3464                 return 0;
3465         default:
3466                 return 1;
3467         }
3468 }
3469
3470
3471 void
3472 ARDOUR_UI::disconnect_from_jack ()
3473 {
3474         if (engine) {
3475                 if( engine->disconnect_from_jack ()) {
3476                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3477                         msg.run ();
3478                 }
3479
3480                 update_sample_rate (0);
3481         }
3482 }
3483
3484 void
3485 ARDOUR_UI::reconnect_to_jack ()
3486 {
3487         if (engine) {
3488                 if (engine->reconnect_to_jack ()) {
3489                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3490                         msg.run ();
3491                 }
3492
3493                 update_sample_rate (0);
3494         }
3495 }
3496
3497 void
3498 ARDOUR_UI::use_config ()
3499 {
3500         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3501         if (node) {
3502                 set_transport_controllable_state (*node);
3503         }
3504 }
3505
3506 void
3507 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3508 {
3509         if (Config->get_primary_clock_delta_edit_cursor()) {
3510                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3511         } else {
3512                 primary_clock.set (pos, 0, true);
3513         }
3514
3515         if (Config->get_secondary_clock_delta_edit_cursor()) {
3516                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3517         } else {
3518                 secondary_clock.set (pos);
3519         }
3520
3521         if (big_clock_window->get()) {
3522                 big_clock.set (pos);
3523         }
3524 }
3525
3526
3527 void
3528 ARDOUR_UI::step_edit_status_change (bool yn)
3529 {
3530         // XXX should really store pre-step edit status of things
3531         // we make insensitive
3532
3533         if (yn) {
3534                 rec_button.set_visual_state (3);
3535                 rec_button.set_sensitive (false);
3536         } else {
3537                 rec_button.set_visual_state (0);
3538                 rec_button.set_sensitive (true);
3539         }
3540 }
3541
3542 void
3543 ARDOUR_UI::record_state_changed ()
3544 {
3545         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3546
3547         if (!_session || !big_clock_window->get()) {
3548                 /* why bother - the clock isn't visible */
3549                 return;
3550         }
3551
3552         Session::RecordState const r = _session->record_status ();
3553         bool const h = _session->have_rec_enabled_track ();
3554
3555         if (r == Session::Recording && h)  {
3556                 big_clock.set_widget_name ("BigClockRecording");
3557         } else {
3558                 big_clock.set_widget_name ("BigClockNonRecording");
3559         }
3560 }
3561
3562 bool
3563 ARDOUR_UI::first_idle ()
3564 {
3565         if (_session) {
3566                 _session->allow_auto_play (true);
3567         }
3568
3569         if (editor) {
3570                 editor->first_idle();
3571         }
3572
3573         Keyboard::set_can_save_keybindings (true);
3574         return false;
3575 }
3576
3577 void
3578 ARDOUR_UI::store_clock_modes ()
3579 {
3580         XMLNode* node = new XMLNode(X_("ClockModes"));
3581
3582         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3583                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3584         }
3585
3586         _session->add_extra_xml (*node);
3587         _session->set_dirty ();
3588 }
3589
3590
3591
3592 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3593         : Controllable (name), ui (u), type(tp)
3594 {
3595
3596 }
3597
3598 void
3599 ARDOUR_UI::TransportControllable::set_value (double val)
3600 {
3601         if (type == ShuttleControl) {
3602                 double fract;
3603
3604                 if (val == 0.5) {
3605                         fract = 0.0;
3606                 } else {
3607                         if (val < 0.5) {
3608                                 fract = -((0.5 - val)/0.5);
3609                         } else {
3610                                 fract = ((val - 0.5)/0.5);
3611                         }
3612                 }
3613
3614                 ui.set_shuttle_fract (fract);
3615                 return;
3616         }
3617
3618         if (val < 0.5) {
3619                 /* do nothing: these are radio-style actions */
3620                 return;
3621         }
3622
3623         const char *action = 0;
3624
3625         switch (type) {
3626         case Roll:
3627                 action = X_("Roll");
3628                 break;
3629         case Stop:
3630                 action = X_("Stop");
3631                 break;
3632         case GotoStart:
3633                 action = X_("Goto Start");
3634                 break;
3635         case GotoEnd:
3636                 action = X_("Goto End");
3637                 break;
3638         case AutoLoop:
3639                 action = X_("Loop");
3640                 break;
3641         case PlaySelection:
3642                 action = X_("Play Selection");
3643                 break;
3644         case RecordEnable:
3645                 action = X_("Record");
3646                 break;
3647         default:
3648                 break;
3649         }
3650
3651         if (action == 0) {
3652                 return;
3653         }
3654
3655         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3656
3657         if (act) {
3658                 act->activate ();
3659         }
3660 }
3661
3662 double
3663 ARDOUR_UI::TransportControllable::get_value (void) const
3664 {
3665         float val = 0.0;
3666
3667         switch (type) {
3668         case Roll:
3669                 break;
3670         case Stop:
3671                 break;
3672         case GotoStart:
3673                 break;
3674         case GotoEnd:
3675                 break;
3676         case AutoLoop:
3677                 break;
3678         case PlaySelection:
3679                 break;
3680         case RecordEnable:
3681                 break;
3682         case ShuttleControl:
3683                 break;
3684         default:
3685                 break;
3686         }
3687
3688         return val;
3689 }
3690
3691 void
3692 ARDOUR_UI::TransportControllable::set_id (const string& str)
3693 {
3694         _id = str;
3695 }
3696
3697 void
3698 ARDOUR_UI::setup_profile ()
3699 {
3700         if (gdk_screen_width() < 1200) {
3701                 Profile->set_small_screen ();
3702         }
3703
3704
3705         if (getenv ("ARDOUR_SAE")) {
3706                 Profile->set_sae ();
3707                 Profile->set_single_package ();
3708         }
3709 }
3710
3711 void
3712 ARDOUR_UI::toggle_translations ()
3713 {
3714         using namespace Glib;
3715         
3716         RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3717         if (act) {
3718                 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3719                 if (ract) {
3720                         
3721                         string i18n_killer = ARDOUR::translation_kill_path();
3722                         
3723                         bool already_enabled = !ARDOUR::translations_are_disabled ();
3724                         
3725                         if (ract->get_active ()) {
3726 /* we don't care about errors */
3727                                 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3728                                 close (fd);
3729                         } else {
3730 /* we don't care about errors */
3731                                 unlink (i18n_killer.c_str());
3732                         }
3733                         
3734                         if (already_enabled != ract->get_active()) {
3735                                 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3736                                                    false,
3737                                                    Gtk::MESSAGE_WARNING,
3738                                                    Gtk::BUTTONS_OK);
3739                                 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3740                                 win.set_position (Gtk::WIN_POS_CENTER);
3741                                 win.present ();
3742                                 win.run ();
3743                         }
3744                 }
3745         }
3746 }        
3747
3748 /** Add a window proxy to our list, so that its state will be saved.
3749  *  This call also causes the window to be created and opened if its
3750  *  state was saved as `visible'.
3751  */
3752 void
3753 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3754 {
3755         _window_proxies.push_back (p);
3756         p->maybe_show ();
3757 }
3758
3759 /** Remove a window proxy from our list.  Must be called if a WindowProxy
3760  *  is deleted, to prevent hanging pointers.
3761  */
3762 void
3763 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3764 {
3765         _window_proxies.remove (p);
3766 }
3767
3768 int
3769 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3770 {
3771         MissingFileDialog dialog (s, str, type);
3772
3773         dialog.show ();
3774         dialog.present ();
3775
3776         int result = dialog.run ();
3777         dialog.hide ();
3778
3779         switch (result) {
3780         case RESPONSE_OK:
3781                 break;
3782         default:
3783                 return 1; // quit entire session load
3784         }
3785
3786         result = dialog.get_action ();
3787
3788         return result;
3789 }
3790
3791 int
3792 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3793 {
3794         AmbiguousFileDialog dialog (file, hits);
3795
3796         dialog.show ();
3797         dialog.present ();
3798
3799         dialog.run ();
3800         return dialog.get_which ();
3801 }