more fixes to get things moving along
[ardour.git] / gtk2_ardour / main.cc
1 /*
2     Copyright (C) 2001-2004 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     $Id$
19 */
20
21 #include <sys/types.h>
22 #include <sys/mman.h>
23 #include <sys/wait.h>
24 #include <cerrno>
25 #include <cstdlib>
26 #include <signal.h>
27 #include <unistd.h>
28
29 #include <sigc++/bind.h>
30 #include <gtkmm/settings.h>
31
32 #include <pbd/error.h>
33 #include <pbd/textreceiver.h>
34 #include <pbd/platform.h>
35 #include <pbd/platform_factory.h>
36 #include <pbd/failed_constructor.h>
37 #include <pbd/pthread_utils.h>
38
39 #include <jack/jack.h>
40
41 #include <ardour/version.h>
42 #include <ardour/ardour.h>
43 #include <ardour/audioengine.h>
44
45 #include <gtkmm/main.h>
46 #include <gtkmm2ext/popup.h>
47 #include <gtkmm2ext/utils.h>
48
49 #include "version.h"
50 #include "ardour_ui.h"
51 #include "opts.h"
52
53 #include "i18n.h"
54
55 using namespace Gtk;
56 using namespace GTK_ARDOUR;
57 using namespace ARDOUR;
58 using namespace sigc;
59
60 Transmitter  error (Transmitter::Error);
61 Transmitter  info (Transmitter::Info);
62 Transmitter  fatal (Transmitter::Fatal);
63 Transmitter  warning (Transmitter::Warning);
64 TextReceiver text_receiver ("ardour");
65
66 extern int curvetest (string);
67
68 static ARDOUR_UI  *ui = 0;
69
70 static void
71 shutdown (int status)
72 {
73         char* msg;
74
75         if (status) {
76
77                 msg = _("ardour is killing itself for a clean exit\n");
78                 write (1, msg, strlen (msg));
79                 /* drastic, but perhaps necessary */
80                 kill (-getpgrp(), SIGKILL);     
81                 /*NOTREACHED*/
82
83         } else {
84
85                 if (ui) {
86                         msg = _("stopping user interface\n");
87                         write (1, msg, strlen (msg));
88                         ui->kill();
89                 }
90                 
91                 pthread_cancel_all ();
92         }
93
94         exit (status);
95 }
96
97
98 static void 
99 handler (int sig)
100 {
101         char buf[64];
102         int n;
103
104         /* XXX its doubtful that snprintf() is async-safe */
105         n = snprintf (buf, sizeof(buf), _("%d(%d): received signal %d\n"), getpid(), (int) pthread_self(), sig);
106         write (1, buf, n);
107
108         shutdown (1);
109 }
110
111 static void 
112 handler2 (int sig, siginfo_t* ctxt, void* ignored)
113 {
114         handler (sig);
115 }       
116
117 static void *
118 signal_thread (void *arg)
119 {
120         int sig;
121         sigset_t blocked;
122
123         PBD::ThreadCreated (pthread_self(), X_("Signal"));
124
125         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
126         
127         /* find out what's blocked right now */
128
129         //sigprocmask (SIG_SETMASK, 0, &blocked);
130         if (pthread_sigmask (SIG_SETMASK, 0, &blocked)) {
131                 cerr << "getting blocked signals failed\n";
132         }
133         
134         /* wait for any of the currently blocked signals.
135            
136            According to the man page found in linux 2.6 and 2.4, sigwait() 
137            never returns an error. This is incorrect. Checking the man
138            pages for some other *nix systems makes it clear that
139            sigwait() can return several error codes, one of which 
140            is EINTR. This happens if the thread receives a signal
141            which is not in the blocked set. 
142
143            We do not expect that to happen, and if it did we should generally
144            exit as planned. However, under 2.6, the ptrace facility used 
145            by gdb seems to also cause sigwait() to return with EINTR
146            but with a signal that sigwait cannot understand. As a result, 
147            "sig" is set to zero, an impossible signal number.
148
149            Handling the EINTR code makes it possible to debug 
150            ardour on a 2.6 kernel.
151
152         */
153
154         int swerr;
155
156   again:
157         if ((swerr = sigwait (&blocked, &sig))) {
158                 if (swerr == EINTR) {
159                         goto again;
160                 } else {
161                         cerr << "sigwait failed with " << swerr << endl;
162                 }
163         }
164
165         cerr << "Signal " << sig << " received\n";
166
167         if (sig != SIGSEGV) {
168
169                 /* unblock signals so we can see them during shutdown.
170                    this will help prod developers not to lose sight
171                    of bugs that cause segfaults etc. during shutdown.
172                 */
173
174                 sigprocmask (SIG_UNBLOCK, &blocked, 0);
175         }
176
177         shutdown (1);
178         /*NOTREACHED*/
179         return 0;
180 }
181
182 int
183 catch_signals (void)
184 {
185         struct sigaction action;
186         pthread_t signal_thread_id;
187         sigset_t signals;
188
189 //      if (setpgid (0,0)) {
190         if (setsid ()) {
191                 warning << string_compose (_("cannot become new process group leader (%1)"), 
192                                     strerror (errno))
193                         << endmsg;
194         }
195
196         sigemptyset (&signals);
197         sigaddset(&signals, SIGHUP);
198         sigaddset(&signals, SIGINT);
199         sigaddset(&signals, SIGQUIT);
200         sigaddset(&signals, SIGPIPE);
201         sigaddset(&signals, SIGTERM);
202         sigaddset(&signals, SIGUSR1);
203         sigaddset(&signals, SIGUSR2);
204
205
206         /* install a handler because otherwise
207            pthreads behaviour is undefined when we enter
208            sigwait.
209         */
210         
211         action.sa_handler = handler;
212         action.sa_mask = signals;
213         action.sa_flags = SA_RESTART|SA_RESETHAND;
214
215         for (int i = 1; i < 32; i++) {
216                 if (sigismember (&signals, i)) {
217                         if (sigaction (i, &action, 0)) {
218                                 cerr << string_compose (_("cannot setup signal handling for %1"), i) << endl;
219                                 return -1;
220                         }
221                 }
222         } 
223
224         /* this sets the signal mask for this and all 
225            subsequent threads that do not reset it.
226         */
227         
228         if (pthread_sigmask (SIG_SETMASK, &signals, 0)) {
229                 cerr << string_compose (_("cannot set default signal mask (%1)"), strerror (errno)) << endl;
230                 return -1;
231         }
232
233         /* start a thread to wait for signals */
234
235         if (pthread_create_and_store ("signal", &signal_thread_id, 0, signal_thread, 0)) {
236                 cerr << "cannot create signal catching thread" << endl;
237                 return -1;
238         }
239
240         pthread_detach (signal_thread_id);
241         return 0;
242 }
243
244 string
245 which_ui_rcfile ()
246 {
247         string rcfile;
248         char* envvar;
249
250         if ((envvar = getenv("ARDOUR_UI_RC")) == 0) {
251                 rcfile = find_config_file ("ardour_ui.rc");
252         
253                 if (rcfile.length() == 0) {
254                         warning << _("Without a UI style file, ardour will look strange.\n Please set ARDOUR_UI_RC to point to a valid UI style file") << endmsg;
255                 }
256         } else {
257                 rcfile = envvar;
258         }
259         
260         return rcfile;
261 }
262
263 gint
264 show_ui_callback (void *arg)
265 {
266         ARDOUR_UI * ui = (ARDOUR_UI *) arg;
267
268         ui->hide_splash();
269         ui->show ();
270         
271         return FALSE;
272 }
273
274 gint
275 jack_fooey (GdkEventAny* ignored)
276 {
277         Main::quit ();
278         return FALSE;
279 }
280
281 void
282 jack_foobar ()
283 {
284         Main::quit ();
285 }
286
287 void
288 gui_jack_error ()
289 {
290         Window win (Gtk::WINDOW_POPUP);
291         VBox   vpacker;
292         Button ok (_("OK"));
293         Label label (_("Ardour could not connect to JACK.\n\
294 There are several possible reasons:\n\
295 \n\
296 1) JACK is not running.\n\
297 2) JACK is running as another user, perhaps root.\n\
298 3) There is already another client called \"ardour\".\n\
299 \n\
300 Please consider the possibilities, and perhaps (re)start JACK."));
301
302         vpacker.set_spacing (12);
303         vpacker.pack_start (label);
304         vpacker.pack_start (ok, false, false);
305         
306         win.set_title (_("ardour: unplugged"));
307         win.set_border_width (7);
308         win.add (vpacker);
309         win.show_all ();
310         win.signal_delete_event().connect (sigc::ptr_fun (jack_fooey));
311         win.add_events (Gdk::BUTTON_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK);
312         win.set_position (Gtk::WIN_POS_CENTER);
313
314         ok.signal_clicked().connect (sigc::ptr_fun (jack_foobar));
315         
316         ok.grab_focus ();
317
318         Main::run ();
319 }
320
321 int
322 main (int argc, char *argv[])
323 {
324         ARDOUR::AudioEngine *engine;
325         char *null_file_list[] = { 0 };
326
327         gtk_set_locale ();
328
329         (void)   bindtextdomain (PACKAGE, LOCALEDIR);
330         (void) textdomain (PACKAGE);
331
332         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
333
334         catch_signals ();
335
336         text_receiver.listen_to (error);
337         text_receiver.listen_to (info);
338         text_receiver.listen_to (fatal);
339         text_receiver.listen_to (warning);
340         
341
342         if (parse_opts (argc, argv)) {
343                 exit (1);
344         }
345
346         if (curvetest_file) {
347                 return curvetest (curvetest_file);
348         }
349
350         /* desktop standard themes: just say no! */
351
352         if (getenv("GTK_RC_FILES")) {
353                 unsetenv("GTK_RC_FILES");
354         }
355
356         if (getenv("GTK2_RC_FILES")) {
357                 unsetenv("GTK_RC_FILES");
358         }
359
360         gtk_rc_set_default_files (null_file_list);
361
362         cout << _("Ardour/GTK ") 
363              << VERSIONSTRING
364              << _("\n   (built using ")
365              << gtk_ardour_major_version << '.'
366              << gtk_ardour_minor_version << '.'
367              << gtk_ardour_micro_version
368              << _(" with libardour ")
369              << libardour_major_version << '.'
370              << libardour_minor_version << '.' 
371              << libardour_micro_version 
372 #ifdef __GNUC__
373              << _(" and GCC version ") << __VERSION__ 
374 #endif
375              << ')'
376              << endl;
377         
378         if (just_version) {
379                 exit (0);
380         }
381
382         if (no_splash) {
383                 cerr << _("Copyright (C) 1999-2005 Paul Davis") << endl
384                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
385                      << endl
386                      << _("Ardour comes with ABSOLUTELY NO WARRANTY") << endl
387                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
388                      << _("This is free software, and you are welcome to redistribute it ") << endl
389                      << _("under certain conditions; see the source for copying conditions.")
390                      << endl;
391         }
392
393         try { 
394                 ui = new ARDOUR_UI (&argc, &argv, which_ui_rcfile());
395         } 
396
397         catch (failed_constructor& err) {
398                 error << _("could not create ARDOUR GUI") << endmsg;
399                 exit (1);
400         }
401
402
403         if (!no_splash) {
404                 ui->show_splash ();
405                 if (session_name.length()) {  
406                         gtk_timeout_add (4000, show_ui_callback, ui);
407                 }
408         }
409         
410         try { 
411                 engine = new ARDOUR::AudioEngine (jack_client_name);
412                 ARDOUR::init (*engine, use_vst, try_hw_optimization, handler2);
413                 ui->set_engine (*engine);
414         } 
415
416         catch (AudioEngine::NoBackendAvailable& err) {
417                 gui_jack_error ();
418                 error << string_compose (_("Could not connect to JACK server as  \"%1\""), jack_client_name) <<  endmsg;
419                 return -1;
420         }
421         
422         catch (failed_constructor& err) {
423                 error << _("could not initialize Ardour.") << endmsg;
424                 exit (1);
425         } 
426
427         /* load session, if given */
428         string name, path;
429
430         if (session_name.length()){
431                 bool isnew;
432
433                 if (Session::find_session (session_name, path, name, isnew)) {
434                         error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg;
435                 } else {
436
437                         if (new_session) {
438
439                                 /* command line required that the session be new */
440
441                                 if (isnew) {
442                                         
443                                         /* popup the new session dialog
444                                            once everything else is OK.
445                                         */
446
447                                         Glib::signal_idle().connect (bind (mem_fun (*ui, &ARDOUR_UI::cmdline_new_session), path));
448                                         ui->set_will_create_new_session_automatically (true);
449
450                                 } else {
451
452                                         /* it wasn't new, but we require a new session */
453
454                                         error << string_compose (_("\n\nA session named \"%1\" already exists.\n\
455 To avoid this message, start ardour as \"ardour %1"), path)
456                                               << endmsg;
457                                         goto out;
458                                 }
459
460                         } else {
461
462                                 /* command line didn't require a new session */
463                                 
464                                 if (isnew) {
465                                         error << string_compose (_("\n\nNo session named \"%1\" exists.\n\
466 To create it from the command line, start ardour as \"ardour --new %1"), path) 
467                                               << endmsg;
468                                         goto out;
469                                 }
470
471                                 ui->load_session (path, name);
472                         }
473                 }
474
475                 if (no_splash) {
476                         ui->show();
477                 }
478
479         } else {
480                 ui->hide_splash ();
481                 ui->show ();
482                 if (!Config->get_no_new_session_dialog()) {
483                         ui->new_session (true);
484                 }
485         }
486
487         ui->run (text_receiver);
488         
489         delete ui;
490         ui = 0;
491
492   out:
493         delete engine;
494         ARDOUR::cleanup ();
495         shutdown (0);
496 }
497