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