ardour
ardour_ui_dialogs.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000 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 /* This file contains any ARDOUR_UI methods that require knowledge of
21  the various dialog boxes, and exists so that no compilation dependency
22  exists between the main ARDOUR_UI modules and their respective classes.
23  This is to cut down on the compile times. It also helps with my sanity.
24 */
25 
26 #include "ardour/audioengine.h"
29 #include "ardour/profile.h"
30 #include "ardour/session.h"
31 #include "control_protocol/control_protocol.h"
32 
33 #include "actions.h"
34 #include "add_route_dialog.h"
35 #include "add_video_dialog.h"
36 #include "ardour_ui.h"
37 #include "big_clock_window.h"
38 #include "bundle_manager.h"
39 #include "global_port_matrix.h"
40 #include "gui_object.h"
41 #include "gui_thread.h"
42 #include "keyeditor.h"
43 #include "location_ui.h"
44 #include "main_clock.h"
45 #include "meter_patterns.h"
46 #include "midi_tracer.h"
47 #include "mixer_ui.h"
48 #include "public_editor.h"
49 #include "rc_option_editor.h"
50 #include "route_params_ui.h"
51 #include "shuttle_control.h"
52 #include "session_option_editor.h"
53 #include "speaker_dialog.h"
54 #include "splash.h"
55 #include "sfdb_ui.h"
56 #include "theme_manager.h"
57 #include "time_info_box.h"
58 #include "timers.h"
59 
60 #include <gtkmm2ext/keyboard.h>
61 
62 #include "i18n.h"
63 
64 using namespace ARDOUR;
65 using namespace PBD;
66 using namespace Glib;
67 using namespace Gtk;
68 using namespace Gtkmm2ext;
69 
70 void
72 {
74 
75  if (!_session) {
77  /* Session option editor cannot exist across change-of-session */
78  session_option_editor.drop_window ();
79  /* Ditto for AddVideoDialog */
80  add_video_dialog.drop_window ();
81  return;
82  }
83 
84  const XMLNode* node = _session->extra_xml (X_("UI"));
85 
86  if (node) {
87  const XMLNodeList& children = node->children();
88  for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
89  if ((*i)->name() == GUIObjectState::xml_node_name) {
90  gui_object_state->load (**i);
91  break;
92  }
93  }
94  }
95 
97 
99 
100  if (shuttle_box) {
101  shuttle_box->set_session (s);
102  }
103 
104  primary_clock->set_session (s);
105  secondary_clock->set_session (s);
106  big_clock->set_session (s);
107  time_info_box->set_session (s);
108  video_timeline->set_session (s);
109 
110  /* sensitize menu bar options that are now valid */
111 
114 
115  if (_session->locations()->num_range_markers()) {
117  } else {
119  }
120 
121  if (!_session->monitor_out()) {
122  Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
123  if (act) {
124  act->set_sensitive (false);
125  }
126  }
127 
128  /* allow wastebasket flush again */
129 
130  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
131  if (act) {
132  act->set_sensitive (true);
133  }
134 
135  /* there are never any selections on startup */
136 
142 
143  rec_button.set_sensitive (true);
144 
145  solo_alert_button.set_active (_session->soloing());
146 
147  setup_session_options ();
148 
149  blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
150 
151  _session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
152  _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
153  _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
154  _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
155  _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
156 
157  _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
158  _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
159  _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
160  _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
161  _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
162  _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
163 
164  /* Clocks are on by default after we are connected to a session, so show that here.
165  */
166 
167  connect_dependents_to_session (s);
168 
169  /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
170  restore their modes or are explicitly set, we will cause the "new" mode to be saved
171  back to the session XML ("Extra") state.
172  */
173 
174  AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
175 
176  Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
177 
178  start_clocking ();
179 
180  map_transport_state ();
181 
182  second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
183  point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
184  point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
185  set_fps_timeout_connection();
186 
187  update_format ();
188 
189  if (meter_box.get_parent()) {
190  transport_tearoff_hbox.remove (meter_box);
191  transport_tearoff_hbox.remove (editor_meter_peak_display);
192  }
193 
194  if (editor_meter) {
195  meter_box.remove(*editor_meter);
196  delete editor_meter;
197  editor_meter = 0;
198  editor_meter_peak_display.hide();
199  }
200 
201  if (meter_box.get_parent()) {
202  transport_tearoff_hbox.remove (meter_box);
203  transport_tearoff_hbox.remove (editor_meter_peak_display);
204  }
205 
206  if (_session &&
207  _session->master_out() &&
208  _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
209 
210  if (!ARDOUR::Profile->get_trx()) {
211  editor_meter = new LevelMeterHBox(_session);
212  editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
213  editor_meter->clear_meters();
214  editor_meter->set_type (_session->master_out()->meter_type());
215  editor_meter->setup_meters (30, 12, 6);
216  editor_meter->show();
217  meter_box.pack_start(*editor_meter);
218  }
219 
220  ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
223 
224  editor_meter_peak_display.set_name ("meterbridge peakindicator");
225  editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
226  editor_meter_peak_display.set_size_request (std::max(9.f, rintf(8.f * ui_scale)), -1);
227  editor_meter_peak_display.set_corner_radius (3.0);
228 
229  editor_meter_max_peak = -INFINITY;
230  editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
231 
232  if (ARDOUR_UI::config()->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
233  transport_tearoff_hbox.pack_start (meter_box, false, false);
234  transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
235  meter_box.show();
236  editor_meter_peak_display.show();
237  }
238  }
239 }
240 
241 int
242 ARDOUR_UI::unload_session (bool hide_stuff)
243 {
244  if (_session) {
246  }
247 
248  if (_session && _session->dirty()) {
249  std::vector<std::string> actions;
250  actions.push_back (_("Don't close"));
251  actions.push_back (_("Just close"));
252  actions.push_back (_("Save and close"));
253  switch (ask_about_saving_session (actions)) {
254  case -1:
255  // cancel
256  return 1;
257 
258  case 1:
259  _session->save_state ("");
260  break;
261  }
262  }
263 
264  {
265  // tear down session specific CPI (owned by rc_config_editor which can remain)
267  for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
268  if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
269  (*i)->protocol->tear_down_gui ();
270  }
271  }
272  }
273 
274  if (hide_stuff) {
275  editor->hide ();
276  mixer->hide ();
277  meterbridge->hide ();
278  audio_port_matrix->hide();
279  midi_port_matrix->hide();
280  route_params->hide();
281  }
282 
283  second_connection.disconnect ();
284  point_one_second_connection.disconnect ();
285  point_zero_something_second_connection.disconnect();
286  fps_connection.disconnect();
287 
288  if (editor_meter) {
289  meter_box.remove(*editor_meter);
290  delete editor_meter;
291  editor_meter = 0;
292  editor_meter_peak_display.hide();
293  }
294 
296 
297  rec_button.set_sensitive (false);
298 
300 
301  if (ARDOUR_UI::instance()->video_timeline) {
303  }
304 
305  stop_clocking ();
306 
307  /* drop everything attached to the blink signal */
308 
309  blink_connection.disconnect ();
310 
311  delete _session;
312  _session = 0;
313 
314  session_loaded = false;
315 
316  update_buffer_load ();
317 
318  return 0;
319 }
320 
321 static bool
322 _hide_splash (gpointer arg)
323 {
324  ((ARDOUR_UI*)arg)->hide_splash();
325  return false;
326 }
327 
328 void
330 {
331  if (splash && splash->is_visible()) {
332  // in 2 seconds, hide the splash screen
333  Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
334  }
335 
336  editor->show_window ();
337  editor->present ();
338  /* mixer should now be on top */
339  if (ARDOUR_UI::config()->get_transients_follow_front()) {
341  }
342  _mixer_on_top = false;
343 }
344 
345 void
347 {
348  Glib::RefPtr<Gdk::Window> win;
349  Glib::RefPtr<Gdk::Screen> screen;
350 
351  if (editor) {
352  win = editor->get_window ();
353  }
354 
355  if (win) {
356  screen = win->get_screen();
357  } else {
358  screen = Gdk::Screen::get_default();
359  }
360 
361  if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
362  Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
363  msg.run ();
364  return;
365  }
366 
367  mixer->show_window ();
368  mixer->present ();
369  /* mixer should now be on top */
370  if (ARDOUR_UI::config()->get_transients_follow_front()) {
372  }
373  _mixer_on_top = true;
374 }
375 
376 void
378 {
379  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
380  if (!act) {
381  return;
382  }
383 
384  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
385 
386  if (tact->get_active()) {
387  goto_mixer_window ();
388  } else {
389  mixer->hide ();
390  }
391 }
392 
393 void
395 {
396  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
397  if (!act) {
398  return;
399  }
400 
401  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
402 
403  if (tact->get_active()) {
404  meterbridge->show_window ();
405  } else {
406  meterbridge->hide_window (NULL);
407  }
408 }
409 
410 void
412 {
413  bool obscuring = false;
414  /* currently, if windows are on different
415  screens then we do nothing; but in the
416  future we may want to bring the window
417  to the front or something, so I'm leaving this
418  variable for future use
419  */
420  bool same_screen = true;
421 
422  if (editor && mixer) {
423 
424  /* remeber: Screen != Monitor (Screen is a separately rendered
425  * continuous geometry that make include 1 or more monitors.
426  */
427 
428  if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
429  // different screens, so don't do anything
430  same_screen = false;
431  } else {
432  // they are on the same screen, see if they are obscuring each other
433 
434  gint ex, ey, ew, eh;
435  gint mx, my, mw, mh;
436 
437  editor->get_position (ex, ey);
438  editor->get_size (ew, eh);
439 
440  mixer->get_position (mx, my);
441  mixer->get_size (mw, mh);
442 
443  GdkRectangle e;
444  GdkRectangle m;
445  GdkRectangle r;
446 
447  e.x = ex;
448  e.y = ey;
449  e.width = ew;
450  e.height = eh;
451 
452  m.x = mx;
453  m.y = my;
454  m.width = mw;
455  m.height = mh;
456 
457  if (gdk_rectangle_intersect (&e, &m, &r)) {
458  obscuring = true;
459  }
460  }
461  }
462 
463  if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
464  if (obscuring && same_screen) {
465  goto_editor_window();
466  }
467  } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
468  if (obscuring && same_screen) {
469  goto_mixer_window();
470  }
471  } else if (mixer && mixer->not_visible()) {
472  if (obscuring && same_screen) {
473  goto_mixer_window ();
474  }
475  } else if (editor && editor->not_visible()) {
476  if (obscuring && same_screen) {
477  goto_editor_window ();
478  }
479  } else if (obscuring && same_screen) {
480  //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
481  if (_mixer_on_top) {
482  goto_editor_window ();
483  } else {
484  goto_mixer_window ();
485  }
486  }
487 }
488 
489 void
491 {
492  RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
493  if (!act) {
494  return;
495  }
496 
497  std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
498  while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
499  ++i;
500  }
501 
502  if (i == _midi_tracer_windows.end()) {
503  /* all our MIDITracer windows are visible; make a new one */
504  MidiTracer* t = new MidiTracer ();
505  t->show_all ();
506  _midi_tracer_windows.push_back (t);
507  } else {
508  /* re-use the hidden one */
509  (*i)->show_all ();
510  }
511 }
512 
515 {
516  return new BundleManager (_session);
517 }
518 
521 {
522  return new AddVideoDialog (_session);
523 }
524 
527 {
528  return new SessionOptionEditor (_session);
529 }
530 
533 {
534  return new BigClockWindow (*big_clock);
535 }
536 
537 void
539 {
540  if (_session) {
541  if (_session->locations()->num_range_markers()) {
543  } else {
545  }
546  }
547 }
548 
549 bool
550 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
551 {
552  if (window_was_editor) {
553 
554  if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
555  (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
556  if (big_clock_window) {
557  big_clock_window->set_transient_for (*editor);
558  }
559  }
560 
561  } else {
562 
563  if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
564  (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
565  if (big_clock_window) {
566  big_clock_window->set_transient_for (*mixer);
567  }
568  }
569  }
570 
571  return false;
572 }
573 
574 bool
576 {
579  } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
580  if (_session->master_out()) {
581  ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
582  }
583  } else if (_session->master_out()) {
584  ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
585  }
586  return false;
587 }
588 
589 void
591 {
592  Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
593 
594  if (act) {
595  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
596  if (tact->get_active()) {
597  mixer->maximise_mixer_space ();
598  } else {
599  mixer->restore_mixer_space ();
600  }
601  }
602 }
SessionOptionEditor * create_session_option_editor()
void toggle_mixer_window()
void goto_editor_window()
std::vector< Glib::RefPtr< Gtk::Action > > track_selection_sensitive_actions
Definition: actions.cc:53
AddVideoDialog * create_add_video_dialog()
static bool _hide_splash(gpointer arg)
void session_parameter_changed(std::string)
sigc::connection super_rapid_connect(const sigc::slot< void > &slot)
Definition: timers.cc:189
void xrun_handler(framepos_t)
Definition: ardour_ui.cc:4124
int unload_session(bool hide_stuff=false)
void reset_peak_display()
Definition: ardour_ui.cc:4707
void step_edit_status_change(bool)
Definition: ardour_ui.cc:4452
static AutomationWatch & instance()
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
std::vector< Glib::RefPtr< Gtk::Action > > time_selection_sensitive_actions
Definition: actions.cc:55
void set_session(ARDOUR::Session *)
static Manager & instance()
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > get_action(const char *group, const char *name)
Definition: actions.cc:406
tuple f
Definition: signals.py:35
static ControlProtocolManager & instance()
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
std::list< ControlProtocolInfo * > control_protocol_info
std::vector< Glib::RefPtr< Gtk::Action > > line_selection_sensitive_actions
Definition: actions.cc:56
void every_second()
Definition: ardour_ui.cc:1186
std::vector< Glib::RefPtr< Gtk::Action > > range_sensitive_actions
Definition: actions.cc:60
void map_transport_state()
Definition: ardour_ui.cc:2289
void reset_group_peak_display(ARDOUR::RouteGroup *)
Definition: ardour_ui.cc:4716
std::vector< Glib::RefPtr< Gtk::Action > > point_selection_sensitive_actions
Definition: actions.cc:54
sigc::signal< void, ARDOUR::Route * > ResetRoutePeakDisplays
void every_point_one_seconds()
Definition: ardour_ui.cc:1209
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
void goto_mixer_window()
static uint32_t TertiaryModifier
Definition: keyboard.h:57
#define _(Text)
Definition: i18n.h:11
void record_state_changed()
Definition: ardour_ui.cc:4467
LIBGTKMM2EXT_API void set_sensitive(std::vector< Glib::RefPtr< Gtk::Action > > &actions, bool)
void save_session_at_its_request(std::string)
Definition: ardour_ui.cc:700
void new_midi_tracer_window()
#define X_(Text)
Definition: i18n.h:13
static const std::string xml_node_name
Definition: gui_object.h:39
void sync_session_state()
BundleManager * create_bundle_manager()
void soloing_changed(bool)
Definition: ardour_ui2.cc:516
static uint32_t PrimaryModifier
Definition: keyboard.h:55
VideoTimeLine * video_timeline
Definition: ardour_ui.h:236
void auditioning_changed(bool)
Definition: ardour_ui2.cc:531
void set_session(ARDOUR::Session *)
void set_transient_for(Gtk::Window *)
void toggle_meterbridge()
Definition: amp.h:29
#define gui_context()
Definition: gui_thread.h:36
std::vector< Glib::RefPtr< Gtk::Action > > write_sensitive_actions
Definition: actions.cc:50
std::vector< Glib::RefPtr< Gtk::Action > > session_sensitive_actions
Definition: actions.cc:49
sigc::signal< void > ResetAllPeakDisplays
void toggle_editor_mixer()
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
sigc::connection blink_connect(const sigc::slot< void, bool > &slot)
Definition: timers.cc:171
bool editor_meter_peak_button_release(GdkEventButton *)
sigc::connection second_connect(const sigc::slot< void > &slot)
Definition: timers.cc:177
static sigc::signal< void > ModeChanged
Definition: audio_clock.h:96
bool first_idle()
Definition: ardour_ui.cc:4484
void blink_handler(bool)
Definition: ardour_ui.cc:2353
Definition: xml++.h:95
void handle_locations_change(ARDOUR::Location *)
static UIConfiguration * config()
Definition: ardour_ui.h:188
sigc::signal< void, ARDOUR::RouteGroup * > ResetGroupPeakDisplays
Definition: debug.h:30
void set_session(ARDOUR::Session *)
std::vector< Glib::RefPtr< Gtk::Action > > playlist_selection_sensitive_actions
Definition: actions.cc:57
void update_autosave()
Definition: ardour_ui.cc:730
void store_clock_modes()
Definition: ardour_ui.cc:4499
BigClockWindow * create_big_clock_window()
void every_point_zero_something_seconds()
Definition: ardour_ui.cc:1216
virtual void set_session(ARDOUR::Session *)
static bool modifier_state_equals(guint state, ModifierMask)
Definition: keyboard.cc:526
#define MISSING_INVALIDATOR
Definition: event_loop.h:86
sigc::connection rapid_connect(const sigc::slot< void > &slot)
Definition: timers.cc:183
Editing of options which are obtained from and written back to one of the .rc files.
void reset_route_peak_display(ARDOUR::Route *)
Definition: ardour_ui.cc:4725
void toggle_mixer_space()
bool main_window_state_event_handler(GdkEventWindowState *, bool window_was_editor)