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