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