1 /*
2  * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3  * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2006-2016 David Robillard <d@drobilla.net>
5  * Copyright (C) 2006 Hans Fugal <hans@fugal.net>
6  * Copyright (C) 2006 Nick Mainsbridge <mainsbridge@gmail.com>
7  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8  * Copyright (C) 2007-2015 Tim Mayberry <mojofunk@gmail.com>
9  * Copyright (C) 2007 Doug McLain <doug@nostar.net>
10  * Copyright (C) 2013-2020 Robin Gareus <robin@gareus.org>
11  * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27 
28 /* This file contains any ARDOUR_UI methods that require knowledge of
29    the various dialog boxes, and exists so that no compilation dependency
30    exists between the main ARDOUR_UI modules and their respective classes.
31    This is to cut down on the compile times.  It also helps with my sanity.
32 */
33 
34 #include <vector>
35 
36 #include <gtkmm/treemodelfilter.h>
37 
38 #include "pbd/convert.h"
39 
40 #include "ardour/audioengine.h"
41 #include "ardour/automation_watch.h"
42 #include "ardour/control_protocol_manager.h"
43 #include "ardour/profile.h"
44 #include "ardour/session.h"
45 
46 #include "control_protocol/control_protocol.h"
47 
48 #include "gtkmm2ext/keyboard.h"
49 #include "gtkmm2ext/utils.h"
50 
51 #include "actions.h"
52 #include "add_route_dialog.h"
53 #include "add_video_dialog.h"
54 #include "ardour_ui.h"
55 #include "big_clock_window.h"
56 #include "big_transport_window.h"
57 #include "bundle_manager.h"
58 #include "dsp_stats_window.h"
59 #include "global_port_matrix.h"
60 #include "gui_object.h"
61 #include "gui_thread.h"
62 #include "keyeditor.h"
63 #include "location_ui.h"
64 #include "lua_script_manager.h"
65 #include "luawindow.h"
66 #include "main_clock.h"
67 #include "meterbridge.h"
68 #include "meter_patterns.h"
69 #include "monitor_section.h"
70 #include "midi_tracer.h"
71 #include "mini_timeline.h"
72 #include "mixer_ui.h"
73 #include "plugin_dspload_window.h"
74 #include "public_editor.h"
75 #include "processor_box.h"
76 #include "rc_option_editor.h"
77 #include "recorder_ui.h"
78 #include "route_params_ui.h"
79 #include "shuttle_control.h"
80 #include "session_option_editor.h"
81 #include "speaker_dialog.h"
82 #include "splash.h"
83 #include "sfdb_ui.h"
84 #include "time_info_box.h"
85 #include "timers.h"
86 #include "transport_masters_dialog.h"
87 #include "virtual_keyboard_window.h"
88 
89 #include "pbd/i18n.h"
90 
91 using namespace ARDOUR;
92 using namespace PBD;
93 using namespace Glib;
94 using namespace Gtk;
95 using namespace Gtkmm2ext;
96 using namespace ArdourWidgets;
97 
98 void
set_session(Session * s)99 ARDOUR_UI::set_session (Session *s)
100 {
101 	SessionHandlePtr::set_session (s);
102 
103 	/* adjust sensitivity of menu bar options to reflect presence/absence
104 	 * of session
105 	 */
106 
107 	ActionManager::set_sensitive (ActionManager::session_sensitive_actions, _session);
108 	ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session ? _session->writable() : false);
109 
110 	if (_session && _session->locations()->num_range_markers()) {
111 		ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
112 	} else {
113 		ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
114 	}
115 
116 	transport_ctrl.set_session (s);
117 
118 	if (big_transport_window) {
119 		big_transport_window->set_session (s);
120 	}
121 
122 	if (virtual_keyboard_window) {
123 		virtual_keyboard_window->set_session (s);
124 	}
125 
126 	update_path_label ();
127 
128 	if (!_session) {
129 		WM::Manager::instance().set_session (s);
130 		/* Session option editor cannot exist across change-of-session */
131 		session_option_editor.drop_window ();
132 		/* Ditto for AddVideoDialog */
133 		add_video_dialog.drop_window ();
134 		/* screensaver + layered button sensitivity */
135 		map_transport_state ();
136 		return;
137 	}
138 
139 	const XMLNode* node = _session->extra_xml (X_("UI"));
140 
141 	if (node) {
142 		const XMLNodeList& children = node->children();
143 		for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
144 			if ((*i)->name() == GUIObjectState::xml_node_name) {
145 				gui_object_state->load (**i);
146 				break;
147 			}
148 		}
149 	}
150 
151 	WM::Manager::instance().set_session (s);
152 
153 	AutomationWatch::instance().set_session (s);
154 
155 	shuttle_box.set_session (s);
156 	mini_timeline.set_session (s);
157 	time_info_box->set_session (s);
158 
159 	primary_clock->set_session (s);
160 	secondary_clock->set_session (s);
161 	big_clock->set_session (s);
162 	video_timeline->set_session (s);
163 	lua_script_window->set_session (s);
164 	plugin_dsp_load_window->set_session (s);
165 	dsp_statistics_window->set_session (s);
166 	transport_masters_window->set_session (s);
167 	rc_option_editor->set_session (s);
168 
169 	roll_controllable->set_session (s);
170 	stop_controllable->set_session (s);
171 	goto_start_controllable->set_session (s);
172 	goto_end_controllable->set_session (s);
173 	auto_loop_controllable->set_session (s);
174 	play_selection_controllable->set_session (s);
175 	rec_controllable->set_session (s);
176 
177 	/* allow wastebasket flush again */
178 
179 	Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
180 	if (act) {
181 		act->set_sensitive (true);
182 	}
183 
184 	/* there are never any selections on startup */
185 
186 	ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
187 	ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
188 	ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, false);
189 	ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, false);
190 	ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, false);
191 	ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, false);
192 	ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
193 	ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
194 	ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
195 
196 	solo_alert_button.set_active (_session->soloing());
197 
198 	setup_session_options ();
199 
200 	blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
201 
202 	_session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
203 	_session->StateSaved.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_title, this), gui_context());
204 	_session->StateSaved.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_path_label, this), gui_context());
205 	_session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
206 	_session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
207 	_session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dirty_changed, this), gui_context());
208 
209 	_session->PunchLoopConstraintChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::set_punch_sensitivity, this), gui_context());
210 	_session->auto_punch_location_changed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::set_punch_sensitivity, this), gui_context ());
211 
212 	_session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
213 	_session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
214 	_session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
215 	_session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
216 	_session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
217 	_session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
218 
219 	_session->LatencyUpdated.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_latency_updated, this, _1), gui_context());
220 	session_latency_updated (true);
221 
222 	/* Clocks are on by default after we are connected to a session, so show that here.
223 	*/
224 
225 	connect_dependents_to_session (s);
226 
227 	/* listen to clock mode changes. don't do this earlier because otherwise as the clocks
228 	   restore their modes or are explicitly set, we will cause the "new" mode to be saved
229 	   back to the session XML ("Extra") state.
230 	 */
231 
232 	AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
233 
234 	Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
235 
236 	start_clocking ();
237 
238 	map_transport_state ();
239 
240 	second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
241 	point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
242 	point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
243 	set_fps_timeout_connection();
244 
245 	update_format ();
246 
247 	if (editor_meter_table.get_parent()) {
248 		transport_hbox.remove (editor_meter_table);
249 	}
250 
251 	if (editor_meter) {
252 		editor_meter_table.remove(*editor_meter);
253 		delete editor_meter;
254 		editor_meter = 0;
255 	}
256 
257 	if (editor_meter_table.get_parent()) {
258 		transport_hbox.remove (editor_meter_table);
259 	}
260 	if (editor_meter_peak_display.get_parent ()) {
261 		editor_meter_table.remove (editor_meter_peak_display);
262 	}
263 
264 	if (_session &&
265 	    _session->master_out() &&
266 	    _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
267 
268 		editor_meter = new LevelMeterHBox(_session);
269 		editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
270 		editor_meter->clear_meters();
271 		editor_meter->setup_meters (30, 10, 6);
272 		editor_meter->show();
273 
274 		editor_meter_table.set_spacings(3);
275 		editor_meter_table.attach(*editor_meter,             0,1, 0,1, FILL, EXPAND|FILL, 0, 1);
276 		editor_meter_table.attach(editor_meter_peak_display, 0,1, 1,2, FILL, SHRINK, 0, 0);
277 
278 		editor_meter->show();
279 		editor_meter_peak_display.show();
280 
281 		ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
282 		ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
283 		ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
284 
285 		editor_meter_peak_display.set_name ("meterbridge peakindicator");
286 		editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
287 		editor_meter_peak_display.set_size_request (-1, std::max (5.f, std::min (12.f, rintf (8.f * UIConfiguration::instance().get_ui_scale()))) );
288 		editor_meter_peak_display.set_corner_radius (1.0);
289 
290 		_clear_editor_meter = true;
291 		editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
292 
293 		repack_transport_hbox ();
294 	}
295 
296 	update_title ();
297 }
298 
299 int
unload_session(bool hide_stuff)300 ARDOUR_UI::unload_session (bool hide_stuff)
301 {
302 	if (_session) {
303 		ARDOUR_UI::instance()->video_timeline->sync_session_state();
304 
305 		/* Unconditionally save session-specific GUI settings:
306 		 * Playhead position, zoom/scroll with stationary PH,
307 		 * window and pane positions, etc.
308 		 *
309 		 * While many GUI operations immediately cause an instant.xml
310 		 * save, changing the playhead-pos in particular does not,
311 		 * nor mark the session dirty.
312 		 */
313 		save_ardour_state ();
314 	}
315 
316 	if (_session && _session->dirty()) {
317 		std::vector<std::string> actions;
318 		actions.push_back (_("Don't close"));
319 		if (_session->unnamed()) {
320 			actions.push_back (_("Discard"));
321 		} else {
322 			actions.push_back (_("Just close"));
323 		}
324 		actions.push_back (_("Save and close"));
325 
326 		switch (ask_about_saving_session (actions)) {
327 		case -1:
328 			// cancel
329 			return 1;
330 		case 1:
331 			// save and continue (and handle unnamed sessions)
332 			if (_session->unnamed()) {
333 				rename_session (true);
334 			}
335 			_session->save_state ("");
336 			break;
337 		case 0:
338 			// discard/don't save
339 			break;
340 		}
341 	}
342 
343 
344 	{
345 		// tear down session specific CPI (owned by rc_config_editor which can remain)
346 		ControlProtocolManager& m = ControlProtocolManager::instance ();
347 		for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
348 			if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
349 				(*i)->protocol->tear_down_gui ();
350 			}
351 		}
352 	}
353 
354 	if (hide_stuff) {
355 		close_all_dialogs ();
356 		editor->hide ();
357 		mixer->hide ();
358 		meterbridge->hide ();
359 		audio_port_matrix->hide();
360 		midi_port_matrix->hide();
361 		route_params->hide();
362 	}
363 
364 	second_connection.disconnect ();
365 	point_one_second_connection.disconnect ();
366 	point_zero_something_second_connection.disconnect();
367 	fps_connection.disconnect();
368 
369 	if (editor_meter) {
370 		editor_meter_table.remove(*editor_meter);
371 		delete editor_meter;
372 		editor_meter = 0;
373 		editor_meter_peak_display.hide();
374 	}
375 
376 	ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
377 
378 	WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
379 
380 	if (ARDOUR_UI::instance()->video_timeline) {
381 		ARDOUR_UI::instance()->video_timeline->close_session();
382 	}
383 
384 	stop_clocking ();
385 
386 	/* drop everything attached to the blink signal */
387 
388 	blink_connection.disconnect ();
389 
390 	ARDOUR::Session* session_to_delete = _session;
391 	_session = 0;
392 	delete session_to_delete;
393 
394 	update_title ();
395 
396 	return 0;
397 }
398 
399 void
toggle_editor_and_mixer()400 ARDOUR_UI::toggle_editor_and_mixer ()
401 {
402 	if (editor->tabbed() && mixer->tabbed()) {
403 		/* both in the same window */
404 		if (_tabs.get_current_page() == _tabs.page_num (editor->contents())) {
405 			_tabs.set_current_page (_tabs.page_num (mixer->contents()));
406 		} else if (_tabs.get_current_page() == _tabs.page_num (mixer->contents())) {
407 			_tabs.set_current_page (_tabs.page_num (editor->contents()));
408 		} else {
409 			/* go to mixer */
410 			_tabs.set_current_page (_tabs.page_num (mixer->contents()));
411 		}
412 		return;
413 	}
414 
415 
416 	if (editor->tabbed() && !mixer->tabbed()) {
417 		/* editor is tabbed, mixer is not */
418 
419 		Gtk::Window* mwin = mixer->current_toplevel ();
420 
421 		if (!mwin) {
422 			/* mixer's own window doesn't exist */
423 			mixer->make_visible ();
424 		} else if (!mwin->is_mapped ()) {
425 			/* mixer's own window exists but isn't mapped */
426 			mixer->make_visible ();
427 		} else {
428 			/* mixer window is mapped, editor is visible as tab */
429 			Gtk::Widget* f = mwin->get_focus();
430 			if (f && f->has_focus()) {
431 				/* mixer has focus, switch to editor */
432 				editor->make_visible ();
433 			} else {
434 				mixer->make_visible ();
435 			}
436 		}
437 		return;
438 	}
439 
440 	if (!editor->tabbed() && mixer->tabbed()) {
441 		/* mixer is tabbed, editor is not */
442 
443 		Gtk::Window* ewin = editor->current_toplevel ();
444 
445 		if (!ewin) {
446 			/* mixer's own window doesn't exist */
447 			editor->make_visible ();
448 		} else if (!ewin->is_mapped ()) {
449 			/* editor's own window exists but isn't mapped */
450 			editor->make_visible ();
451 		} else {
452 			/* editor window is mapped, mixer is visible as tab */
453 			Gtk::Widget* f = ewin->get_focus();
454 			if (f && f->has_focus()) {
455 				/* editor has focus, switch to mixer */
456 				mixer->make_visible ();
457 			} else {
458 				editor->make_visible ();
459 			}
460 		}
461 		return;
462 	}
463 }
464 
465 void
step_up_through_tabs()466 ARDOUR_UI::step_up_through_tabs ()
467 {
468 	std::vector<Tabbable*> candidates;
469 
470 	/* this list must match the order of visibility buttons */
471 
472 	if (recorder->tabbed()) {
473 		candidates.push_back (recorder);
474 	}
475 
476 	if (editor->tabbed()) {
477 		candidates.push_back (editor);
478 	}
479 
480 	if (mixer->tabbed()) {
481 		candidates.push_back (mixer);
482 	}
483 
484 	if (rc_option_editor->tabbed()) {
485 		candidates.push_back (rc_option_editor);
486 	}
487 
488 	if (candidates.size() < 2) {
489 		/* nothing to be done with zero or one visible in tabs */
490 		return;
491 	}
492 
493 	std::vector<Tabbable*>::iterator prev = candidates.end();
494 	std::vector<Tabbable*>::iterator i;
495 	Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
496 
497 	for (i = candidates.begin(); i != candidates.end(); ++i) {
498 		if (w == &(*i)->contents()) {
499 			if (prev != candidates.end()) {
500 				_tabs.set_current_page (_tabs.page_num ((*prev)->contents()));
501 			} else {
502 				_tabs.set_current_page (_tabs.page_num (candidates.back()->contents()));
503 			}
504 			return;
505 		}
506 		prev = i;
507 	}
508 }
509 
510 void
step_down_through_tabs()511 ARDOUR_UI::step_down_through_tabs ()
512 {
513 	std::vector<Tabbable*> candidates;
514 
515 	/* this list must match the order of visibility buttons */
516 
517 	if (recorder->tabbed()) {
518 		candidates.push_back (recorder);
519 	}
520 
521 	if (editor->tabbed()) {
522 		candidates.push_back (editor);
523 	}
524 
525 	if (mixer->tabbed()) {
526 		candidates.push_back (mixer);
527 	}
528 
529 	if (rc_option_editor->tabbed()) {
530 		candidates.push_back (rc_option_editor);
531 	}
532 
533 	if (candidates.size() < 2) {
534 		/* nothing to be done with zero or one visible in tabs */
535 		return;
536 	}
537 
538 	std::vector<Tabbable*>::reverse_iterator next = candidates.rend();
539 	std::vector<Tabbable*>::reverse_iterator i;
540 	Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
541 
542 	for (i = candidates.rbegin(); i != candidates.rend(); ++i) {
543 		if (w == &(*i)->contents()) {
544 			if (next != candidates.rend()) {
545 				_tabs.set_current_page (_tabs.page_num ((*next)->contents()));
546 			} else {
547 				_tabs.set_current_page (_tabs.page_num (candidates.front()->contents()));
548 			}
549 			break;
550 		}
551 		next = i;
552 	}
553 }
554 
555 void
key_change_tabbable_visibility(Tabbable * t)556 ARDOUR_UI::key_change_tabbable_visibility (Tabbable* t)
557 {
558 	if (!t) {
559 		return;
560 	}
561 
562 	if (t->tabbed()) {
563 		_tabs.set_current_page (_tabs.page_num (t->contents()));
564 	} else if (!t->fully_visible()) {
565 		t->make_visible ();
566 	} else {
567 		_main_window.present ();
568 	}
569 }
570 
571 void
button_change_tabbable_visibility(Tabbable * t)572 ARDOUR_UI::button_change_tabbable_visibility (Tabbable* t)
573 {
574 	/* For many/most users, clicking a button in the main window will make it
575 	   the main/front/key window, which will change any stacking relationship they
576 	   were trying to modify by clicking on the button in the first
577 	   place. This button-aware method knows that click on
578 	   a button designed to show/hide a Tabbable that has its own window
579 	   will have made that window be obscured (as the main window comes to
580 	   the front). We therefore *hide* the Tabbable's window if it is even
581 	   partially visible, believing that this is likely because the
582 	   Tabbable window used to be front, the user clicked to change that,
583 	   and before we even get here, the main window has become front.
584 	*/
585 
586 	if (!t) {
587 		return;
588 	}
589 
590 	if (t->tabbed()) {
591 		_tabs.set_current_page (_tabs.page_num (t->contents()));
592 	} else if (t->visible()) {
593 		t->hide();
594 	} else {
595 		t->make_visible ();
596 	}
597 }
598 
599 void
show_tabbable(Tabbable * t)600 ARDOUR_UI::show_tabbable (Tabbable* t)
601 {
602 	if (!t) {
603 		return;
604 	}
605 
606 	t->make_visible ();
607 }
608 
609 void
hide_tabbable(Tabbable * t)610 ARDOUR_UI::hide_tabbable (Tabbable* t)
611 {
612 	if (!t) {
613 		return;
614 	}
615 	t->make_invisible ();
616 }
617 
618 void
attach_tabbable(Tabbable * t)619 ARDOUR_UI::attach_tabbable (Tabbable* t)
620 {
621 	if (!t) {
622 		return;
623 	}
624 
625 	t->attach ();
626 }
627 
628 void
detach_tabbable(Tabbable * t)629 ARDOUR_UI::detach_tabbable (Tabbable* t)
630 {
631 	if (!t) {
632 		return;
633 	}
634 	t->detach ();
635 }
636 
637 void
tabs_page_added(Widget *,guint)638 ARDOUR_UI::tabs_page_added (Widget*,guint)
639 {
640 	if (_tabs.get_n_pages() > 1) {
641 
642 		std::vector<TargetEntry> drag_target_entries;
643 		drag_target_entries.push_back (TargetEntry ("tabbable"));
644 
645 		editor_visibility_button.drag_source_set (drag_target_entries);
646 		mixer_visibility_button.drag_source_set (drag_target_entries);
647 		prefs_visibility_button.drag_source_set (drag_target_entries);
648 		recorder_visibility_button.drag_source_set (drag_target_entries);
649 
650 		editor_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (editor->name(),
651 		                                                                              Pango::FontDescription ("Sans 24"),
652 		                                                                              0, 0,
653 		                                                                              Gdk::Color ("red")));
654 		mixer_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (mixer->name(),
655 		                                                                             Pango::FontDescription ("Sans 24"),
656 		                                                                             0, 0,
657 		                                                                             Gdk::Color ("red")));
658 		prefs_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (rc_option_editor->name(),
659 		                                                                             Pango::FontDescription ("Sans 24"),
660 		                                                                             0, 0,
661 		                                                                             Gdk::Color ("red")));
662 		recorder_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (recorder->name(),
663 		                                                                             Pango::FontDescription ("Sans 24"),
664 		                                                                             0, 0,
665 		                                                                             Gdk::Color ("red")));
666 	}
667 }
668 
669 void
tabs_page_removed(Widget *,guint)670 ARDOUR_UI::tabs_page_removed (Widget*, guint)
671 {
672 	if (_tabs.get_n_pages() < 2) {
673 		editor_visibility_button.drag_source_unset ();
674 		mixer_visibility_button.drag_source_unset ();
675 		prefs_visibility_button.drag_source_unset ();
676 		recorder_visibility_button.drag_source_unset ();
677 	}
678 }
679 
680 void
tabs_switch(GtkNotebookPage *,guint page)681 ARDOUR_UI::tabs_switch (GtkNotebookPage*, guint page)
682 {
683 	if (editor && (page == (guint) _tabs.page_num (editor->contents()))) {
684 
685 		editor_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
686 
687 		if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
688 			mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
689 		}
690 
691 		if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
692 			prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
693 		}
694 
695 		if (recorder && (recorder->tabbed() || recorder->tabbed_by_default())) {
696 			recorder_visibility_button.set_active_state (Gtkmm2ext::Off);
697 		}
698 
699 	} else if (mixer && (page == (guint) _tabs.page_num (mixer->contents()))) {
700 
701 		if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
702 			editor_visibility_button.set_active_state (Gtkmm2ext::Off);
703 		}
704 
705 		mixer_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
706 
707 		if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
708 			prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
709 		}
710 
711 		if (recorder && (recorder->tabbed() || recorder->tabbed_by_default())) {
712 			recorder_visibility_button.set_active_state (Gtkmm2ext::Off);
713 		}
714 
715 	} else if (page == (guint) _tabs.page_num (rc_option_editor->contents())) {
716 
717 		if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
718 			editor_visibility_button.set_active_state (Gtkmm2ext::Off);
719 		}
720 
721 		if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
722 			mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
723 		}
724 
725 		prefs_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
726 
727 		if (recorder && (recorder->tabbed() || recorder->tabbed_by_default())) {
728 			recorder_visibility_button.set_active_state (Gtkmm2ext::Off);
729 		}
730 
731 	} else if (page == (guint) _tabs.page_num (recorder->contents())) {
732 
733 		if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
734 			editor_visibility_button.set_active_state (Gtkmm2ext::Off);
735 		}
736 
737 		if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
738 			mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
739 		}
740 
741 		if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
742 			prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
743 		}
744 
745 		recorder_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
746 
747 	}
748 }
749 
750 void
tabbable_state_change(Tabbable & t)751 ARDOUR_UI::tabbable_state_change (Tabbable& t)
752 {
753 	std::vector<std::string> insensitive_action_names;
754 	std::vector<std::string> sensitive_action_names;
755 	std::vector<std::string> active_action_names;
756 	std::vector<std::string> inactive_action_names;
757 	Glib::RefPtr<Action> action;
758 
759 	enum ViewState {
760 		Tabbed,
761 		Windowed,
762 		Hidden
763 	};
764 	ViewState vs;
765 
766 	if (t.tabbed()) {
767 
768 		insensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
769 		sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
770 		sensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
771 		sensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
772 
773 		vs = Tabbed;
774 
775 	} else if (t.tabbed_by_default ()) {
776 
777 		insensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
778 		insensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
779 		sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
780 		sensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
781 
782 		vs = Hidden;
783 
784 	} else if (t.window_visible()) {
785 
786 		insensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
787 		sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
788 		sensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
789 		sensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
790 
791 		active_action_names.push_back (string_compose ("show-%1", t.menu_name()));
792 		inactive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
793 
794 		vs = Windowed;
795 
796 	} else {
797 
798 		/* not currently visible. allow user to retab it or just make
799 		 * it visible.
800 		 */
801 
802 		insensitive_action_names.push_back (string_compose ("detach-%1", t.menu_name()));
803 		insensitive_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
804 		sensitive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
805 		sensitive_action_names.push_back (string_compose ("attach-%1", t.menu_name()));
806 
807 		active_action_names.push_back (string_compose ("hide-%1", t.menu_name()));
808 		inactive_action_names.push_back (string_compose ("show-%1", t.menu_name()));
809 
810 		vs = Hidden;
811 	}
812 
813 	for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
814 		action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
815 		if (action) {
816 			action->set_sensitive (false);
817 		}
818 	}
819 
820 	for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
821 		action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
822 		if (action) {
823 			action->set_sensitive (true);
824 		}
825 	}
826 
827 	ArdourButton* vis_button = 0;
828 
829 	if (&t == editor) {
830 		vis_button = &editor_visibility_button;
831 	} else if (&t == mixer) {
832 		vis_button = &mixer_visibility_button;
833 	} else if (&t == rc_option_editor) {
834 		vis_button = &prefs_visibility_button;
835 	} else if (&t == recorder) {
836 		vis_button = &recorder_visibility_button;
837 	}
838 
839 	if (!vis_button) {
840 		assert (0);
841 		return;
842 	}
843 
844 	/* First update button states for (other) tabbed windows.
845 	 * (Gtkmm2ext::Off or Gtkmm2ext::ImplicitActive)
846 	 */
847 	tabs_switch (NULL, _tabs.get_current_page ());
848 
849 	switch (vs) {
850 		case Tabbed:
851 			/* nothing to do */
852 			break;
853 		case Windowed:
854 			vis_button->set_active_state (Gtkmm2ext::ExplicitActive);
855 			break;
856 		case Hidden:
857 			vis_button->set_active_state (Gtkmm2ext::Off);
858 			break;
859 	}
860 }
861 
862 void
toggle_meterbridge()863 ARDOUR_UI::toggle_meterbridge ()
864 {
865 	assert (editor && mixer && meterbridge);
866 
867 	bool show = false;
868 	bool obscuring = false;
869 
870 	if (meterbridge->not_visible ()) {
871 		show = true;
872 	} else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
873 	           (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
874 		obscuring = true;
875 	}
876 
877 	if (obscuring && ((editor->own_window() && editor->own_window()->property_has_toplevel_focus()) ||
878 	                  (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
879 		show = true;
880 	}
881 
882 	if (show) {
883 		meterbridge->show_window ();
884 		meterbridge->present ();
885 		meterbridge->raise ();
886 	} else {
887 		meterbridge->hide_window (NULL);
888 	}
889 }
890 
891 void
toggle_luawindow()892 ARDOUR_UI::toggle_luawindow ()
893 {
894 	assert (editor && luawindow);
895 
896 	bool show = false;
897 
898 	if (luawindow->not_visible ()) {
899 		show = true;
900 	}
901 	// TODO check overlap
902 
903 	if (show) {
904 		luawindow->show_window ();
905 		luawindow->present ();
906 		luawindow->raise ();
907 	} else {
908 		luawindow->hide_window (NULL);
909 	}
910 }
911 
912 
913 void
new_midi_tracer_window()914 ARDOUR_UI::new_midi_tracer_window ()
915 {
916 	RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
917 	if (!act) {
918 		return;
919 	}
920 
921 	std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
922 	while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
923 		++i;
924 	}
925 
926 	if (i == _midi_tracer_windows.end()) {
927 		/* all our MIDITracer windows are visible; make a new one */
928 		MidiTracer* t = new MidiTracer ();
929 		t->show_all ();
930 		_midi_tracer_windows.push_back (t);
931 	} else {
932 		/* re-use the hidden one */
933 		(*i)->show_all ();
934 	}
935 }
936 
937 KeyEditor*
create_key_editor()938 ARDOUR_UI::create_key_editor ()
939 {
940 	KeyEditor* kedit = new KeyEditor;
941 
942 	for (std::list<Bindings*>::iterator b = Bindings::bindings.begin(); b != Bindings::bindings.end(); ++b) {
943 		kedit->add_tab ((*b)->name(), **b);
944 	}
945 
946 	return kedit;
947 }
948 
949 BundleManager*
create_bundle_manager()950 ARDOUR_UI::create_bundle_manager ()
951 {
952 	return new BundleManager (_session);
953 }
954 
955 AddVideoDialog*
create_add_video_dialog()956 ARDOUR_UI::create_add_video_dialog ()
957 {
958 	return new AddVideoDialog (_session);
959 }
960 
961 SessionOptionEditor*
create_session_option_editor()962 ARDOUR_UI::create_session_option_editor ()
963 {
964 	return new SessionOptionEditor (_session);
965 }
966 
967 BigClockWindow*
create_big_clock_window()968 ARDOUR_UI::create_big_clock_window ()
969 {
970 	return new BigClockWindow (*big_clock);
971 }
972 
973 BigTransportWindow*
create_big_transport_window()974 ARDOUR_UI::create_big_transport_window ()
975 {
976 	BigTransportWindow* btw = new BigTransportWindow ();
977 	btw->set_session (_session);
978 	return btw;
979 }
980 
981 VirtualKeyboardWindow*
create_virtual_keyboard_window()982 ARDOUR_UI::create_virtual_keyboard_window ()
983 {
984 	VirtualKeyboardWindow* vkbd = new VirtualKeyboardWindow ();
985 	vkbd->set_session (_session);
986 	return vkbd;
987 }
988 
989 void
handle_locations_change(Location *)990 ARDOUR_UI::handle_locations_change (Location *)
991 {
992 	if (_session) {
993 		if (_session->locations()->num_range_markers()) {
994 			ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
995 		} else {
996 			ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
997 		}
998 	}
999 }
1000 
1001 bool
tabbed_window_state_event_handler(GdkEventWindowState * ev,void * object)1002 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
1003 {
1004 	if (object == editor) {
1005 
1006 		if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
1007 		    (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
1008 			if (big_clock_window) {
1009 				big_clock_window->set_transient_for (*editor->own_window());
1010 			}
1011 			if (big_transport_window) {
1012 				big_transport_window->set_transient_for (*editor->own_window());
1013 			}
1014 			if (virtual_keyboard_window) {
1015 				virtual_keyboard_window->set_transient_for (*editor->own_window());
1016 			}
1017 		}
1018 
1019 	} else if (object == mixer) {
1020 
1021 		if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
1022 		    (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
1023 			if (big_clock_window) {
1024 				big_clock_window->set_transient_for (*mixer->own_window());
1025 			}
1026 			if (big_transport_window) {
1027 				big_transport_window->set_transient_for (*mixer->own_window());
1028 			}
1029 			if (virtual_keyboard_window) {
1030 				virtual_keyboard_window->set_transient_for (*mixer->own_window());
1031 			}
1032 		}
1033 	}
1034 
1035 	return false;
1036 }
1037 
1038 bool
editor_meter_peak_button_release(GdkEventButton * ev)1039 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
1040 {
1041 	if (ev->button == 1) {
1042 		ArdourMeter::ResetAllPeakDisplays ();
1043 	}
1044 	return false;
1045 }
1046 
1047 void
toggle_mixer_space()1048 ARDOUR_UI::toggle_mixer_space()
1049 {
1050 	Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Common", "ToggleMaximalMixer");
1051 	if (tact->get_active()) {
1052 		mixer->maximise_mixer_space ();
1053 	} else {
1054 		mixer->restore_mixer_space ();
1055 	}
1056 }
1057 
1058 bool
timecode_button_press(GdkEventButton * ev)1059 ARDOUR_UI::timecode_button_press (GdkEventButton* ev)
1060 {
1061 	if (ev->button != 1 || ev->type != GDK_2BUTTON_PRESS) {
1062 		return false;
1063 	}
1064 	if (_session) {
1065 		session_option_editor->show ();
1066 		session_option_editor->set_current_page (_("Timecode"));
1067 	}
1068 	return true;
1069 }
1070 
1071 bool
format_button_press(GdkEventButton * ev)1072 ARDOUR_UI::format_button_press (GdkEventButton* ev)
1073 {
1074 	if (ev->button != 1 || ev->type != GDK_2BUTTON_PRESS) {
1075 		return false;
1076 	}
1077 	if (_session) {
1078 		session_option_editor->show ();
1079 		session_option_editor->set_current_page (_("Media"));
1080 	}
1081 	return true;
1082 }
1083