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