workaround changes in glibmm 2.49.x
[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         /* look for a "been here before" file for this version or earlier
123          * versions
124          */
125
126         const int current_version = atoi (PROGRAM_VERSION);
127
128         for (int v = current_version; v != 0; --v) {
129                 if (Glib::file_test (ARDOUR::been_here_before_path (v), Glib::FILE_TEST_EXISTS)) {
130                         if (v != current_version) {
131                                 /* older version exists, create the current one */
132                                 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path (current_version).c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
133                         }
134                         return false;
135                 }
136         }
137
138         return true;
139 }
140
141 void
142 ArdourStartup::setup_new_user_page ()
143 {
144         Label* foomatic = manage (new Label);
145
146         foomatic->set_markup (string_compose (_("\
147 <span size=\"larger\">%1 is a digital audio workstation. You can use it to \
148 record, edit and mix multi-track audio. You can produce your \
149 own CDs, mix video soundtracks, or experiment with new \
150 ideas about music and sound. \
151 \n\n\
152 There are a few things that need to be configured before you start \
153 using the program.</span> \
154 "), PROGRAM_NAME));
155         foomatic->set_justify (JUSTIFY_FILL);
156         foomatic->set_line_wrap ();
157
158         HBox* hbox = manage (new HBox);
159         HBox* vbox = manage (new HBox);
160
161         vbox->set_border_width (24);
162
163         hbox->pack_start (*foomatic, true, true);
164         vbox->pack_start (*hbox, true, true);
165
166         foomatic->show ();
167         hbox->show ();
168         vbox->show ();
169
170         new_user_page_index = append_page (*vbox);
171         set_page_type (*vbox, ASSISTANT_PAGE_INTRO);
172         set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME));
173         set_page_header_image (*vbox, icon_pixbuf);
174         set_page_complete (*vbox, true);
175 }
176
177 void
178 ArdourStartup::default_dir_changed ()
179 {
180         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
181         // make new session folder chooser point to the new default
182         new_folder_chooser.set_current_folder (Config->get_default_session_parent_dir());
183         config_changed ();
184 }
185
186 void
187 ArdourStartup::config_changed ()
188 {
189         config_modified = true;
190 }
191
192 void
193 ArdourStartup::setup_first_time_config_page ()
194 {
195         default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME),
196                                                              FILE_CHOOSER_ACTION_SELECT_FOLDER));
197         Gtk::Label* txt = manage (new Label);
198         HBox* hbox = manage (new HBox);
199         VBox* vbox = manage (new VBox);
200
201         txt->set_markup (string_compose (_("\
202 Each project that you work on with %1 has its own folder.\n\
203 These can require a lot of disk space if you are recording audio.\n\
204 \n\
205 Where would you like new %1 sessions to be stored by default?\n\n\
206 <i>(You can put new sessions anywhere, this is just a default)</i>"), PROGRAM_NAME));
207         txt->set_alignment (0.0, 0.0);
208
209         vbox->set_spacing (18);
210         vbox->set_border_width (24);
211
212         hbox->pack_start (*default_dir_chooser, false, true, 8);
213         vbox->pack_start (*txt, false, false);
214         vbox->pack_start (*hbox, false, true);
215
216         cerr << "set default folder to " << poor_mans_glob (Config->get_default_session_parent_dir()) << endl;
217         default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
218         default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed));
219         default_dir_chooser->show ();
220
221         vbox->show_all ();
222
223         default_folder_page_index = append_page (*vbox);
224         set_page_title (*vbox, _("Default folder for new sessions"));
225         set_page_header_image (*vbox, icon_pixbuf);
226         set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
227
228         /* user can just skip all these settings if they want to */
229
230         set_page_complete (*vbox, true);
231 }
232
233 void
234 ArdourStartup::setup_monitoring_choice_page ()
235 {
236         mon_vbox.set_spacing (18);
237         mon_vbox.set_border_width (24);
238
239         HBox* hbox = manage (new HBox);
240         VBox* vbox = manage (new VBox);
241         /* first button will be on by default */
242         RadioButton::Group g (monitor_via_ardour_button.get_group());
243         monitor_via_hardware_button.set_group (g);
244
245         monitor_label.set_markup(_("\
246 While recording instruments or vocals, you probably want to listen to the\n\
247 signal as well as record it. This is called \"monitoring\". There are\n\
248 different ways to do this depending on the equipment you have and the\n\
249 configuration of that equipment. The two most common are presented here.\n\
250 Please choose whichever one is right for your setup.\n\n\
251 <i>(You can change this preference at any time, via the Preferences dialog)</i>\n\n\
252 <i>If you do not understand what this is about, just accept the default.</i>"));
253         monitor_label.set_alignment (0.0, 0.0);
254
255         vbox->set_spacing (6);
256
257         vbox->pack_start (monitor_via_hardware_button, false, true);
258         vbox->pack_start (monitor_via_ardour_button, false, true);
259         hbox->pack_start (*vbox, true, true, 8);
260         mon_vbox.pack_start (monitor_label, false, false);
261         mon_vbox.pack_start (*hbox, false, false);
262
263         mon_vbox.show_all ();
264
265         monitoring_page_index = append_page (mon_vbox);
266         set_page_title (mon_vbox, _("Monitoring Choices"));
267         set_page_header_image (mon_vbox, icon_pixbuf);
268
269         /* user could just click on "Forward" if default
270          * choice is correct.
271          */
272
273         set_page_complete (mon_vbox, true);
274 }
275
276 void
277 ArdourStartup::setup_monitor_section_choice_page ()
278 {
279         mon_sec_vbox.set_spacing (18);
280         mon_sec_vbox.set_border_width (24);
281
282         HBox* hbox = manage (new HBox);
283         VBox* main_vbox = manage (new VBox);
284         VBox* vbox;
285         Label* l = manage (new Label);
286
287         main_vbox->set_spacing (32);
288
289         no_monitor_section_button.set_label (_("Use a Master bus directly"));
290         l->set_alignment (0.0, 1.0);
291         l->set_markup(_("Connect the Master bus directly to your hardware outputs. This is preferable for simple usage."));
292
293         vbox = manage (new VBox);
294         vbox->set_spacing (6);
295         vbox->pack_start (no_monitor_section_button, false, true);
296         vbox->pack_start (*l, false, true);
297
298         main_vbox->pack_start (*vbox, false, false);
299
300         use_monitor_section_button.set_label (_("Use an additional Monitor bus"));
301         l = manage (new Label);
302         l->set_alignment (0.0, 1.0);
303         l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\
304 greater control in monitoring without affecting the mix."));
305
306         vbox = manage (new VBox);
307         vbox->set_spacing (6);
308         vbox->pack_start (use_monitor_section_button, false, true);
309         vbox->pack_start (*l, false, true);
310
311         main_vbox->pack_start (*vbox, false, false);
312
313         RadioButton::Group g (use_monitor_section_button.get_group());
314         no_monitor_section_button.set_group (g);
315
316         if (Config->get_use_monitor_bus()) {
317                 use_monitor_section_button.set_active (true);
318         } else {
319                 no_monitor_section_button.set_active (true);
320         }
321
322         use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
323         no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
324
325         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\
326 <i>If you do not understand what this is about, just accept the default.</i>"));
327         monitor_section_label.set_alignment (0.0, 0.0);
328
329         hbox->pack_start (*main_vbox, true, true, 8);
330         mon_sec_vbox.pack_start (*hbox, false, false);
331         mon_sec_vbox.pack_start (monitor_section_label, false, false);
332
333         mon_sec_vbox.show_all ();
334
335         monitor_section_page_index = append_page (mon_sec_vbox);
336         set_page_title (mon_sec_vbox, _("Monitor Section"));
337         set_page_header_image (mon_sec_vbox, icon_pixbuf);
338
339         /* user could just click on "Forward" if default
340          * choice is correct.
341          */
342
343         set_page_complete (mon_sec_vbox, true);
344 }
345
346 void
347 ArdourStartup::setup_final_page ()
348 {
349         string msg = string_compose (_("%1 is ready for use"), PROGRAM_NAME);
350
351         plugin_disco_button.signal_clicked().connect (sigc::mem_fun(*this, &ArdourStartup::discover_plugins));
352         plugin_disco_button.set_label (_("Scan for Plugins"));
353         plugin_disco_button.show ();
354
355         Gtk::Label* final_label = manage (new Label);
356         final_label->set_markup (string_compose ("<span weight=\"bold\" size=\"large\">%1</span>", msg));
357         final_label->show ();
358
359         VBox* vbox = manage (new VBox);
360         vbox->pack_start (*final_label, true, true);
361         if (!Profile->get_mixbus()) {
362                 vbox->pack_start (plugin_disco_button, true, false);
363         }
364         vbox->show ();
365
366         final_page_index = append_page (*vbox);
367         set_page_complete (*vbox, true);
368         set_page_header_image (*vbox, icon_pixbuf);
369         set_page_type (*vbox, ASSISTANT_PAGE_CONFIRM);
370 }
371
372 void
373 ArdourStartup::discover_plugins () {
374         plugin_disco_button.set_sensitive (false);
375         PluginManager::instance().refresh();
376 }
377
378 void
379 ArdourStartup::on_cancel ()
380 {
381         _response = RESPONSE_CANCEL;
382         gtk_main_quit ();
383 }
384
385 bool
386 ArdourStartup::on_delete_event (GdkEventAny*)
387 {
388         _response = RESPONSE_CLOSE;
389         gtk_main_quit ();
390         return true;
391 }
392
393 void
394 ArdourStartup::on_apply ()
395 {
396         /* file-chooser button does not emit 'current_folder_changed' signal
397          * when a folder from the dropdown or the sidebar is chosen.
398          * -> explicitly poll for the dir as suggested by the gtk documentation.
399          */
400         if (default_dir_chooser && default_dir_chooser->get_filename() != Config->get_default_session_parent_dir ()) {
401                 config_modified = true;
402         }
403
404         if (config_modified) {
405
406                 if (default_dir_chooser) {
407                         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
408                 }
409
410                 if (monitor_via_hardware_button.get_active()) {
411                         Config->set_monitoring_model (ExternalMonitoring);
412                 } else if (monitor_via_ardour_button.get_active()) {
413                         Config->set_monitoring_model (SoftwareMonitoring);
414                 }
415
416                 Config->set_use_monitor_bus (use_monitor_section_button.get_active());
417
418                 Config->save_state ();
419
420         }
421
422         {
423                 /* "touch" the been-here-before path now we've successfully
424                    made it through the first time setup (at least)
425                 */
426                 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
427
428         }
429
430         _response = RESPONSE_OK;
431         gtk_main_quit ();
432 }
433
434
435 void
436 ArdourStartup::move_along_now ()
437 {
438         on_apply ();
439 }