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