diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2019-09-23 14:49:06 -0600 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2019-09-23 14:49:06 -0600 |
commit | 5beeca2e95a7ea70a4225eaca979179649cb2e90 (patch) | |
tree | 832643fc664d4d82d059dbebb7bd658fd79b9a59 /gtk2_ardour/ardour_ui_keys.cc | |
parent | 9c0beeb7591302747eee6e28c448314313f8d54a (diff) |
split apart ardour_ui.cc into a series of distinct source modules.
Should be a 100% no-op - no code was altered, just moved
Diffstat (limited to 'gtk2_ardour/ardour_ui_keys.cc')
-rw-r--r-- | gtk2_ardour/ardour_ui_keys.cc | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/gtk2_ardour/ardour_ui_keys.cc b/gtk2_ardour/ardour_ui_keys.cc new file mode 100644 index 0000000000..17c3ebeb73 --- /dev/null +++ b/gtk2_ardour/ardour_ui_keys.cc @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net> + * Copyright (C) 2005-2017 Tim Mayberry <mojofunk@gmail.com> + * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com> + * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com> + * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com> + * Copyright (C) 2006-2015 David Robillard <d@drobilla.net> + * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net> + * Copyright (C) 2008-2010 Sakari Bergen <sakari.bergen@beatwaves.net> + * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org> + * Copyright (C) 2013-2015 Colin Fletcher <colin.m.fletcher@googlemail.com> + * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk> + * Copyright (C) 2013-2016 Nick Mainsbridge <mainsbridge@gmail.com> + * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com> + * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com> + * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net> + * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef WAF_BUILD +#include "gtk2ardour-config.h" +#include "gtk2ardour-version.h" +#endif + +#include "ardour_ui.h" +#include "debug.h" +#include "keyboard.h" +#include "public_editor.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Gtkmm2ext; +using namespace ArdourWidgets; +using namespace Gtk; +using namespace std; + +bool +ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window) +{ + Gtkmm2ext::Bindings* bindings = 0; + Gtk::Window* window = 0; + + /* until we get ardour bindings working, we are not handling key + * releases yet. + */ + + if (ev->type != GDK_KEY_PRESS) { + return false; + } + + if (event_window == &_main_window) { + + window = event_window; + + /* find current tab contents */ + + Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page()); + + /* see if it uses the ardour binding system */ + + if (w) { + bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings")); + } + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings)); + + } else { + + window = event_window; + + /* see if window uses ardour binding system */ + + bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings")); + } + + /* An empty binding set is treated as if it doesn't exist */ + + if (bindings && bindings->empty()) { + bindings = 0; + } + + return key_press_focus_accelerator_handler (*window, ev, bindings); +} + +static Gtkmm2ext::Bindings* +get_bindings_from_widget_heirarchy (GtkWidget** w) +{ + void* p = NULL; + + while (*w) { + if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) { + break; + } + *w = gtk_widget_get_parent (*w); + } + + return reinterpret_cast<Gtkmm2ext::Bindings*> (p); +} + +bool +ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings) +{ + GtkWindow* win = window.gobj(); + GtkWidget* focus = gtk_window_get_focus (win); + GtkWidget* binding_widget = focus; + bool special_handling_of_unmodified_accelerators = false; + const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK)); + + if (focus) { + + /* some widget has keyboard focus */ + + if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) { + + /* A particular kind of focusable widget currently has keyboard + * focus. All unmodified key events should go to that widget + * first and not be used as an accelerator by default + */ + + special_handling_of_unmodified_accelerators = true; + + } else { + + Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget); + if (focus_bindings) { + bindings = focus_bindings; + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name())); + } + } + } + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n", + win, + ev->keyval, + Gtkmm2ext::show_gdk_event_state (ev->state), + special_handling_of_unmodified_accelerators, + Keyboard::some_magic_widget_has_focus(), + focus, + (focus ? gtk_widget_get_name (focus) : "no focus widget"), + ((ev->state & mask) ? "yes" : "no"), + window.get_title())); + + /* This exists to allow us to override the way GTK handles + key events. The normal sequence is: + + a) event is delivered to a GtkWindow + b) accelerators/mnemonics are activated + c) if (b) didn't handle the event, propagate to + the focus widget and/or focus chain + + The problem with this is that if the accelerators include + keys without modifiers, such as the space bar or the + letter "e", then pressing the key while typing into + a text entry widget results in the accelerator being + activated, instead of the desired letter appearing + in the text entry. + + There is no good way of fixing this, but this + represents a compromise. The idea is that + key events involving modifiers (not Shift) + get routed into the activation pathway first, then + get propagated to the focus widget if necessary. + + If the key event doesn't involve modifiers, + we deliver to the focus widget first, thus allowing + it to get "normal text" without interference + from acceleration. + + Of course, this can also be problematic: if there + is a widget with focus, then it will swallow + all "normal text" accelerators. + */ + + + if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) { + + /* no special handling or there are modifiers in effect: accelerate first */ + + DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n"); + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n", + ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval))); + + DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n"); + KeyboardKey k (ev->state, ev->keyval); + + while (bindings) { + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings)); + + if (bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + + if (binding_widget) { + binding_widget = gtk_widget_get_parent (binding_widget); + if (binding_widget) { + bindings = get_bindings_from_widget_heirarchy (&binding_widget); + } else { + bindings = 0; + } + } else { + bindings = 0; + } + } + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings)); + + if (global_bindings && global_bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + + DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n"); + + if (gtk_window_propagate_key_event (win, ev)) { + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n"); + return true; + } + + } else { + + /* no modifiers, propagate first */ + + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n"); + + if (gtk_window_propagate_key_event (win, ev)) { + DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n"); + return true; + } + + DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n"); + KeyboardKey k (ev->state, ev->keyval); + + while (bindings) { + + DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n"); + + + if (bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + + if (binding_widget) { + binding_widget = gtk_widget_get_parent (binding_widget); + if (binding_widget) { + bindings = get_bindings_from_widget_heirarchy (&binding_widget); + } else { + bindings = 0; + } + } else { + bindings = 0; + } + } + + DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings)); + + if (global_bindings && global_bindings->activate (k, Bindings::Press)) { + DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n"); + return true; + } + } + + DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n"); + return true; +} + + +gint +ARDOUR_UI::transport_numpad_timeout () +{ + _numpad_locate_happening = false; + if (_numpad_timeout_connection.connected() ) + _numpad_timeout_connection.disconnect(); + return 1; +} + +void +ARDOUR_UI::transport_numpad_decimal () +{ + _numpad_timeout_connection.disconnect(); + + if (_numpad_locate_happening) { + if (editor) editor->goto_nth_marker(_pending_locate_num - 1); + _numpad_locate_happening = false; + } else { + _pending_locate_num = 0; + _numpad_locate_happening = true; + _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000); + } +} + +void +ARDOUR_UI::transport_numpad_event (int num) +{ + if ( _numpad_locate_happening ) { + _pending_locate_num = _pending_locate_num*10 + num; + } else { + switch (num) { + case 0: toggle_roll(false, false); break; + case 1: transport_rewind(1); break; + case 2: transport_forward(1); break; + case 3: transport_record(true); break; + case 4: toggle_session_auto_loop(); break; + case 5: transport_record(false); toggle_session_auto_loop(); break; + case 6: toggle_punch(); break; + case 7: toggle_click(); break; + case 8: toggle_auto_return(); break; + case 9: toggle_follow_edits(); break; + } + } +} |