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/pthread_utils.h"
35 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
36 #include "pbd/boost_debug.h"
39 #include "ardour/revision.h"
40 #include "ardour/version.h"
41 #include "ardour/ardour.h"
42 #include "ardour/audioengine.h"
43 #include "ardour/session_utils.h"
44 #include "ardour/filesystem_paths.h"
46 #include <gtkmm/main.h>
47 #include <gtkmm2ext/application.h>
48 #include <gtkmm2ext/popup.h>
49 #include <gtkmm2ext/utils.h>
51 #include <fontconfig/fontconfig.h>
55 #include "ardour_ui.h"
62 #include <Carbon/Carbon.h>
67 using namespace ARDOUR_COMMAND_LINE;
68 using namespace ARDOUR;
71 TextReceiver text_receiver ("ardour");
73 extern int curvetest (string);
75 static ARDOUR_UI *ui = 0;
76 static const char* localedir = LOCALEDIR;
81 MessageDialog win (string_compose (_("%1 could not connect to the audio backend."), PROGRAM_NAME),
86 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
87 win.set_default_response (RESPONSE_CLOSE);
90 win.set_position (Gtk::WIN_POS_CENTER);
96 /* we just don't care about the result, but we want to block */
101 static void export_search_path (const string& base_dir, const char* varname, const char* dir)
104 const char * cstr = getenv (varname);
115 setenv (varname, path.c_str(), 1);
120 #include <mach-o/dyld.h>
121 #include <sys/param.h>
123 extern void set_language_preference (); // cocoacarbon.mm
126 fixup_bundle_environment (int, char* [])
128 if (!getenv ("ARDOUR_BUNDLED")) {
132 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
134 set_language_preference ();
136 char execpath[MAXPATHLEN+1];
137 uint32_t pathsz = sizeof (execpath);
139 _NSGetExecutablePath (execpath, &pathsz);
142 std::string exec_dir = Glib::path_get_dirname (execpath);
143 std::string bundle_dir;
144 std::string userconfigdir = user_config_directory();
146 bundle_dir = Glib::path_get_dirname (exec_dir);
149 if (!ARDOUR::translations_are_enabled ()) {
150 localedir = "/this/cannot/exist";
152 /* force localedir into the bundle */
154 vector<string> lpath;
155 lpath.push_back (bundle_dir);
156 lpath.push_back ("Resources");
157 lpath.push_back ("locale");
158 localedir = strdup (Glib::build_filename (lpath).c_str());
162 export_search_path (bundle_dir, "ARDOUR_DLL_PATH", "/lib");
164 /* inside an OS X .app bundle, there is no difference
165 between DATA and CONFIG locations, since OS X doesn't
166 attempt to do anything to expose the notion of
167 machine-independent shared data.
170 export_search_path (bundle_dir, "ARDOUR_DATA_PATH", "/Resources");
171 export_search_path (bundle_dir, "ARDOUR_CONFIG_PATH", "/Resources");
172 export_search_path (bundle_dir, "ARDOUR_INSTANT_XML_PATH", "/Resources");
173 export_search_path (bundle_dir, "LADSPA_PATH", "/Plugins");
174 export_search_path (bundle_dir, "VAMP_PATH", "/lib");
175 export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines");
177 setenv ("SUIL_MODULE_DIR", (bundle_dir + "/lib").c_str(), 1);
178 setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(getenv ("PATH"))).c_str(), 1);
180 /* unset GTK_RC_FILES so that we only load the RC files that we define
183 unsetenv ("GTK_RC_FILES");
185 /* write a pango.rc file and tell pango to use it. we'd love
186 to put this into the PROGRAM_NAME.app bundle and leave it there,
187 but the user may not have write permission. so ...
189 we also have to make sure that the user ardour directory
193 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
194 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
198 path = Glib::build_filename (userconfigdir, "pango.rc");
199 std::ofstream pangorc (path.c_str());
201 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
203 pangorc << "[Pango]\nModuleFiles="
204 << Glib::build_filename (bundle_dir, "Resources/pango.modules")
208 setenv ("PANGO_RC_FILE", path.c_str(), 1);
212 setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
213 setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
214 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
217 static void load_custom_fonts() {
218 /* this code will only compile on OS X 10.6 and above, and we currently do not
219 * need it for earlier versions since we fall back on a non-monospace,
222 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
223 std::string ardour_mono_file;
225 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
226 cerr << _("Cannot find ArdourMono TrueType font") << endl;
232 ttf = CFStringCreateWithBytes(
233 kCFAllocatorDefault, (UInt8*) ardour_mono_file.c_str(),
234 ardour_mono_file.length(),
235 kCFStringEncodingUTF8, FALSE);
236 fontURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, ttf, kCFURLPOSIXPathStyle, TRUE);
237 if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error) != true) {
238 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
246 fixup_bundle_environment (int /*argc*/, char* argv[])
248 /* THIS IS FOR LINUX - its just about the only place where its
249 * acceptable to build paths directly using '/'.
252 if (!getenv ("ARDOUR_BUNDLED")) {
256 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
259 std::string dir_path = Glib::path_get_dirname (Glib::path_get_dirname (argv[0]));
260 std::string userconfigdir = user_config_directory();
263 if (!ARDOUR::translations_are_enabled ()) {
264 localedir = "/this/cannot/exist";
266 /* force localedir into the bundle */
267 vector<string> lpath;
268 lpath.push_back (dir_path);
269 lpath.push_back ("share");
270 lpath.push_back ("locale");
271 localedir = realpath (Glib::build_filename (lpath).c_str(), NULL);
275 /* note that this function is POSIX/Linux specific, so using / as
276 a dir separator in this context is just fine.
279 export_search_path (dir_path, "ARDOUR_DLL_PATH", "/lib");
280 export_search_path (dir_path, "ARDOUR_CONFIG_PATH", "/etc");
281 export_search_path (dir_path, "ARDOUR_INSTANT_XML_PATH", "/share");
282 export_search_path (dir_path, "ARDOUR_DATA_PATH", "/share");
283 export_search_path (dir_path, "LADSPA_PATH", "/plugins");
284 export_search_path (dir_path, "VAMP_PATH", "/lib");
285 export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines");
287 setenv ("SUIL_MODULE_DIR", (dir_path + "/lib").c_str(), 1);
288 setenv ("PATH", (dir_path + "/bin:" + std::string(getenv ("PATH"))).c_str(), 1);
290 /* unset GTK_RC_FILES so that we only load the RC files that we define
293 unsetenv ("GTK_RC_FILES");
295 /* Tell fontconfig where to find fonts.conf. Use the system version
296 if it exists, otherwise use the stuff we included in the bundle
299 if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
300 setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
301 setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
303 error << _("No fontconfig file found on your system. Things may looked very odd or ugly") << endmsg;
306 /* write a pango.rc file and tell pango to use it. we'd love
307 to put this into the Ardour.app bundle and leave it there,
308 but the user may not have write permission. so ...
310 we also have to make sure that the user ardour directory
314 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
315 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
319 path = Glib::build_filename (userconfigdir, "pango.rc");
320 std::ofstream pangorc (path.c_str());
322 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
324 pangorc << "[Pango]\nModuleFiles="
325 << Glib::build_filename (userconfigdir, "pango.modules")
330 setenv ("PANGO_RC_FILE", path.c_str(), 1);
332 /* similar for GDK pixbuf loaders, but there's no RC file required
333 to specify where it lives.
336 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
339 /* this doesn't do much but setting it should prevent various parts of the GTK/GNU stack
340 from looking outside the bundle to find the charset.alias file.
342 setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
346 static void load_custom_fonts() {
347 std::string ardour_mono_file;
348 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
349 cerr << _("Cannot find ArdourMono TrueType font") << endl;
352 FcConfig *config = FcInitLoadConfigAndFonts();
353 FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(ardour_mono_file.c_str()));
354 if (ret == FcFalse) {
355 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
357 ret = FcConfigSetCurrent(config);
358 if (ret == FcFalse) {
359 cerr << _("Failed to set fontconfig configuration.") << endl;
366 tell_about_backend_death (void* /* ignored */)
368 if (AudioEngine::instance()->processed_frames() == 0) {
369 /* died during startup */
370 MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
371 msg.set_position (Gtk::WIN_POS_CENTER);
372 msg.set_secondary_text (string_compose (_(
373 "%2 exited unexpectedly, and without notifying %1.\n\
375 This could be due to misconfiguration or to an error inside %2.\n\
377 Click OK to exit %1."), PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
384 /* engine has already run, so this is a mid-session backend death */
386 MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
387 msg.set_secondary_text (string_compose (_("%2 exited unexpectedly, and without notifying %1."),
388 PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
391 return false; /* do not call again */
395 sigpipe_handler (int /*signal*/)
397 /* XXX fix this so that we do this again after a reconnect to the backend
400 static bool done_the_backend_thing = false;
402 if (!done_the_backend_thing) {
403 AudioEngine::instance()->died ();
404 g_idle_add (tell_about_backend_death, 0);
405 done_the_backend_thing = true;
409 #ifdef WINDOWS_VST_SUPPORT
411 extern int windows_vst_gui_init (int* argc, char** argv[]);
413 /* this is called from the entry point of a wine-compiled
414 executable that is linked against gtk2_ardour built
418 int ardour_main (int argc, char *argv[])
420 int main (int argc, char *argv[])
423 fixup_bundle_environment (argc, argv);
425 load_custom_fonts(); /* needs to happend before any gtk and pango init calls */
427 if (!Glib::thread_supported()) {
435 #ifdef WINDOWS_VST_SUPPORT
436 /* this does some magic that is needed to make GTK and Wine's own
437 X11 client interact properly.
439 windows_vst_gui_init (&argc, &argv);
443 cerr << "bnd txt domain [" << PACKAGE << "] to " << localedir << endl;
445 (void) bindtextdomain (PACKAGE, localedir);
446 /* our i18n translations are all in UTF-8, so make sure
447 that even if the user locale doesn't specify UTF-8,
448 we use that when handling them.
450 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
453 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
455 // catch error message system signals ();
457 text_receiver.listen_to (error);
458 text_receiver.listen_to (info);
459 text_receiver.listen_to (fatal);
460 text_receiver.listen_to (warning);
462 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
463 if (getenv ("BOOST_DEBUG")) {
464 boost_debug_shared_ptr_show_live_debugging (true);
468 if (parse_opts (argc, argv)) {
474 << _(" (built using ")
477 << _(" and GCC version ") << __VERSION__
487 cerr << _("Copyright (C) 1999-2012 Paul Davis") << endl
488 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker, Robin Gareus") << endl
490 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
491 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
492 << _("This is free software, and you are welcome to redistribute it ") << endl
493 << _("under certain conditions; see the source for copying conditions.")
497 /* some GUI objects need this */
499 if (!ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) {
500 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
504 if (curvetest_file) {
505 return curvetest (curvetest_file);
508 if (::signal (SIGPIPE, sigpipe_handler)) {
509 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
513 ui = new ARDOUR_UI (&argc, &argv, localedir);
514 } catch (failed_constructor& err) {
515 error << string_compose (_("could not create %1 GUI"), PROGRAM_NAME) << endmsg;
519 ui->run (text_receiver);
520 Gtkmm2ext::Application::instance()->cleanup();
525 pthread_cancel_all ();
529 #ifdef WINDOWS_VST_SUPPORT
530 } // end of extern C block