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