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