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 <jack/jack.h>
41 #include "ardour/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"
48 #include <gtkmm/main.h>
49 #include <gtkmm2ext/application.h>
50 #include <gtkmm2ext/popup.h>
51 #include <gtkmm2ext/utils.h>
53 #include <fontconfig/fontconfig.h>
57 #include "ardour_ui.h"
64 #include <Carbon/Carbon.h>
69 using namespace ARDOUR_COMMAND_LINE;
70 using namespace ARDOUR;
73 TextReceiver text_receiver ("ardour");
75 extern int curvetest (string);
77 static ARDOUR_UI *ui = 0;
78 static const char* localedir = LOCALEDIR;
83 MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
87 win.set_secondary_text(string_compose (_("There are several possible reasons:\n\
89 1) JACK is not running.\n\
90 2) JACK is running as another user, perhaps root.\n\
91 3) There is already another client called \"%1\".\n\
93 Please consider the possibilities, and perhaps (re)start JACK."), PROGRAM_NAME));
95 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
96 win.set_default_response (RESPONSE_CLOSE);
99 win.set_position (Gtk::WIN_POS_CENTER);
105 /* we just don't care about the result, but we want to block */
110 static void export_search_path (const string& base_dir, const char* varname, const char* dir)
113 const char * cstr = getenv (varname);
124 setenv (varname, path.c_str(), 1);
129 #include <mach-o/dyld.h>
130 #include <sys/param.h>
132 extern void set_language_preference (); // cocoacarbon.mm
135 fixup_bundle_environment (int, char* [])
137 if (!getenv ("ARDOUR_BUNDLED")) {
141 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
143 set_language_preference ();
145 char execpath[MAXPATHLEN+1];
146 uint32_t pathsz = sizeof (execpath);
148 _NSGetExecutablePath (execpath, &pathsz);
151 std::string exec_dir = Glib::path_get_dirname (execpath);
152 std::string bundle_dir;
153 std::string userconfigdir = user_config_directory();
155 bundle_dir = Glib::path_get_dirname (exec_dir);
158 if (!ARDOUR::translations_are_enabled ()) {
159 localedir = "/this/cannot/exist";
161 /* force localedir into the bundle */
163 vector<string> lpath;
164 lpath.push_back (bundle_dir);
165 lpath.push_back ("share");
166 lpath.push_back ("locale");
167 localedir = strdup (Glib::build_filename (lpath).c_str());
171 export_search_path (bundle_dir, "ARDOUR_DLL_PATH", "/lib");
173 /* inside an OS X .app bundle, there is no difference
174 between DATA and CONFIG locations, since OS X doesn't
175 attempt to do anything to expose the notion of
176 machine-independent shared data.
179 export_search_path (bundle_dir, "ARDOUR_DATA_PATH", "/Resources");
180 export_search_path (bundle_dir, "ARDOUR_CONFIG_PATH", "/Resources");
181 export_search_path (bundle_dir, "ARDOUR_INSTANT_XML_PATH", "/Resources");
182 export_search_path (bundle_dir, "LADSPA_PATH", "/Plugins");
183 export_search_path (bundle_dir, "VAMP_PATH", "/lib");
184 export_search_path (bundle_dir, "SUIL_MODULE_DIR", "/lib");
185 export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines");
187 setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(getenv ("PATH"))).c_str(), 1);
189 /* unset GTK_RC_FILES so that we only load the RC files that we define
192 unsetenv ("GTK_RC_FILES");
194 /* write a pango.rc file and tell pango to use it. we'd love
195 to put this into the PROGRAM_NAME.app bundle and leave it there,
196 but the user may not have write permission. so ...
198 we also have to make sure that the user ardour directory
202 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
203 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
207 path = Glib::build_filename (userconfigdir, "pango.rc");
208 std::ofstream pangorc (path.c_str());
210 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
212 pangorc << "[Pango]\nModuleFiles="
213 << Glib::build_filename (bundle_dir, "Resources/pango.modules")
217 setenv ("PANGO_RC_FILE", path.c_str(), 1);
221 setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
222 setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
223 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
226 static void load_custom_fonts() {
227 /* this code will only compile on OS X 10.6 and above, and we currently do not
228 * need it for earlier versions since we fall back on a non-monospace,
231 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
232 std::string ardour_mono_file;
234 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
235 cerr << _("Cannot find ArdourMono TrueType font") << endl;
241 ttf = CFStringCreateWithBytes(
242 kCFAllocatorDefault, (UInt8*) ardour_mono_file.c_str(),
243 ardour_mono_file.length(),
244 kCFStringEncodingUTF8, FALSE);
245 fontURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, ttf, kCFURLPOSIXPathStyle, TRUE);
246 if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error) != true) {
247 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
255 fixup_bundle_environment (int /*argc*/, char* argv[])
257 /* THIS IS FOR LINUX - its just about the only place where its
258 * acceptable to build paths directly using '/'.
261 if (!getenv ("ARDOUR_BUNDLED")) {
265 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
268 std::string dir_path = Glib::path_get_dirname (Glib::path_get_dirname (argv[0]));
269 std::string userconfigdir = user_config_directory();
272 if (!ARDOUR::translations_are_enabled ()) {
273 localedir = "/this/cannot/exist";
275 /* force localedir into the bundle */
276 vector<string> lpath;
277 lpath.push_back (dir_path);
278 lpath.push_back ("share");
279 lpath.push_back ("locale");
280 localedir = realpath (Glib::build_filename (lpath).c_str(), NULL);
284 /* note that this function is POSIX/Linux specific, so using / as
285 a dir separator in this context is just fine.
288 export_search_path (dir_path, "ARDOUR_DLL_PATH", "/lib");
289 export_search_path (dir_path, "ARDOUR_CONFIG_PATH", "/etc");
290 export_search_path (dir_path, "ARDOUR_INSTANT_XML_PATH", "/share");
291 export_search_path (dir_path, "ARDOUR_DATA_PATH", "/share");
292 export_search_path (dir_path, "LADSPA_PATH", "/plugins");
293 export_search_path (dir_path, "VAMP_PATH", "/lib");
294 export_search_path (dir_path, "SUIL_MODULE_DIR", "/lib");
295 export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines");
297 setenv ("PATH", (dir_path + "/bin:" + std::string(getenv ("PATH"))).c_str(), 1);
299 /* unset GTK_RC_FILES so that we only load the RC files that we define
302 unsetenv ("GTK_RC_FILES");
304 /* Tell fontconfig where to find fonts.conf. Use the system version
305 if it exists, otherwise use the stuff we included in the bundle
308 if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
309 setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
310 setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
312 error << _("No fontconfig file found on your system. Things may looked very odd or ugly") << endmsg;
315 /* write a pango.rc file and tell pango to use it. we'd love
316 to put this into the Ardour.app bundle and leave it there,
317 but the user may not have write permission. so ...
319 we also have to make sure that the user ardour directory
323 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
324 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
328 path = Glib::build_filename (userconfigdir, "pango.rc");
329 std::ofstream pangorc (path.c_str());
331 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
333 pangorc << "[Pango]\nModuleFiles="
334 << Glib::build_filename (userconfigdir, "pango.modules")
339 setenv ("PANGO_RC_FILE", path.c_str(), 1);
341 /* similar for GDK pixbuf loaders, but there's no RC file required
342 to specify where it lives.
345 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
348 /* this doesn't do much but setting it should prevent various parts of the GTK/GNU stack
349 from looking outside the bundle to find the charset.alias file.
351 setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
355 static void load_custom_fonts() {
356 std::string ardour_mono_file;
357 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
358 cerr << _("Cannot find ArdourMono TrueType font") << endl;
361 FcConfig *config = FcInitLoadConfigAndFonts();
362 FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(ardour_mono_file.c_str()));
363 if (ret == FcFalse) {
364 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
366 ret = FcConfigSetCurrent(config);
367 if (ret == FcFalse) {
368 cerr << _("Failed to set fontconfig configuration.") << endl;
375 tell_about_backend_death (void* /* ignored */)
377 if (AudioEngine::instance()->processed_frames() == 0) {
378 /* died during startup */
379 MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
380 msg.set_position (Gtk::WIN_POS_CENTER);
381 msg.set_secondary_text (string_compose (_(
382 "%2 exited unexpectedly, and without notifying %1.\n\
384 This could be due to misconfiguration or to an error inside %2.\n\
386 Click OK to exit %1."), PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
393 /* engine has already run, so this is a mid-session backend death */
395 MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
396 msg.set_secondary_text (string_compose (_("%2 exited unexpectedly, and without notifying %1."),
397 PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
400 return false; /* do not call again */
404 sigpipe_handler (int /*signal*/)
406 /* XXX fix this so that we do this again after a reconnect to the backend
409 static bool done_the_backend_thing = false;
411 if (!done_the_backend_thing) {
412 AudioEngine::instance()->died ();
413 g_idle_add (tell_about_backend_death, 0);
414 done_the_backend_thing = true;
418 #ifdef WINDOWS_VST_SUPPORT
420 extern int windows_vst_gui_init (int* argc, char** argv[]);
422 /* this is called from the entry point of a wine-compiled
423 executable that is linked against gtk2_ardour built
427 int ardour_main (int argc, char *argv[])
429 int main (int argc, char *argv[])
432 fixup_bundle_environment (argc, argv);
434 load_custom_fonts(); /* needs to happend before any gtk and pango init calls */
436 if (!Glib::thread_supported()) {
444 #ifdef WINDOWS_VST_SUPPORT
445 /* this does some magic that is needed to make GTK and Wine's own
446 X11 client interact properly.
448 windows_vst_gui_init (&argc, &argv);
452 cerr << "bnd txt domain [" << PACKAGE << "] to " << localedir << endl;
454 (void) bindtextdomain (PACKAGE, localedir);
455 /* our i18n translations are all in UTF-8, so make sure
456 that even if the user locale doesn't specify UTF-8,
457 we use that when handling them.
459 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
462 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
464 // catch error message system signals ();
466 text_receiver.listen_to (error);
467 text_receiver.listen_to (info);
468 text_receiver.listen_to (fatal);
469 text_receiver.listen_to (warning);
471 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
472 if (getenv ("BOOST_DEBUG")) {
473 boost_debug_shared_ptr_show_live_debugging (true);
477 if (parse_opts (argc, argv)) {
481 if (curvetest_file) {
482 return curvetest (curvetest_file);
487 << _(" (built using ")
490 << _(" and GCC version ") << __VERSION__
500 cerr << _("Copyright (C) 1999-2012 Paul Davis") << endl
501 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker, Robin Gareus") << endl
503 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
504 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
505 << _("This is free software, and you are welcome to redistribute it ") << endl
506 << _("under certain conditions; see the source for copying conditions.")
510 /* some GUI objects need this */
514 if (::signal (SIGPIPE, sigpipe_handler)) {
515 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
519 ui = new ARDOUR_UI (&argc, &argv, localedir);
520 } catch (failed_constructor& err) {
521 error << string_compose (_("could not create %1 GUI"), PROGRAM_NAME) << endmsg;
525 ui->run (text_receiver);
526 Gtkmm2ext::Application::instance()->cleanup();
530 pthread_cancel_all ();
534 #ifdef WINDOWS_VST_SUPPORT
535 } // end of extern C block