(merge from 2.0-ongoing -r1911:1912) fix audio clock handling of key press; fix crash...
[ardour.git] / gtk2_ardour / keyboard.cc
1 /*
2     Copyright (C) 2001 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 #include "ardour_ui.h"
21
22 #include <algorithm>
23 #include <fstream>
24
25 #include <ctype.h>
26
27 #include <gdk/gdkkeysyms.h>
28 #include <pbd/error.h>
29
30 #include "keyboard.h"
31 #include "gui_thread.h"
32
33 #include "i18n.h"
34
35 using namespace PBD;
36
37 #define KBD_DEBUG 1
38 bool debug_keyboard = false;
39
40 guint Keyboard::edit_but = 3;
41 guint Keyboard::edit_mod = GDK_CONTROL_MASK;
42 guint Keyboard::delete_but = 3;
43 guint Keyboard::delete_mod = GDK_SHIFT_MASK;
44 guint Keyboard::snap_mod = GDK_MOD3_MASK;
45
46 uint32_t Keyboard::Control = GDK_CONTROL_MASK;
47 uint32_t Keyboard::Shift = GDK_SHIFT_MASK;
48 uint32_t Keyboard::Alt = GDK_MOD1_MASK;
49 uint32_t Keyboard::Meta;
50
51 Keyboard* Keyboard::_the_keyboard = 0;
52
53 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
54
55 GdkModifierType Keyboard::RelevantModifierKeyMask;
56
57 bool Keyboard::_some_magic_widget_has_focus = false;
58
59 void
60 Keyboard::magic_widget_grab_focus () 
61 {
62         _some_magic_widget_has_focus = true;
63 }
64
65 void
66 Keyboard::magic_widget_drop_focus ()
67 {
68         _some_magic_widget_has_focus = false;
69 }
70
71 bool
72 Keyboard::some_magic_widget_has_focus ()
73 {
74         return _some_magic_widget_has_focus;
75 }
76
77 Keyboard::Keyboard ()
78 {
79         if (_the_keyboard == 0) {
80                 _the_keyboard = this;
81         }
82
83         RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
84
85         /* figure out Meta */
86
87         uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
88         int i;
89
90         for (i = 0; possible_meta[i]; ++i) {
91                 if (!(RelevantModifierKeyMask & possible_meta[i])) {
92                         break;
93                 }
94         }
95         Meta = possible_meta[i];
96
97         snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
98
99         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
100         set_state (*node);
101 }
102
103 Keyboard::~Keyboard ()
104 {
105         gtk_key_snooper_remove (snooper_id);
106 }
107
108 XMLNode& 
109 Keyboard::get_state (void)
110 {
111         XMLNode* node = new XMLNode ("Keyboard");
112         char buf[32];
113
114         snprintf (buf, sizeof (buf), "%d", edit_but);
115         node->add_property ("edit-button", buf);
116         snprintf (buf, sizeof (buf), "%d", edit_mod);
117         node->add_property ("edit-modifier", buf);
118         snprintf (buf, sizeof (buf), "%d", delete_but);
119         node->add_property ("delete-button", buf);
120         snprintf (buf, sizeof (buf), "%d", delete_mod);
121         node->add_property ("delete-modifier", buf);
122         snprintf (buf, sizeof (buf), "%d", snap_mod);
123         node->add_property ("snap-modifier", buf);
124
125         return *node;
126 }
127
128 int 
129 Keyboard::set_state (const XMLNode& node)
130 {
131         const XMLProperty* prop;
132
133         if ((prop = node.property ("edit-button")) != 0) {
134                 sscanf (prop->value().c_str(), "%d", &edit_but);
135         } 
136
137         if ((prop = node.property ("edit-modifier")) != 0) {
138                 sscanf (prop->value().c_str(), "%d", &edit_mod);
139         } 
140
141         if ((prop = node.property ("delete-button")) != 0) {
142                 sscanf (prop->value().c_str(), "%d", &delete_but);
143         } 
144
145         if ((prop = node.property ("delete-modifier")) != 0) {
146                 sscanf (prop->value().c_str(), "%d", &delete_mod);
147         } 
148
149         if ((prop = node.property ("snap-modifier")) != 0) {
150                 sscanf (prop->value().c_str(), "%d", &snap_mod);
151         } 
152
153         return 0;
154 }
155
156 gint
157 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
158 {
159         return ((Keyboard *) data)->snooper (widget, event);
160 }
161
162 gint
163 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
164 {
165         uint32_t keyval;
166
167 #if KBD_DEBUG
168         if (debug_keyboard) {
169                 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
170                      << endl;
171         }
172 #endif
173
174         if (event->keyval == GDK_Shift_R) {
175                 keyval = GDK_Shift_L;
176
177         } else  if (event->keyval == GDK_Control_R) {
178                 keyval = GDK_Control_L;
179
180         } else {
181                 keyval = event->keyval;
182         }
183                 
184         if (event->type == GDK_KEY_PRESS) {
185
186                 if (find (state.begin(), state.end(), keyval) == state.end()) {
187                         state.push_back (keyval);
188                         sort (state.begin(), state.end());
189                 }
190
191         } else if (event->type == GDK_KEY_RELEASE) {
192
193                 State::iterator i;
194                 
195                 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
196                         state.erase (i);
197                         sort (state.begin(), state.end());
198                 } 
199
200         }
201
202         return false;
203 }
204
205 bool
206 Keyboard::key_is_down (uint32_t keyval)
207 {
208         return find (state.begin(), state.end(), keyval) != state.end();
209 }
210
211 bool
212 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
213 {
214         return false;
215 }
216
217 bool
218 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
219 {
220         switch (ev->detail) {
221         case GDK_NOTIFY_INFERIOR:
222                 if (debug_keyboard) {
223                         cerr << "INFERIOR crossing ... out\n";
224                 }
225                 break;
226
227         case GDK_NOTIFY_VIRTUAL:
228                 if (debug_keyboard) {
229                         cerr << "VIRTUAL crossing ... out\n";
230                 }
231                 /* fallthru */
232
233         default:
234                 if (debug_keyboard) {
235                         cerr << "REAL CROSSING ... out\n";
236                         cerr << "clearing current target\n";
237                 }
238                 state.clear ();
239         }
240
241         return false;
242 }
243
244 void
245 Keyboard::set_edit_button (guint but)
246 {
247         edit_but = but;
248 }
249
250 void
251 Keyboard::set_edit_modifier (guint mod)
252 {
253         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
254         edit_mod = mod;
255         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
256 }
257
258 void
259 Keyboard::set_delete_button (guint but)
260 {
261         delete_but = but;
262 }
263
264 void
265 Keyboard::set_delete_modifier (guint mod)
266 {
267         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
268         delete_mod = mod;
269         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
270 }
271
272 void
273 Keyboard::set_meta_modifier (guint mod)
274 {
275         /* we don't include Meta in the RelevantModifierKeyMask because its not used
276            in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
277            set at all is that X Window has no convention for the keyboard modifier
278            that Meta should use. Some Linux distributions bind NumLock to Mod2, which
279            is our default Meta modifier, and this causes severe problems.
280         */
281         Meta = mod;
282 }
283
284 void
285 Keyboard::set_snap_modifier (guint mod)
286 {
287         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
288         snap_mod = mod;
289         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
290 }
291
292 bool
293 Keyboard::is_edit_event (GdkEventButton *ev)
294 {
295
296         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
297                 (ev->button == Keyboard::edit_button()) && 
298                 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
299 }
300
301 bool
302 Keyboard::is_delete_event (GdkEventButton *ev)
303 {
304         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
305                 (ev->button == Keyboard::delete_button()) && 
306                 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
307 }
308
309 bool
310 Keyboard::is_context_menu_event (GdkEventButton *ev)
311 {
312         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
313                 (ev->button == 3) && 
314                 ((ev->state & RelevantModifierKeyMask) == 0);
315 }
316
317 bool 
318 Keyboard::no_modifiers_active (guint state)
319 {
320         return (state & RelevantModifierKeyMask) == 0;
321 }
322
323 bool
324 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
325 {
326         return (state & mask) == (guint) mask;
327 }
328
329 bool
330 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
331 {
332         return (state & RelevantModifierKeyMask) == (guint) mask;
333 }
334
335 Selection::Operation
336 Keyboard::selection_type (guint state)
337 {
338         /* note that there is no modifier for "Add" */
339
340         if (modifier_state_equals (state, Shift)) {
341                 return Selection::Extend;
342         } else if (modifier_state_equals (state, Control)) {
343                 return Selection::Toggle;
344         } else {
345                 return Selection::Set;
346         }
347 }