clean up patch change/sysex headers.
[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 "time_info_box.h"
47 #include "opts.h"
48 #include "utils.h"
49
50 #include "pbd/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         /* catch up on parameters */
105
106         boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
107         Config->map_parameters (pc);
108
109         UIConfiguration::instance().reset_dpi ();
110 }
111
112 void
113 ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
114 {
115         DisplaySuspender ds;
116         BootMessage (_("Setup Editor"));
117         editor->set_session (s);
118         BootMessage (_("Setup Mixer"));
119         mixer->set_session (s);
120         meterbridge->set_session (s);
121         luawindow->set_session (s);
122
123         /* its safe to do this now */
124
125         BootMessage (_("Reload Session History"));
126         s->restore_history ("");
127 }
128
129 /** The main editor window has been closed */
130 gint
131 ARDOUR_UI::exit_on_main_window_close (GdkEventAny * /*ev*/)
132 {
133 #ifdef TOP_MENUBAR
134         /* just hide the window, and return - the top menu stays up */
135         editor->hide ();
136         return TRUE;
137 #else
138         /* time to get out of here */
139         finish();
140         return TRUE;
141 #endif
142 }
143
144 GtkNotebook*
145 ARDOUR_UI::tab_window_root_drop (GtkNotebook* src,
146                                  GtkWidget* w,
147                                  gint x,
148                                  gint y,
149                                  gpointer)
150 {
151         using namespace std;
152         Gtk::Notebook* nb = 0;
153         Gtk::Window* win = 0;
154         Gtkmm2ext::Tabbable* tabbable = 0;
155
156
157         if (w == GTK_WIDGET(editor->contents().gobj())) {
158                 tabbable = editor;
159         } else if (w == GTK_WIDGET(mixer->contents().gobj())) {
160                 tabbable = mixer;
161         } else if (w == GTK_WIDGET(rc_option_editor->contents().gobj())) {
162                 tabbable = rc_option_editor;
163         } else {
164                 return 0;
165         }
166
167         nb = tabbable->tab_root_drop ();
168         win = tabbable->own_window ();
169
170         if (nb) {
171                 win->move (x, y);
172                 win->show_all ();
173                 win->present ();
174                 return nb->gobj();
175         }
176
177         return 0; /* what was that? */
178 }
179
180 bool
181 ARDOUR_UI::idle_ask_about_quit ()
182 {
183         if (_session && _session->dirty()) {
184                 finish ();
185         } else {
186                 /* no session or session not dirty, but still ask anyway */
187
188                 Gtk::MessageDialog msg (string_compose (_("Quit %1?"), PROGRAM_NAME),
189                                         false, /* no markup */
190                                         Gtk::MESSAGE_INFO,
191                                         Gtk::BUTTONS_YES_NO,
192                                         true); /* modal */
193                 msg.set_default_response (Gtk::RESPONSE_YES);
194
195                 if (msg.run() == Gtk::RESPONSE_YES) {
196                         finish ();
197                 }
198         }
199
200         /* not reached but keep the compiler happy */
201
202         return false;
203 }
204
205 bool
206 ARDOUR_UI::main_window_delete_event (GdkEventAny* ev)
207 {
208         /* quit the application as soon as we go idle. If we call this here,
209          * the window manager/desktop can think we're taking too longer to
210          * handle the "delete" event
211          */
212
213         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_ask_about_quit));
214
215         return true;
216 }
217
218 static GtkNotebook*
219 tab_window_root_drop (GtkNotebook* src,
220                       GtkWidget* w,
221                       gint x,
222                       gint y,
223                       gpointer user_data)
224 {
225         return ARDOUR_UI::instance()->tab_window_root_drop (src, w, x, y, user_data);
226 }
227
228 int
229 ARDOUR_UI::setup_windows ()
230 {
231         /* actions do not need to be defined when we load keybindings. They
232          * will be lazily discovered. But bindings do need to exist when we
233          * create windows/tabs with their own binding sets.
234          */
235
236         keyboard->setup_keybindings ();
237
238         _tabs.set_show_border(false);
239         _tabs.signal_switch_page().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_switch));
240         _tabs.signal_page_added().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_added));
241         _tabs.signal_page_removed().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_removed));
242
243         rc_option_editor = new RCOptionEditor;
244         rc_option_editor->StateChange.connect (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_state_change));
245
246         if (create_editor ()) {
247                 error << _("UI: cannot setup editor") << endmsg;
248                 return -1;
249         }
250
251         if (create_mixer ()) {
252                 error << _("UI: cannot setup mixer") << endmsg;
253                 return -1;
254         }
255
256         if (create_meterbridge ()) {
257                 error << _("UI: cannot setup meterbridge") << endmsg;
258                 return -1;
259         }
260
261         if (create_luawindow ()) {
262                 error << _("UI: cannot setup luawindow") << endmsg;
263                 return -1;
264         }
265
266         /* order of addition affects order seen in initial window display */
267
268         rc_option_editor->add_to_notebook (_tabs, _("Preferences"));
269         mixer->add_to_notebook (_tabs, _("Mixer"));
270         editor->add_to_notebook (_tabs, _("Editor"));
271
272         time_info_box = new TimeInfoBox (false);
273         /* all other dialogs are created conditionally */
274
275         we_have_dependents ();
276
277 #ifdef TOP_MENUBAR
278         EventBox* status_bar_event_box = manage (new EventBox);
279
280         status_bar_event_box->add (status_bar_label);
281         status_bar_event_box->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
282         status_bar_label.set_size_request (300, -1);
283
284         status_bar_label.show ();
285         status_bar_event_box->show ();
286
287         status_bar_event_box->signal_button_press_event().connect (mem_fun (*this, &ARDOUR_UI::status_bar_button_press));
288
289         status_bar_hpacker.pack_start (*status_bar_event_box, true, true, 6);
290         status_bar_hpacker.pack_start (menu_bar_base, false, false, 2);
291 #else
292         top_packer.pack_start (menu_bar_base, false, false);
293 #endif
294
295         main_vpacker.pack_start (top_packer, false, false);
296
297         /* now add the transport frame to the top of main window */
298
299         main_vpacker.pack_start (transport_frame, false, false);
300         main_vpacker.pack_start (_tabs, true, true);
301
302 #ifdef TOP_MENUBAR
303         main_vpacker.pack_start (status_bar_hpacker, false, false);
304 #endif
305
306         for (int i = 0; i < 9; ++i) {
307                 std::string const a = string_compose (X_("script-action-%1"), i + 1);
308                 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
309                 assert (act);
310                 action_script_call_btn[i].set_text (string_compose ("%1", i+1));
311                 action_script_call_btn[i].set_related_action (act);
312                 if (act->get_sensitive ()) {
313                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() & ~Gtkmm2ext::Insensitive));
314                 } else {
315                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() | Gtkmm2ext::Insensitive));
316                 }
317                 const int row = i % 2;
318                 const int col = i / 2;
319                 action_script_table.attach (action_script_call_btn[i], col, col + 1, row, row + 1, EXPAND, EXPAND, 1, 0);
320                 action_script_call_btn[i].set_no_show_all ();
321         }
322         action_script_table.show ();
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         return 0;
400 }