summaryrefslogtreecommitdiff
path: root/gtk2_ardour/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gtk2_ardour/main.cc')
-rw-r--r--gtk2_ardour/main.cc498
1 files changed, 498 insertions, 0 deletions
diff --git a/gtk2_ardour/main.cc b/gtk2_ardour/main.cc
new file mode 100644
index 0000000000..88ea54c44c
--- /dev/null
+++ b/gtk2_ardour/main.cc
@@ -0,0 +1,498 @@
+/*
+ Copyright (C) 2001-2004 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <cerrno>
+#include <cstdlib>
+#include <signal.h>
+#include <unistd.h>
+
+#include <sigc++/bind.h>
+
+#include <pbd/error.h>
+#include <pbd/textreceiver.h>
+#include <pbd/platform.h>
+#include <pbd/platform_factory.h>
+#include <pbd/failed_constructor.h>
+#include <pbd/pthread_utils.h>
+
+#include <jack/jack.h>
+
+#include <ardour/version.h>
+#include <ardour/ardour.h>
+#include <ardour/audioengine.h>
+
+#include <gtk--/main.h>
+#include <gtkmmext/popup.h>
+#include <gtkmmext/utils.h>
+
+#include "version.h"
+#include "ardour_ui.h"
+#include "opts.h"
+
+#include "i18n.h"
+
+using namespace Gtk;
+using namespace GTK_ARDOUR;
+using namespace ARDOUR;
+using namespace SigC;
+
+Transmitter error (Transmitter::Error);
+Transmitter info (Transmitter::Info);
+Transmitter fatal (Transmitter::Fatal);
+Transmitter warning (Transmitter::Warning);
+TextReceiver text_receiver ("ardour");
+
+extern int curvetest (string);
+
+static ARDOUR_UI *ui = 0;
+
+static void
+shutdown (int status)
+{
+ char* msg;
+
+ if (status) {
+
+ msg = _("ardour is killing itself for a clean exit\n");
+ write (1, msg, strlen (msg));
+ /* drastic, but perhaps necessary */
+ kill (-getpgrp(), SIGKILL);
+ /*NOTREACHED*/
+
+ } else {
+
+ if (ui) {
+ msg = _("stopping user interface\n");
+ write (1, msg, strlen (msg));
+ ui->kill();
+ }
+
+ pthread_cancel_all ();
+ }
+
+ exit (status);
+}
+
+
+static void
+handler (int sig)
+{
+ char buf[64];
+ int n;
+
+ /* XXX its doubtful that snprintf() is async-safe */
+ n = snprintf (buf, sizeof(buf), _("%d(%d): received signal %d\n"), getpid(), (int) pthread_self(), sig);
+ write (1, buf, n);
+
+ shutdown (1);
+}
+
+static void
+handler2 (int sig, siginfo_t* ctxt, void* ignored)
+{
+ handler (sig);
+}
+
+static void *
+signal_thread (void *arg)
+{
+ int sig;
+ sigset_t blocked;
+
+ PBD::ThreadCreated (pthread_self(), X_("Signal"));
+
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+
+ /* find out what's blocked right now */
+
+ //sigprocmask (SIG_SETMASK, 0, &blocked);
+ if (pthread_sigmask (SIG_SETMASK, 0, &blocked)) {
+ cerr << "getting blocked signals failed\n";
+ }
+
+ /* wait for any of the currently blocked signals.
+
+ According to the man page found in linux 2.6 and 2.4, sigwait()
+ never returns an error. This is incorrect. Checking the man
+ pages for some other *nix systems makes it clear that
+ sigwait() can return several error codes, one of which
+ is EINTR. This happens if the thread receives a signal
+ which is not in the blocked set.
+
+ We do not expect that to happen, and if it did we should generally
+ exit as planned. However, under 2.6, the ptrace facility used
+ by gdb seems to also cause sigwait() to return with EINTR
+ but with a signal that sigwait cannot understand. As a result,
+ "sig" is set to zero, an impossible signal number.
+
+ Handling the EINTR code makes it possible to debug
+ ardour on a 2.6 kernel.
+
+ */
+
+ int swerr;
+
+ again:
+ if ((swerr = sigwait (&blocked, &sig))) {
+ if (swerr == EINTR) {
+ goto again;
+ } else {
+ cerr << "sigwait failed with " << swerr << endl;
+ }
+ }
+
+ cerr << "Signal " << sig << " received\n";
+
+ if (sig != SIGSEGV) {
+
+ /* unblock signals so we can see them during shutdown.
+ this will help prod developers not to lose sight
+ of bugs that cause segfaults etc. during shutdown.
+ */
+
+ sigprocmask (SIG_UNBLOCK, &blocked, 0);
+ }
+
+ shutdown (1);
+ /*NOTREACHED*/
+ return 0;
+}
+
+int
+catch_signals (void)
+{
+ struct sigaction action;
+ pthread_t signal_thread_id;
+ sigset_t signals;
+
+// if (setpgid (0,0)) {
+ if (setsid ()) {
+ warning << compose (_("cannot become new process group leader (%1)"),
+ strerror (errno))
+ << endmsg;
+ }
+
+ sigemptyset (&signals);
+ sigaddset(&signals, SIGHUP);
+ sigaddset(&signals, SIGINT);
+ sigaddset(&signals, SIGQUIT);
+ sigaddset(&signals, SIGPIPE);
+ sigaddset(&signals, SIGTERM);
+ sigaddset(&signals, SIGUSR1);
+ sigaddset(&signals, SIGUSR2);
+
+
+ /* install a handler because otherwise
+ pthreads behaviour is undefined when we enter
+ sigwait.
+ */
+
+ action.sa_handler = handler;
+ action.sa_mask = signals;
+ action.sa_flags = SA_RESTART|SA_RESETHAND;
+
+ for (int i = 1; i < 32; i++) {
+ if (sigismember (&signals, i)) {
+ if (sigaction (i, &action, 0)) {
+ cerr << compose (_("cannot setup signal handling for %1"), i) << endl;
+ return -1;
+ }
+ }
+ }
+
+ /* this sets the signal mask for this and all
+ subsequent threads that do not reset it.
+ */
+
+ if (pthread_sigmask (SIG_SETMASK, &signals, 0)) {
+ cerr << compose (_("cannot set default signal mask (%1)"), strerror (errno)) << endl;
+ return -1;
+ }
+
+ /* start a thread to wait for signals */
+
+ if (pthread_create_and_store ("signal", &signal_thread_id, 0, signal_thread, 0)) {
+ cerr << "cannot create signal catching thread" << endl;
+ return -1;
+ }
+
+ pthread_detach (signal_thread_id);
+ return 0;
+}
+
+string
+which_ui_rcfile ()
+{
+ string rcfile;
+ char* envvar;
+
+ if ((envvar = getenv("ARDOUR_UI_RC")) == 0) {
+ rcfile = find_config_file ("ardour_ui.rc");
+
+ if (rcfile.length() == 0) {
+ 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;
+ }
+ } else {
+ rcfile = envvar;
+ }
+
+ return rcfile;
+}
+
+gint
+show_ui_callback (void *arg)
+{
+ ARDOUR_UI * ui = (ARDOUR_UI *) arg;
+
+ ui->hide_splash();
+ ui->show ();
+
+ return FALSE;
+}
+
+gint
+jack_fooey (GdkEventAny* ignored)
+{
+ Main::quit ();
+ return FALSE;
+}
+
+void
+jack_foobar ()
+{
+ Main::quit ();
+}
+
+void
+gui_jack_error ()
+{
+ Window win (GTK_WINDOW_DIALOG);
+ VBox vpacker;
+ Button ok (_("OK"));
+ Label label (_("Ardour could not connect to JACK.\n\
+There are several possible reasons:\n\
+\n\
+1) JACK is not running.\n\
+2) JACK is running as another user, perhaps root.\n\
+3) There is already another client called \"ardour\".\n\
+\n\
+Please consider the possibilities, and perhaps (re)start JACK."));
+
+ vpacker.set_spacing (12);
+ vpacker.pack_start (label);
+ vpacker.pack_start (ok, false, false);
+
+ win.set_title (_("ardour: unplugged"));
+ win.set_border_width (7);
+ win.add (vpacker);
+ win.show_all ();
+ win.delete_event.connect (SigC::slot (jack_fooey));
+ win.add_events (GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_PRESS_MASK);
+ win.set_position (GTK_WIN_POS_CENTER);
+ win.realize ();
+ win.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
+
+ ok.clicked.connect (SigC::slot (jack_foobar));
+
+ ok.grab_focus ();
+
+ Main::run ();
+}
+
+int
+main (int argc, char *argv[])
+{
+ ARDOUR::AudioEngine *engine;
+ char *null_file_list[] = { 0 };
+
+ gtk_set_locale ();
+
+ (void) bindtextdomain (PACKAGE, LOCALEDIR);
+ (void) textdomain (PACKAGE);
+
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+
+ catch_signals ();
+
+ text_receiver.listen_to (error);
+ text_receiver.listen_to (info);
+ text_receiver.listen_to (fatal);
+ text_receiver.listen_to (warning);
+
+
+ if (parse_opts (argc, argv)) {
+ exit (1);
+ }
+
+ if (curvetest_file) {
+ return curvetest (curvetest_file);
+ }
+
+ /* desktop standard themes: just say no! */
+
+ if (getenv("GTK_RC_FILES")) {
+ unsetenv("GTK_RC_FILES");
+ }
+
+ if (getenv("GTK2_RC_FILES")) {
+ unsetenv("GTK_RC_FILES");
+ }
+
+ gtk_rc_set_default_files (null_file_list);
+
+ cout << _("Ardour/GTK ")
+ << VERSIONSTRING
+ << _("\n (built using ")
+ << gtk_ardour_major_version << '.'
+ << gtk_ardour_minor_version << '.'
+ << gtk_ardour_micro_version
+ << _(" with libardour ")
+ << libardour_major_version << '.'
+ << libardour_minor_version << '.'
+ << libardour_micro_version
+#ifdef __GNUC__
+ << _(" and GCC version ") << __VERSION__
+#endif
+ << ')'
+ << endl;
+
+ if (just_version) {
+ exit (0);
+ }
+
+ if (no_splash) {
+ cerr << _("Copyright (C) 1999-2005 Paul Davis") << endl
+ << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
+ << endl
+ << _("Ardour comes with ABSOLUTELY NO WARRANTY") << endl
+ << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
+ << _("This is free software, and you are welcome to redistribute it ") << endl
+ << _("under certain conditions; see the source for copying conditions.")
+ << endl;
+ }
+
+ try {
+ ui = new ARDOUR_UI (&argc, &argv, which_ui_rcfile());
+ }
+
+ catch (failed_constructor& err) {
+ error << _("could not create ARDOUR GUI") << endmsg;
+ exit (1);
+ }
+
+
+ if (!no_splash) {
+ ui->show_splash ();
+ if (session_name.length()) {
+ gtk_timeout_add (4000, show_ui_callback, ui);
+ }
+ }
+
+ try {
+ engine = new ARDOUR::AudioEngine (jack_client_name);
+ ARDOUR::init (*engine, use_vst, try_hw_optimization, handler2);
+ ui->set_engine (*engine);
+ }
+
+ catch (AudioEngine::NoBackendAvailable& err) {
+ gui_jack_error ();
+ error << compose (_("Could not connect to JACK server as \"%1\""), jack_client_name) << endmsg;
+ return -1;
+ }
+
+ catch (failed_constructor& err) {
+ error << _("could not initialize Ardour.") << endmsg;
+ exit (1);
+ }
+
+ /* load session, if given */
+ string name, path;
+
+ if (session_name.length()){
+ bool isnew;
+
+ if (Session::find_session (session_name, path, name, isnew)) {
+ error << compose(_("could not load command line session \"%1\""), session_name) << endmsg;
+ } else {
+
+ if (new_session) {
+
+ /* command line required that the session be new */
+
+ if (isnew) {
+
+ /* popup the new session dialog
+ once everything else is OK.
+ */
+
+ Main::idle.connect (bind (slot (*ui, &ARDOUR_UI::cmdline_new_session), path));
+ ui->set_will_create_new_session_automatically (true);
+
+ } else {
+
+ /* it wasn't new, but we require a new session */
+
+ error << compose (_("\n\nA session named \"%1\" already exists.\n\
+To avoid this message, start ardour as \"ardour %1"), path)
+ << endmsg;
+ goto out;
+ }
+
+ } else {
+
+ /* command line didn't require a new session */
+
+ if (isnew) {
+ error << compose (_("\n\nNo session named \"%1\" exists.\n\
+To create it from the command line, start ardour as \"ardour --new %1"), path)
+ << endmsg;
+ goto out;
+ }
+
+ ui->load_session (path, name);
+ }
+ }
+
+ if (no_splash) {
+ ui->show();
+ }
+
+ } else {
+ ui->hide_splash ();
+ ui->show ();
+ if (!Config->get_no_new_session_dialog()) {
+ ui->new_session (true);
+ }
+ }
+
+ ui->run (text_receiver);
+
+ delete ui;
+ ui = 0;
+
+ out:
+ delete engine;
+ ARDOUR::cleanup ();
+ shutdown (0);
+}
+