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