2 * Copyright (C) 2009-2011 David Robillard <d@drobilla.net>
3 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
4 * Copyright (C) 2009-2016 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2012-2015 Tim Mayberry <mojofunk@gmail.com>
6 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
7 * Copyright (C) 2013 Colin Fletcher <colin.m.fletcher@googlemail.com>
8 * Copyright (C) 2013 Michael R. Fisher <mfisher@bketech.com>
9 * Copyright (C) 2015 John Emmas <john@creativepost.co.uk>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "gtk2ardour-config.h"
28 #include "gtk2ardour-version.h"
34 #include "pbd/gstdio_compat.h"
38 #include "pbd/basename.h"
39 #include "pbd/failed_constructor.h"
40 #include "pbd/scoped_file_descriptor.h"
41 #include "pbd/file_utils.h"
42 #include "pbd/replace_all.h"
43 #include "pbd/whitespace.h"
44 #include "pbd/stacktrace.h"
45 #include "pbd/openuri.h"
47 #include "ardour/audioengine.h"
48 #include "ardour/filesystem_paths.h"
49 #include "ardour/filename_extensions.h"
50 #include "ardour/plugin_manager.h"
51 #include "ardour/recent_sessions.h"
52 #include "ardour/session.h"
53 #include "ardour/session_state_utils.h"
54 #include "ardour/template_utils.h"
55 #include "ardour/profile.h"
57 #include "gtkmm2ext/utils.h"
59 #include "new_user_wizard.h"
61 #include "ui_config.h"
63 #include "plugin_scan_dialog.h"
71 using namespace ARDOUR;
72 using namespace ARDOUR_UI_UTILS;
74 NewUserWizard::NewUserWizard ()
75 : config_modified (false)
76 , default_dir_chooser (0)
77 , monitor_via_hardware_button (string_compose (_("Use an external mixer or the hardware mixer of your audio interface.\n"
78 "%1 will play NO role in monitoring"), PROGRAM_NAME))
79 , monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME))
80 , audio_page_index (-1)
81 , new_user_page_index (-1)
82 , default_folder_page_index (-1)
83 , monitoring_page_index (-1)
84 , final_page_index (-1)
86 set_position (WIN_POS_CENTER);
87 set_border_width (12);
89 if (! (icon_pixbuf = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
90 throw failed_constructor();
93 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
94 Glib::RefPtr<Gdk::Pixbuf> icon;
96 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
97 window_icons.push_back (icon);
99 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
100 window_icons.push_back (icon);
102 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
103 window_icons.push_back (icon);
105 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
106 window_icons.push_back (icon);
108 if (!window_icons.empty ()) {
109 set_default_icon_list (window_icons);
112 setup_new_user_page ();
113 setup_first_time_config_page ();
114 setup_monitoring_choice_page ();
115 setup_monitor_section_choice_page ();
119 NewUserWizard::~NewUserWizard ()
124 NewUserWizard::required ()
126 if (Glib::file_test (ARDOUR::been_here_before_path (), Glib::FILE_TEST_EXISTS)) {
134 NewUserWizard::setup_new_user_page ()
136 Label* foomatic = manage (new Label);
138 foomatic->set_markup (string_compose (_("\
139 <span size=\"larger\">%1 is a digital audio workstation. You can use it to \
140 record, edit and mix multi-track audio. You can produce your \
141 own CDs, mix video soundtracks, or experiment with new \
142 ideas about music and sound. \
144 There are a few things that need to be configured before you start \
145 using the program.</span> \
147 foomatic->set_justify (JUSTIFY_FILL);
148 foomatic->set_line_wrap ();
150 VBox* vbox = manage (new VBox);
151 vbox->set_border_width (24);
152 vbox->pack_start (*foomatic, true, true, 12);
155 Label* barmatic = manage (new Label);
156 barmatic->set_text (_("GUI and Font scaling:"));
158 Label* bazmatic = manage (new Label);
159 bazmatic->set_markup (_("<small><i>This can later be changed in Preferences > Appearance.</i></small>"));
161 ui_font_scale.append_text (_("100%"));
162 ui_font_scale.append_text (_("150%"));
163 ui_font_scale.append_text (_("200%"));
164 ui_font_scale.append_text (_("250%"));
165 ui_font_scale.set_active_text (_("100%"));
167 HBox* hbox = manage (new HBox);
168 HBox* cbox = manage (new HBox);
170 hbox->pack_start (*barmatic, false, false);
171 hbox->pack_start (ui_font_scale, false, false);
172 cbox->pack_start (*hbox, true, false);
174 vbox->pack_start (*cbox, false, false, 2);
175 vbox->pack_start (*bazmatic, false, false);
177 ui_font_scale.show ();
183 guess_default_ui_scale ();
184 ui_font_scale.signal_changed ().connect (sigc::mem_fun (*this, &NewUserWizard::rescale_ui));
190 new_user_page_index = append_page (*vbox);
191 set_page_type (*vbox, ASSISTANT_PAGE_INTRO);
192 set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME));
193 set_page_header_image (*vbox, icon_pixbuf);
194 set_page_complete (*vbox, true);
198 NewUserWizard::rescale_ui ()
200 int rn = ui_font_scale.get_active_row_number ();
204 float ui_scale = 100 + rn * 50;
205 UIConfiguration::instance ().set_font_scale (1024 * ui_scale);
206 UIConfiguration::instance ().reset_dpi ();
210 NewUserWizard::guess_default_ui_scale ()
214 GdkScreen* screen = gdk_display_get_screen (gdk_display_get_default (), 0);
215 gint n_monitors = gdk_screen_get_n_monitors (screen);
221 for (gint i = 0; i < n_monitors; ++i) {
223 gdk_screen_get_monitor_geometry (screen, i, &rect);
224 width = std::max (width, rect.width);
225 height = std::max (height, rect.height);
228 float wx = width / 1920.f;
229 float hx = height / 1080.f;
230 float sx = std::min (wx, hx);
233 ui_font_scale.set_active (0); // 100%
234 } else if (sx < 1.6) {
235 ui_font_scale.set_active (1); // 150%
236 } else if (sx < 2.1) {
237 ui_font_scale.set_active (2); // 200%
239 ui_font_scale.set_active (3); // 250%
245 NewUserWizard::default_dir_changed ()
247 Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
248 // make new session folder chooser point to the new default
249 new_folder_chooser.set_current_folder (Config->get_default_session_parent_dir());
254 NewUserWizard::config_changed ()
256 config_modified = true;
260 NewUserWizard::setup_first_time_config_page ()
262 default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME),
263 FILE_CHOOSER_ACTION_SELECT_FOLDER));
264 Gtk::Label* txt = manage (new Label);
265 HBox* hbox = manage (new HBox);
266 VBox* vbox = manage (new VBox);
268 txt->set_markup (string_compose (_("\
269 Each project that you work on with %1 has its own folder.\n\
270 These can require a lot of disk space if you are recording audio.\n\
272 Where would you like new %1 sessions to be stored by default?\n\n\
273 <i>(You can put new sessions anywhere, this is just a default)</i>"), PROGRAM_NAME));
274 txt->set_alignment (0.0, 0.0);
276 vbox->set_spacing (18);
277 vbox->set_border_width (24);
279 hbox->pack_start (*default_dir_chooser, false, true, 8);
280 vbox->pack_start (*txt, false, false);
281 vbox->pack_start (*hbox, false, true);
283 cerr << "set default folder to " << poor_mans_glob (Config->get_default_session_parent_dir()) << endl;
284 Gtkmm2ext::add_volume_shortcuts (*default_dir_chooser);
285 default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
286 default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &NewUserWizard::default_dir_changed));
287 default_dir_chooser->show ();
291 default_folder_page_index = append_page (*vbox);
292 set_page_title (*vbox, _("Default folder for new sessions"));
293 set_page_header_image (*vbox, icon_pixbuf);
294 set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
296 /* user can just skip all these settings if they want to */
298 set_page_complete (*vbox, true);
302 NewUserWizard::setup_monitoring_choice_page ()
304 mon_vbox.set_spacing (18);
305 mon_vbox.set_border_width (24);
307 HBox* hbox = manage (new HBox);
308 VBox* vbox = manage (new VBox);
309 /* first button will be on by default */
310 RadioButton::Group g (monitor_via_ardour_button.get_group());
311 monitor_via_hardware_button.set_group (g);
313 monitor_label.set_markup(_("\
314 While recording instruments or vocals, you probably want to listen to the\n\
315 signal as well as record it. This is called \"monitoring\". There are\n\
316 different ways to do this depending on the equipment you have and the\n\
317 configuration of that equipment. The two most common are presented here.\n\
318 Please choose whichever one is right for your setup.\n\n\
319 <i>(You can change this preference at any time, via the Preferences dialog)</i>\n\n\
320 <i>If you do not understand what this is about, just accept the default.</i>"));
321 monitor_label.set_alignment (0.0, 0.0);
323 vbox->set_spacing (6);
325 vbox->pack_start (monitor_via_hardware_button, false, true);
326 vbox->pack_start (monitor_via_ardour_button, false, true);
327 hbox->pack_start (*vbox, true, true, 8);
328 mon_vbox.pack_start (monitor_label, false, false);
329 mon_vbox.pack_start (*hbox, false, false);
331 mon_vbox.show_all ();
333 monitoring_page_index = append_page (mon_vbox);
334 set_page_title (mon_vbox, _("Monitoring Choices"));
335 set_page_header_image (mon_vbox, icon_pixbuf);
337 monitor_via_hardware_button.signal_toggled().connect (sigc::mem_fun (*this, &NewUserWizard::config_changed));
338 monitor_via_ardour_button.signal_toggled().connect (sigc::mem_fun (*this, &NewUserWizard::config_changed));
340 /* user could just click on "Forward" if default
344 set_page_complete (mon_vbox, true);
348 NewUserWizard::setup_monitor_section_choice_page ()
350 mon_sec_vbox.set_spacing (18);
351 mon_sec_vbox.set_border_width (24);
353 HBox* hbox = manage (new HBox);
354 VBox* main_vbox = manage (new VBox);
356 Label* l = manage (new Label);
358 main_vbox->set_spacing (32);
360 no_monitor_section_button.set_label (_("Use a Master bus directly"));
361 l->set_alignment (0.0, 1.0);
362 l->set_markup(_("Connect the Master bus directly to your hardware outputs. This is preferable for simple usage."));
364 vbox = manage (new VBox);
365 vbox->set_spacing (6);
366 vbox->pack_start (no_monitor_section_button, false, true);
367 vbox->pack_start (*l, false, true);
369 main_vbox->pack_start (*vbox, false, false);
371 use_monitor_section_button.set_label (_("Use an additional Monitor bus"));
372 l = manage (new Label);
373 l->set_alignment (0.0, 1.0);
374 l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\
375 greater control in monitoring without affecting the mix."));
377 vbox = manage (new VBox);
378 vbox->set_spacing (6);
379 vbox->pack_start (use_monitor_section_button, false, true);
380 vbox->pack_start (*l, false, true);
382 main_vbox->pack_start (*vbox, false, false);
384 RadioButton::Group g (use_monitor_section_button.get_group());
385 no_monitor_section_button.set_group (g);
387 if (Config->get_use_monitor_bus()) {
388 use_monitor_section_button.set_active (true);
390 no_monitor_section_button.set_active (true);
393 use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &NewUserWizard::config_changed));
394 no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &NewUserWizard::config_changed));
396 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\
397 <i>If you do not understand what this is about, just accept the default.</i>"));
398 monitor_section_label.set_alignment (0.0, 0.0);
400 hbox->pack_start (*main_vbox, true, true, 8);
401 mon_sec_vbox.pack_start (*hbox, false, false);
402 mon_sec_vbox.pack_start (monitor_section_label, false, false);
404 mon_sec_vbox.show_all ();
406 monitor_section_page_index = append_page (mon_sec_vbox);
407 set_page_title (mon_sec_vbox, _("Monitor Section"));
408 set_page_header_image (mon_sec_vbox, icon_pixbuf);
410 /* user could just click on "Forward" if default
414 set_page_complete (mon_sec_vbox, true);
418 NewUserWizard::setup_final_page ()
420 string msg = string_compose (_("%1 is ready for use"), PROGRAM_NAME);
422 plugin_disco_button.signal_clicked().connect (sigc::mem_fun(*this, &NewUserWizard::discover_plugins));
423 plugin_disco_button.set_label (_("Scan for Plugins"));
424 plugin_disco_button.show ();
426 Gtk::Label* final_label = manage (new Label);
427 final_label->set_markup (string_compose ("<span weight=\"bold\" size=\"large\">%1</span>", msg));
428 final_label->show ();
430 VBox* vbox = manage (new VBox);
431 vbox->pack_start (*final_label, true, true);
432 /* Mixbus sets this parameter to true by default, Ardour sets it to false */
433 if (!Config->get_discover_vst_on_start()) {
434 vbox->pack_start (plugin_disco_button, true, false);
438 final_page_index = append_page (*vbox);
439 set_page_complete (*vbox, true);
440 set_page_header_image (*vbox, icon_pixbuf);
441 set_page_type (*vbox, ASSISTANT_PAGE_CONFIRM);
445 NewUserWizard::discover_plugins ()
447 plugin_disco_button.set_sensitive (false);
448 PluginScanDialog psd (false, true);
453 NewUserWizard::on_cancel ()
455 _signal_response (int (RESPONSE_CANCEL));
459 NewUserWizard::on_delete_event (GdkEventAny*)
461 _signal_response (int (RESPONSE_CLOSE));
466 NewUserWizard::on_apply ()
468 /* file-chooser button does not emit 'current_folder_changed' signal
469 * when a folder from the dropdown or the sidebar is chosen.
470 * -> explicitly poll for the dir as suggested by the gtk documentation.
472 if (default_dir_chooser && default_dir_chooser->get_filename() != Config->get_default_session_parent_dir ()) {
473 config_modified = true;
476 if (config_modified) {
478 if (default_dir_chooser) {
479 Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
482 if (monitor_via_hardware_button.get_active()) {
483 Config->set_monitoring_model (ExternalMonitoring);
484 } else if (monitor_via_ardour_button.get_active()) {
485 Config->set_monitoring_model (SoftwareMonitoring);
488 Config->set_use_monitor_bus (use_monitor_section_button.get_active());
490 Config->save_state ();
495 /* "touch" the been-here-before path now we've successfully
496 made it through the first time setup (at least)
498 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
502 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
503 std::string dspd (Config->get_default_session_parent_dir());
504 Searchpath ds (ARDOUR::ardour_data_search_path());
505 ds.add_subdirectory_to_paths ("sessions");
506 vector<string> demos;
507 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
509 ARDOUR::RecentSessions rs;
510 ARDOUR::read_recent_sessions (rs);
512 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
513 /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
514 std::string name = basename_nosuffix (basename_nosuffix (*i));
515 std::string path = Glib::build_filename (dspd, name);
516 /* skip if session-dir already exists */
517 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
520 /* skip sessions that are already in 'recent'.
521 * eg. a new user changed <session-default-dir> shorly after installation
523 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
524 if ((*r).first == name) {
529 PBD::FileArchive ar (*i);
530 if (0 == ar.inflate (dspd)) {
531 store_recent_sessions (name, path);
532 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
538 _signal_response (int (RESPONSE_OK));
543 NewUserWizard::move_along_now ()