d949b899c5f06b82e106702c032eb8acb6b29388
[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 += "/../Surfaces";
171         path += ':';
172         path += dir_path;
173         path += "/../Panners";
174
175         setenv ("ARDOUR_DLL_PATH", path.c_str(), 1);
176
177         path += dir_path;
178         path += "/../Resources";
179
180         /* inside an OS X .app bundle, there is no difference
181            between DATA and CONFIG locations, since OS X doesn't
182            attempt to do anything to expose the notion of
183            machine-independent shared data.
184         */
185
186         setenv ("ARDOUR_DATA_PATH", path.c_str(), 1);
187         setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
188         setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
189
190         export_search_path (dir_path, "LADSPA_PATH", "/../Plugins");
191         export_search_path (dir_path, "VAMP_PATH", "/../Frameworks");
192
193         /* in theory these do not need to be set since they would be found
194            using ARDOUR_DATA_PATH or ARDOUR_CONFIG_PATH suffixed by a suitable
195            folder/directory name. However, the way we bundle Ardour on OS X
196            uses Capitalized names for these folders which differs from
197            the hard-coded folder/directory name. In addition each of them
198            lives at the top level of the .app/Contents tree, rather
199            than within Resources or Frameworks.
200         */
201         
202         export_search_path (dir_path, "ARDOUR_PANNER_PATH", "/../Panners");
203         export_search_path (dir_path, "ARDOUR_SURFACES_PATH", "/../Surfaces");
204         export_search_path (dir_path, "ARDOUR_MIDIMAPS_PATH", "/../MidiMaps");
205         export_search_path (dir_path, "ARDOUR_MCP_PATH", "../MCP");
206         export_search_path (dir_path, "ARDOUR_EXPORT_FORMATS_PATH", "/../ExportFormats");
207
208         path = dir_path;
209         path += "/../Frameworks/clearlooks";
210
211         setenv ("GTK_PATH", path.c_str(), 1);
212
213         /* unset GTK_RC_FILES so that we only load the RC files that we define
214          */
215
216         unsetenv ("GTK_RC_FILES");
217
218         if (!ARDOUR::translations_are_disabled ()) {
219
220                 path = dir_path;
221                 path += "/../Resources/locale";
222
223                 localedir = strdup (path.c_str());
224                 setenv ("GTK_LOCALEDIR", localedir, 1);
225         }
226
227         /* write a pango.rc file and tell pango to use it. we'd love
228            to put this into the PROGRAM_NAME.app bundle and leave it there,
229            but the user may not have write permission. so ...
230
231            we also have to make sure that the user ardour directory
232            actually exists ...
233         */
234
235         try {
236                 sys::create_directories (user_config_directory ());
237         }
238         catch (const sys::filesystem_error& ex) {
239                 error << _("Could not create user configuration directory") << endmsg;
240         }
241
242         sys::path pangopath = user_config_directory();
243         pangopath /= "pango.rc";
244         path = pangopath.to_string();
245
246         std::ofstream pangorc (path.c_str());
247         if (!pangorc) {
248                 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
249                 return;
250         } else {
251                 pangorc << "[Pango]\nModuleFiles=";
252
253                 pangopath = dir_path;
254                 pangopath /= "..";
255                 pangopath /= "Resources";
256                 pangopath /= "pango.modules";
257
258                 pangorc << pangopath.to_string() << endl;
259
260                 pangorc.close ();
261
262                 setenv ("PANGO_RC_FILE", path.c_str(), 1);
263         }
264
265         // gettext charset aliases
266
267         setenv ("CHARSETALIASDIR", path.c_str(), 1);
268
269         // font config
270
271         path = dir_path;
272         path += "/../Resources/fonts.conf";
273
274         setenv ("FONTCONFIG_FILE", path.c_str(), 1);
275
276         // GDK Pixbuf loader module file
277
278         path = dir_path;
279         path += "/../Resources/gdk-pixbuf.loaders";
280
281         setenv ("GDK_PIXBUF_MODULE_FILE", path.c_str(), 1);
282
283         if (getenv ("ARDOUR_WITH_JACK")) {
284                 // JACK driver dir
285
286                 path = dir_path;
287                 path += "/../Frameworks";
288
289                 setenv ("JACK_DRIVER_DIR", path.c_str(), 1);
290         }
291 }
292
293 #else
294
295 void
296 fixup_bundle_environment (int /*argc*/, char* argv[])
297 {
298         /* THIS IS FOR LINUX - its just about the only place where its
299          * acceptable to build paths directly using '/'.
300          */
301
302         if (!getenv ("ARDOUR_BUNDLED")) {
303                 return;
304         }
305
306         EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
307
308         Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (argv[0]));
309         Glib::ustring path;
310         Glib::ustring userconfigdir = user_config_directory().to_string();
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         export_search_path (dir_path, "ARDOUR_DLL_PATH", "/lib");
317         export_search_path (dir_path, "ARDOUR_CONFIG_PATH", "/etc");
318         export_search_path (dir_path, "ARDOUR_INSTANT_XML_PATH", "/share");
319         export_search_path (dir_path, "ARDOUR_DATA_PATH", "/share");
320
321         export_search_path (dir_path, "LADSPA_PATH", "/../plugins");
322         export_search_path (dir_path, "VAMP_PATH", "/lib");
323
324         path = dir_path;
325         path += "/lib/clearlooks";
326         setenv ("GTK_PATH", path.c_str(), 1);
327
328         /* unset GTK_RC_FILES so that we only load the RC files that we define
329          */
330
331         unsetenv ("GTK_RC_FILES");
332
333         if (!ARDOUR::translations_are_disabled ()) {
334                 path = dir_path;
335                 path += "/share/locale";
336
337                 localedir = strdup (path.c_str());
338                 setenv ("GTK_LOCALEDIR", localedir, 1);
339         }
340
341         /* Tell fontconfig where to find fonts.conf. Use the system version
342            if it exists, otherwise use the stuff we included in the bundle
343         */
344
345         if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
346                 setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
347                 setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
348         } else {
349                 /* use the one included in the bundle */
350                 
351                 path = Glib::build_filename (dir_path, "etc/fonts/fonts.conf");
352                 setenv ("FONTCONFIG_FILE", path.c_str(), 1);
353                 path = Glib::build_filename (dir_path, "etc/fonts");
354                 setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
355         }
356
357         /* write a pango.rc file and tell pango to use it. we'd love
358            to put this into the Ardour.app bundle and leave it there,
359            but the user may not have write permission. so ...
360
361            we also have to make sure that the user ardour directory
362            actually exists ...
363         */
364
365         if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
366                 error << string_compose (_("cannot create user ardour folder %1 (%2)"), userconfigdir, strerror (errno))
367                       << endmsg;
368                 return;
369         } 
370
371         Glib::ustring mpath;
372         
373         path = Glib::build_filename (userconfigdir, "pango.rc");
374         
375         std::ofstream pangorc (path.c_str());
376         if (!pangorc) {
377                 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
378         } else {
379                 mpath = Glib::build_filename (userconfigdir, "pango.modules");
380                 
381                 pangorc << "[Pango]\nModuleFiles=";
382                 pangorc << mpath << endl;
383                 pangorc.close ();
384         }
385         
386         setenv ("PANGO_RC_FILE", path.c_str(), 1);
387
388         /* similar for GDK pixbuf loaders, but there's no RC file required
389            to specify where it lives.
390         */
391         
392         mpath = Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders");
393         setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
394 }
395
396 #endif
397
398 static gboolean
399 tell_about_jack_death (void* /* ignored */)
400 {
401         if (AudioEngine::instance()->processed_frames() == 0) {
402                 /* died during startup */
403                 MessageDialog msg (_("JACK exited"), false);
404                 msg.set_position (Gtk::WIN_POS_CENTER);
405                 msg.set_secondary_text (string_compose (_(
406 "JACK exited unexpectedly, and without notifying %1.\n\
407 \n\
408 This could be due to misconfiguration or to an error inside JACK.\n\
409 \n\
410 Click OK to exit %1."), PROGRAM_NAME));
411
412                 msg.run ();
413                 _exit (0);
414
415         } else {
416
417                 /* engine has already run, so this is a mid-session JACK death */
418
419                 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false));
420                 msg->set_secondary_text (string_compose (_(
421 "JACK exited unexpectedly, and without notifying %1.\n\
422 \n\
423 This is probably due to an error inside JACK. You should restart JACK\n\
424 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
425 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
426                 msg->present ();
427         }
428         return false; /* do not call again */
429 }
430
431 static void
432 sigpipe_handler (int /*signal*/)
433 {
434         /* XXX fix this so that we do this again after a reconnect to JACK
435          */
436
437         static bool done_the_jack_thing = false;
438
439         if (!done_the_jack_thing) {
440                 AudioEngine::instance()->died ();
441                 g_idle_add (tell_about_jack_death, 0);
442                 done_the_jack_thing =  true;
443         }
444 }
445
446 #ifdef HAVE_LV2
447 void close_external_ui_windows();
448 #endif
449
450 #ifdef WINDOWS_VST_SUPPORT
451
452 extern int windows_vst_gui_init (int* argc, char** argv[]);
453
454 /* this is called from the entry point of a wine-compiled
455    executable that is linked against gtk2_ardour built
456    as a shared library.
457 */
458 extern "C" {
459 int ardour_main (int argc, char *argv[])
460 #else
461 int main (int argc, char *argv[])
462 #endif
463 {
464         fixup_bundle_environment (argc, argv);
465
466         if (!Glib::thread_supported()) {
467                 Glib::thread_init();
468         }
469
470         gtk_set_locale ();
471
472 #ifdef WINDOWS_VST_SUPPORT
473         /* this does some magic that is needed to make GTK and Wine's own
474            X11 client interact properly.
475         */
476         windows_vst_gui_init (&argc, &argv);
477 #endif
478
479         (void) bindtextdomain (PACKAGE, localedir);
480         /* our i18n translations are all in UTF-8, so make sure
481            that even if the user locale doesn't specify UTF-8,
482            we use that when handling them.
483         */
484         (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
485         (void) textdomain (PACKAGE);
486
487         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
488
489         // catch error message system signals ();
490
491         text_receiver.listen_to (error);
492         text_receiver.listen_to (info);
493         text_receiver.listen_to (fatal);
494         text_receiver.listen_to (warning);
495
496 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
497         if (getenv ("BOOST_DEBUG")) {
498                 boost_debug_shared_ptr_show_live_debugging (true);
499         }
500 #endif
501
502         if (parse_opts (argc, argv)) {
503                 exit (1);
504         }
505
506         if (curvetest_file) {
507                 return curvetest (curvetest_file);
508         }
509
510         cout << PROGRAM_NAME
511              << VERSIONSTRING
512              << _(" (built using ")
513              << svn_revision
514 #ifdef __GNUC__
515              << _(" and GCC version ") << __VERSION__
516 #endif
517              << ')'
518              << endl;
519
520         if (just_version) {
521                 exit (0);
522         }
523
524         if (no_splash) {
525                 cerr << _("Copyright (C) 1999-2012 Paul Davis") << endl
526                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
527                      << endl
528                      << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
529                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
530                      << _("This is free software, and you are welcome to redistribute it ") << endl
531                      << _("under certain conditions; see the source for copying conditions.")
532                      << endl;
533         }
534
535         /* some GUI objects need this */
536
537         PBD::ID::init ();
538
539         if (::signal (SIGPIPE, sigpipe_handler)) {
540                 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
541         }
542
543         try {
544                 ui = new ARDOUR_UI (&argc, &argv);
545         } catch (failed_constructor& err) {
546                 error << _("could not create ARDOUR GUI") << endmsg;
547                 exit (1);
548         }
549
550         ui->run (text_receiver);
551         Gtkmm2ext::Application::instance()->cleanup();
552         ui = 0;
553
554         ARDOUR::cleanup ();
555         pthread_cancel_all ();
556
557 #ifdef HAVE_LV2
558         close_external_ui_windows();
559 #endif
560         return 0;
561 }
562 #ifdef WINDOWS_VST_SUPPORT
563 } // end of extern C block
564 #endif
565