remove all lines to avoid recompiles after commits
[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 */
19
20 #include <sys/types.h>
21 #include <sys/mman.h>
22 #include <sys/wait.h>
23 #include <cerrno>
24 #include <cstdlib>
25 #include <signal.h>
26 #include <unistd.h>
27
28 #include <sigc++/bind.h>
29 #include <gtkmm/settings.h>
30
31 #include <pbd/error.h>
32 #include <pbd/textreceiver.h>
33 #include <pbd/failed_constructor.h>
34 #include <pbd/pthread_utils.h>
35
36 #include <jack/jack.h>
37
38 #include <ardour/version.h>
39 #include <ardour/ardour.h>
40 #include <ardour/audioengine.h>
41
42 #include <gtkmm/main.h>
43 #include <gtkmm2ext/popup.h>
44 #include <gtkmm2ext/utils.h>
45
46 #include "svn_revision.h"
47 #include "version.h"
48 #include "ardour_ui.h"
49 #include "opts.h"
50 #include "enums.h"
51
52 #include "i18n.h"
53
54 using namespace Gtk;
55 using namespace GTK_ARDOUR;
56 using namespace ARDOUR;
57 using namespace PBD;
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                         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 signal_thread (void *arg)
107 {
108         int sig;
109         sigset_t blocked;
110
111         PBD::ThreadCreated (pthread_self(), X_("Signal"));
112
113         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
114         
115         /* find out what's blocked right now */
116
117         //sigprocmask (SIG_SETMASK, 0, &blocked);
118         if (pthread_sigmask (SIG_SETMASK, 0, &blocked)) {
119                 cerr << "getting blocked signals failed\n";
120         }
121         
122         /* wait for any of the currently blocked signals.
123            
124            According to the man page found in linux 2.6 and 2.4, sigwait() 
125            never returns an error. This is incorrect. Checking the man
126            pages for some other *nix systems makes it clear that
127            sigwait() can return several error codes, one of which 
128            is EINTR. This happens if the thread receives a signal
129            which is not in the blocked set. 
130
131            We do not expect that to happen, and if it did we should generally
132            exit as planned. However, under 2.6, the ptrace facility used 
133            by gdb seems to also cause sigwait() to return with EINTR
134            but with a signal that sigwait cannot understand. As a result, 
135            "sig" is set to zero, an impossible signal number.
136
137            Handling the EINTR code makes it possible to debug 
138            ardour on a 2.6 kernel.
139
140         */
141
142         int swerr;
143
144   again:
145         if ((swerr = sigwait (&blocked, &sig))) {
146                 if (swerr == EINTR) {
147                         goto again;
148                 } else {
149                         cerr << "sigwait failed with " << swerr << endl;
150                 }
151         }
152
153         cerr << "Signal " << sig << " received\n";
154
155         if (sig != SIGSEGV) {
156
157                 /* unblock signals so we can see them during shutdown.
158                    this will help prod developers not to lose sight
159                    of bugs that cause segfaults etc. during shutdown.
160                 */
161
162                 sigprocmask (SIG_UNBLOCK, &blocked, 0);
163         }
164
165         shutdown (1);
166         /*NOTREACHED*/
167         return 0;
168 }
169
170 int
171 catch_signals (void)
172 {
173         struct sigaction action;
174         pthread_t signal_thread_id;
175         sigset_t signals;
176
177 //      if (setpgid (0,0)) {
178         if (setsid ()) {
179                 warning << string_compose (_("cannot become new process group leader (%1)"), 
180                                     strerror (errno))
181                         << endmsg;
182         }
183
184         sigemptyset (&signals);
185         sigaddset(&signals, SIGHUP);
186         sigaddset(&signals, SIGINT);
187         sigaddset(&signals, SIGQUIT);
188         sigaddset(&signals, SIGPIPE);
189         sigaddset(&signals, SIGTERM);
190         sigaddset(&signals, SIGUSR1);
191         sigaddset(&signals, SIGUSR2);
192
193
194         /* install a handler because otherwise
195            pthreads behaviour is undefined when we enter
196            sigwait.
197         */
198         
199         action.sa_handler = handler;
200         action.sa_mask = signals;
201         action.sa_flags = SA_RESTART|SA_RESETHAND;
202
203         for (int i = 1; i < 32; i++) {
204                 if (sigismember (&signals, i)) {
205                         if (sigaction (i, &action, 0)) {
206                                 cerr << string_compose (_("cannot setup signal handling for %1"), i) << endl;
207                                 return -1;
208                         }
209                 }
210         } 
211
212         /* this sets the signal mask for this and all 
213            subsequent threads that do not reset it.
214         */
215         
216         if (pthread_sigmask (SIG_SETMASK, &signals, 0)) {
217                 cerr << string_compose (_("cannot set default signal mask (%1)"), strerror (errno)) << endl;
218                 return -1;
219         }
220
221         /* start a thread to wait for signals */
222
223         if (pthread_create_and_store ("signal", &signal_thread_id, 0, signal_thread, 0)) {
224                 cerr << "cannot create signal catching thread" << endl;
225                 return -1;
226         }
227
228         pthread_detach (signal_thread_id);
229         return 0;
230 }
231
232 string
233 which_ui_rcfile ()
234 {
235         string rcfile;
236         char* env;
237
238         if ((env = getenv ("ARDOUR2_UI_RC")) != 0 && strlen (env)) {
239                 rcfile = env;
240         } else {
241                 rcfile = "ardour2_ui.rc";
242         }
243
244         rcfile = find_config_file (rcfile);
245         
246         if (rcfile.empty()) {
247                 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;
248         } else {
249                 cerr << "Loading ui configuration file " << rcfile << endl;
250         }
251         
252         return rcfile;
253 }
254
255 gint
256 show_ui_callback (void *arg)
257 {
258         ARDOUR_UI * ui = (ARDOUR_UI *) arg;
259
260         ui->hide_splash();
261         
262         return FALSE;
263 }
264
265 void
266 gui_jack_error ()
267 {
268         MessageDialog win (_("Ardour could not connect to JACK."),
269                      false,
270                      Gtk::MESSAGE_INFO,
271                      (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
272 win.set_secondary_text(_("There are several possible reasons:\n\
273 \n\
274 1) JACK is not running.\n\
275 2) JACK is running as another user, perhaps root.\n\
276 3) There is already another client called \"ardour\".\n\
277 \n\
278 Please consider the possibilities, and perhaps (re)start JACK."));
279
280         win.add_button (Stock::QUIT, RESPONSE_CLOSE);
281         win.set_default_response (RESPONSE_CLOSE);
282         
283         win.show_all ();
284         win.set_position (Gtk::WIN_POS_CENTER);
285
286         if (!no_splash) {
287                 ui->hide_splash ();
288         }
289
290         /* we just don't care about the result, but we want to block */
291
292         win.run ();
293 }
294
295 static bool
296 maybe_load_session ()
297 {
298         /* If no session name is given: we're not loading a session yet, nor creating a new one */
299         if (!session_name.length()) {
300                 ui->hide_splash ();
301                 if (!Config->get_no_new_session_dialog()) {
302                        ui->new_session ();
303                 }
304
305                 return true;
306         }
307
308         /* Load session or start the new session dialog */
309         string name, path;
310
311         bool isnew;
312
313         if (Session::find_session (session_name, path, name, isnew)) {
314                 error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg;
315                 return false;
316         }
317
318         if (!new_session) {
319                         
320                 /* Loading a session, but the session doesn't exist */
321                 if (isnew) {
322                         error << string_compose (_("\n\nNo session named \"%1\" exists.\n"
323                                                    "To create it from the command line, start ardour as \"ardour --new %1"), path) 
324                               << endmsg;
325                         return false;
326                 }
327
328                 if (ui->load_session (path, name)) {
329                         /* it failed */
330                         return false;
331                 }
332
333         } else {
334
335                 /*  TODO: This bit of code doesn't work properly yet
336                     Glib::signal_idle().connect (bind (mem_fun (*ui, &ARDOUR_UI::cmdline_new_session), path));
337                     ui->set_will_create_new_session_automatically (true); 
338                 */
339                 
340                 /* Show the NSD */
341                 ui->hide_splash ();
342                 if (!Config->get_no_new_session_dialog()) {
343                        ui->new_session ();
344                 }
345         }
346
347         return true;
348 }
349
350 #ifdef VST_SUPPORT
351 /* this is called from the entry point of a wine-compiled
352    executable that is linked against gtk2_ardour built
353    as a shared library.
354 */
355 extern "C" {
356 int ardour_main (int argc, char *argv[])
357 #else
358 int main (int argc, char *argv[])
359 #endif
360
361 {
362         ARDOUR::AudioEngine *engine;
363         vector<Glib::ustring> null_file_list;
364
365         Glib::thread_init();
366         gtk_set_locale ();
367
368         (void) bindtextdomain (PACKAGE, LOCALEDIR);
369         /* our i18n translations are all in UTF-8, so make sure
370            that even if the user locale doesn't specify UTF-8,
371            we use that when handling them.
372         */
373         (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
374         (void) textdomain (PACKAGE);
375
376         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
377
378         // catch error message system signals ();
379
380         text_receiver.listen_to (error);
381         text_receiver.listen_to (info);
382         text_receiver.listen_to (fatal);
383         text_receiver.listen_to (warning);
384
385         if (parse_opts (argc, argv)) {
386                 exit (1);
387         }
388
389         if (curvetest_file) {
390                 return curvetest (curvetest_file);
391         }
392         
393         cout << _("Ardour/GTK ") 
394              << VERSIONSTRING
395              << _("\n   (built using ")
396              << ardour_svn_revision
397 #ifdef __GNUC__
398              << _(" and GCC version ") << __VERSION__ 
399 #endif
400              << ')'
401              << endl;
402         
403         if (just_version) {
404                 exit (0);
405         }
406
407         if (no_splash) {
408                 cerr << _("Copyright (C) 1999-2006 Paul Davis") << endl
409                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
410                      << endl
411                      << _("Ardour comes with ABSOLUTELY NO WARRANTY") << endl
412                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
413                      << _("This is free software, and you are welcome to redistribute it ") << endl
414                      << _("under certain conditions; see the source for copying conditions.")
415                      << endl;
416         }
417
418         /* some GUI objects need this */
419
420         PBD::ID::init ();
421
422         try { 
423                 ui = new ARDOUR_UI (&argc, &argv, which_ui_rcfile());
424         } catch (failed_constructor& err) {
425                 error << _("could not create ARDOUR GUI") << endmsg;
426                 exit (1);
427         }
428
429         if (!keybindings_path.empty()) {
430                 ui->set_keybindings_path (keybindings_path);
431         }
432
433         if (!no_splash) {
434                 ui->show_splash ();
435                 if (session_name.length()) {  
436                         g_timeout_add (4000, show_ui_callback, ui);
437                 }
438         }
439
440         try {
441                 ARDOUR::init (use_vst, try_hw_optimization);
442                 setup_gtk_ardour_enums ();
443                 Config->set_current_owner (ConfigVariableBase::Interface);
444
445                 try { 
446                         engine = new ARDOUR::AudioEngine (jack_client_name);
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                 }
452                 
453                 ui->set_engine (*engine);
454
455         } catch (failed_constructor& err) {
456                 error << _("could not initialize Ardour.") << endmsg;
457                 return -1;
458         } 
459
460         ui->start_engine ();
461
462         if (maybe_load_session ()) {
463                 ui->run (text_receiver);
464                 ui = 0;
465         }
466
467         delete engine;
468         ARDOUR::cleanup ();
469         shutdown (0);
470
471         return 0;
472 }
473 #ifdef VST_SUPPORT
474 } // end of extern C block
475 #endif
476