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