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