set ARDOUR_SURFACES_PATH for a bundle, just like ARDOUR_PANNER_PATH
[ardour2.git] / gtk2_ardour / main.cc
blob0497bccb788f54da71688e814496247909d0b14d
1 /*
2 Copyright (C) 2001-2007 Paul Davis
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.
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.
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.
20 #include <cstdlib>
21 #include <signal.h>
22 #include <cerrno>
23 #include <fstream>
25 #include <sigc++/bind.h>
26 #include <gtkmm/settings.h>
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 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
35 #include "pbd/boost_debug.h"
36 #endif
38 #include <jack/jack.h>
40 #include "ardour/svn_revision.h"
41 #include "ardour/version.h"
42 #include "ardour/ardour.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/session_utils.h"
45 #include "ardour/filesystem_paths.h"
47 #include <gtkmm/main.h>
48 #include <gtkmm2ext/application.h>
49 #include <gtkmm2ext/popup.h>
50 #include <gtkmm2ext/utils.h>
52 #include "version.h"
53 #include "utils.h"
54 #include "ardour_ui.h"
55 #include "opts.h"
56 #include "enums.h"
58 #include "i18n.h"
60 using namespace std;
61 using namespace Gtk;
62 using namespace ARDOUR_COMMAND_LINE;
63 using namespace ARDOUR;
64 using namespace PBD;
66 TextReceiver text_receiver ("ardour");
68 extern int curvetest (string);
70 static ARDOUR_UI *ui = 0;
71 static const char* localedir = LOCALEDIR;
73 void
74 gui_jack_error ()
76 MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
77 false,
78 Gtk::MESSAGE_INFO,
79 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
80 win.set_secondary_text(_("There are several possible reasons:\n\
81 \n\
82 1) JACK is not running.\n\
83 2) JACK is running as another user, perhaps root.\n\
84 3) There is already another client called \"ardour\".\n\
85 \n\
86 Please consider the possibilities, and perhaps (re)start JACK."));
88 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
89 win.set_default_response (RESPONSE_CLOSE);
91 win.show_all ();
92 win.set_position (Gtk::WIN_POS_CENTER);
94 if (!no_splash) {
95 ui->hide_splash ();
98 /* we just don't care about the result, but we want to block */
100 win.run ();
104 #ifdef __APPLE__
106 #include <mach-o/dyld.h>
107 #include <sys/param.h>
109 extern void set_language_preference (); // cocoacarbon.mm
111 void
112 fixup_bundle_environment (int, char* [])
114 if (!getenv ("ARDOUR_BUNDLED")) {
115 return;
118 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
120 set_language_preference ();
122 char execpath[MAXPATHLEN+1];
123 uint32_t pathsz = sizeof (execpath);
125 _NSGetExecutablePath (execpath, &pathsz);
127 std::string exec_path (execpath);
128 std::string dir_path = Glib::path_get_dirname (exec_path);
129 std::string path;
130 const char *cstr = getenv ("PATH");
132 /* ensure that we find any bundled executables (e.g. JACK),
133 and find them before any instances of the same name
134 elsewhere in PATH
137 path = dir_path;
139 /* JACK is often in /usr/local/bin and since Info.plist refuses to
140 set PATH, we have to force this in order to discover a running
141 instance of JACK ...
144 path += ':';
145 path += "/usr/local/bin";
147 if (cstr) {
148 path += ':';
149 path += cstr;
151 setenv ("PATH", path.c_str(), 1);
153 path = dir_path;
154 path += "/../Resources";
155 path += dir_path;
156 path += "/../Resources/Surfaces";
157 path += dir_path;
158 path += "/../Resources/Panners";
160 setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
162 path = user_config_directory().to_string();
163 path += ':';
164 path += dir_path;
165 path += "/../Resources/icons:";
166 path += dir_path;
167 path += "/../Resources/pixmaps:";
168 path += dir_path;
169 path += "/../Resources/share:";
170 path += dir_path;
171 path += "/../Resources";
173 setenv ("ARDOUR_PATH", path.c_str(), 1);
174 setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
176 path = dir_path;
177 path += "/../Resources";
178 setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
180 cstr = getenv ("LADSPA_PATH");
181 if (cstr) {
182 path = cstr;
183 path += ':';
184 } else {
185 path = "";
187 path += dir_path;
188 path += "/../Plugins";
190 setenv ("LADSPA_PATH", path.c_str(), 1);
192 cstr = getenv ("VAMP_PATH");
193 if (cstr) {
194 path = cstr;
195 path += ':';
196 } else {
197 path = "";
199 path += dir_path;
200 path += "/../Frameworks";
202 setenv ("VAMP_PATH", path.c_str(), 1);
204 cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
205 if (cstr) {
206 path = cstr;
207 path += ':';
208 } else {
209 path = "";
211 path += dir_path;
212 path += "/../Surfaces";
214 setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
216 cstr = getenv ("ARDOUR_PANNER_PATH");
217 if (cstr) {
218 path = cstr;
219 path += ':';
220 } else {
221 path = "";
223 path += dir_path;
224 path += "/lib/panners";
226 setenv ("ARDOUR_PANNER_PATH", path.c_str(), 1);
228 cstr = getenv ("ARDOUR_SURFACES_PATH");
229 if (cstr) {
230 path = cstr;
231 path += ':';
232 } else {
233 path = "";
235 path += dir_path;
236 path += "/lib/surfaces";
238 setenv ("ARDOUR_SURFACES_PATH", path.c_str(), 1);
241 path = dir_path;
242 path += "/../Frameworks/clearlooks";
244 setenv ("GTK_PATH", path.c_str(), 1);
246 /* unset GTK_RC_FILES so that we only load the RC files that we define
249 unsetenv ("GTK_RC_FILES");
251 if (!ARDOUR::translations_are_disabled ()) {
253 path = dir_path;
254 path += "/../Resources/locale";
256 localedir = strdup (path.c_str());
257 setenv ("GTK_LOCALEDIR", localedir, 1);
260 /* write a pango.rc file and tell pango to use it. we'd love
261 to put this into the PROGRAM_NAME.app bundle and leave it there,
262 but the user may not have write permission. so ...
264 we also have to make sure that the user ardour directory
265 actually exists ...
268 try {
269 sys::create_directories (user_config_directory ());
271 catch (const sys::filesystem_error& ex) {
272 error << _("Could not create user configuration directory") << endmsg;
275 sys::path pangopath = user_config_directory();
276 pangopath /= "pango.rc";
277 path = pangopath.to_string();
279 std::ofstream pangorc (path.c_str());
280 if (!pangorc) {
281 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
282 return;
283 } else {
284 pangorc << "[Pango]\nModuleFiles=";
286 pangopath = dir_path;
287 pangopath /= "..";
288 pangopath /= "Resources";
289 pangopath /= "pango.modules";
291 pangorc << pangopath.to_string() << endl;
293 pangorc.close ();
295 setenv ("PANGO_RC_FILE", path.c_str(), 1);
298 // gettext charset aliases
300 setenv ("CHARSETALIASDIR", path.c_str(), 1);
302 // font config
304 path = dir_path;
305 path += "/../Resources/fonts.conf";
307 setenv ("FONTCONFIG_FILE", path.c_str(), 1);
309 // GDK Pixbuf loader module file
311 path = dir_path;
312 path += "/../Resources/gdk-pixbuf.loaders";
314 setenv ("GDK_PIXBUF_MODULE_FILE", path.c_str(), 1);
316 if (getenv ("ARDOUR_WITH_JACK")) {
317 // JACK driver dir
319 path = dir_path;
320 path += "/../Frameworks";
322 setenv ("JACK_DRIVER_DIR", path.c_str(), 1);
326 #else
328 void
329 fixup_bundle_environment (int /*argc*/, char* argv[])
331 if (!getenv ("ARDOUR_BUNDLED")) {
332 return;
335 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
337 Glib::ustring exec_path = argv[0];
338 Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (exec_path));
339 Glib::ustring path;
340 const char *cstr = getenv ("PATH");
341 Glib::ustring userconfigdir = user_config_directory().to_string();
343 /* ensure that we find any bundled executables (e.g. JACK),
344 and find them before any instances of the same name
345 elsewhere in PATH
348 /* note that this function is POSIX/Linux specific, so using / as
349 a dir separator in this context is just fine.
352 path = dir_path;
353 path += "/etc:";
354 path += dir_path;
355 path += "/lib/surfaces:";
356 path += dir_path;
357 path += "/lib/panners:";
359 setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
361 path = userconfigdir;
362 path += ':';
363 path += dir_path;
364 path += "/etc/icons:";
365 path += dir_path;
366 path += "/etc/pixmaps:";
367 path += dir_path;
368 path += "/share:";
369 path += dir_path;
370 path += "/etc";
372 setenv ("ARDOUR_PATH", path.c_str(), 1);
373 setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
375 path = dir_path;
376 path += "/etc";
377 setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
379 cstr = getenv ("LADSPA_PATH");
380 if (cstr) {
381 path = cstr;
382 path += ':';
383 } else {
384 path = "";
386 path += dir_path;
387 path += "/lib/plugins";
389 setenv ("LADSPA_PATH", path.c_str(), 1);
391 cstr = getenv ("VAMP_PATH");
392 if (cstr) {
393 path = cstr;
394 path += ':';
395 } else {
396 path = "";
398 path += dir_path;
399 path += "/lib";
401 setenv ("VAMP_PATH", path.c_str(), 1);
403 cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
404 if (cstr) {
405 path = cstr;
406 path += ':';
407 } else {
408 path = "";
410 path += dir_path;
411 path += "/lib/surfaces";
413 setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
415 cstr = getenv ("ARDOUR_PANNER_PATH");
416 if (cstr) {
417 path = cstr;
418 path += ':';
419 } else {
420 path = "";
422 path += dir_path;
423 path += "/lib/panners";
425 setenv ("ARDOUR_PANNER_PATH", path.c_str(), 1);
427 path = dir_path;
428 path += "/lib/clearlooks";
430 setenv ("GTK_PATH", path.c_str(), 1);
432 /* unset GTK_RC_FILES so that we only load the RC files that we define
435 unsetenv ("GTK_RC_FILES");
437 if (!ARDOUR::translations_are_disabled ()) {
438 path = dir_path;
439 path += "/share/locale";
441 localedir = strdup (path.c_str());
442 setenv ("GTK_LOCALEDIR", localedir, 1);
445 /* write a pango.rc file and tell pango to use it. we'd love
446 to put this into the Ardour.app bundle and leave it there,
447 but the user may not have write permission. so ...
449 we also have to make sure that the user ardour directory
450 actually exists ...
453 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
454 error << string_compose (_("cannot create user ardour folder %1 (%2)"), userconfigdir, strerror (errno))
455 << endmsg;
456 } else {
458 Glib::ustring mpath;
460 path = Glib::build_filename (userconfigdir, "pango.rc");
462 std::ofstream pangorc (path.c_str());
463 if (!pangorc) {
464 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
465 } else {
466 mpath = Glib::build_filename (userconfigdir, "pango.modules");
468 pangorc << "[Pango]\nModuleFiles=";
469 pangorc << mpath << endl;
470 pangorc.close ();
473 setenv ("PANGO_RC_FILE", path.c_str(), 1);
475 /* similar for GDK pixbuf loaders, but there's no RC file required
476 to specify where it lives.
479 mpath = Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders");
480 setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
484 #endif
486 static gboolean
487 tell_about_jack_death (void* /* ignored */)
489 if (AudioEngine::instance()->processed_frames() == 0) {
490 /* died during startup */
491 MessageDialog msg (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
492 msg.set_position (Gtk::WIN_POS_CENTER);
493 msg.set_secondary_text (string_compose (_(
494 "JACK exited unexpectedly, and without notifying %1.\n\
496 This could be due to misconfiguration or to an error inside JACK.\n\
498 Click OK to exit %1."), PROGRAM_NAME));
500 msg.run ();
501 _exit (0);
503 } else {
505 /* engine has already run, so this is a mid-session JACK death */
507 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE));
508 msg->set_secondary_text (string_compose (_(
509 "JACK exited unexpectedly, and without notifying %1.\n\
511 This is probably due to an error inside JACK. You should restart JACK\n\
512 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
513 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
514 msg->present ();
516 return false; /* do not call again */
519 static void
520 sigpipe_handler (int /*signal*/)
522 /* XXX fix this so that we do this again after a reconnect to JACK
525 static bool done_the_jack_thing = false;
527 if (!done_the_jack_thing) {
528 AudioEngine::instance()->died ();
529 g_idle_add (tell_about_jack_death, 0);
530 done_the_jack_thing = true;
534 #ifdef HAVE_LV2
535 void close_external_ui_windows();
536 #endif
538 #ifdef VST_SUPPORT
540 extern int gui_init (int* argc, char** argv[]);
542 /* this is called from the entry point of a wine-compiled
543 executable that is linked against gtk2_ardour built
544 as a shared library.
546 extern "C" {
547 int ardour_main (int argc, char *argv[])
548 #else
549 int main (int argc, char *argv[])
550 #endif
552 fixup_bundle_environment (argc, argv);
554 if (!Glib::thread_supported()) {
555 Glib::thread_init();
558 gtk_set_locale ();
560 #ifdef VST_SUPPORT
561 /* this does some magic that is needed to make GTK and Wine's own
562 X11 client interact properly.
564 gui_init (&argc, &argv);
565 #endif
567 (void) bindtextdomain (PACKAGE, localedir);
568 /* our i18n translations are all in UTF-8, so make sure
569 that even if the user locale doesn't specify UTF-8,
570 we use that when handling them.
572 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
573 (void) textdomain (PACKAGE);
575 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
577 // catch error message system signals ();
579 text_receiver.listen_to (error);
580 text_receiver.listen_to (info);
581 text_receiver.listen_to (fatal);
582 text_receiver.listen_to (warning);
584 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
585 if (getenv ("BOOST_DEBUG")) {
586 boost_debug_shared_ptr_show_live_debugging (true);
588 #endif
590 if (parse_opts (argc, argv)) {
591 exit (1);
594 if (curvetest_file) {
595 return curvetest (curvetest_file);
598 cout << PROGRAM_NAME
599 << VERSIONSTRING
600 << _(" (built using ")
601 << svn_revision
602 #ifdef __GNUC__
603 << _(" and GCC version ") << __VERSION__
604 #endif
605 << ')'
606 << endl;
608 if (just_version) {
609 exit (0);
612 if (no_splash) {
613 cerr << _("Copyright (C) 1999-2011 Paul Davis") << endl
614 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
615 << endl
616 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
617 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
618 << _("This is free software, and you are welcome to redistribute it ") << endl
619 << _("under certain conditions; see the source for copying conditions.")
620 << endl;
623 /* some GUI objects need this */
625 PBD::ID::init ();
627 if (::signal (SIGPIPE, sigpipe_handler)) {
628 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
631 try {
632 ui = new ARDOUR_UI (&argc, &argv);
633 } catch (failed_constructor& err) {
634 error << _("could not create ARDOUR GUI") << endmsg;
635 exit (1);
638 ui->run (text_receiver);
639 Gtkmm2ext::Application::instance()->cleanup();
640 ui = 0;
642 ARDOUR::cleanup ();
643 pthread_cancel_all ();
645 #ifdef HAVE_LV2
646 close_external_ui_windows();
647 #endif
648 return 0;
650 #ifdef VST_SUPPORT
651 } // end of extern C block
652 #endif