basic adoption of new mouse binding facility
[ardour.git] / gtk2_ardour / main.cc
1 /*
2     Copyright (C) 2001-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 #include <cstdlib>
21 #include <signal.h>
22 #include <cerrno>
23 #include <fstream>
24
25 #include <sigc++/bind.h>
26 #include <gtkmm/settings.h>
27
28 #include "pbd/error.h"
29 #include "pbd/epa.h"
30 #include "pbd/file_utils.h"
31 #include "pbd/textreceiver.h"
32 #include "pbd/failed_constructor.h"
33 #include "pbd/pthread_utils.h"
34 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
35 #include "pbd/boost_debug.h"
36 #endif
37
38 #include <jack/jack.h>
39
40 #include "ardour/svn_revision.h"
41 #include "ardour/version.h"
42 #include "ardour/ardour.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/session_utils.h"
45 #include "ardour/filesystem_paths.h"
46
47 #include <gtkmm/main.h>
48 #include <gtkmm2ext/application.h>
49 #include <gtkmm2ext/popup.h>
50 #include <gtkmm2ext/utils.h>
51
52 #include "version.h"
53 #include "utils.h"
54 #include "ardour_ui.h"
55 #include "opts.h"
56 #include "enums.h"
57
58 #include "i18n.h"
59
60 using namespace std;
61 using namespace Gtk;
62 using namespace ARDOUR_COMMAND_LINE;
63 using namespace ARDOUR;
64 using namespace PBD;
65
66 TextReceiver text_receiver ("ardour");
67
68 extern int curvetest (string);
69
70 static ARDOUR_UI  *ui = 0;
71 static const char* localedir = LOCALEDIR;
72
73 void
74 gui_jack_error ()
75 {
76         MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
77                      false,
78                      Gtk::MESSAGE_INFO,
79                      (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
80 win.set_secondary_text(_("There are several possible reasons:\n\
81 \n\
82 1) JACK is not running.\n\
83 2) JACK is running as another user, perhaps root.\n\
84 3) There is already another client called \"ardour\".\n\
85 \n\
86 Please consider the possibilities, and perhaps (re)start JACK."));
87
88         win.add_button (Stock::QUIT, RESPONSE_CLOSE);
89         win.set_default_response (RESPONSE_CLOSE);
90
91         win.show_all ();
92         win.set_position (Gtk::WIN_POS_CENTER);
93
94         if (!no_splash) {
95                 ui->hide_splash ();
96         }
97
98         /* we just don't care about the result, but we want to block */
99
100         win.run ();
101 }
102
103
104 #ifdef __APPLE__
105
106 #include <mach-o/dyld.h>
107 #include <sys/param.h>
108
109 extern void set_language_preference (); // cocoacarbon.mm
110
111 void
112 fixup_bundle_environment (int, char* [])
113 {
114         if (!getenv ("ARDOUR_BUNDLED")) {
115                 return;
116         }
117
118         EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
119
120         set_language_preference ();
121
122         char execpath[MAXPATHLEN+1];
123         uint32_t pathsz = sizeof (execpath);
124
125         _NSGetExecutablePath (execpath, &pathsz);
126
127         std::string exec_path (execpath);
128         std::string dir_path = Glib::path_get_dirname (exec_path);
129         std::string path;
130         const char *cstr = getenv ("PATH");
131
132         /* ensure that we find any bundled executables (e.g. JACK),
133            and find them before any instances of the same name
134            elsewhere in PATH
135         */
136
137         path = dir_path;
138
139         /* JACK is often in /usr/local/bin and since Info.plist refuses to 
140            set PATH, we have to force this in order to discover a running
141            instance of JACK ...
142         */
143         
144         path += ':';
145         path += "/usr/local/bin";
146
147         if (cstr) {
148                 path += ':';
149                 path += cstr;
150         }
151         setenv ("PATH", path.c_str(), 1);
152
153         path = dir_path;
154         path += "/../Resources";
155         path += dir_path;
156         path += "/../Resources/Surfaces";
157         path += dir_path;
158         path += "/../Resources/Panners";
159
160         setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
161
162         path = user_config_directory().to_string();
163         path += ':';
164         path += dir_path;
165         path += "/../Resources/icons:";
166         path += dir_path;
167         path += "/../Resources/pixmaps:";
168         path += dir_path;
169         path += "/../Resources/share:";
170         path += dir_path;
171         path += "/../Resources";
172
173         setenv ("ARDOUR_PATH", path.c_str(), 1);
174         setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
175
176         path = dir_path;
177         path += "/../Resources";
178         setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
179
180         cstr = getenv ("LADSPA_PATH");
181         if (cstr) {
182                 path = cstr;
183                 path += ':';
184         } else {
185                 path = "";
186         }
187         path += dir_path;
188         path += "/../Plugins";
189
190         setenv ("LADSPA_PATH", path.c_str(), 1);
191
192         cstr = getenv ("VAMP_PATH");
193         if (cstr) {
194                 path = cstr;
195                 path += ':';
196         } else {
197                 path = "";
198         }
199         path += dir_path;
200         path += "/../Frameworks";
201
202         setenv ("VAMP_PATH", path.c_str(), 1);
203
204         cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
205         if (cstr) {
206                 path = cstr;
207                 path += ':';
208         } else {
209                 path = "";
210         }
211         path += dir_path;
212         path += "/../Surfaces";
213
214         setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
215
216         cstr = getenv ("ARDOUR_PANNER_PATH");
217         if (cstr) {
218                 path = cstr;
219                 path += ':';
220         } else {
221                 path = "";
222         }
223         path += dir_path;
224         path += "/lib/panners";
225         
226         setenv ("ARDOUR_PANNER_PATH", path.c_str(), 1);
227
228         path = dir_path;
229         path += "/../Frameworks/clearlooks";
230
231         setenv ("GTK_PATH", path.c_str(), 1);
232
233         /* unset GTK_RC_FILES so that we only load the RC files that we define
234          */
235
236         unsetenv ("GTK_RC_FILES");
237
238         if (!ARDOUR::translations_are_disabled ()) {
239
240                 path = dir_path;
241                 path += "/../Resources/locale";
242                 
243                 localedir = strdup (path.c_str());
244                 setenv ("GTK_LOCALEDIR", localedir, 1);
245         }
246
247         /* write a pango.rc file and tell pango to use it. we'd love
248            to put this into the PROGRAM_NAME.app bundle and leave it there,
249            but the user may not have write permission. so ...
250
251            we also have to make sure that the user ardour directory
252            actually exists ...
253         */
254
255         try {
256                 sys::create_directories (user_config_directory ());
257         }
258         catch (const sys::filesystem_error& ex) {
259                 error << _("Could not create user configuration directory") << endmsg;
260         }
261
262         sys::path pangopath = user_config_directory();
263         pangopath /= "pango.rc";
264         path = pangopath.to_string();
265
266         std::ofstream pangorc (path.c_str());
267         if (!pangorc) {
268                 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
269                 return;
270         } else {
271                 pangorc << "[Pango]\nModuleFiles=";
272
273                 pangopath = dir_path;
274                 pangopath /= "..";
275                 pangopath /= "Resources";
276                 pangopath /= "pango.modules";
277
278                 pangorc << pangopath.to_string() << endl;
279
280                 pangorc.close ();
281
282                 setenv ("PANGO_RC_FILE", path.c_str(), 1);
283         }
284
285         // gettext charset aliases
286
287         setenv ("CHARSETALIASDIR", path.c_str(), 1);
288
289         // font config
290
291         path = dir_path;
292         path += "/../Resources/fonts.conf";
293
294         setenv ("FONTCONFIG_FILE", path.c_str(), 1);
295
296         // GDK Pixbuf loader module file
297
298         path = dir_path;
299         path += "/../Resources/gdk-pixbuf.loaders";
300
301         setenv ("GDK_PIXBUF_MODULE_FILE", path.c_str(), 1);
302
303         if (getenv ("ARDOUR_WITH_JACK")) {
304                 // JACK driver dir
305
306                 path = dir_path;
307                 path += "/../Frameworks";
308
309                 setenv ("JACK_DRIVER_DIR", path.c_str(), 1);
310         }
311 }
312
313 #else
314
315 void
316 fixup_bundle_environment (int /*argc*/, char* argv[])
317 {
318         if (!getenv ("ARDOUR_BUNDLED")) {
319                 return;
320         }
321         
322         EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
323
324         Glib::ustring exec_path = argv[0];
325         Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (exec_path));
326         Glib::ustring path;
327         const char *cstr = getenv ("PATH");
328         Glib::ustring userconfigdir = user_config_directory().to_string();
329
330         /* ensure that we find any bundled executables (e.g. JACK),
331            and find them before any instances of the same name
332            elsewhere in PATH
333         */
334
335         /* note that this function is POSIX/Linux specific, so using / as 
336            a dir separator in this context is just fine.
337         */
338
339         path = dir_path;
340         path += "/etc:";
341         path += dir_path;
342         path += "/lib/surfaces:";
343         path += dir_path;
344         path += "/lib/panners:";
345
346         setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
347
348         path = userconfigdir;
349         path += ':';
350         path += dir_path;
351         path += "/etc/icons:";
352         path += dir_path;
353         path += "/etc/pixmaps:";
354         path += dir_path;
355         path += "/share:";
356         path += dir_path;
357         path += "/etc";
358
359         setenv ("ARDOUR_PATH", path.c_str(), 1);
360         setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
361
362         path = dir_path;
363         path += "/etc";
364         setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
365
366         cstr = getenv ("LADSPA_PATH");
367         if (cstr) {
368                 path = cstr;
369                 path += ':';
370         } else {
371                 path = "";
372         }
373         path += dir_path;
374         path += "/lib/plugins";
375         
376         setenv ("LADSPA_PATH", path.c_str(), 1);
377
378         cstr = getenv ("VAMP_PATH");
379         if (cstr) {
380                 path = cstr;
381                 path += ':';
382         } else {
383                 path = "";
384         }
385         path += dir_path;
386         path += "/lib";
387         
388         setenv ("VAMP_PATH", path.c_str(), 1);
389
390         cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
391         if (cstr) {
392                 path = cstr;
393                 path += ':';
394         } else {
395                 path = "";
396         }
397         path += dir_path;
398         path += "/lib/surfaces";
399         
400         setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
401
402         cstr = getenv ("ARDOUR_PANNER_PATH");
403         if (cstr) {
404                 path = cstr;
405                 path += ':';
406         } else {
407                 path = "";
408         }
409         path += dir_path;
410         path += "/lib/panners";
411         
412         setenv ("ARDOUR_PANNER_PATH", path.c_str(), 1);
413
414         path = dir_path;
415         path += "/lib/clearlooks";
416
417         setenv ("GTK_PATH", path.c_str(), 1);
418
419         /* unset GTK_RC_FILES so that we only load the RC files that we define
420          */
421
422         unsetenv ("GTK_RC_FILES");
423
424         if (!ARDOUR::translations_are_disabled ()) {
425                 path = dir_path;
426                 path += "/share/locale";
427                 
428                 localedir = strdup (path.c_str());
429                 setenv ("GTK_LOCALEDIR", localedir, 1);
430         }
431
432         /* write a pango.rc file and tell pango to use it. we'd love
433            to put this into the Ardour.app bundle and leave it there,
434            but the user may not have write permission. so ... 
435
436            we also have to make sure that the user ardour directory
437            actually exists ...
438         */
439
440         if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
441                 error << string_compose (_("cannot create user ardour folder %1 (%2)"), userconfigdir, strerror (errno))
442                       << endmsg;
443         } else {
444
445                 Glib::ustring mpath;
446
447                 path = Glib::build_filename (userconfigdir, "pango.rc");
448
449                 std::ofstream pangorc (path.c_str());
450                 if (!pangorc) {
451                         error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
452                 } else {
453                         mpath = Glib::build_filename (userconfigdir, "pango.modules");
454                         
455                         pangorc << "[Pango]\nModuleFiles=";
456                         pangorc << mpath << endl;
457                         pangorc.close ();
458                 }
459
460                 setenv ("PANGO_RC_FILE", path.c_str(), 1);
461
462                 /* similar for GDK pixbuf loaders, but there's no RC file required
463                    to specify where it lives.
464                 */
465
466                 mpath = Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders");
467                 setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
468         }
469 }
470
471 #endif
472
473 static gboolean
474 tell_about_jack_death (void* /* ignored */)
475 {
476         if (AudioEngine::instance()->processed_frames() == 0) {
477                 /* died during startup */
478                 MessageDialog msg (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
479                 msg.set_position (Gtk::WIN_POS_CENTER);
480                 msg.set_secondary_text (string_compose (_(
481 "JACK exited unexpectedly, and without notifying %1.\n\
482 \n\
483 This could be due to misconfiguration or to an error inside JACK.\n\
484 \n\
485 Click OK to exit %1."), PROGRAM_NAME));
486     
487                 msg.run ();
488                 _exit (0);
489                 
490         } else {
491
492                 /* engine has already run, so this is a mid-session JACK death */
493                 
494                 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE));
495                 msg->set_secondary_text (string_compose (_(
496 "JACK exited unexpectedly, and without notifying %1.\n\
497 \n\
498 This is probably due to an error inside JACK. You should restart JACK\n\
499 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
500 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
501                 msg->present ();
502         }
503         return false; /* do not call again */
504 }
505
506 static void
507 sigpipe_handler (int /*signal*/)
508 {
509         /* XXX fix this so that we do this again after a reconnect to JACK
510          */
511
512         static bool done_the_jack_thing = false;
513         
514         if (!done_the_jack_thing) {
515                 AudioEngine::instance()->died ();
516                 g_idle_add (tell_about_jack_death, 0);
517                 done_the_jack_thing =  true;
518         }
519 }
520
521 #ifdef HAVE_LV2
522 void close_external_ui_windows();
523 #endif
524
525 #ifdef VST_SUPPORT
526
527 extern int gui_init (int* argc, char** argv[]);
528
529 /* this is called from the entry point of a wine-compiled
530    executable that is linked against gtk2_ardour built
531    as a shared library.
532 */
533 extern "C" {
534 int ardour_main (int argc, char *argv[])
535 #else
536 int main (int argc, char *argv[])
537 #endif
538 {
539         fixup_bundle_environment (argc, argv);
540
541         if (!Glib::thread_supported()) {
542                 Glib::thread_init();
543         }
544
545         gtk_set_locale ();
546
547 #ifdef VST_SUPPORT
548         /* this does some magic that is needed to make GTK and Wine's own
549            X11 client interact properly.
550         */
551         gui_init (&argc, &argv);
552 #endif
553
554         (void) bindtextdomain (PACKAGE, localedir);
555         /* our i18n translations are all in UTF-8, so make sure
556            that even if the user locale doesn't specify UTF-8,
557            we use that when handling them.
558         */
559         (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
560         (void) textdomain (PACKAGE);
561
562         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
563
564         // catch error message system signals ();
565
566         text_receiver.listen_to (error);
567         text_receiver.listen_to (info);
568         text_receiver.listen_to (fatal);
569         text_receiver.listen_to (warning);
570
571 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
572         if (getenv ("BOOST_DEBUG")) {
573                 boost_debug_shared_ptr_show_live_debugging (true);
574         }
575 #endif
576
577         if (parse_opts (argc, argv)) {
578                 exit (1);
579         }
580
581         if (curvetest_file) {
582                 return curvetest (curvetest_file);
583         }
584
585         cout << PROGRAM_NAME
586              << VERSIONSTRING
587              << _(" (built using ")
588              << svn_revision
589 #ifdef __GNUC__
590              << _(" and GCC version ") << __VERSION__
591 #endif
592              << ')'
593              << endl;
594
595         if (just_version) {
596                 exit (0);
597         }
598
599         if (no_splash) {
600                 cerr << _("Copyright (C) 1999-2011 Paul Davis") << endl
601                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
602                      << endl
603                      << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
604                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
605                      << _("This is free software, and you are welcome to redistribute it ") << endl
606                      << _("under certain conditions; see the source for copying conditions.")
607                      << endl;
608         }
609
610         /* some GUI objects need this */
611
612         PBD::ID::init ();
613
614         if (::signal (SIGPIPE, sigpipe_handler)) {
615                 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
616         }
617
618         try {
619                 ui = new ARDOUR_UI (&argc, &argv);
620         } catch (failed_constructor& err) {
621                 error << _("could not create ARDOUR GUI") << endmsg;
622                 exit (1);
623         }
624
625         ui->run (text_receiver);
626         Gtkmm2ext::Application::instance()->cleanup();
627         ui = 0;
628
629         ARDOUR::cleanup ();
630         pthread_cancel_all ();
631
632 #ifdef HAVE_LV2
633         close_external_ui_windows();
634 #endif
635         return 0;
636 }
637 #ifdef VST_SUPPORT
638 } // end of extern C block
639 #endif
640