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