2 Copyright (C) 2001-2012 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.
26 #include <sigc++/bind.h>
27 #include <gtkmm/settings.h>
29 #include "pbd/error.h"
31 #include "pbd/file_utils.h"
32 #include "pbd/textreceiver.h"
33 #include "pbd/failed_constructor.h"
34 #include "pbd/pathexpand.h"
35 #include "pbd/pthread_utils.h"
36 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
37 #include "pbd/boost_debug.h"
40 #include "ardour/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 <fontconfig/fontconfig.h>
56 #include "ardour_ui.h"
63 #include <Carbon/Carbon.h>
68 using namespace ARDOUR_COMMAND_LINE;
69 using namespace ARDOUR;
72 TextReceiver text_receiver ("ardour");
74 extern int curvetest (string);
76 static ARDOUR_UI *ui = 0;
77 static const char* localedir = LOCALEDIR;
82 MessageDialog win (string_compose (_("%1 could not connect to the audio backend."), PROGRAM_NAME),
87 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
88 win.set_default_response (RESPONSE_CLOSE);
91 win.set_position (Gtk::WIN_POS_CENTER);
97 /* we just don't care about the result, but we want to block */
102 static void export_search_path (const string& base_dir, const char* varname, const char* dir)
105 const char * cstr = g_getenv (varname);
116 g_setenv (varname, path.c_str(), 1);
121 #include <mach-o/dyld.h>
122 #include <sys/param.h>
124 extern void set_language_preference (); // cocoacarbon.mm
127 fixup_bundle_environment (int, char* [])
129 if (!g_getenv ("ARDOUR_BUNDLED")) {
133 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
135 set_language_preference ();
137 char execpath[MAXPATHLEN+1];
138 uint32_t pathsz = sizeof (execpath);
140 _NSGetExecutablePath (execpath, &pathsz);
143 std::string exec_dir = Glib::path_get_dirname (execpath);
144 std::string bundle_dir;
145 std::string userconfigdir = user_config_directory();
147 bundle_dir = Glib::path_get_dirname (exec_dir);
150 if (!ARDOUR::translations_are_enabled ()) {
151 localedir = "/this/cannot/exist";
153 /* force localedir into the bundle */
155 vector<string> lpath;
156 lpath.push_back (bundle_dir);
157 lpath.push_back ("Resources");
158 lpath.push_back ("locale");
159 localedir = strdup (Glib::build_filename (lpath).c_str());
163 export_search_path (bundle_dir, "ARDOUR_DLL_PATH", "/lib");
165 /* inside an OS X .app bundle, there is no difference
166 between DATA and CONFIG locations, since OS X doesn't
167 attempt to do anything to expose the notion of
168 machine-independent shared data.
171 export_search_path (bundle_dir, "ARDOUR_DATA_PATH", "/Resources");
172 export_search_path (bundle_dir, "ARDOUR_CONFIG_PATH", "/Resources");
173 export_search_path (bundle_dir, "ARDOUR_INSTANT_XML_PATH", "/Resources");
174 export_search_path (bundle_dir, "LADSPA_PATH", "/Plugins");
175 export_search_path (bundle_dir, "VAMP_PATH", "/lib");
176 export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines");
178 g_setenv ("SUIL_MODULE_DIR", (bundle_dir + "/lib").c_str(), 1);
179 g_setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(g_getenv ("PATH"))).c_str(), 1);
181 /* unset GTK_RC_FILES so that we only load the RC files that we define
184 g_unsetenv ("GTK_RC_FILES");
186 /* write a pango.rc file and tell pango to use it. we'd love
187 to put this into the PROGRAM_NAME.app bundle and leave it there,
188 but the user may not have write permission. so ...
190 we also have to make sure that the user ardour directory
194 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
195 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
199 path = Glib::build_filename (userconfigdir, "pango.rc");
200 std::ofstream pangorc (path.c_str());
202 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
204 pangorc << "[Pango]\nModuleFiles="
205 << Glib::build_filename (bundle_dir, "Resources/pango.modules")
209 g_setenv ("PANGO_RC_FILE", path.c_str(), 1);
213 g_setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
214 g_setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
215 g_setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
218 static void load_custom_fonts() {
219 /* this code will only compile on OS X 10.6 and above, and we currently do not
220 * need it for earlier versions since we fall back on a non-monospace,
223 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
224 std::string ardour_mono_file;
226 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
227 cerr << _("Cannot find ArdourMono TrueType font") << endl;
233 ttf = CFStringCreateWithBytes(
234 kCFAllocatorDefault, (UInt8*) ardour_mono_file.c_str(),
235 ardour_mono_file.length(),
236 kCFStringEncodingUTF8, FALSE);
237 fontURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, ttf, kCFURLPOSIXPathStyle, TRUE);
238 if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error) != true) {
239 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
247 fixup_bundle_environment (int /*argc*/, char* argv[])
249 /* THIS IS FOR LINUX - its just about the only place where its
250 * acceptable to build paths directly using '/'.
253 if (!g_getenv ("ARDOUR_BUNDLED")) {
257 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
260 std::string dir_path = Glib::path_get_dirname (Glib::path_get_dirname (argv[0]));
261 std::string userconfigdir = user_config_directory();
264 if (!ARDOUR::translations_are_enabled ()) {
265 localedir = "/this/cannot/exist";
267 /* force localedir into the bundle */
268 vector<string> lpath;
269 lpath.push_back (dir_path);
270 lpath.push_back ("share");
271 lpath.push_back ("locale");
272 localedir = canonical_path (Glib::build_filename (lpath)).c_str();
276 /* note that this function is POSIX/Linux specific, so using / as
277 a dir separator in this context is just fine.
280 export_search_path (dir_path, "ARDOUR_DLL_PATH", "/lib");
281 export_search_path (dir_path, "ARDOUR_CONFIG_PATH", "/etc");
282 export_search_path (dir_path, "ARDOUR_INSTANT_XML_PATH", "/share");
283 export_search_path (dir_path, "ARDOUR_DATA_PATH", "/share");
284 export_search_path (dir_path, "LADSPA_PATH", "/plugins");
285 export_search_path (dir_path, "VAMP_PATH", "/lib");
286 export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines");
288 g_setenv ("SUIL_MODULE_DIR", (dir_path + "/lib").c_str(), 1);
289 g_setenv ("PATH", (dir_path + "/bin:" + std::string(g_getenv ("PATH"))).c_str(), 1);
291 /* unset GTK_RC_FILES so that we only load the RC files that we define
294 g_unsetenv ("GTK_RC_FILES");
296 /* Tell fontconfig where to find fonts.conf. Use the system version
297 if it exists, otherwise use the stuff we included in the bundle
300 if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
301 g_setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
302 g_setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
304 error << _("No fontconfig file found on your system. Things may looked very odd or ugly") << endmsg;
307 /* write a pango.rc file and tell pango to use it. we'd love
308 to put this into the Ardour.app bundle and leave it there,
309 but the user may not have write permission. so ...
311 we also have to make sure that the user ardour directory
315 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
316 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
320 path = Glib::build_filename (userconfigdir, "pango.rc");
321 std::ofstream pangorc (path.c_str());
323 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
325 pangorc << "[Pango]\nModuleFiles="
326 << Glib::build_filename (userconfigdir, "pango.modules")
331 g_setenv ("PANGO_RC_FILE", path.c_str(), 1);
333 /* similar for GDK pixbuf loaders, but there's no RC file required
334 to specify where it lives.
337 g_setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
340 /* this doesn't do much but setting it should prevent various parts of the GTK/GNU stack
341 from looking outside the bundle to find the charset.alias file.
343 g_setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
347 static void load_custom_fonts() {
348 std::string ardour_mono_file;
349 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
350 cerr << _("Cannot find ArdourMono TrueType font") << endl;
353 FcConfig *config = FcInitLoadConfigAndFonts();
354 FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(ardour_mono_file.c_str()));
355 if (ret == FcFalse) {
356 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
358 ret = FcConfigSetCurrent(config);
359 if (ret == FcFalse) {
360 cerr << _("Failed to set fontconfig configuration.") << endl;
367 tell_about_backend_death (void* /* ignored */)
369 if (AudioEngine::instance()->processed_frames() == 0) {
370 /* died during startup */
371 MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
372 msg.set_position (Gtk::WIN_POS_CENTER);
373 msg.set_secondary_text (string_compose (_(
374 "%2 exited unexpectedly, and without notifying %1.\n\
376 This could be due to misconfiguration or to an error inside %2.\n\
378 Click OK to exit %1."), PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
385 /* engine has already run, so this is a mid-session backend death */
387 MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
388 msg.set_secondary_text (string_compose (_("%2 exited unexpectedly, and without notifying %1."),
389 PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
392 return false; /* do not call again */
396 sigpipe_handler (int /*signal*/)
398 /* XXX fix this so that we do this again after a reconnect to the backend
401 static bool done_the_backend_thing = false;
403 if (!done_the_backend_thing) {
404 AudioEngine::instance()->died ();
405 g_idle_add (tell_about_backend_death, 0);
406 done_the_backend_thing = true;
410 #ifdef WINDOWS_VST_SUPPORT
412 extern int windows_vst_gui_init (int* argc, char** argv[]);
414 /* this is called from the entry point of a wine-compiled
415 executable that is linked against gtk2_ardour built
419 int ardour_main (int argc, char *argv[])
421 int main (int argc, char *argv[])
424 fixup_bundle_environment (argc, argv);
426 load_custom_fonts(); /* needs to happend before any gtk and pango init calls */
428 if (!Glib::thread_supported()) {
436 #ifdef WINDOWS_VST_SUPPORT
437 /* this does some magic that is needed to make GTK and Wine's own
438 X11 client interact properly.
440 windows_vst_gui_init (&argc, &argv);
444 cerr << "bnd txt domain [" << PACKAGE << "] to " << localedir << endl;
446 (void) bindtextdomain (PACKAGE, localedir);
447 /* our i18n translations are all in UTF-8, so make sure
448 that even if the user locale doesn't specify UTF-8,
449 we use that when handling them.
451 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
454 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
456 // catch error message system signals ();
458 text_receiver.listen_to (error);
459 text_receiver.listen_to (info);
460 text_receiver.listen_to (fatal);
461 text_receiver.listen_to (warning);
463 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
464 if (g_getenv ("BOOST_DEBUG")) {
465 boost_debug_shared_ptr_show_live_debugging (true);
469 if (parse_opts (argc, argv)) {
475 << _(" (built using ")
478 << _(" and GCC version ") << __VERSION__
488 cerr << _("Copyright (C) 1999-2012 Paul Davis") << endl
489 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker, Robin Gareus") << endl
491 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
492 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
493 << _("This is free software, and you are welcome to redistribute it ") << endl
494 << _("under certain conditions; see the source for copying conditions.")
498 /* some GUI objects need this */
500 if (!ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) {
501 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
505 if (curvetest_file) {
506 return curvetest (curvetest_file);
509 #ifndef PLATFORM_WINDOWS
510 if (::signal (SIGPIPE, sigpipe_handler)) {
511 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
516 ui = new ARDOUR_UI (&argc, &argv, localedir);
517 } catch (failed_constructor& err) {
518 error << string_compose (_("could not create %1 GUI"), PROGRAM_NAME) << endmsg;
522 ui->run (text_receiver);
523 Gtkmm2ext::Application::instance()->cleanup();
528 pthread_cancel_all ();
532 #ifdef WINDOWS_VST_SUPPORT
533 } // end of extern C block