Zoom session when the mouse pointer is moved up and down during a playhead drag.
[ardour2.git] / gtk2_ardour / main.cc
blob4e1f43a496f79854d31fe499193711c1a4f59e01
1 /*
2 Copyright (C) 2001-2007 Paul Davis
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.
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.
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.
20 #include <cstdlib>
21 #include <signal.h>
22 #include <cerrno>
23 #include <fstream>
25 #include <sigc++/bind.h>
26 #include <gtkmm/settings.h>
28 #include "pbd/error.h"
29 #include "pbd/epa.h"
30 #include "pbd/file_utils.h"
31 #include "pbd/textreceiver.h"
32 #include "pbd/failed_constructor.h"
33 #include "pbd/pthread_utils.h"
34 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
35 #include "pbd/boost_debug.h"
36 #endif
38 #include <jack/jack.h>
40 #include "ardour/svn_revision.h"
41 #include "ardour/version.h"
42 #include "ardour/ardour.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/session_utils.h"
45 #include "ardour/filesystem_paths.h"
47 #include <gtkmm/main.h>
48 #include <gtkmm2ext/application.h>
49 #include <gtkmm2ext/popup.h>
50 #include <gtkmm2ext/utils.h>
52 #include "version.h"
53 #include "utils.h"
54 #include "ardour_ui.h"
55 #include "opts.h"
56 #include "enums.h"
58 #include "i18n.h"
60 using namespace std;
61 using namespace Gtk;
62 using namespace ARDOUR_COMMAND_LINE;
63 using namespace ARDOUR;
64 using namespace PBD;
66 TextReceiver text_receiver ("ardour");
68 extern int curvetest (string);
70 static ARDOUR_UI *ui = 0;
71 static const char* localedir = LOCALEDIR;
73 void
74 gui_jack_error ()
76 MessageDialog win (string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME),
77 false,
78 Gtk::MESSAGE_INFO,
79 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
80 win.set_secondary_text(_("There are several possible reasons:\n\
81 \n\
82 1) JACK is not running.\n\
83 2) JACK is running as another user, perhaps root.\n\
84 3) There is already another client called \"ardour\".\n\
85 \n\
86 Please consider the possibilities, and perhaps (re)start JACK."));
88 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
89 win.set_default_response (RESPONSE_CLOSE);
91 win.show_all ();
92 win.set_position (Gtk::WIN_POS_CENTER);
94 if (!no_splash) {
95 ui->hide_splash ();
98 /* we just don't care about the result, but we want to block */
100 win.run ();
103 static void export_search_path (const string& base_dir, const char* varname, const char* dir)
105 string path;
106 const char * cstr = getenv (varname);
108 if (cstr) {
109 path = cstr;
110 path += ':';
111 } else {
112 path = "";
114 path += base_dir;
115 path += dir;
117 setenv (varname, path.c_str(), 1);
120 #ifdef __APPLE__
122 #include <mach-o/dyld.h>
123 #include <sys/param.h>
125 extern void set_language_preference (); // cocoacarbon.mm
127 void
128 fixup_bundle_environment (int, char* [])
130 if (!getenv ("ARDOUR_BUNDLED")) {
131 return;
134 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
136 set_language_preference ();
138 char execpath[MAXPATHLEN+1];
139 uint32_t pathsz = sizeof (execpath);
141 _NSGetExecutablePath (execpath, &pathsz);
143 std::string exec_path (execpath);
144 std::string dir_path = Glib::path_get_dirname (exec_path);
145 std::string path;
146 const char *cstr = getenv ("PATH");
148 /* ensure that we find any bundled executables (e.g. JACK),
149 and find them before any instances of the same name
150 elsewhere in PATH
153 path = dir_path;
155 /* JACK is often in /usr/local/bin and since Info.plist refuses to
156 set PATH, we have to force this in order to discover a running
157 instance of JACK ...
160 path += ':';
161 path += "/usr/local/bin";
163 if (cstr) {
164 path += ':';
165 path += cstr;
167 setenv ("PATH", path.c_str(), 1);
169 path = dir_path;
170 path += "/../Resources";
171 path += dir_path;
172 path += "/../Resources/Surfaces";
173 path += dir_path;
174 path += "/../Resources/Panners";
176 setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
178 path = user_config_directory().to_string();
179 path += ':';
180 path += dir_path;
181 path += "/../Resources/icons:";
182 path += dir_path;
183 path += "/../Resources/pixmaps:";
184 path += dir_path;
185 path += "/../Resources/share:";
186 path += dir_path;
187 path += "/../Resources";
189 setenv ("ARDOUR_PATH", path.c_str(), 1);
190 setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
192 path = dir_path;
193 path += "/../Resources";
194 setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
196 export_search_path (dir_path, "LADSPA_PATH", "/../Plugins");
197 export_search_path (dir_path, "VAMP_PATH", "/../Frameworks");
198 export_search_path (dir_path, "ARDOUR_PANNER_PATH", "/lib/panners");
199 export_search_path (dir_path, "ARDOUR_SURFACES_PATH", "/lib/surfaces");
200 export_search_path (dir_path, "ARDOUR_MIDIMAPS_PATH", "/share/midi_maps");
201 export_search_path (dir_path, "ARDOUR_EXPORT_FORMATS_PATH", "/share/exports");
203 path = dir_path;
204 path += "/../Frameworks/clearlooks";
206 setenv ("GTK_PATH", path.c_str(), 1);
208 /* unset GTK_RC_FILES so that we only load the RC files that we define
211 unsetenv ("GTK_RC_FILES");
213 if (!ARDOUR::translations_are_disabled ()) {
215 path = dir_path;
216 path += "/../Resources/locale";
218 localedir = strdup (path.c_str());
219 setenv ("GTK_LOCALEDIR", localedir, 1);
222 /* write a pango.rc file and tell pango to use it. we'd love
223 to put this into the PROGRAM_NAME.app bundle and leave it there,
224 but the user may not have write permission. so ...
226 we also have to make sure that the user ardour directory
227 actually exists ...
230 try {
231 sys::create_directories (user_config_directory ());
233 catch (const sys::filesystem_error& ex) {
234 error << _("Could not create user configuration directory") << endmsg;
237 sys::path pangopath = user_config_directory();
238 pangopath /= "pango.rc";
239 path = pangopath.to_string();
241 std::ofstream pangorc (path.c_str());
242 if (!pangorc) {
243 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
244 return;
245 } else {
246 pangorc << "[Pango]\nModuleFiles=";
248 pangopath = dir_path;
249 pangopath /= "..";
250 pangopath /= "Resources";
251 pangopath /= "pango.modules";
253 pangorc << pangopath.to_string() << endl;
255 pangorc.close ();
257 setenv ("PANGO_RC_FILE", path.c_str(), 1);
260 // gettext charset aliases
262 setenv ("CHARSETALIASDIR", path.c_str(), 1);
264 // font config
266 path = dir_path;
267 path += "/../Resources/fonts.conf";
269 setenv ("FONTCONFIG_FILE", path.c_str(), 1);
271 // GDK Pixbuf loader module file
273 path = dir_path;
274 path += "/../Resources/gdk-pixbuf.loaders";
276 setenv ("GDK_PIXBUF_MODULE_FILE", path.c_str(), 1);
278 if (getenv ("ARDOUR_WITH_JACK")) {
279 // JACK driver dir
281 path = dir_path;
282 path += "/../Frameworks";
284 setenv ("JACK_DRIVER_DIR", path.c_str(), 1);
288 #else
290 void
291 fixup_bundle_environment (int /*argc*/, char* argv[])
293 if (!getenv ("ARDOUR_BUNDLED")) {
294 return;
297 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
299 Glib::ustring exec_path = argv[0];
300 Glib::ustring dir_path = Glib::path_get_dirname (Glib::path_get_dirname (exec_path));
301 Glib::ustring path;
302 Glib::ustring userconfigdir = user_config_directory().to_string();
304 /* ensure that we find any bundled executables (e.g. JACK),
305 and find them before any instances of the same name
306 elsewhere in PATH
309 /* note that this function is POSIX/Linux specific, so using / as
310 a dir separator in this context is just fine.
313 path = dir_path;
314 path += "/etc:";
315 path += dir_path;
316 path += "/lib/surfaces:";
317 path += dir_path;
318 path += "/lib/panners:";
320 setenv ("ARDOUR_MODULE_PATH", path.c_str(), 1);
322 path = userconfigdir;
323 path += ':';
324 path += dir_path;
325 path += "/etc/icons:";
326 path += dir_path;
327 path += "/etc/pixmaps:";
328 path += dir_path;
329 path += "/share:";
330 path += dir_path;
331 path += "/etc";
333 setenv ("ARDOUR_PATH", path.c_str(), 1);
334 setenv ("ARDOUR_CONFIG_PATH", path.c_str(), 1);
336 path = dir_path;
337 path += "/etc";
338 setenv ("ARDOUR_INSTANT_XML_PATH", path.c_str(), 1);
340 export_search_path (dir_path, "LADSPA_PATH", "/../plugins");
341 export_search_path (dir_path, "VAMP_PATH", "/lib");
342 export_search_path (dir_path, "ARDOUR_PANNER_PATH", "/lib/panners");
343 export_search_path (dir_path, "ARDOUR_SURFACES_PATH", "/lib/surfaces");
344 export_search_path (dir_path, "ARDOUR_MIDIMAPS_PATH", "/share/midi_maps");
345 export_search_path (dir_path, "ARDOUR_EXPORT_FORMATS_PATH", "/share/export");
347 path = dir_path;
348 path += "/lib/clearlooks";
349 setenv ("GTK_PATH", path.c_str(), 1);
351 /* unset GTK_RC_FILES so that we only load the RC files that we define
354 unsetenv ("GTK_RC_FILES");
356 if (!ARDOUR::translations_are_disabled ()) {
357 path = dir_path;
358 path += "/share/locale";
360 localedir = strdup (path.c_str());
361 setenv ("GTK_LOCALEDIR", localedir, 1);
364 /* write a pango.rc file and tell pango to use it. we'd love
365 to put this into the Ardour.app bundle and leave it there,
366 but the user may not have write permission. so ...
368 we also have to make sure that the user ardour directory
369 actually exists ...
372 if (g_mkdir_with_parents (userconfigdir.c_str(), 0755) < 0) {
373 error << string_compose (_("cannot create user ardour folder %1 (%2)"), userconfigdir, strerror (errno))
374 << endmsg;
375 } else {
377 Glib::ustring mpath;
379 path = Glib::build_filename (userconfigdir, "pango.rc");
381 std::ofstream pangorc (path.c_str());
382 if (!pangorc) {
383 error << string_compose (_("cannot open pango.rc file %1") , path) << endmsg;
384 } else {
385 mpath = Glib::build_filename (userconfigdir, "pango.modules");
387 pangorc << "[Pango]\nModuleFiles=";
388 pangorc << mpath << endl;
389 pangorc.close ();
392 setenv ("PANGO_RC_FILE", path.c_str(), 1);
394 /* similar for GDK pixbuf loaders, but there's no RC file required
395 to specify where it lives.
398 mpath = Glib::build_filename (userconfigdir, "gdk-pixbuf.loaders");
399 setenv ("GDK_PIXBUF_MODULE_FILE", mpath.c_str(), 1);
403 #endif
405 static gboolean
406 tell_about_jack_death (void* /* ignored */)
408 if (AudioEngine::instance()->processed_frames() == 0) {
409 /* died during startup */
410 MessageDialog msg (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
411 msg.set_position (Gtk::WIN_POS_CENTER);
412 msg.set_secondary_text (string_compose (_(
413 "JACK exited unexpectedly, and without notifying %1.\n\
415 This could be due to misconfiguration or to an error inside JACK.\n\
417 Click OK to exit %1."), PROGRAM_NAME));
419 msg.run ();
420 _exit (0);
422 } else {
424 /* engine has already run, so this is a mid-session JACK death */
426 MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE));
427 msg->set_secondary_text (string_compose (_(
428 "JACK exited unexpectedly, and without notifying %1.\n\
430 This is probably due to an error inside JACK. You should restart JACK\n\
431 and reconnect %1 to it, or exit %1 now. You cannot save your\n\
432 session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
433 msg->present ();
435 return false; /* do not call again */
438 static void
439 sigpipe_handler (int /*signal*/)
441 /* XXX fix this so that we do this again after a reconnect to JACK
444 static bool done_the_jack_thing = false;
446 if (!done_the_jack_thing) {
447 AudioEngine::instance()->died ();
448 g_idle_add (tell_about_jack_death, 0);
449 done_the_jack_thing = true;
453 #ifdef HAVE_LV2
454 void close_external_ui_windows();
455 #endif
457 #ifdef VST_SUPPORT
459 extern int gui_init (int* argc, char** argv[]);
461 /* this is called from the entry point of a wine-compiled
462 executable that is linked against gtk2_ardour built
463 as a shared library.
465 extern "C" {
466 int ardour_main (int argc, char *argv[])
467 #else
468 int main (int argc, char *argv[])
469 #endif
471 fixup_bundle_environment (argc, argv);
473 if (!Glib::thread_supported()) {
474 Glib::thread_init();
477 gtk_set_locale ();
479 #ifdef VST_SUPPORT
480 /* this does some magic that is needed to make GTK and Wine's own
481 X11 client interact properly.
483 gui_init (&argc, &argv);
484 #endif
486 (void) bindtextdomain (PACKAGE, localedir);
487 /* our i18n translations are all in UTF-8, so make sure
488 that even if the user locale doesn't specify UTF-8,
489 we use that when handling them.
491 (void) bind_textdomain_codeset (PACKAGE,"UTF-8");
492 (void) textdomain (PACKAGE);
494 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
496 // catch error message system signals ();
498 text_receiver.listen_to (error);
499 text_receiver.listen_to (info);
500 text_receiver.listen_to (fatal);
501 text_receiver.listen_to (warning);
503 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
504 if (getenv ("BOOST_DEBUG")) {
505 boost_debug_shared_ptr_show_live_debugging (true);
507 #endif
509 if (parse_opts (argc, argv)) {
510 exit (1);
513 if (curvetest_file) {
514 return curvetest (curvetest_file);
517 cout << PROGRAM_NAME
518 << VERSIONSTRING
519 << _(" (built using ")
520 << svn_revision
521 #ifdef __GNUC__
522 << _(" and GCC version ") << __VERSION__
523 #endif
524 << ')'
525 << endl;
527 if (just_version) {
528 exit (0);
531 if (no_splash) {
532 cerr << _("Copyright (C) 1999-2011 Paul Davis") << endl
533 << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
534 << endl
535 << string_compose (_("%1 comes with ABSOLUTELY NO WARRANTY"), PROGRAM_NAME) << endl
536 << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
537 << _("This is free software, and you are welcome to redistribute it ") << endl
538 << _("under certain conditions; see the source for copying conditions.")
539 << endl;
542 /* some GUI objects need this */
544 PBD::ID::init ();
546 if (::signal (SIGPIPE, sigpipe_handler)) {
547 cerr << _("Cannot xinstall SIGPIPE error handler") << endl;
550 try {
551 ui = new ARDOUR_UI (&argc, &argv);
552 } catch (failed_constructor& err) {
553 error << _("could not create ARDOUR GUI") << endmsg;
554 exit (1);
557 ui->run (text_receiver);
558 Gtkmm2ext::Application::instance()->cleanup();
559 ui = 0;
561 ARDOUR::cleanup ();
562 pthread_cancel_all ();
564 #ifdef HAVE_LV2
565 close_external_ui_windows();
566 #endif
567 return 0;
569 #ifdef VST_SUPPORT
570 } // end of extern C block
571 #endif