First-time startup logic update.
[ardour.git] / gtk2_ardour / startup.cc
1 /*
2     Copyright (C) 2010 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 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
23 #endif
24
25 #include <algorithm>
26 #include <fcntl.h>
27
28 #include "pbd/gstdio_compat.h"
29
30 #include <gtkmm/main.h>
31 #include <gtkmm/filechooser.h>
32
33 #include "pbd/failed_constructor.h"
34 #include "pbd/scoped_file_descriptor.h"
35 #include "pbd/file_utils.h"
36 #include "pbd/replace_all.h"
37 #include "pbd/whitespace.h"
38 #include "pbd/stacktrace.h"
39 #include "pbd/openuri.h"
40
41 #include "ardour/audioengine.h"
42 #include "ardour/filesystem_paths.h"
43 #include "ardour/filename_extensions.h"
44 #include "ardour/plugin_manager.h"
45 #include "ardour/recent_sessions.h"
46 #include "ardour/session.h"
47 #include "ardour/session_state_utils.h"
48 #include "ardour/template_utils.h"
49 #include "ardour/profile.h"
50
51 #include "startup.h"
52 #include "opts.h"
53 #include "engine_dialog.h"
54 #include "pbd/i18n.h"
55 #include "utils.h"
56
57 using namespace std;
58 using namespace Gtk;
59 using namespace Gdk;
60 using namespace Glib;
61 using namespace PBD;
62 using namespace ARDOUR;
63 using namespace ARDOUR_UI_UTILS;
64
65 ArdourStartup* ArdourStartup::the_startup = 0;
66
67 ArdourStartup::ArdourStartup ()
68         : _response (RESPONSE_OK)
69         , config_modified (false)
70         , default_dir_chooser (0)
71         , monitor_via_hardware_button (string_compose (_("Use an external mixer or the hardware mixer of your audio interface.\n"
72                                                          "%1 will play NO role in monitoring"), PROGRAM_NAME))
73         , monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME))
74         , audio_page_index (-1)
75         , new_user_page_index (-1)
76         , default_folder_page_index (-1)
77         , monitoring_page_index (-1)
78         , final_page_index (-1)
79 {
80         set_position (WIN_POS_CENTER);
81         set_border_width (12);
82
83         if (! (icon_pixbuf = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
84                 throw failed_constructor();
85         }
86
87         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
88         Glib::RefPtr<Gdk::Pixbuf> icon;
89
90         if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
91                 window_icons.push_back (icon);
92         }
93         if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
94                 window_icons.push_back (icon);
95         }
96         if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
97                 window_icons.push_back (icon);
98         }
99         if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
100                 window_icons.push_back (icon);
101         }
102         if (!window_icons.empty ()) {
103                 set_default_icon_list (window_icons);
104         }
105
106         setup_new_user_page ();
107         setup_first_time_config_page ();
108         setup_monitoring_choice_page ();
109         setup_monitor_section_choice_page ();
110         setup_final_page ();
111
112         the_startup = this;
113 }
114
115 ArdourStartup::~ArdourStartup ()
116 {
117 }
118
119 bool
120 ArdourStartup::required ()
121 {
122         const int current_version = atoi (PROGRAM_VERSION);
123
124         if (Glib::file_test (ARDOUR::been_here_before_path (), Glib::FILE_TEST_EXISTS)) {
125                 return false;
126         }
127
128         return true;
129 }
130
131 void
132 ArdourStartup::setup_new_user_page ()
133 {
134         Label* foomatic = manage (new Label);
135
136         foomatic->set_markup (string_compose (_("\
137 <span size=\"larger\">%1 is a digital audio workstation. You can use it to \
138 record, edit and mix multi-track audio. You can produce your \
139 own CDs, mix video soundtracks, or experiment with new \
140 ideas about music and sound. \
141 \n\n\
142 There are a few things that need to be configured before you start \
143 using the program.</span> \
144 "), PROGRAM_NAME));
145         foomatic->set_justify (JUSTIFY_FILL);
146         foomatic->set_line_wrap ();
147
148         HBox* hbox = manage (new HBox);
149         HBox* vbox = manage (new HBox);
150
151         vbox->set_border_width (24);
152
153         hbox->pack_start (*foomatic, true, true);
154         vbox->pack_start (*hbox, true, true);
155
156         foomatic->show ();
157         hbox->show ();
158         vbox->show ();
159
160         new_user_page_index = append_page (*vbox);
161         set_page_type (*vbox, ASSISTANT_PAGE_INTRO);
162         set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME));
163         set_page_header_image (*vbox, icon_pixbuf);
164         set_page_complete (*vbox, true);
165 }
166
167 void
168 ArdourStartup::default_dir_changed ()
169 {
170         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
171         // make new session folder chooser point to the new default
172         new_folder_chooser.set_current_folder (Config->get_default_session_parent_dir());
173         config_changed ();
174 }
175
176 void
177 ArdourStartup::config_changed ()
178 {
179         config_modified = true;
180 }
181
182 void
183 ArdourStartup::setup_first_time_config_page ()
184 {
185         default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME),
186                                                              FILE_CHOOSER_ACTION_SELECT_FOLDER));
187         Gtk::Label* txt = manage (new Label);
188         HBox* hbox = manage (new HBox);
189         VBox* vbox = manage (new VBox);
190
191         txt->set_markup (string_compose (_("\
192 Each project that you work on with %1 has its own folder.\n\
193 These can require a lot of disk space if you are recording audio.\n\
194 \n\
195 Where would you like new %1 sessions to be stored by default?\n\n\
196 <i>(You can put new sessions anywhere, this is just a default)</i>"), PROGRAM_NAME));
197         txt->set_alignment (0.0, 0.0);
198
199         vbox->set_spacing (18);
200         vbox->set_border_width (24);
201
202         hbox->pack_start (*default_dir_chooser, false, true, 8);
203         vbox->pack_start (*txt, false, false);
204         vbox->pack_start (*hbox, false, true);
205
206         cerr << "set default folder to " << poor_mans_glob (Config->get_default_session_parent_dir()) << endl;
207         default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
208         default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed));
209         default_dir_chooser->show ();
210
211         vbox->show_all ();
212
213         default_folder_page_index = append_page (*vbox);
214         set_page_title (*vbox, _("Default folder for new sessions"));
215         set_page_header_image (*vbox, icon_pixbuf);
216         set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
217
218         /* user can just skip all these settings if they want to */
219
220         set_page_complete (*vbox, true);
221 }
222
223 void
224 ArdourStartup::setup_monitoring_choice_page ()
225 {
226         mon_vbox.set_spacing (18);
227         mon_vbox.set_border_width (24);
228
229         HBox* hbox = manage (new HBox);
230         VBox* vbox = manage (new VBox);
231         /* first button will be on by default */
232         RadioButton::Group g (monitor_via_ardour_button.get_group());
233         monitor_via_hardware_button.set_group (g);
234
235         monitor_label.set_markup(_("\
236 While recording instruments or vocals, you probably want to listen to the\n\
237 signal as well as record it. This is called \"monitoring\". There are\n\
238 different ways to do this depending on the equipment you have and the\n\
239 configuration of that equipment. The two most common are presented here.\n\
240 Please choose whichever one is right for your setup.\n\n\
241 <i>(You can change this preference at any time, via the Preferences dialog)</i>\n\n\
242 <i>If you do not understand what this is about, just accept the default.</i>"));
243         monitor_label.set_alignment (0.0, 0.0);
244
245         vbox->set_spacing (6);
246
247         vbox->pack_start (monitor_via_hardware_button, false, true);
248         vbox->pack_start (monitor_via_ardour_button, false, true);
249         hbox->pack_start (*vbox, true, true, 8);
250         mon_vbox.pack_start (monitor_label, false, false);
251         mon_vbox.pack_start (*hbox, false, false);
252
253         mon_vbox.show_all ();
254
255         monitoring_page_index = append_page (mon_vbox);
256         set_page_title (mon_vbox, _("Monitoring Choices"));
257         set_page_header_image (mon_vbox, icon_pixbuf);
258
259         /* user could just click on "Forward" if default
260          * choice is correct.
261          */
262
263         set_page_complete (mon_vbox, true);
264 }
265
266 void
267 ArdourStartup::setup_monitor_section_choice_page ()
268 {
269         mon_sec_vbox.set_spacing (18);
270         mon_sec_vbox.set_border_width (24);
271
272         HBox* hbox = manage (new HBox);
273         VBox* main_vbox = manage (new VBox);
274         VBox* vbox;
275         Label* l = manage (new Label);
276
277         main_vbox->set_spacing (32);
278
279         no_monitor_section_button.set_label (_("Use a Master bus directly"));
280         l->set_alignment (0.0, 1.0);
281         l->set_markup(_("Connect the Master bus directly to your hardware outputs. This is preferable for simple usage."));
282
283         vbox = manage (new VBox);
284         vbox->set_spacing (6);
285         vbox->pack_start (no_monitor_section_button, false, true);
286         vbox->pack_start (*l, false, true);
287
288         main_vbox->pack_start (*vbox, false, false);
289
290         use_monitor_section_button.set_label (_("Use an additional Monitor bus"));
291         l = manage (new Label);
292         l->set_alignment (0.0, 1.0);
293         l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\
294 greater control in monitoring without affecting the mix."));
295
296         vbox = manage (new VBox);
297         vbox->set_spacing (6);
298         vbox->pack_start (use_monitor_section_button, false, true);
299         vbox->pack_start (*l, false, true);
300
301         main_vbox->pack_start (*vbox, false, false);
302
303         RadioButton::Group g (use_monitor_section_button.get_group());
304         no_monitor_section_button.set_group (g);
305
306         if (Config->get_use_monitor_bus()) {
307                 use_monitor_section_button.set_active (true);
308         } else {
309                 no_monitor_section_button.set_active (true);
310         }
311
312         use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
313         no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
314
315         monitor_section_label.set_markup(_("<i>You can change this preference at any time via the Preferences dialog.\nYou can also add or remove the monitor section to/from any session.</i>\n\n\
316 <i>If you do not understand what this is about, just accept the default.</i>"));
317         monitor_section_label.set_alignment (0.0, 0.0);
318
319         hbox->pack_start (*main_vbox, true, true, 8);
320         mon_sec_vbox.pack_start (*hbox, false, false);
321         mon_sec_vbox.pack_start (monitor_section_label, false, false);
322
323         mon_sec_vbox.show_all ();
324
325         monitor_section_page_index = append_page (mon_sec_vbox);
326         set_page_title (mon_sec_vbox, _("Monitor Section"));
327         set_page_header_image (mon_sec_vbox, icon_pixbuf);
328
329         /* user could just click on "Forward" if default
330          * choice is correct.
331          */
332
333         set_page_complete (mon_sec_vbox, true);
334 }
335
336 void
337 ArdourStartup::setup_final_page ()
338 {
339         string msg = string_compose (_("%1 is ready for use"), PROGRAM_NAME);
340
341         plugin_disco_button.signal_clicked().connect (sigc::mem_fun(*this, &ArdourStartup::discover_plugins));
342         plugin_disco_button.set_label (_("Scan for Plugins"));
343         plugin_disco_button.show ();
344
345         Gtk::Label* final_label = manage (new Label);
346         final_label->set_markup (string_compose ("<span weight=\"bold\" size=\"large\">%1</span>", msg));
347         final_label->show ();
348
349         VBox* vbox = manage (new VBox);
350         vbox->pack_start (*final_label, true, true);
351         if (!Profile->get_mixbus()) {
352                 vbox->pack_start (plugin_disco_button, true, false);
353         }
354         vbox->show ();
355
356         final_page_index = append_page (*vbox);
357         set_page_complete (*vbox, true);
358         set_page_header_image (*vbox, icon_pixbuf);
359         set_page_type (*vbox, ASSISTANT_PAGE_CONFIRM);
360 }
361
362 void
363 ArdourStartup::discover_plugins () {
364         plugin_disco_button.set_sensitive (false);
365         PluginManager::instance().refresh();
366 }
367
368 void
369 ArdourStartup::on_cancel ()
370 {
371         _response = RESPONSE_CANCEL;
372         gtk_main_quit ();
373 }
374
375 bool
376 ArdourStartup::on_delete_event (GdkEventAny*)
377 {
378         _response = RESPONSE_CLOSE;
379         gtk_main_quit ();
380         return true;
381 }
382
383 void
384 ArdourStartup::on_apply ()
385 {
386         /* file-chooser button does not emit 'current_folder_changed' signal
387          * when a folder from the dropdown or the sidebar is chosen.
388          * -> explicitly poll for the dir as suggested by the gtk documentation.
389          */
390         if (default_dir_chooser && default_dir_chooser->get_filename() != Config->get_default_session_parent_dir ()) {
391                 config_modified = true;
392         }
393
394         if (config_modified) {
395
396                 if (default_dir_chooser) {
397                         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
398                 }
399
400                 if (monitor_via_hardware_button.get_active()) {
401                         Config->set_monitoring_model (ExternalMonitoring);
402                 } else if (monitor_via_ardour_button.get_active()) {
403                         Config->set_monitoring_model (SoftwareMonitoring);
404                 }
405
406                 Config->set_use_monitor_bus (use_monitor_section_button.get_active());
407
408                 Config->save_state ();
409
410         }
411
412         {
413                 /* "touch" the been-here-before path now we've successfully
414                    made it through the first time setup (at least)
415                 */
416                 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
417
418         }
419
420         _response = RESPONSE_OK;
421         gtk_main_quit ();
422 }
423
424
425 void
426 ArdourStartup::move_along_now ()
427 {
428         on_apply ();
429 }