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