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