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