Fix MIDI disk-writer flush
[ardour.git] / gtk2_ardour / ardour_ui_dependents.cc
1 /*
2  * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
4  * Copyright (C) 2006-2015 Tim Mayberry <mojofunk@gmail.com>
5  * Copyright (C) 2007-2011 David Robillard <d@drobilla.net>
6  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
7  * Copyright (C) 2013-2018 Robin Gareus <robin@gareus.org>
8  * Copyright (C) 2016-2018 Ben Loftis <ben@harrisonconsoles.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #ifdef WAF_BUILD
26 #include "gtk2ardour-config.h"
27 #endif
28
29 /* this file exists solely to break compilation dependencies that
30    would connect changes to the mixer or editor objects.
31 */
32
33 #include <cstdio>
34
35 #include "pbd/error.h"
36 #include "pbd/i18n.h"
37
38 #include "ardour/session.h"
39 #include "ardour/lv2_plugin.h"
40
41 #include "gtkmm2ext/bindings.h"
42
43 #include "actions.h"
44 #include "ardour_message.h"
45 #include "ardour_ui.h"
46 #include "public_editor.h"
47 #include "meterbridge.h"
48 #include "luainstance.h"
49 #include "luawindow.h"
50 #include "mixer_ui.h"
51 #include "keyboard.h"
52 #include "keyeditor.h"
53 #include "splash.h"
54 #include "rc_option_editor.h"
55 #include "route_params_ui.h"
56 #include "time_info_box.h"
57 #include "step_entry.h"
58 #include "opts.h"
59 #include "utils.h"
60
61 #ifdef GDK_WINDOWING_X11
62 #include <gdk/gdkx.h>
63 #endif
64
65 using namespace Gtk;
66 using namespace PBD;
67
68 namespace ARDOUR {
69         class Session;
70         class Route;
71 }
72
73 using namespace ARDOUR;
74 using namespace Gtkmm2ext;
75
76 void
77 ARDOUR_UI::we_have_dependents ()
78 {
79         install_dependent_actions ();
80
81         /* The monitor section relies on at least 1 action defined by us. Since that
82          * action now exists, give it a chance to use it.
83          */
84         mixer->monitor_section().use_others_actions ();
85
86         /* Create "static" actions that apply to all ProcessorBoxes
87          */
88         ProcessorBox::register_actions ();
89         StepEntry::setup_actions_and_bindings ();
90
91         /* Global, editor, mixer, processor box actions are defined now. Link
92            them with any bindings, so that GTK does not get a chance to define
93            the GTK accel map entries first when we ask the GtkUIManager to
94            create menus/widgets.
95
96            If GTK adds the actions to its accel map before we do, we lose our
97            freedom to use any keys. More precisely, we can use any keys, but
98            ones that GTK considers illegal as accelerators will not show up in
99            menus.
100
101            There are other dynamic actions that can be created by a monitor
102            section, by step entry dialogs. These need to be handled
103            separately. They don't tend to use GTK-illegal bindings and more
104            importantly they don't have menus showing the bindings, so it is
105            less of an issue.
106         */
107
108         Gtkmm2ext::Bindings::associate_all ();
109
110         editor->setup_tooltips ();
111         editor->UpdateAllTransportClocks.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_transport_clocks));
112
113         /* catch up on tabbable state, in the right order to leave the editor
114          * selected by default
115          */
116
117         tabbable_state_change (*rc_option_editor);
118         tabbable_state_change (*mixer);
119         tabbable_state_change (*editor);
120
121         /* all actions are defined */
122
123         ActionManager::load_menus (ARDOUR_COMMAND_LINE::menus_file);
124
125         /* catch up on parameters */
126
127         boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
128         Config->map_parameters (pc);
129
130         UIConfiguration::instance().reset_dpi ();
131 }
132
133 void
134 ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
135 {
136         DisplaySuspender ds;
137         BootMessage (_("Setup Editor"));
138         editor->set_session (s);
139         BootMessage (_("Setup Mixer"));
140         mixer->set_session (s);
141         meterbridge->set_session (s);
142         luawindow->set_session (s);
143
144         /* its safe to do this now */
145
146         BootMessage (_("Reload Session History"));
147         s->restore_history ("");
148 }
149
150 /** The main editor window has been closed */
151 gint
152 ARDOUR_UI::exit_on_main_window_close (GdkEventAny * /*ev*/)
153 {
154 #ifdef __APPLE__
155         /* just hide the window, and return - the top menu stays up */
156         editor->hide ();
157         return TRUE;
158 #else
159         /* time to get out of here */
160         finish();
161         return TRUE;
162 #endif
163 }
164
165 GtkNotebook*
166 ARDOUR_UI::tab_window_root_drop (GtkNotebook* src,
167                                  GtkWidget* w,
168                                  gint x,
169                                  gint y,
170                                  gpointer)
171 {
172         using namespace std;
173         Gtk::Notebook* nb = 0;
174         Gtk::Window* win = 0;
175         ArdourWidgets::Tabbable* tabbable = 0;
176
177
178         if (w == GTK_WIDGET(editor->contents().gobj())) {
179                 tabbable = editor;
180         } else if (w == GTK_WIDGET(mixer->contents().gobj())) {
181                 tabbable = mixer;
182         } else if (w == GTK_WIDGET(rc_option_editor->contents().gobj())) {
183                 tabbable = rc_option_editor;
184         } else {
185                 return 0;
186         }
187
188         nb = tabbable->tab_root_drop ();
189         win = tabbable->own_window ();
190
191         if (nb) {
192                 win->move (x, y);
193                 win->show_all ();
194                 win->present ();
195                 return nb->gobj();
196         }
197
198         return 0; /* what was that? */
199 }
200
201 bool
202 ARDOUR_UI::idle_ask_about_quit ()
203 {
204         if (_session && _session->dirty()) {
205                 finish ();
206         } else {
207                 /* no session or session not dirty, but still ask anyway */
208
209                 ArdourMessageDialog msg (string_compose (_("Quit %1?"), PROGRAM_NAME),
210                                          false, /* no markup */
211                                          Gtk::MESSAGE_INFO,
212                                          Gtk::BUTTONS_YES_NO,
213                                          true); /* modal */
214                 msg.set_default_response (Gtk::RESPONSE_YES);
215
216                 if (msg.run() == Gtk::RESPONSE_YES) {
217                         finish ();
218                 }
219         }
220
221         /* not reached but keep the compiler happy */
222
223         return false;
224 }
225
226 bool
227 ARDOUR_UI::main_window_delete_event (GdkEventAny* ev)
228 {
229         /* quit the application as soon as we go idle. If we call this here,
230          * the window manager/desktop can think we're taking too longer to
231          * handle the "delete" event
232          */
233
234         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_ask_about_quit));
235
236         return true;
237 }
238
239 static GtkNotebook*
240 tab_window_root_drop (GtkNotebook* src,
241                       GtkWidget* w,
242                       gint x,
243                       gint y,
244                       gpointer user_data)
245 {
246         return ARDOUR_UI::instance()->tab_window_root_drop (src, w, x, y, user_data);
247 }
248
249 int
250 ARDOUR_UI::setup_windows ()
251 {
252         _tabs.set_show_border(false);
253         _tabs.signal_switch_page().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_switch));
254         _tabs.signal_page_added().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_added));
255         _tabs.signal_page_removed().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_removed));
256
257         rc_option_editor = new RCOptionEditor;
258         rc_option_editor->StateChange.connect (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_state_change));
259
260         if (create_editor ()) {
261                 error << _("UI: cannot setup editor") << endmsg;
262                 return -1;
263         }
264
265         if (create_mixer ()) {
266                 error << _("UI: cannot setup mixer") << endmsg;
267                 return -1;
268         }
269
270         if (create_meterbridge ()) {
271                 error << _("UI: cannot setup meterbridge") << endmsg;
272                 return -1;
273         }
274
275         if (create_luawindow ()) {
276                 error << _("UI: cannot setup luawindow") << endmsg;
277                 return -1;
278         }
279
280         time_info_box = new TimeInfoBox ("ToolbarTimeInfo", false);
281         /* all other dialogs are created conditionally */
282
283         we_have_dependents ();
284
285         /* order of addition affects order seen in initial window display */
286
287         rc_option_editor->add_to_notebook (_tabs, _("Preferences"));
288         mixer->add_to_notebook (_tabs, _("Mixer"));
289         editor->add_to_notebook (_tabs, _("Editor"));
290
291         top_packer.pack_start (menu_bar_base, false, false);
292
293         main_vpacker.pack_start (top_packer, false, false);
294
295         ArdourWidgets::ArdourDropShadow *spacer = manage (new (ArdourWidgets::ArdourDropShadow));
296         spacer->set_size_request( -1, 4 );
297         spacer->show();
298
299         /* now add the transport sample to the top of main window */
300
301         main_vpacker.pack_start ( *spacer, false, false);
302         main_vpacker.pack_start (transport_frame, false, false);
303         main_vpacker.pack_start (_tabs, true, true);
304
305         LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_action_script_btn));
306
307         for (int i = 0; i < MAX_LUA_ACTION_BUTTONS; ++i) {
308                 std::string const a = string_compose (X_("script-action-%1"), i + 1);
309                 Glib::RefPtr<Action> act = ActionManager::get_action(X_("LuaAction"), a.c_str());
310                 assert (act);
311                 action_script_call_btn[i].set_text (string_compose ("%1%2", std::hex, i+1));
312                 action_script_call_btn[i].set_related_action (act);
313                 action_script_call_btn[i].signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::bind_lua_action_script), i), false);
314                 if (act->get_sensitive ()) {
315                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() & ~Gtkmm2ext::Insensitive));
316                 } else {
317                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() | Gtkmm2ext::Insensitive));
318                 }
319                 action_script_call_btn[i].set_sizing_text ("88");
320                 action_script_call_btn[i].set_no_show_all ();
321         }
322
323         setup_transport();
324         build_menu_bar ();
325         setup_tooltips ();
326
327         _main_window.signal_delete_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::main_window_delete_event));
328
329         /* pack the main vpacker into the main window and show everything
330          */
331
332         _main_window.add (main_vpacker);
333         transport_frame.show_all ();
334
335         const XMLNode* mnode = main_window_settings ();
336
337         if (mnode) {
338                 XMLProperty const * prop;
339                 gint x = -1;
340                 gint y = -1;
341                 gint w = -1;
342                 gint h = -1;
343
344                 if ((prop = mnode->property (X_("x"))) != 0) {
345                         x = atoi (prop->value());
346                 }
347
348                 if ((prop = mnode->property (X_("y"))) != 0) {
349                         y = atoi (prop->value());
350                 }
351
352                 if ((prop = mnode->property (X_("w"))) != 0) {
353                         w = atoi (prop->value());
354                 }
355
356                 if ((prop = mnode->property (X_("h"))) != 0) {
357                         h = atoi (prop->value());
358                 }
359
360                 if (x >= 0 && y >= 0 && w >= 0 && h >= 0) {
361                         _main_window.set_position (Gtk::WIN_POS_NONE);
362                 }
363
364                 if (x >= 0 && y >= 0) {
365                         _main_window.move (x, y);
366                 }
367
368                 if (w > 0 && h > 0) {
369                         _main_window.set_default_size (w, h);
370                 }
371
372                 std::string current_tab;
373
374                 if ((prop = mnode->property (X_("current-tab"))) != 0) {
375                         current_tab = prop->value();
376                 } else {
377                         current_tab = "editor";
378                 }
379                 if (mixer && current_tab == "mixer") {
380                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
381                 } else if (rc_option_editor && current_tab == "preferences") {
382                         _tabs.set_current_page (_tabs.page_num (rc_option_editor->contents()));
383                 } else if (editor) {
384                         _tabs.set_current_page (_tabs.page_num (editor->contents()));
385                 }
386         }
387
388         setup_toplevel_window (_main_window, "", this);
389         _main_window.show_all ();
390
391         _tabs.set_show_tabs (false);
392
393         /* It would be nice if Gtkmm had wrapped this rather than just
394          * deprecating the old set_window_creation_hook() method, but oh well...
395          */
396         g_signal_connect (_tabs.gobj(), "create-window", (GCallback) ::tab_window_root_drop, this);
397
398 #ifdef GDK_WINDOWING_X11
399         /* allow externalUIs to be transient, on top of the main window */
400         LV2Plugin::set_main_window_id (GDK_DRAWABLE_XID(_main_window.get_window()->gobj()));
401 #endif
402
403         return 0;
404 }
405
406 bool
407 ARDOUR_UI::bind_lua_action_script (GdkEventButton*ev, int i)
408 {
409         if (!_session) {
410                 return false;
411         }
412         LuaInstance *li = LuaInstance::instance();
413         std::string name;
414         if (ev->button != 3 && !(ev->button == 1 && !li->lua_action_name (i, name))) {
415                 return false;
416         }
417         if (Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::TertiaryModifier)) {
418                 li->remove_lua_action (i);
419         } else {
420                 li->interactive_add (LuaScriptInfo::EditorAction, i);
421         }
422         return true;
423 }
424
425 void
426 ARDOUR_UI::update_action_script_btn (int i, const std::string& n)
427 {
428         if (i < 0 || i >= MAX_LUA_ACTION_BUTTONS) {
429                 return;
430         }
431         if (LuaInstance::instance()->lua_action_has_icon (i)) {
432                 uintptr_t ii = i;
433                 action_script_call_btn[i].set_icon (&LuaInstance::render_action_icon, (void*)ii);
434         } else {
435                 action_script_call_btn[i].set_icon (0, 0);
436         }
437
438         std::string const a = string_compose (X_("script-action-%1"), i + 1);
439         Glib::RefPtr<Action> act = ActionManager::get_action(X_("LuaAction"), a.c_str());
440         assert (act);
441         if (n.empty ()) {
442                 act->set_label (string_compose (_("Unset #%1"), i + 1));
443                 act->set_tooltip (_("No action bound\nRight-click to assign"));
444                 act->set_sensitive (false);
445         } else {
446                 act->set_label (n);
447                 act->set_tooltip (string_compose (_("%1\n\nClick to run\nRight-click to re-assign\nShift+right-click to unassign"), n));
448                 act->set_sensitive (true);
449         }
450         KeyEditor::UpdateBindings ();
451 }