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/svn_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 /* unset GTK_RC_FILES so that we only load the RC files that we define
190 unsetenv ("GTK_RC_FILES");
192 /* write a pango.rc file and tell pango to use it. we'd love
193 to put this into the PROGRAM_NAME.app bundle and leave it there,
194 but the user may not have write permission. so ...
196 we also have to make sure that the user ardour directory
200 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
201 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
205 path = Glib::build_filename (userconfigdir, "pango.rc");
206 std::ofstream pangorc (path.c_str());
208 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
210 pangorc << "[Pango]\nModuleFiles="
211 << Glib::build_filename (bundle_dir, "Resources/pango.modules")
215 setenv ("PANGO_RC_FILE", path.c_str(), 1);
219 setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
220 setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
221 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
224 static void load_custom_fonts() {
225 #if MAC_OS_X_VERSION_MIN_REQUIRED > 1060
226 std::string ardour_mono_file;
228 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
229 cerr << _("Cannot find ArdourMono TrueType font") << endl;
235 ttf = CFStringCreateWithBytes(
236 kCFAllocatorDefault, (UInt8*) ardour_mono_file.c_str(),
237 ardour_mono_file.length(),
238 kCFStringEncodingUTF8, FALSE);
239 fontURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, ttf, kCFURLPOSIXPathStyle, TRUE);
240 if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error) != true) {
241 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
244 /* no real usable API for this on OS X 10.5 or below */
251 fixup_bundle_environment (int /*argc*/, char* argv[])
253 /* THIS IS FOR LINUX - its just about the only place where its
254 * acceptable to build paths directly using '/'.
257 if (!getenv ("ARDOUR_BUNDLED")) {
261 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
264 std::string dir_path = Glib::path_get_dirname (Glib::path_get_dirname (argv[0]));
265 std::string userconfigdir = user_config_directory();
268 if (!ARDOUR::translations_are_enabled ()) {
269 localedir = "/this/cannot/exist";
271 /* force localedir into the bundle */
272 vector<string> lpath;
273 lpath.push_back (dir_path);
274 lpath.push_back ("share");
275 lpath.push_back ("locale");
276 localedir = realpath (Glib::build_filename (lpath).c_str(), NULL);
280 /* note that this function is POSIX/Linux specific, so using / as
281 a dir separator in this context is just fine.
284 export_search_path (dir_path, "ARDOUR_DLL_PATH", "/lib");
285 export_search_path (dir_path, "ARDOUR_CONFIG_PATH", "/etc");
286 export_search_path (dir_path, "ARDOUR_INSTANT_XML_PATH", "/share");
287 export_search_path (dir_path, "ARDOUR_DATA_PATH", "/share");
288 export_search_path (dir_path, "LADSPA_PATH", "/plugins");
289 export_search_path (dir_path, "VAMP_PATH", "/lib");
290 export_search_path (dir_path, "SUIL_MODULE_DIR", "/lib");
291 export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines");
293 /* unset GTK_RC_FILES so that we only load the RC files that we define
296 unsetenv ("GTK_RC_FILES");
298 /* Tell fontconfig where to find fonts.conf. Use the system version
299 if it exists, otherwise use the stuff we included in the bundle
302 if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
303 setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
304 setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
306 error << _("No fontconfig file found on your system. Things may looked very odd or ugly") << endmsg;
309 /* write a pango.rc file and tell pango to use it. we'd love
310 to put this into the Ardour.app bundle and leave it there,
311 but the user may not have write permission. so ...
313 we also have to make sure that the user ardour directory
317 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
318 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
322 path = Glib::build_filename (userconfigdir, "pango.rc");
323 std::ofstream pangorc (path.c_str());
325 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
327 pangorc << "[Pango]\nModuleFiles="
328 << Glib::build_filename (userconfigdir, "pango.modules")
333 setenv ("PANGO_RC_FILE", path.c_str(), 1);
335 /* similar for GDK pixbuf loaders, but there's no RC file required
336 to specify where it lives.
339 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
342 /* this doesn't do much but setting it should prevent various parts of the GTK/GNU stack
343 from looking outside the bundle to find the charset.alias file.
345 setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
349 static void load_custom_fonts() {
350 std::string ardour_mono_file;
351 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
352 cerr << _("Cannot find ArdourMono TrueType font") << endl;
355 FcConfig *config = FcInitLoadConfigAndFonts();
356 FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(ardour_mono_file.c_str()));
357 if (ret == FcFalse) {
358 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
360 ret = FcConfigSetCurrent(config);
361 if (ret == FcFalse) {
362 cerr << _("Failed to set fontconfig configuration.") << endl;
369 tell_about_jack_death (void* /* ignored */)
371 if (AudioEngine::instance()->processed_frames() == 0) {
372 /* died during startup */
373 MessageDialog msg (_("JACK exited"), false);
374 msg.set_position (Gtk::WIN_POS_CENTER);
375 msg.set_secondary_text (string_compose (_(
376 "JACK exited unexpectedly, and without notifying %1.\n\
378 This could be due to misconfiguration or to an error inside JACK.\n\
380 Click OK to exit %1."), PROGRAM_NAME));
387 /* engine has already run, so this is a mid-session JACK death */
389 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false));
390 msg->set_secondary_text (string_compose (_(
391 "JACK exited unexpectedly, and without notifying %1.\n\
393 This is probably due to an error inside JACK. You should restart JACK\n\
394 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
395 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
398 return false; /* do not call again */
402 sigpipe_handler (int /*signal*/)
404 /* XXX fix this so that we do this again after a reconnect to JACK
407 static bool done_the_jack_thing = false;
409 if (!done_the_jack_thing) {
410 AudioEngine::instance()->died ();
411 g_idle_add (tell_about_jack_death, 0);
412 done_the_jack_thing = true;
416 #ifdef WINDOWS_VST_SUPPORT
418 extern int windows_vst_gui_init (int* argc, char** argv[]);
420 /* this is called from the entry point of a wine-compiled
421 executable that is linked against gtk2_ardour built
425 int ardour_main (int argc, char *argv[])
427 int main (int argc, char *argv[])
430 fixup_bundle_environment (argc, argv);
432 load_custom_fonts(); /* needs to happend before any gtk and pango init calls */
434 if (!Glib::thread_supported()) {
442 #ifdef WINDOWS_VST_SUPPORT
443 /* this does some magic that is needed to make GTK and Wine's own
444 X11 client interact properly.
446 windows_vst_gui_init (&argc, &argv);
450 cerr << "bnd txt domain [" << PACKAGE << "] to " << localedir << endl;
452 (void) bindtextdomain (PACKAGE, localedir);
453 /* our i18n translations are all in UTF-8, so make sure
454 that even if the user locale doesn't specify UTF-8,
455 we use that when handling them.
457 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
460 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
462 // catch error message system signals ();
464 text_receiver.listen_to (error);
465 text_receiver.listen_to (info);
466 text_receiver.listen_to (fatal);
467 text_receiver.listen_to (warning);
469 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
470 if (getenv ("BOOST_DEBUG")) {
471 boost_debug_shared_ptr_show_live_debugging (true);
475 if (parse_opts (argc, argv)) {
479 if (curvetest_file) {
480 return curvetest (curvetest_file);
485 << _(" (built using ")
488 << _(" and GCC version ") << __VERSION__
498 cerr << _("Copyright (C) 1999-2012 Paul Davis") << endl
499 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker, Robin Gareus") << endl
501 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
502 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
503 << _("This is free software, and you are welcome to redistribute it ") << endl
504 << _("under certain conditions; see the source for copying conditions.")
508 /* some GUI objects need this */
512 if (::signal (SIGPIPE, sigpipe_handler)) {
513 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
517 ui = new ARDOUR_UI (&argc, &argv, localedir);
518 } catch (failed_constructor& err) {
519 error << string_compose (_("could not create %1 GUI"), PROGRAM_NAME) << endmsg;
523 ui->run (text_receiver);
524 Gtkmm2ext::Application::instance()->cleanup();
528 pthread_cancel_all ();
532 #ifdef WINDOWS_VST_SUPPORT
533 } // end of extern C block