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