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