Fix crash when X11 is not available for VST UIs
[ardour.git] / gtk2_ardour / ardour_ui_startup.cc
1 /*
2  * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
3  * Copyright (C) 2005-2017 Tim Mayberry <mojofunk@gmail.com>
4  * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
6  * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
7  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
8  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
9  * Copyright (C) 2008-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10  * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11  * Copyright (C) 2013-2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
12  * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
13  * Copyright (C) 2013-2016 Nick Mainsbridge <mainsbridge@gmail.com>
14  * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
15  * Copyright (C) 2015 AndrĂ© Nusser <andre.nusser@googlemail.com>
16  * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net>
17  * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 2 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along
30  * with this program; if not, write to the Free Software Foundation, Inc.,
31  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32  */
33
34 #ifdef WAF_BUILD
35 #include "gtk2ardour-config.h"
36 #include "gtk2ardour-version.h"
37 #endif
38
39 #ifndef PLATFORM_WINDOWS
40 #include <sys/resource.h>
41 #endif
42
43 #ifdef __FreeBSD__
44 #include <sys/types.h>
45 #include <sys/sysctl.h>
46 #endif
47
48 #include <glib.h>
49 #include "pbd/gstdio_compat.h"
50
51 #include <gtkmm/stock.h>
52
53 #include "pbd/basename.h"
54 #include "pbd/file_utils.h"
55
56 #include "ardour/audioengine.h"
57 #include "ardour/filename_extensions.h"
58 #include "ardour/filesystem_paths.h"
59 #include "ardour/profile.h"
60
61 #include "gtkmm2ext/application.h"
62
63 #include "ambiguous_file_dialog.h"
64 #include "ardour_message.h"
65 #include "ardour_ui.h"
66 #include "debug.h"
67 #include "engine_dialog.h"
68 #include "keyboard.h"
69 #include "missing_file_dialog.h"
70 #include "nsm.h"
71 #include "opts.h"
72 #include "pingback.h"
73 #include "public_editor.h"
74 #include "splash.h"
75
76 #include "pbd/i18n.h"
77
78 using namespace ARDOUR;
79 using namespace PBD;
80 using namespace Gtk;
81 using namespace Gtkmm2ext;
82 using namespace std;
83
84
85 static bool
86 _hide_splash (gpointer arg)
87 {
88         ((ARDOUR_UI*)arg)->hide_splash();
89         return false;
90 }
91
92 bool
93 ARDOUR_UI::first_idle ()
94 {
95         if (_session) {
96                 _session->allow_auto_play (true);
97         }
98
99         if (editor) {
100                 editor->first_idle();
101         }
102
103         /* in 1 second, hide the splash screen
104          *
105          * Consider hiding it *now*. If a user opens opens a dialog
106          * during that one second while the splash is still visible,
107          * the dialog will push-back the splash.
108          * Closing the dialog later will pop it back.
109          */
110         Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
111
112         Keyboard::set_can_save_keybindings (true);
113         return false;
114 }
115
116 void
117 ARDOUR_UI::setup_profile ()
118 {
119         if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
120                 Profile->set_small_screen ();
121         }
122
123         if (g_getenv ("MIXBUS")) {
124                 Profile->set_mixbus ();
125         }
126 }
127
128 int
129 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
130 {
131         MissingFileDialog dialog (s, str, type);
132
133         dialog.show ();
134         dialog.present ();
135
136         int result = dialog.run ();
137         dialog.hide ();
138
139         switch (result) {
140         case RESPONSE_OK:
141                 break;
142         default:
143                 return 1; // quit entire session load
144         }
145
146         result = dialog.get_action ();
147
148         return result;
149 }
150
151 int
152 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
153 {
154         AmbiguousFileDialog dialog (file, hits);
155
156         dialog.show ();
157         dialog.present ();
158
159         dialog.run ();
160
161         return dialog.get_which ();
162 }
163
164 void
165 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
166 {
167         const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
168         const char* end_big = "</span>";
169         const char* start_mono = "<tt>";
170         const char* end_mono = "</tt>";
171
172         ArdourMessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
173                                                    "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
174                                                    "From now on, use the backup copy with older versions of %3"),
175                                                  xml_path, backup_path, PROGRAM_NAME,
176                                                  start_big, end_big,
177                                                  start_mono, end_mono), true);
178
179         msg.run ();
180 }
181
182
183 int
184 ARDOUR_UI::sr_mismatch_dialog (samplecnt_t desired, samplecnt_t actual)
185 {
186         HBox* hbox = new HBox();
187         Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
188         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
189         Label  message (string_compose (_("\
190 This session was created with a sample rate of %1 Hz, but\n\
191 %2 is currently running at %3 Hz.  If you load this session,\n\
192 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
193
194         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
195         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
196         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
197         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
198         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
199         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
200         dialog.set_default_response (RESPONSE_ACCEPT);
201         dialog.set_position (WIN_POS_CENTER);
202         message.show();
203         image->show();
204         hbox->show();
205
206         switch (dialog.run()) {
207         case RESPONSE_ACCEPT:
208                 return 0;
209         default:
210                 break;
211         }
212
213         return 1;
214 }
215
216 void
217 ARDOUR_UI::sr_mismatch_message (samplecnt_t desired, samplecnt_t actual)
218 {
219         ArdourMessageDialog msg (string_compose (_("\
220 This session was created with a sample rate of %1 Hz, but\n\
221 %2 is currently running at %3 Hz.\n\
222 Audio will be recorded and played at the wrong sample rate.\n\
223 Re-Configure the Audio Engine in\n\
224 Menu > Window > Audio/Midi Setup"),
225                                 desired, PROGRAM_NAME, actual),
226                         true,
227                         Gtk::MESSAGE_WARNING);
228         msg.run ();
229 }
230
231
232 XMLNode*
233 ARDOUR_UI::preferences_settings () const
234 {
235         XMLNode* node = 0;
236
237         if (_session) {
238                 node = _session->instant_xml(X_("Preferences"));
239         } else {
240                 node = Config->instant_xml(X_("Preferences"));
241         }
242
243         if (!node) {
244                 node = new XMLNode (X_("Preferences"));
245         }
246
247         return node;
248 }
249
250 XMLNode*
251 ARDOUR_UI::mixer_settings () const
252 {
253         XMLNode* node = 0;
254
255         if (_session) {
256                 node = _session->instant_xml(X_("Mixer"));
257         } else {
258                 node = Config->instant_xml(X_("Mixer"));
259         }
260
261         if (!node) {
262                 node = new XMLNode (X_("Mixer"));
263         }
264
265         return node;
266 }
267
268 XMLNode*
269 ARDOUR_UI::main_window_settings () const
270 {
271         XMLNode* node = 0;
272
273         if (_session) {
274                 node = _session->instant_xml(X_("Main"));
275         } else {
276                 node = Config->instant_xml(X_("Main"));
277         }
278
279         if (!node) {
280                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
281                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
282                 }
283         }
284
285         if (!node) {
286                 node = new XMLNode (X_("Main"));
287         }
288
289         return node;
290 }
291
292 XMLNode*
293 ARDOUR_UI::editor_settings () const
294 {
295         XMLNode* node = 0;
296
297         if (_session) {
298                 node = _session->instant_xml(X_("Editor"));
299         } else {
300                 node = Config->instant_xml(X_("Editor"));
301         }
302
303         if (!node) {
304                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
305                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
306                 }
307         }
308
309         if (!node) {
310                 node = new XMLNode (X_("Editor"));
311         }
312
313         return node;
314 }
315
316 XMLNode*
317 ARDOUR_UI::keyboard_settings () const
318 {
319         XMLNode* node = 0;
320
321         node = Config->extra_xml(X_("Keyboard"));
322
323         if (!node) {
324                 node = new XMLNode (X_("Keyboard"));
325         }
326
327         return node;
328 }
329
330 void
331 ARDOUR_UI::hide_splash ()
332 {
333         Splash::drop ();
334 }
335
336 void
337 ARDOUR_UI::check_announcements ()
338 {
339 #ifdef PHONE_HOME
340         string _annc_filename;
341
342 #ifdef __APPLE__
343         _annc_filename = PROGRAM_NAME "_announcements_osx_";
344 #elif defined PLATFORM_WINDOWS
345         _annc_filename = PROGRAM_NAME "_announcements_windows_";
346 #else
347         _annc_filename = PROGRAM_NAME "_announcements_linux_";
348 #endif
349         _annc_filename.append (VERSIONSTRING);
350
351         _announce_string = "";
352
353         std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
354         FILE* fin = g_fopen (path.c_str(), "rb");
355         if (fin) {
356                 while (!feof (fin)) {
357                         char tmp[1024];
358                         size_t len;
359                         if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
360                                 break;
361                         }
362                         _announce_string.append (tmp, len);
363                 }
364                 fclose (fin);
365         }
366
367         pingback (VERSIONSTRING, path);
368 #endif
369 }
370
371 int
372 ARDOUR_UI::nsm_init ()
373 {
374         const char *nsm_url;
375
376         if ((nsm_url = g_getenv ("NSM_URL")) == 0) {
377                 return 0;
378         }
379
380         nsm = new NSM_Client;
381
382         if (nsm->init (nsm_url)) {
383                 delete nsm;
384                 nsm = 0;
385                 error << _("NSM: initialization failed") << endmsg;
386                 return -1;
387         }
388
389         /* the ardour executable may have different names:
390          *
391          * waf's obj.target for distro versions: eg ardour4, ardourvst4
392          * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
393          * argv[0] does not apply since we need the wrapper-script (not the binary itself)
394          *
395          * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
396          */
397         const char *process_name = g_getenv ("ARDOUR_SELF");
398         nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour6");
399
400         unsigned int i = 0;
401         // wait for announce reply from nsm server
402         for ( i = 0; i < 5000; ++i) {
403                 nsm->check ();
404
405                 Glib::usleep (i);
406                 if (nsm->is_active()) {
407                         break;
408                 }
409         }
410         if (i == 5000) {
411                 error << _("NSM server did not announce itself") << endmsg;
412                 return -1;
413         }
414         // wait for open command from nsm server
415         for ( i = 0; i < 5000; ++i) {
416                 nsm->check ();
417                 Glib::usleep (1000);
418                 if (nsm->client_id ()) {
419                         break;
420                 }
421         }
422
423         if (i == 5000) {
424                 error << _("NSM: no client ID provided") << endmsg;
425                 return -1;
426         }
427
428         if (_session && nsm) {
429                 _session->set_nsm_state( nsm->is_active() );
430         } else {
431                 error << _("NSM: no session created") << endmsg;
432                 return -1;
433         }
434
435         // nsm requires these actions disabled
436         vector<string> action_names;
437         action_names.push_back("SaveAs");
438         action_names.push_back("Rename");
439         action_names.push_back("New");
440         action_names.push_back("Open");
441         action_names.push_back("Recent");
442         action_names.push_back("Close");
443
444         for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
445                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
446                 if (act) {
447                         act->set_sensitive (false);
448                 }
449         }
450
451         return 0;
452 }
453
454 void
455 ARDOUR_UI::sfsm_response (StartupFSM::Result r)
456 {
457         DEBUG_TRACE (DEBUG::GuiStartup, string_compose (X_("startup FSM response %1\n"), r));
458
459         switch (r) {
460         case StartupFSM::ExitProgram:
461                 queue_finish ();
462                 break;
463
464         case StartupFSM::LoadSession:
465
466                 if (load_session_from_startup_fsm () == 0) {
467                         delete startup_fsm;
468                         startup_fsm = 0;
469                         startup_done ();
470                 } else {
471                         startup_fsm->reset ();
472                 }
473
474                 break;
475         }
476 }
477
478 int
479 ARDOUR_UI::starting ()
480 {
481         Application* app = Application::instance();
482
483         if (ARDOUR_COMMAND_LINE::check_announcements) {
484                 check_announcements ();
485         }
486
487         app->ready ();
488
489         /* we need to create this early because it may need to set the
490          *  audio backend end up.
491          */
492
493         EngineControl* amd;
494
495         try {
496                 amd = dynamic_cast<EngineControl*> (audio_midi_setup.get (true));
497         } catch (...) {
498                 std::cerr << "audio-midi engine setup failed."<< std::endl;
499                 return -1;
500         }
501
502         if (nsm_init ()) {
503                 return -1;
504         } else  {
505
506
507                 startup_fsm = new StartupFSM (*amd);
508                 startup_fsm->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::sfsm_response));
509
510                 /* Note: entire startup process could happen in this one call
511                  * if:
512                  *
513                  * 1) not a new user
514                  * 2) session name provided on command line (and valid)
515                  * 3) no audio/MIDI setup required
516                  */
517
518                 startup_fsm->start ();
519         }
520
521         return 0;
522 }
523
524 int
525 ARDOUR_UI::load_session_from_startup_fsm ()
526 {
527         const string session_path = startup_fsm->session_path;
528         const string session_name = startup_fsm->session_name;
529         const string session_template = startup_fsm->session_template;
530         const bool   session_is_new = startup_fsm->session_is_new;
531         const BusProfile bus_profile = startup_fsm->bus_profile;
532
533         std::cerr  << " loading from " << session_path << " as " << session_name << " templ " << session_template << " is_new " << session_is_new << " bp " << bus_profile.master_out_channels << std::endl;
534
535         if (session_is_new) {
536
537                 if (build_session (session_path, session_name, &bus_profile)) {
538                         return -1;
539                 }
540
541                 if (!session_template.empty() && session_template.substr (0, 11) == "urn:ardour:") {
542                         meta_session_setup (session_template.substr (11));
543                 }
544
545                 return 0;
546         }
547
548         return load_session (session_path, session_name, session_template);
549
550 }
551
552 void
553 ARDOUR_UI::startup_done ()
554 {
555         /* ShouldQuit is a desktop environment mechanism that tells the
556            application it should exit for reasons external to the application
557            itself.
558
559            During startup, startupFSM handles ShouldQuit. But it is done now,
560            and we have to take over responsibility.
561         */
562         Application::instance()->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
563
564         use_config ();
565
566         WM::Manager::instance().show_visible ();
567
568         /* We have to do this here since goto_editor_window() ends up calling show_all() on the
569          * editor window, and we may want stuff to be hidden.
570          */
571         _status_bar_visibility.update ();
572
573         BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
574 }
575
576 void
577 ARDOUR_UI::use_config ()
578 {
579         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
580         if (node) {
581                 set_transport_controllable_state (*node);
582         }
583 }
584
585 void
586 ARDOUR_UI::check_memory_locking ()
587 {
588 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
589         /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
590         return;
591 #else // !__APPLE__
592
593         XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
594
595         if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
596
597                 struct rlimit limits;
598                 int64_t ram;
599                 long pages, page_size;
600 #ifdef __FreeBSD__
601                 size_t pages_len=sizeof(pages);
602                 if ((page_size = getpagesize()) < 0 ||
603                                 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
604 #else
605                 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
606 #endif
607                 {
608                         ram = 0;
609                 } else {
610                         ram = (int64_t) pages * (int64_t) page_size;
611                 }
612
613                 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
614                         return;
615                 }
616
617                 if (limits.rlim_cur != RLIM_INFINITY) {
618
619                         if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
620
621                                 ArdourMessageDialog msg (
622                                         string_compose (
623                                                 _("WARNING: Your system has a limit for maximum amount of locked memory. "
624                                                   "This might cause %1 to run out of memory before your system "
625                                                   "runs out of memory. \n\n"
626                                                   "You can view the memory limit with 'ulimit -l', "
627                                                   "and it is normally controlled by %2"),
628                                                 PROGRAM_NAME,
629 #ifdef __FreeBSD__
630                                                 X_("/etc/login.conf")
631 #else
632                                                 X_(" /etc/security/limits.conf")
633 #endif
634                                         ).c_str());
635
636                                 msg.set_default_response (RESPONSE_OK);
637
638                                 VBox* vbox = msg.get_vbox();
639                                 HBox hbox;
640                                 CheckButton cb (_("Do not show this window again"));
641                                 hbox.pack_start (cb, true, false);
642                                 vbox->pack_start (hbox);
643                                 cb.show();
644                                 vbox->show();
645                                 hbox.show ();
646
647                                 msg.run ();
648
649                                 if (cb.get_active()) {
650                                         XMLNode node (X_("no-memory-warning"));
651                                         Config->add_instant_xml (node);
652                                 }
653                         }
654                 }
655         }
656 #endif // !__APPLE__
657 }