Fix thinkos in cubasish theme
[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_name ("lua action button");
312                 action_script_call_btn[i].set_text (string_compose ("%1%2", std::hex, i+1));
313                 action_script_call_btn[i].set_related_action (act);
314                 action_script_call_btn[i].signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::bind_lua_action_script), i), false);
315                 if (act->get_sensitive ()) {
316                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() & ~Gtkmm2ext::Insensitive));
317                 } else {
318                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() | Gtkmm2ext::Insensitive));
319                 }
320                 action_script_call_btn[i].set_sizing_text ("88");
321                 action_script_call_btn[i].set_no_show_all ();
322         }
323
324         setup_transport();
325         build_menu_bar ();
326         setup_tooltips ();
327
328         _main_window.signal_delete_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::main_window_delete_event));
329
330         /* pack the main vpacker into the main window and show everything
331          */
332
333         _main_window.add (main_vpacker);
334         transport_frame.show_all ();
335
336         const XMLNode* mnode = main_window_settings ();
337
338         if (mnode) {
339                 XMLProperty const * prop;
340                 gint x = -1;
341                 gint y = -1;
342                 gint w = -1;
343                 gint h = -1;
344
345                 if ((prop = mnode->property (X_("x"))) != 0) {
346                         x = atoi (prop->value());
347                 }
348
349                 if ((prop = mnode->property (X_("y"))) != 0) {
350                         y = atoi (prop->value());
351                 }
352
353                 if ((prop = mnode->property (X_("w"))) != 0) {
354                         w = atoi (prop->value());
355                 }
356
357                 if ((prop = mnode->property (X_("h"))) != 0) {
358                         h = atoi (prop->value());
359                 }
360
361                 if (x >= 0 && y >= 0 && w >= 0 && h >= 0) {
362                         _main_window.set_position (Gtk::WIN_POS_NONE);
363                 }
364
365                 if (x >= 0 && y >= 0) {
366                         _main_window.move (x, y);
367                 }
368
369                 if (w > 0 && h > 0) {
370                         _main_window.set_default_size (w, h);
371                 }
372
373                 std::string current_tab;
374
375                 if ((prop = mnode->property (X_("current-tab"))) != 0) {
376                         current_tab = prop->value();
377                 } else {
378                         current_tab = "editor";
379                 }
380                 if (mixer && current_tab == "mixer") {
381                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
382                 } else if (rc_option_editor && current_tab == "preferences") {
383                         _tabs.set_current_page (_tabs.page_num (rc_option_editor->contents()));
384                 } else if (editor) {
385                         _tabs.set_current_page (_tabs.page_num (editor->contents()));
386                 }
387         }
388
389         setup_toplevel_window (_main_window, "", this);
390         _main_window.show_all ();
391
392         _tabs.set_show_tabs (false);
393
394         /* It would be nice if Gtkmm had wrapped this rather than just
395          * deprecating the old set_window_creation_hook() method, but oh well...
396          */
397         g_signal_connect (_tabs.gobj(), "create-window", (GCallback) ::tab_window_root_drop, this);
398
399 #ifdef GDK_WINDOWING_X11
400         /* allow externalUIs to be transient, on top of the main window */
401         LV2Plugin::set_main_window_id (GDK_DRAWABLE_XID(_main_window.get_window()->gobj()));
402 #endif
403
404         return 0;
405 }
406
407 bool
408 ARDOUR_UI::bind_lua_action_script (GdkEventButton*ev, int i)
409 {
410         if (!_session) {
411                 return false;
412         }
413         LuaInstance *li = LuaInstance::instance();
414         std::string name;
415         if (ev->button != 3 && !(ev->button == 1 && !li->lua_action_name (i, name))) {
416                 return false;
417         }
418         if (Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::TertiaryModifier)) {
419                 li->remove_lua_action (i);
420         } else {
421                 li->interactive_add (LuaScriptInfo::EditorAction, i);
422         }
423         return true;
424 }
425
426 void
427 ARDOUR_UI::update_action_script_btn (int i, const std::string& n)
428 {
429         if (i < 0 || i >= MAX_LUA_ACTION_BUTTONS) {
430                 return;
431         }
432         if (LuaInstance::instance()->lua_action_has_icon (i)) {
433                 uintptr_t ii = i;
434                 action_script_call_btn[i].set_icon (&LuaInstance::render_action_icon, (void*)ii);
435         } else {
436                 action_script_call_btn[i].set_icon (0, 0);
437         }
438
439         std::string const a = string_compose (X_("script-action-%1"), i + 1);
440         Glib::RefPtr<Action> act = ActionManager::get_action(X_("LuaAction"), a.c_str());
441         assert (act);
442         if (n.empty ()) {
443                 act->set_label (string_compose (_("Unset #%1"), i + 1));
444                 act->set_tooltip (_("No action bound\nRight-click to assign"));
445                 act->set_sensitive (false);
446         } else {
447                 act->set_label (n);
448                 act->set_tooltip (string_compose (_("%1\n\nClick to run\nRight-click to re-assign\nShift+right-click to unassign"), n));
449                 act->set_sensitive (true);
450         }
451         KeyEditor::UpdateBindings ();
452 }