menu and action update
[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 << string_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 << string_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 << string_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_POPUP);
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.signal_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
313         ok.signal_clicked().connect (sigc::ptr_fun (jack_foobar));
314         
315         ok.grab_focus ();
316
317         Main::run ();
318 }
319
320 int
321 main (int argc, char *argv[])
322 {
323         ARDOUR::AudioEngine *engine;
324         char *null_file_list[] = { 0 };
325
326         gtk_set_locale ();
327
328         (void)   bindtextdomain (PACKAGE, LOCALEDIR);
329         (void) textdomain (PACKAGE);
330
331         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
332
333         catch_signals ();
334
335         text_receiver.listen_to (error);
336         text_receiver.listen_to (info);
337         text_receiver.listen_to (fatal);
338         text_receiver.listen_to (warning);
339         
340
341         if (parse_opts (argc, argv)) {
342                 exit (1);
343         }
344
345         if (curvetest_file) {
346                 return curvetest (curvetest_file);
347         }
348
349         /* desktop standard themes: just say no! */
350
351         if (getenv("GTK_RC_FILES")) {
352                 unsetenv("GTK_RC_FILES");
353         }
354
355         if (getenv("GTK2_RC_FILES")) {
356                 unsetenv("GTK_RC_FILES");
357         }
358
359         gtk_rc_set_default_files (null_file_list);
360
361         cout << _("Ardour/GTK ") 
362              << VERSIONSTRING
363              << _("\n   (built using ")
364              << gtk_ardour_major_version << '.'
365              << gtk_ardour_minor_version << '.'
366              << gtk_ardour_micro_version
367              << _(" with libardour ")
368              << libardour_major_version << '.'
369              << libardour_minor_version << '.' 
370              << libardour_micro_version 
371 #ifdef __GNUC__
372              << _(" and GCC version ") << __VERSION__ 
373 #endif
374              << ')'
375              << endl;
376         
377         if (just_version) {
378                 exit (0);
379         }
380
381         if (no_splash) {
382                 cerr << _("Copyright (C) 1999-2005 Paul Davis") << endl
383                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
384                      << endl
385                      << _("Ardour comes with ABSOLUTELY NO WARRANTY") << endl
386                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
387                      << _("This is free software, and you are welcome to redistribute it ") << endl
388                      << _("under certain conditions; see the source for copying conditions.")
389                      << endl;
390         }
391
392         try { 
393                 ui = new ARDOUR_UI (&argc, &argv, which_ui_rcfile());
394         } 
395
396         catch (failed_constructor& err) {
397                 error << _("could not create ARDOUR GUI") << endmsg;
398                 exit (1);
399         }
400
401
402         if (!no_splash) {
403                 ui->show_splash ();
404                 if (session_name.length()) {  
405                         gtk_timeout_add (4000, show_ui_callback, ui);
406                 }
407         }
408         
409         try { 
410                 engine = new ARDOUR::AudioEngine (jack_client_name);
411                 ARDOUR::init (*engine, use_vst, try_hw_optimization, handler2);
412                 ui->set_engine (*engine);
413         } 
414
415         catch (AudioEngine::NoBackendAvailable& err) {
416                 gui_jack_error ();
417                 error << string_compose (_("Could not connect to JACK server as  \"%1\""), jack_client_name) <<  endmsg;
418                 return -1;
419         }
420         
421         catch (failed_constructor& err) {
422                 error << _("could not initialize Ardour.") << endmsg;
423                 exit (1);
424         } 
425
426         /* load session, if given */
427         string name, path;
428
429         if (session_name.length()){
430                 bool isnew;
431
432                 if (Session::find_session (session_name, path, name, isnew)) {
433                         error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg;
434                 } else {
435
436                         if (new_session) {
437
438                                 /* command line required that the session be new */
439
440                                 if (isnew) {
441                                         
442                                         /* popup the new session dialog
443                                            once everything else is OK.
444                                         */
445
446                                         Glib::signal_idle().connect (bind (mem_fun (*ui, &ARDOUR_UI::cmdline_new_session), path));
447                                         ui->set_will_create_new_session_automatically (true);
448
449                                 } else {
450
451                                         /* it wasn't new, but we require a new session */
452
453                                         error << string_compose (_("\n\nA session named \"%1\" already exists.\n\
454 To avoid this message, start ardour as \"ardour %1"), path)
455                                               << endmsg;
456                                         goto out;
457                                 }
458
459                         } else {
460
461                                 /* command line didn't require a new session */
462                                 
463                                 if (isnew) {
464                                         error << string_compose (_("\n\nNo session named \"%1\" exists.\n\
465 To create it from the command line, start ardour as \"ardour --new %1"), path) 
466                                               << endmsg;
467                                         goto out;
468                                 }
469
470                                 ui->load_session (path, name);
471                         }
472                 }
473
474                 if (no_splash) {
475                         ui->show();
476                 }
477
478         } else {
479                 ui->hide_splash ();
480                 ui->show ();
481                 if (!Config->get_no_new_session_dialog()) {
482                         ui->new_session (true);
483                 }
484         }
485
486         ui->run (text_receiver);
487         
488         delete ui;
489         ui = 0;
490
491   out:
492         delete engine;
493         ARDOUR::cleanup ();
494         shutdown (0);
495 }
496