3578f6f0d54a9a7e63b5b37878febec905014c40
[ardour.git] / gtk2_ardour / ardour_ui_dependents.cc
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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 /* this file exists solely to break compilation dependencies that
25    would connect changes to the mixer or editor objects.
26 */
27
28 #include <cstdio>
29
30 #include "pbd/error.h"
31
32 #include "ardour/session.h"
33
34 #include "gtkmm2ext/bindings.h"
35
36 #include "actions.h"
37 #include "ardour_ui.h"
38 #include "public_editor.h"
39 #include "meterbridge.h"
40 #include "luainstance.h"
41 #include "luawindow.h"
42 #include "mixer_ui.h"
43 #include "keyboard.h"
44 #include "keyeditor.h"
45 #include "splash.h"
46 #include "rc_option_editor.h"
47 #include "route_params_ui.h"
48 #include "time_info_box.h"
49 #include "opts.h"
50 #include "utils.h"
51
52 #include "pbd/i18n.h"
53
54 using namespace Gtk;
55 using namespace PBD;
56
57 namespace ARDOUR {
58         class Session;
59         class Route;
60 }
61
62 using namespace ARDOUR;
63 using namespace Gtkmm2ext;
64
65 void
66 ARDOUR_UI::we_have_dependents ()
67 {
68         install_actions ();
69
70         /* other windows and related key-event-handling contexts have already
71          * called Bindings::get_bindings() to setup their list of keybindings.
72          * Do that here for the global bindings.
73          */
74
75         if ((global_bindings = Bindings::get_bindings (X_("Global"))) == 0) {
76                 error << _("Global keybindings are missing") << endmsg;
77         }
78
79         ProcessorBox::register_actions ();
80
81         /* Global, editor, mixer, processor box actions are defined now. Link
82            them with any bindings, so that GTK does not get a chance to define
83            the GTK accel map entries first when we ask the GtkUIManager to
84            create menus/widgets.
85
86            If GTK adds the actions to its accel map before we do, we lose our
87            freedom to use any keys. More precisely, we can use any keys, but
88            ones that GTK considers illegal as accelerators will not show up in
89            menus.
90
91            There are other dynamic actions that can be created by a monitor
92            section, by step entry dialogs. These need to be handled
93            separately. They don't tend to use GTK-illegal bindings and more
94            importantly they don't have menus showing the bindings, so it is
95            less of an issue.
96         */
97
98         Gtkmm2ext::Bindings::associate_all ();
99
100         editor->setup_tooltips ();
101         editor->UpdateAllTransportClocks.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_transport_clocks));
102
103         /* catch up on tabbable state, in the right order to leave the editor
104          * selected by default
105          */
106
107         tabbable_state_change (*rc_option_editor);
108         tabbable_state_change (*mixer);
109         tabbable_state_change (*editor);
110
111         /* all actions are defined */
112
113         ActionManager::load_menus (ARDOUR_COMMAND_LINE::menus_file);
114
115         /* catch up on parameters */
116
117         boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
118         Config->map_parameters (pc);
119
120         UIConfiguration::instance().reset_dpi ();
121 }
122
123 void
124 ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
125 {
126         DisplaySuspender ds;
127         BootMessage (_("Setup Editor"));
128         editor->set_session (s);
129         BootMessage (_("Setup Mixer"));
130         mixer->set_session (s);
131         meterbridge->set_session (s);
132         luawindow->set_session (s);
133
134         /* its safe to do this now */
135
136         BootMessage (_("Reload Session History"));
137         s->restore_history ("");
138 }
139
140 /** The main editor window has been closed */
141 gint
142 ARDOUR_UI::exit_on_main_window_close (GdkEventAny * /*ev*/)
143 {
144 #ifdef __APPLE__
145         /* just hide the window, and return - the top menu stays up */
146         editor->hide ();
147         return TRUE;
148 #else
149         /* time to get out of here */
150         finish();
151         return TRUE;
152 #endif
153 }
154
155 GtkNotebook*
156 ARDOUR_UI::tab_window_root_drop (GtkNotebook* src,
157                                  GtkWidget* w,
158                                  gint x,
159                                  gint y,
160                                  gpointer)
161 {
162         using namespace std;
163         Gtk::Notebook* nb = 0;
164         Gtk::Window* win = 0;
165         ArdourWidgets::Tabbable* tabbable = 0;
166
167
168         if (w == GTK_WIDGET(editor->contents().gobj())) {
169                 tabbable = editor;
170         } else if (w == GTK_WIDGET(mixer->contents().gobj())) {
171                 tabbable = mixer;
172         } else if (w == GTK_WIDGET(rc_option_editor->contents().gobj())) {
173                 tabbable = rc_option_editor;
174         } else {
175                 return 0;
176         }
177
178         nb = tabbable->tab_root_drop ();
179         win = tabbable->own_window ();
180
181         if (nb) {
182                 win->move (x, y);
183                 win->show_all ();
184                 win->present ();
185                 return nb->gobj();
186         }
187
188         return 0; /* what was that? */
189 }
190
191 bool
192 ARDOUR_UI::idle_ask_about_quit ()
193 {
194         if (_session && _session->dirty()) {
195                 finish ();
196         } else {
197                 /* no session or session not dirty, but still ask anyway */
198
199                 Gtk::MessageDialog msg (string_compose (_("Quit %1?"), PROGRAM_NAME),
200                                         false, /* no markup */
201                                         Gtk::MESSAGE_INFO,
202                                         Gtk::BUTTONS_YES_NO,
203                                         true); /* modal */
204                 msg.set_default_response (Gtk::RESPONSE_YES);
205
206                 if (msg.run() == Gtk::RESPONSE_YES) {
207                         finish ();
208                 }
209         }
210
211         /* not reached but keep the compiler happy */
212
213         return false;
214 }
215
216 bool
217 ARDOUR_UI::main_window_delete_event (GdkEventAny* ev)
218 {
219         /* quit the application as soon as we go idle. If we call this here,
220          * the window manager/desktop can think we're taking too longer to
221          * handle the "delete" event
222          */
223
224         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_ask_about_quit));
225
226         return true;
227 }
228
229 static GtkNotebook*
230 tab_window_root_drop (GtkNotebook* src,
231                       GtkWidget* w,
232                       gint x,
233                       gint y,
234                       gpointer user_data)
235 {
236         return ARDOUR_UI::instance()->tab_window_root_drop (src, w, x, y, user_data);
237 }
238
239 int
240 ARDOUR_UI::setup_windows ()
241 {
242         /* actions do not need to be defined when we load keybindings. They
243          * will be lazily discovered. But bindings do need to exist when we
244          * create windows/tabs with their own binding sets.
245          */
246
247         keyboard->setup_keybindings ();
248
249         _tabs.set_show_border(false);
250         _tabs.signal_switch_page().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_switch));
251         _tabs.signal_page_added().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_added));
252         _tabs.signal_page_removed().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_removed));
253
254         rc_option_editor = new RCOptionEditor;
255         rc_option_editor->StateChange.connect (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_state_change));
256
257         if (create_editor ()) {
258                 error << _("UI: cannot setup editor") << endmsg;
259                 return -1;
260         }
261
262         if (create_mixer ()) {
263                 error << _("UI: cannot setup mixer") << endmsg;
264                 return -1;
265         }
266
267         if (create_meterbridge ()) {
268                 error << _("UI: cannot setup meterbridge") << endmsg;
269                 return -1;
270         }
271
272         if (create_luawindow ()) {
273                 error << _("UI: cannot setup luawindow") << endmsg;
274                 return -1;
275         }
276
277         /* order of addition affects order seen in initial window display */
278
279         rc_option_editor->add_to_notebook (_tabs, _("Preferences"));
280         mixer->add_to_notebook (_tabs, _("Mixer"));
281         editor->add_to_notebook (_tabs, _("Editor"));
282
283         time_info_box = new TimeInfoBox ("ToolbarTimeInfo", false);
284         /* all other dialogs are created conditionally */
285
286         we_have_dependents ();
287
288         top_packer.pack_start (menu_bar_base, false, false);
289
290         main_vpacker.pack_start (top_packer, false, false);
291
292         ArdourWidgets::ArdourDropShadow *spacer = manage (new (ArdourWidgets::ArdourDropShadow));
293         spacer->set_size_request( -1, 4 );
294         spacer->show();
295
296         /* now add the transport sample to the top of main window */
297
298         main_vpacker.pack_start ( *spacer, false, false);
299         main_vpacker.pack_start (transport_frame, false, false);
300         main_vpacker.pack_start (_tabs, true, true);
301
302         LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_action_script_btn));
303
304         for (int i = 0; i < MAX_LUA_ACTION_SCRIPTS; ++i) {
305                 std::string const a = string_compose (X_("script-action-%1"), i + 1);
306                 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
307                 assert (act);
308                 action_script_call_btn[i].set_text (string_compose ("%1", i+1));
309                 action_script_call_btn[i].set_related_action (act);
310                 action_script_call_btn[i].signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::bind_lua_action_script), i), false);
311                 if (act->get_sensitive ()) {
312                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() & ~Gtkmm2ext::Insensitive));
313                 } else {
314                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() | Gtkmm2ext::Insensitive));
315                 }
316                 const int row = i % 2;
317                 const int col = i / 2;
318                 action_script_table.attach (action_script_call_btn[i], col, col + 1, row, row + 1, EXPAND, EXPAND, 1, 0);
319                 action_script_call_btn[i].set_no_show_all ();
320         }
321         action_script_table.show ();
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         return 0;
399 }
400
401 bool
402 ARDOUR_UI::bind_lua_action_script (GdkEventButton*ev, int i)
403 {
404         if (ev->button != 3) {
405                 return false;
406         }
407         LuaInstance *li = LuaInstance::instance();
408         if (Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::TertiaryModifier)) {
409                 li->remove_lua_action (i);
410         } else {
411                 li->interactive_add (LuaScriptInfo::EditorAction, i);
412         }
413         return true;
414 }
415
416 void
417 ARDOUR_UI::update_action_script_btn (int i, const std::string& n)
418 {
419         if (LuaInstance::instance()->lua_action_has_icon (i)) {
420                 uintptr_t ii = i;
421                 action_script_call_btn[i].set_icon (&LuaInstance::render_action_icon, (void*)ii);
422         } else {
423                 action_script_call_btn[i].set_icon (0, 0);
424         }
425
426         std::string const a = string_compose (X_("script-action-%1"), i + 1);
427         Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
428         assert (act);
429         if (n.empty ()) {
430                 act->set_label (string_compose (_("Unset #%1"), i + 1));
431                 act->set_tooltip (_("No action bound\nRight-click to assign"));
432                 act->set_sensitive (false);
433         } else {
434                 act->set_label (n);
435                 act->set_tooltip (string_compose (_("%1\n\nClick to run\nRight-click to re-assign\nShift+right-click to unassign"), n));
436                 act->set_sensitive (true);
437         }
438         KeyEditor::UpdateBindings ();
439 }