po name changes, again?
[ardour.git] / gtk2_ardour / main.cc
1 /*
2     Copyright (C) 2001-2007 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <cstdlib>
21 #include <signal.h>
22 #include <cerrno>
23 #include <fstream>
24
25 #include <sigc++/bind.h>
26 #include <gtkmm/settings.h>
27
28 #include "pbd/error.h"
29 #include "pbd/epa.h"
30 #include "pbd/file_utils.h"
31 #include "pbd/textreceiver.h"
32 #include "pbd/failed_constructor.h"
33 #include "pbd/pthread_utils.h"
34
35 #include <jack/jack.h>
36
37 #include "ardour/svn_revision.h"
38 #include "ardour/version.h"
39 #include "ardour/ardour.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/session_utils.h"
42 #include "ardour/filesystem_paths.h"
43
44 #include <gtkmm/main.h>
45 #include <gtkmm2ext/application.h>
46 #include <gtkmm2ext/popup.h>
47 #include <gtkmm2ext/utils.h>
48
49 #include "version.h"
50 #include "utils.h"
51 #include "ardour_ui.h"
52 #include "opts.h"
53 #include "enums.h"
54
55 #include "i18n.h"
56
57 using namespace std;
58 using namespace Gtk;
59 using namespace ARDOUR_COMMAND_LINE;
60 using namespace ARDOUR;
61 using namespace PBD;
62
63 TextReceiver text_receiver ("ardour");
64
65 extern int curvetest (string);
66
67 static ARDOUR_UI  *ui = 0;
68 static const char* localedir = LOCALEDIR;
69
70 void
71 gui_jack_error ()
72 {
73         MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
74                      false,
75                      Gtk::MESSAGE_INFO,
76                      (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
77 win.set_secondary_text(_("There are several possible reasons:\n\
78 \n\
79 1) JACK is not running.\n\
80 2) JACK is running as another user, perhaps root.\n\
81 3) There is already another client called \"ardour\".\n\
82 \n\
83 Please consider the possibilities, and perhaps (re)start JACK."));
84
85         win.add_button (Stock::QUIT, RESPONSE_CLOSE);
86         win.set_default_response (RESPONSE_CLOSE);
87
88         win.show_all ();
89         win.set_position (Gtk::WIN_POS_CENTER);
90
91         if (!no_splash) {
92                 ui->hide_splash ();
93         }
94
95         /* we just don't care about the result, but we want to block */
96
97         win.run ();
98 }
99
100
101 #ifdef __APPLE__
102
103 #include <mach-o/dyld.h>
104 #include <sys/param.h>
105
106 extern void set_language_preference (); // cocoacarbon.mm
107
108 void
109 fixup_bundle_environment ()
110 {
111         if (!getenv ("ARDOUR_BUNDLED")) {
112                 return;
113         }
114
115         EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
116
117         set_language_preference ();
118
119         char execpath[MAXPATHLEN+1];
120         uint32_t pathsz = sizeof (execpath);
121
122         _NSGetExecutablePath (execpath, &pathsz);
123
124         std::string exec_path (execpath);
125         std::string dir_path = Glib::path_get_dirname (exec_path);
126         std::string path;
127         const char *cstr = getenv ("PATH");
128
129         /* ensure that we find any bundled executables (e.g. JACK),
130            and find them before any instances of the same name
131            elsewhere in PATH
132         */
133
134         path = dir_path;
135
136         /* JACK is often in /usr/local/bin and since Info.plist refuses to 
137            set PATH, we have to force this in order to discover a running
138            instance of JACK ...
139         */
140         
141         path += ':';
142         path += "/usr/local/bin";
143
144         if (cstr) {
145                 path += ':';
146                 path += cstr;
147         }
148         setenv ("PATH", path.c_str(), 1);
149
150         path = dir_path;
151         path += "/../Resources";
152         path += dir_path;
153         path += "/../Resources/Surfaces";
154         path += dir_path;
155         path += "/../Resources/Panners";
156
157         setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
158
159         path = user_config_directory().to_string();
160         path += ':';
161         path += dir_path;
162         path += "/../Resources/icons:";
163         path += dir_path;
164         path += "/../Resources/pixmaps:";
165         path += dir_path;
166         path += "/../Resources/share:";
167         path += dir_path;
168         path += "/../Resources";
169
170         setenv ("ARDOUR_PATH", path.c_str(), 1);
171         setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
172
173         path = dir_path;
174         path += "/../Resources";
175         setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
176
177         cstr = getenv ("LADSPA_PATH");
178         if (cstr) {
179                 path = cstr;
180                 path += ':';
181         } else {
182                 path = "";
183         }
184         path += dir_path;
185         path += "/../Plugins";
186
187         setenv ("LADSPA_PATH", path.c_str(), 1);
188
189         cstr = getenv ("VAMP_PATH");
190         if (cstr) {
191                 path = cstr;
192                 path += ':';
193         } else {
194                 path = "";
195         }
196         path += dir_path;
197         path += "/../Frameworks";
198
199         setenv ("VAMP_PATH", path.c_str(), 1);
200
201         cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
202         if (cstr) {
203                 path = cstr;
204                 path += ':';
205         } else {
206                 path = "";
207         }
208         path += dir_path;
209         path += "/../Surfaces";
210
211         setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
212
213         cstr = getenv ("LV2_PATH");
214         if (cstr) {
215                 path = cstr;
216                 path += ':';
217         } else {
218                 path = "";
219         }
220         path += dir_path;
221         path += "/../Plugins";
222
223         setenv ("LV2_PATH", path.c_str(), 1);
224
225         path = dir_path;
226         path += "/../Frameworks/clearlooks";
227
228         setenv ("GTK_PATH", path.c_str(), 1);
229
230         if (!ARDOUR::translations_are_disabled ()) {
231
232                 path = dir_path;
233                 path += "/../Resources/locale";
234                 
235                 localedir = strdup (path.c_str());
236                 setenv ("GTK_LOCALEDIR", localedir, 1);
237         }
238
239         /* write a pango.rc file and tell pango to use it. we'd love
240            to put this into the PROGRAM_NAME.app bundle and leave it there,
241            but the user may not have write permission. so ...
242
243            we also have to make sure that the user ardour directory
244            actually exists ...
245         */
246
247         try {
248                 sys::create_directories (user_config_directory ());
249         }
250         catch (const sys::filesystem_error& ex) {
251                 error << _("Could not create user configuration directory") << endmsg;
252         }
253
254         sys::path pangopath = user_config_directory();
255         pangopath /= "pango.rc";
256         path = pangopath.to_string();
257
258         std::ofstream pangorc (path.c_str());
259         if (!pangorc) {
260                 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
261                 return;
262         } else {
263                 pangorc << "[Pango]\nModuleFiles=";
264
265                 pangopath = dir_path;
266                 pangopath /= "..";
267                 pangopath /= "Resources";
268                 pangopath /= "pango.modules";
269
270                 pangorc << pangopath.to_string() << endl;
271
272                 pangorc.close ();
273
274                 setenv ("PANGO_RC_FILE", path.c_str(), 1);
275         }
276
277         // gettext charset aliases
278
279         setenv ("CHARSETALIASDIR", path.c_str(), 1);
280
281         // font config
282
283         path = dir_path;
284         path += "/../Resources/fonts.conf";
285
286         setenv ("FONTCONFIG_FILE", path.c_str(), 1);
287
288         // GDK Pixbuf loader module file
289
290         path = dir_path;
291         path += "/../Resources/gdk-pixbuf.loaders";
292
293         setenv ("GDK_PIXBUF_MODULE_FILE", path.c_str(), 1);
294
295         if (getenv ("ARDOUR_WITH_JACK")) {
296                 // JACK driver dir
297
298                 path = dir_path;
299                 path += "/../Frameworks";
300
301                 setenv ("JACK_DRIVER_DIR", path.c_str(), 1);
302         }
303 }
304
305 #else
306
307 void
308 fixup_bundle_environment (int argc, char* argv[])
309 {
310         if (!getenv ("ARDOUR_BUNDLED")) {
311                 return;
312         }
313         
314         EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
315
316         Glib::ustring exec_path = argv[0];
317         Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (exec_path));
318         Glib::ustring path;
319         const char *cstr = getenv ("PATH");
320         Glib::ustring userconfigdir = user_config_directory().to_string();
321
322         /* ensure that we find any bundled executables (e.g. JACK),
323            and find them before any instances of the same name
324            elsewhere in PATH
325         */
326
327         /* note that this function is POSIX/Linux specific, so using / as 
328            a dir separator in this context is just fine.
329         */
330
331         path = dir_path;
332         path += "/etc:";
333         path += dir_path;
334         path += "/lib/surfaces:";
335         path += dir_path;
336         path += "/lib/panners:";
337
338         setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
339
340         path = userconfigdir;
341         path += ':';
342         path += dir_path;
343         path += "/etc/icons:";
344         path += dir_path;
345         path += "/etc/pixmaps:";
346         path += dir_path;
347         path += "/share:";
348         path += dir_path;
349         path += "/etc";
350
351         setenv ("ARDOUR_PATH", path.c_str(), 1);
352         setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
353
354         path = dir_path;
355         path += "/etc";
356         setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
357
358         cstr = getenv ("LADSPA_PATH");
359         if (cstr) {
360                 path = cstr;
361                 path += ':';
362         } else {
363                 path = "";
364         }
365         path += dir_path;
366         path += "/lib/plugins";
367         
368         setenv ("LADSPA_PATH", path.c_str(), 1);
369
370         cstr = getenv ("VAMP_PATH");
371         if (cstr) {
372                 path = cstr;
373                 path += ':';
374         } else {
375                 path = "";
376         }
377         path += dir_path;
378         path += "/lib";
379         
380         setenv ("VAMP_PATH", path.c_str(), 1);
381
382         cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
383         if (cstr) {
384                 path = cstr;
385                 path += ':';
386         } else {
387                 path = "";
388         }
389         path += dir_path;
390         path += "/lib/surfaces";
391         
392         setenv ("ARDOUR_CONTROL_SURFACE_PATH", path.c_str(), 1);
393
394         cstr = getenv ("LV2_PATH");
395         if (cstr) {
396                 path = cstr;
397                 path += ':';
398         } else {
399                 path = "";
400         }
401         path += dir_path;
402         path += "/lib/plugins";
403         
404         setenv ("LV2_PATH", path.c_str(), 1);
405
406         path = dir_path;
407         path += "/lib/clearlooks";
408
409         setenv ("GTK_PATH", path.c_str(), 1);
410
411         if (!ARDOUR::translations_are_disabled ()) {
412                 path = dir_path;
413                 path += "/share/locale";
414                 
415                 localedir = strdup (path.c_str());
416                 setenv ("GTK_LOCALEDIR", localedir, 1);
417         }
418
419         /* write a pango.rc file and tell pango to use it. we'd love
420            to put this into the Ardour.app bundle and leave it there,
421            but the user may not have write permission. so ... 
422
423            we also have to make sure that the user ardour directory
424            actually exists ...
425         */
426
427         if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
428                 error << string_compose (_("cannot create user ardour folder %1 (%2)"), userconfigdir, strerror (errno))
429                       << endmsg;
430         } else {
431
432                 Glib::ustring mpath;
433
434                 path = Glib::build_filename (userconfigdir, "pango.rc");
435
436                 std::ofstream pangorc (path.c_str());
437                 if (!pangorc) {
438                         error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
439                 } else {
440                         mpath = Glib::build_filename (userconfigdir, "pango.modules");
441                         
442                         pangorc << "[Pango]\nModuleFiles=";
443                         pangorc << mpath << endl;
444                         pangorc.close ();
445                 }
446
447                 setenv ("PANGO_RC_FILE", path.c_str(), 1);
448
449                 /* similar for GDK pixbuf loaders, but there's no RC file required
450                    to specify where it lives.
451                 */
452
453                 mpath = Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders");
454                 setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
455         }
456 }
457
458 #endif
459
460 static gboolean
461 tell_about_jack_death (void* /* ignored */)
462 {
463         if (AudioEngine::instance()->processed_frames() == 0) {
464                 /* died during startup */
465                 MessageDialog msg (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
466                 msg.set_position (Gtk::WIN_POS_CENTER);
467                 msg.set_secondary_text (string_compose (_(
468 "JACK exited unexpectedly, and without notifying %1.\n\
469 \n\
470 This could be due to misconfiguration or to an error inside JACK.\n\
471 \n\
472 Click OK to exit %1."), PROGRAM_NAME));
473     
474                 msg.run ();
475                 _exit (0);
476                 
477         } else {
478
479                 /* engine has already run, so this is a mid-session JACK death */
480                 
481                 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE));
482                 msg->set_secondary_text (string_compose (_(
483 "JACK exited unexpectedly, and without notifying %1.\n\
484 \n\
485 This is probably due to an error inside JACK. You should restart JACK\n\
486 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
487 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
488                 msg->present ();
489         }
490         return false; /* do not call again */
491 }
492
493 static void
494 sigpipe_handler (int /*signal*/)
495 {
496         /* XXX fix this so that we do this again after a reconnect to JACK
497          */
498
499         static bool done_the_jack_thing = false;
500         
501         if (!done_the_jack_thing) {
502                 AudioEngine::instance()->died ();
503                 g_idle_add (tell_about_jack_death, 0);
504                 done_the_jack_thing =  true;
505         }
506 }
507
508 #ifdef HAVE_LV2
509 void close_external_ui_windows();
510 #endif
511
512 #ifdef VST_SUPPORT
513
514 extern int gui_init (int* argc, char** argv[]);
515
516 /* this is called from the entry point of a wine-compiled
517    executable that is linked against gtk2_ardour built
518    as a shared library.
519 */
520 extern "C" {
521 int ardour_main (int argc, char *argv[])
522 #else
523 int main (int argc, char *argv[])
524 #endif
525 {
526 #ifdef __APPLE__
527         fixup_bundle_environment ();
528 #endif
529
530         if (!Glib::thread_supported())
531                 Glib::thread_init();
532
533         gtk_set_locale ();
534
535 #ifdef VST_SUPPORT
536         /* this does some magic that is needed to make GTK and Wine's own
537            X11 client interact properly.
538         */
539         gui_init (&argc, &argv);
540 #endif
541
542         (void) bindtextdomain (PACKAGE, localedir);
543         /* our i18n translations are all in UTF-8, so make sure
544            that even if the user locale doesn't specify UTF-8,
545            we use that when handling them.
546         */
547         (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
548         (void) textdomain (PACKAGE);
549
550         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
551
552         // catch error message system signals ();
553
554         text_receiver.listen_to (error);
555         text_receiver.listen_to (info);
556         text_receiver.listen_to (fatal);
557         text_receiver.listen_to (warning);
558
559         if (parse_opts (argc, argv)) {
560                 exit (1);
561         }
562
563         if (curvetest_file) {
564                 return curvetest (curvetest_file);
565         }
566
567         cout << PROGRAM_NAME
568              << VERSIONSTRING
569              << _(" (built using ")
570              << svn_revision
571 #ifdef __GNUC__
572              << _(" and GCC version ") << __VERSION__
573 #endif
574              << ')'
575              << endl;
576
577         if (just_version) {
578                 exit (0);
579         }
580
581         if (no_splash) {
582                 cerr << _("Copyright (C) 1999-2010 Paul Davis") << endl
583                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
584                      << endl
585                      << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
586                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
587                      << _("This is free software, and you are welcome to redistribute it ") << endl
588                      << _("under certain conditions; see the source for copying conditions.")
589                      << endl;
590         }
591
592         /* some GUI objects need this */
593
594         PBD::ID::init ();
595
596         if (::signal (SIGPIPE, sigpipe_handler)) {
597                 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
598         }
599
600         try {
601                 ui = new ARDOUR_UI (&argc, &argv);
602         } catch (failed_constructor& err) {
603                 error << _("could not create ARDOUR GUI") << endmsg;
604                 exit (1);
605         }
606
607         ui->run (text_receiver);
608         Gtkmm2ext::Application::instance()->cleanup();
609         ui = 0;
610
611         ARDOUR::cleanup ();
612         pthread_cancel_all ();
613
614 #ifdef HAVE_LV2
615         close_external_ui_windows();
616 #endif
617         return 0;
618 }
619 #ifdef VST_SUPPORT
620 } // end of extern C block
621 #endif
622