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