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"
65 using namespace ARDOUR_COMMAND_LINE;
66 using namespace ARDOUR;
69 TextReceiver text_receiver ("ardour");
71 extern int curvetest (string);
73 static ARDOUR_UI *ui = 0;
74 static const char* localedir = LOCALEDIR;
79 MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
83 win.set_secondary_text(string_compose (_("There are several possible reasons:\n\
85 1) JACK is not running.\n\
86 2) JACK is running as another user, perhaps root.\n\
87 3) There is already another client called \"%1\".\n\
89 Please consider the possibilities, and perhaps (re)start JACK."), PROGRAM_NAME));
91 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
92 win.set_default_response (RESPONSE_CLOSE);
95 win.set_position (Gtk::WIN_POS_CENTER);
101 /* we just don't care about the result, but we want to block */
106 static void export_search_path (const string& base_dir, const char* varname, const char* dir)
109 const char * cstr = getenv (varname);
120 setenv (varname, path.c_str(), 1);
125 #include <mach-o/dyld.h>
126 #include <sys/param.h>
128 extern void set_language_preference (); // cocoacarbon.mm
131 fixup_bundle_environment (int, char* [])
133 if (!getenv ("ARDOUR_BUNDLED")) {
137 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
139 set_language_preference ();
141 char execpath[MAXPATHLEN+1];
142 uint32_t pathsz = sizeof (execpath);
144 _NSGetExecutablePath (execpath, &pathsz);
147 std::string exec_dir = Glib::path_get_dirname (execpath);
148 std::string bundle_dir;
149 std::string userconfigdir = user_config_directory();
151 bundle_dir = Glib::path_get_dirname (exec_dir);
154 if (!ARDOUR::translations_are_enabled ()) {
155 localedir = "/this/cannot/exist";
157 /* force localedir into the bundle */
159 vector<string> lpath;
160 lpath.push_back (bundle_dir);
161 lpath.push_back ("share");
162 lpath.push_back ("locale");
163 localedir = strdup (Glib::build_filename (lpath).c_str());
167 export_search_path (bundle_dir, "ARDOUR_DLL_PATH", "/lib");
169 /* inside an OS X .app bundle, there is no difference
170 between DATA and CONFIG locations, since OS X doesn't
171 attempt to do anything to expose the notion of
172 machine-independent shared data.
175 export_search_path (bundle_dir, "ARDOUR_DATA_PATH", "/Resources");
176 export_search_path (bundle_dir, "ARDOUR_CONFIG_PATH", "/Resources");
177 export_search_path (bundle_dir, "ARDOUR_INSTANT_XML_PATH", "/Resources");
178 export_search_path (bundle_dir, "LADSPA_PATH", "/Plugins");
179 export_search_path (bundle_dir, "VAMP_PATH", "/lib");
180 export_search_path (bundle_dir, "SUIL_MODULE_DIR", "/lib");
181 export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines");
183 /* unset GTK_RC_FILES so that we only load the RC files that we define
186 unsetenv ("GTK_RC_FILES");
188 /* write a pango.rc file and tell pango to use it. we'd love
189 to put this into the PROGRAM_NAME.app bundle and leave it there,
190 but the user may not have write permission. so ...
192 we also have to make sure that the user ardour directory
196 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
197 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
201 path = Glib::build_filename (userconfigdir, "pango.rc");
202 std::ofstream pangorc (path.c_str());
204 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
206 pangorc << "[Pango]\nModuleFiles="
207 << Glib::build_filename (bundle_dir, "Resources/pango.modules")
211 setenv ("PANGO_RC_FILE", path.c_str(), 1);
215 setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
216 setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
217 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (bundle_dir, "Resources/gdk-pixbuf.loaders").c_str(), 1);
220 #include <Carbon/Carbon.h>
222 static void load_custom_fonts() {
223 #if 0 // untested OSX code
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, ardour_mono_filec_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 (!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 = realpath (Glib::build_filename (lpath).c_str(), NULL);
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, "SUIL_MODULE_DIR", "/lib");
287 export_search_path (dir_path, "GTK_PATH", "/lib/gtkengines");
289 /* unset GTK_RC_FILES so that we only load the RC files that we define
292 unsetenv ("GTK_RC_FILES");
294 /* Tell fontconfig where to find fonts.conf. Use the system version
295 if it exists, otherwise use the stuff we included in the bundle
298 if (Glib::file_test ("/etc/fonts/fonts.conf", Glib::FILE_TEST_EXISTS)) {
299 setenv ("FONTCONFIG_FILE", "/etc/fonts/fonts.conf", 1);
300 setenv ("FONTCONFIG_PATH", "/etc/fonts", 1);
302 error << _("No fontconfig file found on your system. Things may looked very odd or ugly") << endmsg;
305 /* write a pango.rc file and tell pango to use it. we'd love
306 to put this into the Ardour.app bundle and leave it there,
307 but the user may not have write permission. so ...
309 we also have to make sure that the user ardour directory
313 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
314 error << string_compose (_("cannot create user %3 folder %1 (%2)"), userconfigdir, strerror (errno), PROGRAM_NAME)
318 path = Glib::build_filename (userconfigdir, "pango.rc");
319 std::ofstream pangorc (path.c_str());
321 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
323 pangorc << "[Pango]\nModuleFiles="
324 << Glib::build_filename (userconfigdir, "pango.modules")
329 setenv ("PANGO_RC_FILE", path.c_str(), 1);
331 /* similar for GDK pixbuf loaders, but there's no RC file required
332 to specify where it lives.
335 setenv ("GDK_PIXBUF_MODULE_FILE", Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders").c_str(), 1);
338 /* this doesn't do much but setting it should prevent various parts of the GTK/GNU stack
339 from looking outside the bundle to find the charset.alias file.
341 setenv ("CHARSETALIASDIR", dir_path.c_str(), 1);
345 static void load_custom_fonts() {
346 std::string ardour_mono_file;
347 if (!find_file_in_search_path (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
348 cerr << _("Cannot find ArdourMono TrueType font") << endl;
351 FcConfig *config = FcInitLoadConfigAndFonts();
352 FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(ardour_mono_file.c_str()));
353 if (ret == FcFalse) {
354 cerr << _("Cannot load ArdourMono TrueType font.") << endl;
356 ret = FcConfigSetCurrent(config);
357 if (ret == FcFalse) {
358 cerr << _("Failed to set fontconfig configuration.") << endl;
365 tell_about_jack_death (void* /* ignored */)
367 if (AudioEngine::instance()->processed_frames() == 0) {
368 /* died during startup */
369 MessageDialog msg (_("JACK exited"), false);
370 msg.set_position (Gtk::WIN_POS_CENTER);
371 msg.set_secondary_text (string_compose (_(
372 "JACK exited unexpectedly, and without notifying %1.\n\
374 This could be due to misconfiguration or to an error inside JACK.\n\
376 Click OK to exit %1."), PROGRAM_NAME));
383 /* engine has already run, so this is a mid-session JACK death */
385 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false));
386 msg->set_secondary_text (string_compose (_(
387 "JACK exited unexpectedly, and without notifying %1.\n\
389 This is probably due to an error inside JACK. You should restart JACK\n\
390 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
391 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
394 return false; /* do not call again */
398 sigpipe_handler (int /*signal*/)
400 /* XXX fix this so that we do this again after a reconnect to JACK
403 static bool done_the_jack_thing = false;
405 if (!done_the_jack_thing) {
406 AudioEngine::instance()->died ();
407 g_idle_add (tell_about_jack_death, 0);
408 done_the_jack_thing = true;
412 #ifdef WINDOWS_VST_SUPPORT
414 extern int windows_vst_gui_init (int* argc, char** argv[]);
416 /* this is called from the entry point of a wine-compiled
417 executable that is linked against gtk2_ardour built
421 int ardour_main (int argc, char *argv[])
423 int main (int argc, char *argv[])
426 fixup_bundle_environment (argc, argv);
428 load_custom_fonts(); /* needs to happend before any gtk and pango init calls */
430 if (!Glib::thread_supported()) {
438 #ifdef WINDOWS_VST_SUPPORT
439 /* this does some magic that is needed to make GTK and Wine's own
440 X11 client interact properly.
442 windows_vst_gui_init (&argc, &argv);
446 cerr << "bnd txt domain [" << PACKAGE << "] to " << localedir << endl;
448 (void) bindtextdomain (PACKAGE, localedir);
449 /* our i18n translations are all in UTF-8, so make sure
450 that even if the user locale doesn't specify UTF-8,
451 we use that when handling them.
453 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
456 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
458 // catch error message system signals ();
460 text_receiver.listen_to (error);
461 text_receiver.listen_to (info);
462 text_receiver.listen_to (fatal);
463 text_receiver.listen_to (warning);
465 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
466 if (getenv ("BOOST_DEBUG")) {
467 boost_debug_shared_ptr_show_live_debugging (true);
471 if (parse_opts (argc, argv)) {
475 if (curvetest_file) {
476 return curvetest (curvetest_file);
481 << _(" (built using ")
484 << _(" and GCC version ") << __VERSION__
494 cerr << _("Copyright (C) 1999-2012 Paul Davis") << endl
495 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker, Robin Gareus") << endl
497 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
498 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
499 << _("This is free software, and you are welcome to redistribute it ") << endl
500 << _("under certain conditions; see the source for copying conditions.")
504 /* some GUI objects need this */
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();
524 pthread_cancel_all ();
528 #ifdef WINDOWS_VST_SUPPORT
529 } // end of extern C block