2 * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2015 Tim Mayberry <mojofunk@gmail.com>
5 * Copyright (C) 2007-2011 David Robillard <d@drobilla.net>
6 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
7 * Copyright (C) 2013-2018 Robin Gareus <robin@gareus.org>
8 * Copyright (C) 2016-2018 Ben Loftis <ben@harrisonconsoles.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "gtk2ardour-config.h"
29 /* this file exists solely to break compilation dependencies that
30 would connect changes to the mixer or editor objects.
35 #include "pbd/error.h"
38 #include "ardour/session.h"
39 #include "ardour/lv2_plugin.h"
41 #include "gtkmm2ext/bindings.h"
44 #include "ardour_message.h"
45 #include "ardour_ui.h"
46 #include "public_editor.h"
47 #include "meterbridge.h"
48 #include "luainstance.h"
49 #include "luawindow.h"
52 #include "keyeditor.h"
54 #include "rc_option_editor.h"
55 #include "route_params_ui.h"
56 #include "time_info_box.h"
57 #include "step_entry.h"
61 #ifdef GDK_WINDOWING_X11
73 using namespace ARDOUR;
74 using namespace Gtkmm2ext;
77 ARDOUR_UI::we_have_dependents ()
79 install_dependent_actions ();
81 /* The monitor section relies on at least 1 action defined by us. Since that
82 * action now exists, give it a chance to use it.
84 mixer->monitor_section().use_others_actions ();
86 /* Create "static" actions that apply to all ProcessorBoxes
88 ProcessorBox::register_actions ();
89 StepEntry::setup_actions_and_bindings ();
91 /* Global, editor, mixer, processor box actions are defined now. Link
92 them with any bindings, so that GTK does not get a chance to define
93 the GTK accel map entries first when we ask the GtkUIManager to
96 If GTK adds the actions to its accel map before we do, we lose our
97 freedom to use any keys. More precisely, we can use any keys, but
98 ones that GTK considers illegal as accelerators will not show up in
101 There are other dynamic actions that can be created by a monitor
102 section, by step entry dialogs. These need to be handled
103 separately. They don't tend to use GTK-illegal bindings and more
104 importantly they don't have menus showing the bindings, so it is
108 Gtkmm2ext::Bindings::associate_all ();
110 editor->setup_tooltips ();
111 editor->UpdateAllTransportClocks.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_transport_clocks));
113 /* catch up on tabbable state, in the right order to leave the editor
114 * selected by default
117 tabbable_state_change (*rc_option_editor);
118 tabbable_state_change (*mixer);
119 tabbable_state_change (*editor);
121 /* all actions are defined */
123 ActionManager::load_menus (ARDOUR_COMMAND_LINE::menus_file);
125 /* catch up on parameters */
127 boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
128 Config->map_parameters (pc);
130 UIConfiguration::instance().reset_dpi ();
134 ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
137 BootMessage (_("Setup Editor"));
138 editor->set_session (s);
139 BootMessage (_("Setup Mixer"));
140 mixer->set_session (s);
141 meterbridge->set_session (s);
142 luawindow->set_session (s);
144 /* its safe to do this now */
146 BootMessage (_("Reload Session History"));
147 s->restore_history ("");
150 /** The main editor window has been closed */
152 ARDOUR_UI::exit_on_main_window_close (GdkEventAny * /*ev*/)
155 /* just hide the window, and return - the top menu stays up */
159 /* time to get out of here */
166 ARDOUR_UI::tab_window_root_drop (GtkNotebook* src,
173 Gtk::Notebook* nb = 0;
174 Gtk::Window* win = 0;
175 ArdourWidgets::Tabbable* tabbable = 0;
178 if (w == GTK_WIDGET(editor->contents().gobj())) {
180 } else if (w == GTK_WIDGET(mixer->contents().gobj())) {
182 } else if (w == GTK_WIDGET(rc_option_editor->contents().gobj())) {
183 tabbable = rc_option_editor;
188 nb = tabbable->tab_root_drop ();
189 win = tabbable->own_window ();
198 return 0; /* what was that? */
202 ARDOUR_UI::idle_ask_about_quit ()
204 if (_session && _session->dirty()) {
207 /* no session or session not dirty, but still ask anyway */
209 ArdourMessageDialog msg (string_compose (_("Quit %1?"), PROGRAM_NAME),
210 false, /* no markup */
214 msg.set_default_response (Gtk::RESPONSE_YES);
216 if (msg.run() == Gtk::RESPONSE_YES) {
221 /* not reached but keep the compiler happy */
227 ARDOUR_UI::main_window_delete_event (GdkEventAny* ev)
229 /* quit the application as soon as we go idle. If we call this here,
230 * the window manager/desktop can think we're taking too longer to
231 * handle the "delete" event
234 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_ask_about_quit));
240 tab_window_root_drop (GtkNotebook* src,
246 return ARDOUR_UI::instance()->tab_window_root_drop (src, w, x, y, user_data);
250 ARDOUR_UI::setup_windows ()
252 _tabs.set_show_border(false);
253 _tabs.signal_switch_page().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_switch));
254 _tabs.signal_page_added().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_added));
255 _tabs.signal_page_removed().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_removed));
257 rc_option_editor = new RCOptionEditor;
258 rc_option_editor->StateChange.connect (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_state_change));
260 if (create_editor ()) {
261 error << _("UI: cannot setup editor") << endmsg;
265 if (create_mixer ()) {
266 error << _("UI: cannot setup mixer") << endmsg;
270 if (create_meterbridge ()) {
271 error << _("UI: cannot setup meterbridge") << endmsg;
275 if (create_luawindow ()) {
276 error << _("UI: cannot setup luawindow") << endmsg;
280 time_info_box = new TimeInfoBox ("ToolbarTimeInfo", false);
281 /* all other dialogs are created conditionally */
283 we_have_dependents ();
285 /* order of addition affects order seen in initial window display */
287 rc_option_editor->add_to_notebook (_tabs, _("Preferences"));
288 mixer->add_to_notebook (_tabs, _("Mixer"));
289 editor->add_to_notebook (_tabs, _("Editor"));
291 top_packer.pack_start (menu_bar_base, false, false);
293 main_vpacker.pack_start (top_packer, false, false);
295 ArdourWidgets::ArdourDropShadow *spacer = manage (new (ArdourWidgets::ArdourDropShadow));
296 spacer->set_size_request( -1, 4 );
299 /* now add the transport sample to the top of main window */
301 main_vpacker.pack_start ( *spacer, false, false);
302 main_vpacker.pack_start (transport_frame, false, false);
303 main_vpacker.pack_start (_tabs, true, true);
305 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_action_script_btn));
307 for (int i = 0; i < MAX_LUA_ACTION_BUTTONS; ++i) {
308 std::string const a = string_compose (X_("script-action-%1"), i + 1);
309 Glib::RefPtr<Action> act = ActionManager::get_action(X_("LuaAction"), a.c_str());
311 action_script_call_btn[i].set_name ("lua action button");
312 action_script_call_btn[i].set_text (string_compose ("%1%2", std::hex, i+1));
313 action_script_call_btn[i].set_related_action (act);
314 action_script_call_btn[i].signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::bind_lua_action_script), i), false);
315 if (act->get_sensitive ()) {
316 action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() & ~Gtkmm2ext::Insensitive));
318 action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() | Gtkmm2ext::Insensitive));
320 action_script_call_btn[i].set_sizing_text ("88");
321 action_script_call_btn[i].set_no_show_all ();
328 _main_window.signal_delete_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::main_window_delete_event));
330 /* pack the main vpacker into the main window and show everything
333 _main_window.add (main_vpacker);
334 transport_frame.show_all ();
336 const XMLNode* mnode = main_window_settings ();
339 XMLProperty const * prop;
345 if ((prop = mnode->property (X_("x"))) != 0) {
346 x = atoi (prop->value());
349 if ((prop = mnode->property (X_("y"))) != 0) {
350 y = atoi (prop->value());
353 if ((prop = mnode->property (X_("w"))) != 0) {
354 w = atoi (prop->value());
357 if ((prop = mnode->property (X_("h"))) != 0) {
358 h = atoi (prop->value());
361 if (x >= 0 && y >= 0 && w >= 0 && h >= 0) {
362 _main_window.set_position (Gtk::WIN_POS_NONE);
365 if (x >= 0 && y >= 0) {
366 _main_window.move (x, y);
369 if (w > 0 && h > 0) {
370 _main_window.set_default_size (w, h);
373 std::string current_tab;
375 if ((prop = mnode->property (X_("current-tab"))) != 0) {
376 current_tab = prop->value();
378 current_tab = "editor";
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()));
385 _tabs.set_current_page (_tabs.page_num (editor->contents()));
389 setup_toplevel_window (_main_window, "", this);
390 _main_window.show_all ();
392 _tabs.set_show_tabs (false);
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...
397 g_signal_connect (_tabs.gobj(), "create-window", (GCallback) ::tab_window_root_drop, this);
399 #ifdef GDK_WINDOWING_X11
400 /* allow externalUIs to be transient, on top of the main window */
401 LV2Plugin::set_main_window_id (GDK_DRAWABLE_XID(_main_window.get_window()->gobj()));
408 ARDOUR_UI::bind_lua_action_script (GdkEventButton*ev, int i)
413 LuaInstance *li = LuaInstance::instance();
415 if (ev->button != 3 && !(ev->button == 1 && !li->lua_action_name (i, name))) {
418 if (Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::TertiaryModifier)) {
419 li->remove_lua_action (i);
421 li->interactive_add (LuaScriptInfo::EditorAction, i);
427 ARDOUR_UI::update_action_script_btn (int i, const std::string& n)
429 if (i < 0 || i >= MAX_LUA_ACTION_BUTTONS) {
432 if (LuaInstance::instance()->lua_action_has_icon (i)) {
434 action_script_call_btn[i].set_icon (&LuaInstance::render_action_icon, (void*)ii);
436 action_script_call_btn[i].set_icon (0, 0);
439 std::string const a = string_compose (X_("script-action-%1"), i + 1);
440 Glib::RefPtr<Action> act = ActionManager::get_action(X_("LuaAction"), a.c_str());
443 act->set_label (string_compose (_("Unset #%1"), i + 1));
444 act->set_tooltip (_("No action bound\nRight-click to assign"));
445 act->set_sensitive (false);
448 act->set_tooltip (string_compose (_("%1\n\nClick to run\nRight-click to re-assign\nShift+right-click to unassign"), n));
449 act->set_sensitive (true);
451 KeyEditor::UpdateBindings ();