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