handle multiple imports of the same file better (via better source naming); make...
[ardour2.git] / gtk2_ardour / main.cc
blob3862a30f60f58d05798331cc9512dfe7daf3874a
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/file_utils.h"
30 #include "pbd/textreceiver.h"
31 #include "pbd/failed_constructor.h"
32 #include "pbd/pthread_utils.h"
34 #include <jack/jack.h>
36 #include "ardour/svn_revision.h"
37 #include "ardour/version.h"
38 #include "ardour/ardour.h"
39 #include "ardour/audioengine.h"
40 #include "ardour/session_utils.h"
41 #include "ardour/filesystem_paths.h"
43 #include <gtkmm/main.h>
44 #include <gtkmm2ext/application.h>
45 #include <gtkmm2ext/popup.h>
46 #include <gtkmm2ext/utils.h>
48 #include "version.h"
49 #include "utils.h"
50 #include "ardour_ui.h"
51 #include "opts.h"
52 #include "enums.h"
54 #include "i18n.h"
56 using namespace std;
57 using namespace Gtk;
58 using namespace ARDOUR_COMMAND_LINE;
59 using namespace ARDOUR;
60 using namespace PBD;
62 TextReceiver text_receiver ("ardour");
64 extern int curvetest (string);
66 static ARDOUR_UI *ui = 0;
67 static const char* localedir = LOCALEDIR;
69 void
70 gui_jack_error ()
72 MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
73 false,
74 Gtk::MESSAGE_INFO,
75 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
76 win.set_secondary_text(_("There are several possible reasons:\n\
77 \n\
78 1) JACK is not running.\n\
79 2) JACK is running as another user, perhaps root.\n\
80 3) There is already another client called \"ardour\".\n\
81 \n\
82 Please consider the possibilities, and perhaps (re)start JACK."));
84 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
85 win.set_default_response (RESPONSE_CLOSE);
87 win.show_all ();
88 win.set_position (Gtk::WIN_POS_CENTER);
90 if (!no_splash) {
91 ui->hide_splash ();
94 /* we just don't care about the result, but we want to block */
96 win.run ();
100 #ifdef __APPLE__
102 #include <mach-o/dyld.h>
103 #include <sys/param.h>
105 extern void set_language_preference (); // cocoacarbon.mm
107 void
108 fixup_bundle_environment ()
110 if (!getenv ("ARDOUR_BUNDLED")) {
111 return;
114 set_language_preference ();
116 char execpath[MAXPATHLEN+1];
117 uint32_t pathsz = sizeof (execpath);
119 _NSGetExecutablePath (execpath, &pathsz);
121 std::string exec_path (execpath);
122 std::string dir_path = Glib::path_get_dirname (exec_path);
123 std::string path;
124 const char *cstr = getenv ("PATH");
126 /* ensure that we find any bundled executables (e.g. JACK),
127 and find them before any instances of the same name
128 elsewhere in PATH
131 path = dir_path;
133 /* JACK is often in /usr/local/bin and since Info.plist refuses to
134 set PATH, we have to force this in order to discover a running
135 instance of JACK ...
138 path += ':';
139 path += "/usr/local/bin";
141 if (cstr) {
142 path += ':';
143 path += cstr;
145 setenv ("PATH", path.c_str(), 1);
147 path = dir_path;
148 path += "/../Resources";
149 path += dir_path;
150 path += "/../Resources/Surfaces";
151 path += dir_path;
152 path += "/../Resources/Panners";
154 setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
156 path = user_config_directory.to_string();
157 path += ':';
158 path += dir_path;
159 path += "/../Resources/icons:";
160 path += dir_path;
161 path += "/../Resources/pixmaps:";
162 path += dir_path;
163 path += "/../Resources/share:";
164 path += dir_path;
165 path += "/../Resources";
167 setenv ("ARDOUR_PATH", path.c_str(), 1);
168 setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
169 setenv ("ARDOUR_DATA_PATH", path.c_str(), 1);
171 path = dir_path;
172 path += "/../Resources";
173 setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
175 cstr = getenv ("LADSPA_PATH");
176 if (cstr) {
177 path = cstr;
178 path += ':';
179 } else {
180 path = "";
182 path += dir_path;
183 path += "/../Plugins";
185 setenv ("LADSPA_PATH", path.c_str(), 1);
187 cstr = getenv ("VAMP_PATH");
188 if (cstr) {
189 path = cstr;
190 path += ':';
191 } else {
192 path = "";
194 path += dir_path;
195 path += "/../Frameworks";
197 setenv ("VAMP_PATH", path.c_str(), 1);
199 cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
200 if (cstr) {
201 path = cstr;
202 path += ':';
203 } else {
204 path = "";
206 path += dir_path;
207 path += "/../Surfaces";
209 setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
211 cstr = getenv ("LV2_PATH");
212 if (cstr) {
213 path = cstr;
214 path += ':';
215 } else {
216 path = "";
218 path += dir_path;
219 path += "/../Plugins";
221 setenv ("LV2_PATH", path.c_str(), 1);
223 path = dir_path;
224 path += "/../Frameworks/clearlooks";
226 setenv ("GTK_PATH", path.c_str(), 1);
228 if (!ARDOUR::translations_are_disabled ()) {
230 path = dir_path;
231 path += "/../Resources/locale";
233 localedir = strdup (path.c_str());
234 setenv ("GTK_LOCALEDIR", localedir, 1);
237 /* write a pango.rc file and tell pango to use it. we'd love
238 to put this into the PROGRAM_NAME.app bundle and leave it there,
239 but the user may not have write permission. so ...
241 we also have to make sure that the user ardour directory
242 actually exists ...
245 try {
246 sys::create_directories (user_config_directory ());
248 catch (const sys::filesystem_error& ex) {
249 error << _("Could not create user configuration directory") << endmsg;
252 sys::path pangopath = user_config_directory();
253 pangopath /= "pango.rc";
254 path = pangopath.to_string();
256 std::ofstream pangorc (path.c_str());
257 if (!pangorc) {
258 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
259 return;
260 } else {
261 pangorc << "[Pango]\nModuleFiles=";
263 pangopath = dir_path;
264 pangopath /= "..";
265 pangopath /= "Resources";
266 pangopath /= "pango.modules";
268 pangorc << pangopath.to_string() << endl;
270 pangorc.close ();
272 setenv ("PANGO_RC_FILE", path.c_str(), 1);
275 // gettext charset aliases
277 setenv ("CHARSETALIASDIR", path.c_str(), 1);
279 // font config
281 path = dir_path;
282 path += "/../Resources/fonts.conf";
284 setenv ("FONTCONFIG_FILE", path.c_str(), 1);
286 // GDK Pixbuf loader module file
288 path = dir_path;
289 path += "/../Resources/gdk-pixbuf.loaders";
291 setenv ("GDK_PIXBUF_MODULE_FILE", path.c_str(), 1);
293 if (getenv ("ARDOUR_WITH_JACK")) {
294 // JACK driver dir
296 path = dir_path;
297 path += "/../Frameworks";
299 setenv ("JACK_DRIVER_DIR", path.c_str(), 1);
303 #else
305 void
306 fixup_bundle_environment (int argc, char* argv[])
308 if (!getenv ("ARDOUR_BUNDLED")) {
309 return;
312 Glib::ustring exec_path = argv[0];
313 Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (exec_path));
314 Glib::ustring path;
315 const char *cstr = getenv ("PATH");
316 Glib::ustring userconfigdir = user_config_directory().to_string();
318 /* ensure that we find any bundled executables (e.g. JACK),
319 and find them before any instances of the same name
320 elsewhere in PATH
323 /* note that this function is POSIX/Linux specific, so using / as
324 a dir separator in this context is just fine.
327 path = dir_path;
328 path += "/etc:";
329 path += dir_path;
330 path += "/lib/surfaces:";
331 path += dir_path;
332 path += "/lib/panners:";
334 setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
336 path = userconfigdir;
337 path += ':';
338 path += dir_path;
339 path += "/etc/icons:";
340 path += dir_path;
341 path += "/etc/pixmaps:";
342 path += dir_path;
343 path += "/share:";
344 path += dir_path;
345 path += "/etc";
347 setenv ("ARDOUR_PATH", path.c_str(), 1);
348 setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
349 setenv ("ARDOUR_DATA_PATH", path.c_str(), 1);
351 path = dir_path;
352 path += "/etc";
353 setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
355 cstr = getenv ("LADSPA_PATH");
356 if (cstr) {
357 path = cstr;
358 path += ':';
359 } else {
360 path = "";
362 path += dir_path;
363 path += "/lib/plugins";
365 setenv ("LADSPA_PATH", path.c_str(), 1);
367 cstr = getenv ("VAMP_PATH");
368 if (cstr) {
369 path = cstr;
370 path += ':';
371 } else {
372 path = "";
374 path += dir_path;
375 path += "/lib";
377 setenv ("VAMP_PATH", path.c_str(), 1);
379 cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
380 if (cstr) {
381 path = cstr;
382 path += ':';
383 } else {
384 path = "";
386 path += dir_path;
387 path += "/lib/surfaces";
389 setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
391 cstr = getenv ("LV2_PATH");
392 if (cstr) {
393 path = cstr;
394 path += ':';
395 } else {
396 path = "";
398 path += dir_path;
399 path += "/lib/plugins";
401 setenv ("LV2_PATH", path.c_str(), 1);
403 path = dir_path;
404 path += "/lib/clearlooks";
406 setenv ("GTK_PATH", path.c_str(), 1);
408 if (!ARDOUR::translations_are_disabled ()) {
409 path = dir_path;
410 path += "/share/locale";
412 localedir = strdup (path.c_str());
413 setenv ("GTK_LOCALEDIR", localedir, 1);
416 /* write a pango.rc file and tell pango to use it. we'd love
417 to put this into the Ardour.app bundle and leave it there,
418 but the user may not have write permission. so ...
420 we also have to make sure that the user ardour directory
421 actually exists ...
424 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
425 error << string_compose (_("cannot create user ardour folder %1 (%2)"), userconfigdir, strerror (errno))
426 << endmsg;
427 } else {
429 Glib::ustring mpath;
431 path = Glib::build_filename (userconfigdir, "pango.rc");
433 std::ofstream pangorc (path.c_str());
434 if (!pangorc) {
435 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
436 } else {
437 mpath = Glib::build_filename (userconfigdir, "pango.modules");
439 pangorc << "[Pango]\nModuleFiles=";
440 pangorc << mpath << endl;
441 pangorc.close ();
444 setenv ("PANGO_RC_FILE", path.c_str(), 1);
446 /* similar for GDK pixbuf loaders, but there's no RC file required
447 to specify where it lives.
450 mpath = Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders");
451 setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
455 #endif
457 static gboolean
458 tell_about_jack_death (void* /* ignored */)
460 if (AudioEngine::instance()->processed_frames() == 0) {
461 /* died during startup */
462 MessageDialog msg (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
463 msg.set_position (Gtk::WIN_POS_CENTER);
464 msg.set_secondary_text (string_compose (_(
465 "JACK exited unexpectedly, and without notifying %1.\n\
467 This could be due to misconfiguration or to an error inside JACK.\n\
469 Click OK to exit %1."), PROGRAM_NAME));
471 msg.run ();
472 _exit (0);
474 } else {
476 /* engine has already run, so this is a mid-session JACK death */
478 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE));
479 msg->set_secondary_text (string_compose (_(
480 "JACK exited unexpectedly, and without notifying %1.\n\
482 This is probably due to an error inside JACK. You should restart JACK\n\
483 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
484 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
485 msg->present ();
487 return false; /* do not call again */
490 static void
491 sigpipe_handler (int sig)
493 /* XXX fix this so that we do this again after a reconnect to JACK
496 static bool done_the_jack_thing = false;
498 if (!done_the_jack_thing) {
499 AudioEngine::instance()->died ();
500 g_idle_add (tell_about_jack_death, 0);
501 done_the_jack_thing = true;
505 #ifdef HAVE_LV2
506 void close_external_ui_windows();
507 #endif
509 #ifdef VST_SUPPORT
511 extern int gui_init (int* argc, char** argv[]);
513 /* this is called from the entry point of a wine-compiled
514 executable that is linked against gtk2_ardour built
515 as a shared library.
517 extern "C" {
518 int ardour_main (int argc, char *argv[])
519 #else
520 int main (int argc, char *argv[])
521 #endif
523 #ifdef __APPLE__
524 fixup_bundle_environment ();
525 #endif
527 if (!Glib::thread_supported())
528 Glib::thread_init();
530 gtk_set_locale ();
532 #ifdef VST_SUPPORT
533 /* this does some magic that is needed to make GTK and Wine's own
534 X11 client interact properly.
536 gui_init (&argc, &argv);
537 #endif
539 (void) bindtextdomain (PACKAGE, localedir);
540 /* our i18n translations are all in UTF-8, so make sure
541 that even if the user locale doesn't specify UTF-8,
542 we use that when handling them.
544 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
545 (void) textdomain (PACKAGE);
547 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
549 // catch error message system signals ();
551 text_receiver.listen_to (error);
552 text_receiver.listen_to (info);
553 text_receiver.listen_to (fatal);
554 text_receiver.listen_to (warning);
556 if (parse_opts (argc, argv)) {
557 exit (1);
560 if (curvetest_file) {
561 return curvetest (curvetest_file);
564 cout << PROGRAM_NAME
565 << VERSIONSTRING
566 << _(" (built using ")
567 << svn_revision
568 #ifdef __GNUC__
569 << _(" and GCC version ") << __VERSION__
570 #endif
571 << ')'
572 << endl;
574 if (just_version) {
575 exit (0);
578 if (no_splash) {
579 cerr << _("Copyright (C) 1999-2010 Paul Davis") << endl
580 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
581 << endl
582 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
583 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
584 << _("This is free software, and you are welcome to redistribute it ") << endl
585 << _("under certain conditions; see the source for copying conditions.")
586 << endl;
589 /* some GUI objects need this */
591 PBD::ID::init ();
593 if (::signal (SIGPIPE, sigpipe_handler)) {
594 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
597 try {
598 ui = new ARDOUR_UI (&argc, &argv);
599 } catch (failed_constructor& err) {
600 error << _("could not create ARDOUR GUI") << endmsg;
601 exit (1);
604 ui->run (text_receiver);
605 Gtkmm2ext::Application::instance()->cleanup();
606 ui = 0;
608 ARDOUR::cleanup ();
609 pthread_cancel_all ();
611 #ifdef HAVE_LV2
612 close_external_ui_windows();
613 #endif
614 return 0;
616 #ifdef VST_SUPPORT
617 } // end of extern C block
618 #endif