1 /*
2 * Copyright (C) 2001-2016 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2011-2012 Carl Hetherington <carl@carlh.net>
4 * Copyright (C) 2013 Colin Fletcher <colin.m.fletcher@googlemail.com>
5 * Copyright (C) 2015-2016 Nick Mainsbridge <mainsbridge@gmail.com>
6 * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
7 * Copyright (C) 2016 Tim Mayberry <mojofunk@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #include <vector>
25
26 #include <algorithm>
27 #include <cerrno>
28 #include <ctype.h>
29
30 #include "pbd/gstdio_compat.h"
31
32 #include <gtkmm/widget.h>
33 #include <gtkmm/window.h>
34 #include <gtkmm/accelmap.h>
35 #include <gdk/gdkkeysyms.h>
36
37 #include "pbd/error.h"
38 #include "pbd/convert.h"
39 #include "pbd/file_utils.h"
40 #include "pbd/search_path.h"
41 #include "pbd/xml++.h"
42 #include "pbd/debug.h"
43 #include "pbd/unwind.h"
44
45 #include "gtkmm2ext/actions.h"
46 #include "gtkmm2ext/bindings.h"
47 #include "gtkmm2ext/keyboard.h"
48 #include "gtkmm2ext/debug.h"
49 #include "gtkmm2ext/utils.h"
50
51 #include "pbd/i18n.h"
52
53 using namespace PBD;
54 using namespace Gtk;
55 using namespace Gtkmm2ext;
56 using namespace std;
57
58 guint Keyboard::edit_but = 3;
59 guint Keyboard::edit_mod = GDK_CONTROL_MASK;
60 guint Keyboard::delete_but = 3;
61 guint Keyboard::delete_mod = GDK_SHIFT_MASK;
62 guint Keyboard::insert_note_but = 1;
63 guint Keyboard::insert_note_mod = GDK_CONTROL_MASK;
64
65 #ifdef __APPLE__
66
67 guint Keyboard::PrimaryModifier = GDK_MOD2_MASK; // Command
68 guint Keyboard::SecondaryModifier = GDK_CONTROL_MASK; // Control
69 guint Keyboard::TertiaryModifier = GDK_SHIFT_MASK; // Shift
70 guint Keyboard::Level4Modifier = GDK_MOD1_MASK; // Alt/Option
71 guint Keyboard::CopyModifier = GDK_CONTROL_MASK; // Control
72 guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK;
73 guint Keyboard::button2_modifiers = Keyboard::SecondaryModifier|Keyboard::Level4Modifier;
74
primary_modifier_name()75 const char* Keyboard::primary_modifier_name() { return _("Command"); }
secondary_modifier_name()76 const char* Keyboard::secondary_modifier_name() { return _("Control"); }
tertiary_modifier_name()77 const char* Keyboard::tertiary_modifier_name() { return S_("Key|Shift"); }
level4_modifier_name()78 const char* Keyboard::level4_modifier_name() { return _("Option"); }
79
primary_modifier_short_name()80 const char* Keyboard::primary_modifier_short_name() { return _("Cmd"); }
secondary_modifier_short_name()81 const char* Keyboard::secondary_modifier_short_name() { return _("Ctrl"); }
tertiary_modifier_short_name()82 const char* Keyboard::tertiary_modifier_short_name() { return S_("Key|Shift"); }
level4_modifier_short_name()83 const char* Keyboard::level4_modifier_short_name() { return _("Opt"); }
84
85 guint Keyboard::snap_mod = Keyboard::Level4Modifier|Keyboard::TertiaryModifier; // XXX this is probably completely wrong
86 guint Keyboard::snap_delta_mod = Keyboard::Level4Modifier;
87
88 #else
89
90 guint Keyboard::PrimaryModifier = GDK_CONTROL_MASK; // Control
91 guint Keyboard::SecondaryModifier = GDK_MOD1_MASK; // Alt/Option
92 guint Keyboard::TertiaryModifier = GDK_SHIFT_MASK; // Shift
93 guint Keyboard::Level4Modifier = GDK_MOD4_MASK|GDK_SUPER_MASK; // Mod4/Windows
94 guint Keyboard::CopyModifier = GDK_CONTROL_MASK;
95 guint Keyboard::RangeSelectModifier = GDK_SHIFT_MASK;
96 guint Keyboard::button2_modifiers = 0; /* not used */
97
primary_modifier_name()98 const char* Keyboard::primary_modifier_name() { return _("Control"); }
secondary_modifier_name()99 const char* Keyboard::secondary_modifier_name() { return _("Alt"); }
tertiary_modifier_name()100 const char* Keyboard::tertiary_modifier_name() { return S_("Key|Shift"); }
level4_modifier_name()101 const char* Keyboard::level4_modifier_name() { return _("Windows"); }
102
primary_modifier_short_name()103 const char* Keyboard::primary_modifier_short_name() { return _("Ctrl"); }
secondary_modifier_short_name()104 const char* Keyboard::secondary_modifier_short_name() { return _("Alt"); }
tertiary_modifier_short_name()105 const char* Keyboard::tertiary_modifier_short_name() { return S_("Key|Shift"); }
level4_modifier_short_name()106 const char* Keyboard::level4_modifier_short_name() { return _("Win"); }
107
108 guint Keyboard::snap_mod = Keyboard::SecondaryModifier;
109 guint Keyboard::snap_delta_mod = Keyboard::SecondaryModifier|Keyboard::Level4Modifier;
110
111 #endif
112
113 guint Keyboard::GainFineScaleModifier = Keyboard::PrimaryModifier;
114 guint Keyboard::GainExtraFineScaleModifier = Keyboard::SecondaryModifier;
115
116 guint Keyboard::ScrollZoomVerticalModifier = Keyboard::SecondaryModifier;
117 guint Keyboard::ScrollZoomHorizontalModifier = Keyboard::PrimaryModifier;
118 guint Keyboard::ScrollHorizontalModifier = Keyboard::TertiaryModifier;
119
120 Keyboard* Keyboard::_the_keyboard = 0;
121 Gtk::Window* Keyboard::current_window = 0;
122 bool Keyboard::_some_magic_widget_has_focus = false;
123
124 const int Keyboard::close_window_key = GDK_w;
125 guint Keyboard::close_window_modifier = Keyboard::PrimaryModifier;
126
127 std::string Keyboard::user_keybindings_path;
128 bool Keyboard::can_save_keybindings = false;
129 bool Keyboard::bindings_changed_after_save_became_legal = false;
130 map<string,string> Keyboard::binding_files;
131 string Keyboard::_current_binding_name;
132 string Keyboard::binding_filename_suffix = X_(".keys");
133 Gtk::Window* Keyboard::pre_dialog_active_window = 0;
134
135 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
136 GdkModifierType Keyboard::RelevantModifierKeyMask;
137 sigc::signal0<void> Keyboard::RelevantModifierKeysChanged;
138 sigc::signal1<void,Gtk::Window*> Keyboard::HideMightMeanQuit;
139
140 void
magic_widget_grab_focus()141 Keyboard::magic_widget_grab_focus ()
142 {
143 _some_magic_widget_has_focus = true;
144 }
145
146 void
magic_widget_drop_focus()147 Keyboard::magic_widget_drop_focus ()
148 {
149 _some_magic_widget_has_focus = false;
150 }
151
152 bool
some_magic_widget_has_focus()153 Keyboard::some_magic_widget_has_focus ()
154 {
155 return _some_magic_widget_has_focus;
156 }
157
Keyboard()158 Keyboard::Keyboard ()
159 {
160 if (_the_keyboard == 0) {
161 _the_keyboard = this;
162 _current_binding_name = _("Unknown");
163 }
164
165 reset_relevant_modifier_key_mask();
166
167 snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
168 }
169
~Keyboard()170 Keyboard::~Keyboard ()
171 {
172 gtk_key_snooper_remove (snooper_id);
173 }
174
175 XMLNode&
get_state(void)176 Keyboard::get_state (void)
177 {
178 XMLNode* node = new XMLNode ("Keyboard");
179
180 node->set_property ("copy-modifier", CopyModifier);
181 node->set_property ("edit-button", edit_but);
182 node->set_property ("edit-modifier", edit_mod);
183 node->set_property ("delete-button", delete_but);
184 node->set_property ("delete-modifier", delete_mod);
185 node->set_property ("snap-modifier", snap_mod);
186 node->set_property ("snap-delta-modifier", snap_delta_mod);
187 node->set_property ("insert-note-button", insert_note_but);
188 node->set_property ("insert-note-modifier", insert_note_mod);
189
190 return *node;
191 }
192
193 int
set_state(const XMLNode & node,int)194 Keyboard::set_state (const XMLNode& node, int /*version*/)
195 {
196 node.get_property ("copy-modifier", CopyModifier);
197 node.get_property ("edit-button", edit_but);
198 node.get_property ("edit-modifier", edit_mod);
199 node.get_property ("delete-button", delete_but);
200 node.get_property ("delete-modifier", delete_mod);
201 node.get_property ("snap-modifier", snap_mod);
202 node.get_property ("snap-delta-modifier", snap_delta_mod);
203 node.get_property ("insert-note-button", insert_note_but);
204 node.get_property ("insert-note-modifier", insert_note_mod);
205
206 return 0;
207 }
208
209 gint
_snooper(GtkWidget * widget,GdkEventKey * event,gpointer data)210 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
211 {
212 return ((Keyboard *) data)->snooper (widget, event);
213 }
214
215
216 gint
snooper(GtkWidget * widget,GdkEventKey * event)217 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
218 {
219 uint32_t keyval;
220 bool ret = false;
221
222 DEBUG_TRACE (
223 DEBUG::Keyboard,
224 string_compose (
225 "Snoop widget %1 name: [%6] key %2 [%8] type %3 state %4 [%7] magic %5\n",
226 widget, event->keyval, event->type, event->state, _some_magic_widget_has_focus,
227 gtk_widget_get_name (widget), show_gdk_event_state (event->state), gdk_keyval_name (event->keyval)
228 )
229 );
230
231 if (event->keyval == GDK_Shift_R) {
232 keyval = GDK_Shift_L;
233
234 } else if (event->keyval == GDK_Control_R) {
235 keyval = GDK_Control_L;
236
237 } else {
238 keyval = event->keyval;
239 }
240
241 if (event->state & ScrollZoomVerticalModifier) {
242 /* There is a special and rather hacky situation in Editor which makes
243 it useful to know when the modifier key for vertical zoom has been
244 released, so emit a signal here (see Editor::_stepping_axis_view).
245 Note that the state bit for the modifier key is set for the key-up
246 event when the modifier is released, but not the key-down when it
247 is pressed, so we get here on key-up, which is what we want.
248 */
249 ZoomVerticalModifierReleased (); /* EMIT SIGNAL */
250 }
251
252 if (event->type == GDK_KEY_PRESS) {
253
254 if (find (state.begin(), state.end(), keyval) == state.end()) {
255 state.push_back (keyval);
256 sort (state.begin(), state.end());
257
258 } else {
259
260 /* key is already down. if its also used for release,
261 prevent auto-repeat events.
262 */
263
264 #if 0
265 /* August 2015: we don't have any release bindings
266 */
267
268 for (map<AccelKey,two_strings,AccelKeyLess>::iterator k = release_keys.begin(); k != release_keys.end(); ++k) {
269
270 const AccelKey& ak (k->first);
271
272 if (keyval == ak.get_key() && (Gdk::ModifierType)((event->state & Keyboard::RelevantModifierKeyMask) | Gdk::RELEASE_MASK) == ak.get_mod()) {
273 DEBUG_TRACE (DEBUG::Keyboard, "Suppress auto repeat\n");
274 ret = true;
275 break;
276 }
277 }
278 #endif
279 }
280 }
281
282 if (event->type == GDK_KEY_RELEASE) {
283
284 State::iterator k = find (state.begin(), state.end(), keyval);
285
286 if (k != state.end()) {
287 /* this cannot change the ordering, so need to sort */
288 state.erase (k);
289 if (state.empty()) {
290 DEBUG_TRACE (DEBUG::Keyboard, "no keys down\n");
291 } else {
292 #ifndef NDEBUG
293 if (DEBUG_ENABLED(DEBUG::Keyboard)) {
294 DEBUG_STR_DECL(a);
295 DEBUG_STR_APPEND(a, "keyboard, keys still down: ");
296 for (State::iterator i = state.begin(); i != state.end(); ++i) {
297 DEBUG_STR_APPEND(a, gdk_keyval_name (*i));
298 DEBUG_STR_APPEND(a, ',');
299 }
300 DEBUG_STR_APPEND(a, '\n');
301 DEBUG_TRACE (DEBUG::Keyboard, DEBUG_STR(a).str());
302 }
303 #endif /* NDEBUG */
304 }
305 }
306
307 if (modifier_state_equals (event->state, PrimaryModifier)) {
308
309 /* Special keys that we want to handle in
310 any dialog, no matter whether it uses
311 the regular set of accelerators or not
312 */
313
314 switch (event->keyval) {
315 case close_window_key:
316 if (close_current_dialog ()) {
317 ret = true;
318 }
319 break;
320 }
321 }
322 }
323
324 DEBUG_TRACE (DEBUG::Keyboard, string_compose ("snooper returns %1\n", ret));
325
326 return ret;
327 }
328
329 void
reset_relevant_modifier_key_mask()330 Keyboard::reset_relevant_modifier_key_mask ()
331 {
332 RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
333
334 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | PrimaryModifier);
335 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | SecondaryModifier);
336 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | TertiaryModifier);
337 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | Level4Modifier);
338 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | CopyModifier);
339 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | RangeSelectModifier);
340
341 gtk_accelerator_set_default_mod_mask (RelevantModifierKeyMask);
342
343 RelevantModifierKeysChanged(); /* EMIT SIGNAL */
344 }
345
346 bool
close_current_dialog()347 Keyboard::close_current_dialog ()
348 {
349 if (current_window) {
350
351 HideMightMeanQuit (current_window); /* EMIT SIGNAL */
352
353 current_window->hide ();
354 current_window = 0;
355
356 if (pre_dialog_active_window) {
357 pre_dialog_active_window->present ();
358 pre_dialog_active_window = 0;
359 }
360
361 return true;
362 }
363
364 return false;
365 }
366
367 bool
catch_user_event_for_pre_dialog_focus(GdkEvent * ev,Gtk::Window * w)368 Keyboard::catch_user_event_for_pre_dialog_focus (GdkEvent* ev, Gtk::Window* w)
369 {
370 switch (ev->type) {
371 case GDK_BUTTON_PRESS:
372 case GDK_BUTTON_RELEASE:
373 case GDK_KEY_PRESS:
374 case GDK_KEY_RELEASE:
375 pre_dialog_active_window = w;
376 break;
377
378 case GDK_FOCUS_CHANGE:
379 if (ev->focus_change.in) {
380 pre_dialog_active_window = w;
381 }
382 break;
383
384 default:
385 break;
386 }
387 return false;
388 }
389
390 bool
key_is_down(uint32_t keyval)391 Keyboard::key_is_down (uint32_t keyval)
392 {
393 return find (state.begin(), state.end(), keyval) != state.end();
394 }
395
396 bool
enter_window(GdkEventCrossing *,Gtk::Window * win)397 Keyboard::enter_window (GdkEventCrossing *, Gtk::Window* win)
398 {
399 current_window = win;
400 DEBUG_TRACE (DEBUG::Keyboard, string_compose ("Entering window, title = %1\n", win->get_title()));
401 return false;
402 }
403
404 bool
leave_window(GdkEventCrossing * ev,Gtk::Window *)405 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* /*win*/)
406 {
407 if (ev) {
408 switch (ev->detail) {
409 case GDK_NOTIFY_INFERIOR:
410 DEBUG_TRACE (DEBUG::Keyboard, "INFERIOR crossing ... out\n");
411 break;
412
413 case GDK_NOTIFY_VIRTUAL:
414 DEBUG_TRACE (DEBUG::Keyboard, "VIRTUAL crossing ... out\n");
415 /* fallthrough */
416
417 default:
418 DEBUG_TRACE (DEBUG::Keyboard, "REAL crossing ... out\n");
419 DEBUG_TRACE (DEBUG::Keyboard, "Clearing current target\n");
420 state.clear ();
421 current_window = 0;
422 }
423 } else {
424 DEBUG_TRACE (DEBUG::Keyboard, "LEAVE window without event\n");
425 current_window = 0;
426 }
427
428 return false;
429 }
430
431 bool
focus_in_window(GdkEventFocus *,Gtk::Window * win)432 Keyboard::focus_in_window (GdkEventFocus *, Gtk::Window* win)
433 {
434 current_window = win;
435 DEBUG_TRACE (DEBUG::Keyboard, string_compose ("Focusing in window, title = %1\n", win->get_title()));
436 return false;
437 }
438
439 bool
focus_out_window(GdkEventFocus * ev,Gtk::Window * win)440 Keyboard::focus_out_window (GdkEventFocus * ev, Gtk::Window* win)
441 {
442 if (ev) {
443 state.clear ();
444 current_window = 0;
445 } else {
446 if (win == current_window) {
447 current_window = 0;
448 }
449 }
450
451 DEBUG_TRACE (DEBUG::Keyboard, string_compose ("Foucusing out window, title = %1\n", win->get_title()));
452
453 return false;
454 }
455
456 void
set_edit_button(guint but)457 Keyboard::set_edit_button (guint but)
458 {
459 edit_but = but;
460 }
461
462 void
set_edit_modifier(guint mod)463 Keyboard::set_edit_modifier (guint mod)
464 {
465 edit_mod = mod;
466 reset_relevant_modifier_key_mask();
467 }
468
469 void
set_delete_button(guint but)470 Keyboard::set_delete_button (guint but)
471 {
472 delete_but = but;
473 }
474
475 void
set_delete_modifier(guint mod)476 Keyboard::set_delete_modifier (guint mod)
477 {
478 delete_mod = mod;
479 reset_relevant_modifier_key_mask();
480 }
481
482 void
set_insert_note_button(guint but)483 Keyboard::set_insert_note_button (guint but)
484 {
485 insert_note_but = but;
486 }
487
488 void
set_insert_note_modifier(guint mod)489 Keyboard::set_insert_note_modifier (guint mod)
490 {
491 insert_note_mod = mod;
492 reset_relevant_modifier_key_mask();
493 }
494
495
496 void
set_modifier(uint32_t newval,uint32_t & var)497 Keyboard::set_modifier (uint32_t newval, uint32_t& var)
498 {
499 var = newval;
500 reset_relevant_modifier_key_mask();
501 }
502
503 void
set_snap_modifier(guint mod)504 Keyboard::set_snap_modifier (guint mod)
505 {
506 snap_mod = mod;
507 reset_relevant_modifier_key_mask();
508 }
509
510 void
set_snap_delta_modifier(guint mod)511 Keyboard::set_snap_delta_modifier (guint mod)
512 {
513 snap_delta_mod = mod;
514 reset_relevant_modifier_key_mask();
515 }
516
517 bool
is_edit_event(GdkEventButton * ev)518 Keyboard::is_edit_event (GdkEventButton *ev)
519 {
520 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
521 (ev->button == Keyboard::edit_button()) &&
522 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
523 }
524
525 bool
is_insert_note_event(GdkEventButton * ev)526 Keyboard::is_insert_note_event (GdkEventButton *ev)
527 {
528 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
529 (ev->button == Keyboard::insert_note_button()) &&
530 ((ev->state & RelevantModifierKeyMask) == Keyboard::insert_note_modifier());
531 }
532
533 bool
is_button2_event(GdkEventButton * ev)534 Keyboard::is_button2_event (GdkEventButton* ev)
535 {
536 #ifdef __APPLE__
537 return (ev->button == 2) ||
538 ((ev->button == 1) &&
539 ((ev->state & Keyboard::button2_modifiers) == Keyboard::button2_modifiers));
540 #else
541 return ev->button == 2;
542 #endif
543 }
544
545 bool
is_delete_event(GdkEventButton * ev)546 Keyboard::is_delete_event (GdkEventButton *ev)
547 {
548 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
549 (ev->button == Keyboard::delete_button()) &&
550 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
551 }
552
553 bool
is_context_menu_event(GdkEventButton * ev)554 Keyboard::is_context_menu_event (GdkEventButton *ev)
555 {
556 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
557 (ev->button == 3) &&
558 ((ev->state & RelevantModifierKeyMask) == 0);
559 }
560
561 bool
no_modifiers_active(guint state)562 Keyboard::no_modifiers_active (guint state)
563 {
564 return (state & RelevantModifierKeyMask) == 0;
565 }
566
567 bool
modifier_state_contains(guint state,ModifierMask mask)568 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
569 {
570 return (state & mask) == (guint) mask;
571 }
572
573 bool
modifier_state_equals(guint state,ModifierMask mask)574 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
575 {
576 return (state & RelevantModifierKeyMask) == (guint) mask;
577 }
578
579 void
keybindings_changed()580 Keyboard::keybindings_changed ()
581 {
582 if (Keyboard::can_save_keybindings) {
583 Keyboard::bindings_changed_after_save_became_legal = true;
584 }
585
586 Keyboard::save_keybindings ();
587 }
588
589 void
set_can_save_keybindings(bool yn)590 Keyboard::set_can_save_keybindings (bool yn)
591 {
592 can_save_keybindings = yn;
593 }
594
595 void
save_keybindings()596 Keyboard::save_keybindings ()
597 {
598 if (can_save_keybindings && bindings_changed_after_save_became_legal) {
599 /* Call to specific implementation to save bindings to path */
600 store_keybindings (user_keybindings_path);
601 }
602 }
603
604 bool
load_keybindings(string const & path)605 Keyboard::load_keybindings (string const & path)
606 {
607 try {
608 info << "Loading bindings from " << path << endl;
609
610 /* Call to specific implementation to load bindings from path */
611 read_keybindings (path);
612
613 _current_binding_name = _("Unknown");
614
615 for (map<string,string>::iterator x = binding_files.begin(); x != binding_files.end(); ++x) {
616 if (path == x->second) {
617 _current_binding_name = x->first;
618 break;
619 }
620 }
621
622
623 } catch (...) {
624 error << string_compose (_("key bindings file not found at \"%2\" or contains errors."), path)
625 << endmsg;
626 return false;
627 }
628
629 return true;
630 }
631
632 int
read_keybindings(string const & path)633 Keyboard::read_keybindings (string const & path)
634 {
635 XMLTree tree;
636
637 if (!tree.read (path.c_str())) {
638 return -1;
639 }
640
641 /* toplevel node is "BindingSet; children are "Bindings" */
642
643 XMLNodeList const& children = tree.root()->children();
644
645 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
646 XMLNode const * child = *i;
647 if (child->name() == X_("Bindings")) {
648 XMLProperty const* name = child->property (X_("name"));
649 if (!name) {
650 warning << _("Keyboard binding found without a name") << endmsg;
651 continue;
652 }
653
654 Bindings* b = new Bindings (name->value());
655 b->load (**i);
656 }
657 }
658
659 return 0;
660 }
661
662 int
store_keybindings(string const & path)663 Keyboard::store_keybindings (string const & path)
664 {
665 XMLNode* node = new XMLNode (X_("BindingSet"));
666 XMLNode* bnode;
667 int ret = 0;
668
669 DEBUG_TRACE (DEBUG::Bindings, string_compose ("save bindings to %1\n", path));
670
671 for (list<Bindings*>::const_iterator b = Bindings::bindings.begin(); b != Bindings::bindings.end(); ++b) {
672 bnode = new XMLNode (X_("Bindings"));
673 bnode->set_property (X_("name"), (*b)->name());
674 (*b)->save (*bnode);
675 node->add_child_nocopy (*bnode);
676 }
677
678 XMLTree tree;
679 tree.set_root (node); /* tree now owns root and will delete it */
680
681 if (!tree.write (path)) {
682 error << string_compose (_("Cannot save key bindings to %1"), path) << endmsg;
683 ret = -1;
684 }
685
686 return ret;
687 }
688
689 int
reset_bindings()690 Keyboard::reset_bindings ()
691 {
692 if (Glib::file_test (user_keybindings_path, Glib::FILE_TEST_EXISTS)) {
693
694 string new_path = user_keybindings_path;
695 new_path += ".old";
696
697 if (::g_rename (user_keybindings_path.c_str(), new_path.c_str())) {
698 error << string_compose (_("Cannot rename your own keybinding file (%1)"), strerror (errno)) << endmsg;
699 return -1;
700 }
701 }
702
703 {
704 PBD::Unwinder<bool> uw (can_save_keybindings, false);
705 Bindings::reset_bindings ();
706 setup_keybindings ();
707 Bindings::associate_all ();
708 }
709
710 return 0;
711 }
712