summaryrefslogtreecommitdiff
path: root/gtk2_ardour/ardour_ui_keys.cc
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2019-09-23 14:49:06 -0600
committerPaul Davis <paul@linuxaudiosystems.com>2019-09-23 14:49:06 -0600
commit5beeca2e95a7ea70a4225eaca979179649cb2e90 (patch)
tree832643fc664d4d82d059dbebb7bd658fd79b9a59 /gtk2_ardour/ardour_ui_keys.cc
parent9c0beeb7591302747eee6e28c448314313f8d54a (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.cc327
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;
+ }
+ }
+}