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