Merged with trunk (painfully)
[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         } else {
255                 cerr << "Loading ui configuration file " << rcfile << endl;
256         }
257         
258         return rcfile;
259 }
260
261 gint
262 show_ui_callback (void *arg)
263 {
264         ARDOUR_UI * ui = (ARDOUR_UI *) arg;
265
266         ui->hide_splash();
267         ui->show ();
268         
269         return FALSE;
270 }
271
272 void
273 gui_jack_error ()
274 {
275   MessageDialog win (_("Ardour could not connect to JACK."),
276                      false,
277                      Gtk::MESSAGE_INFO,
278                      (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
279 win.set_secondary_text(_("There are several possible reasons:\n\
280 \n\
281 1) JACK is not running.\n\
282 2) JACK is running as another user, perhaps root.\n\
283 3) There is already another client called \"ardour\".\n\
284 \n\
285 Please consider the possibilities, and perhaps (re)start JACK."));
286
287         win.add_button (Stock::QUIT, RESPONSE_CLOSE);
288         win.set_default_response (RESPONSE_CLOSE);
289         
290         win.show_all ();
291         win.set_position (Gtk::WIN_POS_CENTER);
292
293         /* we just don't care about the result */
294
295         win.run ();
296 }
297
298 static bool
299 maybe_load_session ()
300 {
301
302         /* load session, if given */
303         string name, path;
304
305         if (session_name.length()){
306                 bool isnew;
307
308                 if (Session::find_session (session_name, path, name, isnew)) {
309                         error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg;
310                 } else {
311
312                         if (new_session) {
313
314                                 /* command line required that the session be new */
315
316                                 if (isnew) {
317                                         
318                                         /* popup the new session dialog
319                                            once everything else is OK.
320                                         */
321
322                                         Glib::signal_idle().connect (bind (mem_fun (*ui, &ARDOUR_UI::cmdline_new_session), path));
323                                         ui->set_will_create_new_session_automatically (true);
324
325                                 } else {
326
327                                         /* it wasn't new, but we require a new session */
328
329                                         error << string_compose (_("\n\nA session named \"%1\" already exists.\n\
330 To avoid this message, start ardour as \"ardour %1"), path)
331                                               << endmsg;
332                                         return false;
333                                 }
334
335                         } else {
336
337                                 /* command line didn't require a new session */
338                                 
339                                 if (isnew) {
340                                         error << string_compose (_("\n\nNo session named \"%1\" exists.\n\
341 To create it from the command line, start ardour as \"ardour --new %1"), path) 
342                                               << endmsg;
343                                         return false;
344                                 }
345
346                                 ui->load_session (path, name);
347                         }
348                 }
349
350                 if (no_splash) {
351                         ui->show();
352                 }
353
354         } else {
355                 ui->hide_splash ();
356                 if (!Config->get_no_new_session_dialog()) {
357                        ui->new_session (true);
358                 }
359         }
360
361         return true;
362 }
363
364 int
365 main (int argc, char *argv[])
366 {
367         ARDOUR::AudioEngine *engine;
368         vector<Glib::ustring> null_file_list;
369
370         // needs a better home.
371         Glib::thread_init();
372         
373         gtk_set_locale ();
374
375         (void)   bindtextdomain (PACKAGE, LOCALEDIR);
376         (void) textdomain (PACKAGE);
377
378         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
379
380         // catch_signals ();
381
382         text_receiver.listen_to (error);
383         text_receiver.listen_to (info);
384         text_receiver.listen_to (fatal);
385         text_receiver.listen_to (warning);
386
387         if (parse_opts (argc, argv)) {
388                 exit (1);
389         }
390
391         if (curvetest_file) {
392                 return curvetest (curvetest_file);
393         }
394         
395         cout << _("Ardour/GTK ") 
396              << VERSIONSTRING
397              << _("\n   (built using ")
398              << gtk_ardour_major_version << '.'
399              << gtk_ardour_minor_version << '.'
400              << gtk_ardour_micro_version
401              << _(" with libardour ")
402              << libardour_major_version << '.'
403              << libardour_minor_version << '.' 
404              << libardour_micro_version 
405 #ifdef __GNUC__
406              << _(" and GCC version ") << __VERSION__ 
407 #endif
408              << ')'
409              << endl;
410         
411         if (just_version) {
412                 exit (0);
413         }
414
415         if (no_splash) {
416                 cerr << _("Copyright (C) 1999-2006 Paul Davis") << endl
417                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
418                      << endl
419                      << _("Ardour comes with ABSOLUTELY NO WARRANTY") << endl
420                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
421                      << _("This is free software, and you are welcome to redistribute it ") << endl
422                      << _("under certain conditions; see the source for copying conditions.")
423                      << endl;
424         }
425
426         try { 
427                 ui = new ARDOUR_UI (&argc, &argv, which_ui_rcfile());
428         } 
429
430         catch (failed_constructor& err) {
431                 error << _("could not create ARDOUR GUI") << endmsg;
432                 exit (1);
433         }
434
435
436         if (!no_splash) {
437                 ui->show_splash ();
438                 if (session_name.length()) {  
439                         gtk_timeout_add (4000, show_ui_callback, ui);
440                 }
441         }
442         
443         try { 
444                 engine = new ARDOUR::AudioEngine (jack_client_name);
445                 ARDOUR::init (*engine, use_vst, try_hw_optimization, handler2);
446                 ui->set_engine (*engine);
447         } catch (AudioEngine::NoBackendAvailable& err) {
448                 gui_jack_error ();
449                 error << string_compose (_("Could not connect to JACK server as  \"%1\""), jack_client_name) <<  endmsg;
450                 return -1;
451         } catch (failed_constructor& err) {
452                 error << _("could not initialize Ardour.") << endmsg;
453                 return -1;
454         } 
455
456         if (maybe_load_session ()) {
457                 ui->run (text_receiver);
458                 ui = 0;
459         }
460
461   out:
462         delete engine;
463         ARDOUR::cleanup ();
464         shutdown (0);
465
466         /* just another commit forcing change */
467 }
468