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