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