diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2015-08-05 10:56:36 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2016-02-22 15:31:23 -0500 |
commit | 36023db8aa63d59d475c137e6b394f30e8cde1b7 (patch) | |
tree | 75bacdda3abf7f94f651dc34bbed567c2e140741 /libs/gtkmm2ext/bindings.cc | |
parent | 1b5247ebb9ef89b922c3c0b2a8194d510bdd75e1 (diff) |
change/extend/rework Bindings API to allow replacement and provide stub/hook/call to save bindings
Diffstat (limited to 'libs/gtkmm2ext/bindings.cc')
-rw-r--r-- | libs/gtkmm2ext/bindings.cc | 156 |
1 files changed, 134 insertions, 22 deletions
diff --git a/libs/gtkmm2ext/bindings.cc b/libs/gtkmm2ext/bindings.cc index 8803edc540..260d65101a 100644 --- a/libs/gtkmm2ext/bindings.cc +++ b/libs/gtkmm2ext/bindings.cc @@ -289,8 +289,63 @@ Bindings::activate (KeyboardKey kb, Operation op) return true; } +bool +Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save) +{ + if (!action_map) { + return false; + } + + /* We have to search the existing binding map by both action and + * keybinding, because the following are possible: + * + * - key is already used for a different action + * - action has a different binding + * - key is not used + * - action is not bound + */ + + RefPtr<Action> action = action_map->find_action (action_name); + + if (!action) { + return false; + } + + KeybindingMap* kbm = 0; + + switch (op) { + case Press: + kbm = &press_bindings; + break; + case Release: + kbm = &release_bindings; + break; + } + + KeybindingMap::iterator k = kbm->find (kb); + + if (k != kbm->end()) { + kbm->erase (k); + } + + /* now linear search by action */ + + for (k = kbm->begin(); k != kbm->end(); ++k) { + if (k->second == action) { + kbm->erase (k); + break; + } + } + + add (kb, op, action, can_save); + + /* for now, this never fails */ + + return true; +} + void -Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what) +Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what, bool can_save) { KeybindingMap* kbm = 0; @@ -312,10 +367,20 @@ Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what) k->second = what; } + /* GTK has the useful feature of showing key bindings for actions in + * menus. As of August 2015, we have no interest in trying to + * reimplement this functionality, so we will use it even though we no + * longer use GTK accelerators for handling key events. To do this, we + * need to make sure that there is a fully populated GTK AccelMap set + * up with all bindings/actions. + */ + Gtk::AccelKey gtk_key; - /* tweak the binding so that GTK will accept it and display something - * acceptable + /* tweak the modifier used in the binding so that GTK will accept it + * and display something acceptable. The actual keyval should display + * correctly even if it involves a key that GTK would not allow + * as an accelerator. */ uint32_t gtk_legal_keyval = kb.key(); @@ -326,6 +391,18 @@ Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what) bool entry_exists = Gtk::AccelMap::lookup_entry (what->get_accel_path(), gtk_key); if (!entry_exists || gtk_key.get_key() == 0) { + + /* there is a trick happening here. It turns out that + * gtk_accel_map_add_entry() performs no validation checks on + * the accelerator keyval. This means we can use it to define + * ANY accelerator, even if they violate GTK's rules + * (e.g. about not using navigation keys). This works ONLY when + * the entry in the GTK accelerator map has not already been + * added. The entries will be added by the GTK UIManager when + * building menus, so this code must be called before that + * happens. + */ + Gtk::AccelMap::add_entry (what->get_accel_path(), gtk_binding.key(), (Gdk::ModifierType) gtk_binding.state()); @@ -336,10 +413,14 @@ Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what) if (!Gtk::AccelMap::lookup_entry (what->get_accel_path(), gtk_key) || gtk_key.get_key() == 0) { cerr << "GTK binding using " << gtk_binding << " failed for " << what->get_accel_path() << " existing = " << gtk_key.get_key() << " + " << gtk_key.get_mod() << endl; } + + if (can_save) { + Keyboard::save_keybindings (); + } } void -Bindings::remove (KeyboardKey kb, Operation op) +Bindings::remove (KeyboardKey kb, Operation op, bool can_save) { KeybindingMap* kbm = 0; @@ -357,6 +438,36 @@ Bindings::remove (KeyboardKey kb, Operation op) if (k != kbm->end()) { kbm->erase (k); } + + if (can_save) { + Keyboard::save_keybindings (); + } +} + +void +Bindings::remove (RefPtr<Action> action, Operation op, bool can_save) +{ + KeybindingMap* kbm = 0; + + switch (op) { + case Press: + kbm = &press_bindings; + break; + case Release: + kbm = &release_bindings; + break; + } + + for (KeybindingMap::iterator k = kbm->begin(); k != kbm->end(); ++k) { + if (k->second == action) { + kbm->erase (k); + break; + } + } + + if (can_save) { + Keyboard::save_keybindings (); + } } bool @@ -623,11 +734,11 @@ Bindings::load (const XMLNode& node) } void -Bindings::get_all_actions (std::vector<std::string>& names, - std::vector<std::string>& paths, +Bindings::get_all_actions (std::vector<std::string>& paths, + std::vector<std::string>& labels, std::vector<std::string>& tooltips, std::vector<std::string>& keys, - std::vector<KeyboardKey>& bindings) + std::vector<RefPtr<Action> >& actions) { if (!action_map) { return; @@ -644,30 +755,31 @@ Bindings::get_all_actions (std::vector<std::string>& names, /* get a list of all actions */ - ActionMap::Actions actions; - action_map->get_actions (actions); + ActionMap::Actions all_actions; + action_map->get_actions (all_actions); - for (ActionMap::Actions::const_iterator act = actions.begin(); act != actions.end(); ++act) { - names.push_back ((*act)->get_name()); + for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) { + paths.push_back ((*act)->get_accel_path()); + labels.push_back ((*act)->get_label()); tooltips.push_back ((*act)->get_tooltip()); ReverseMap::iterator r = rmap.find (*act); + if (r != rmap.end()) { keys.push_back (gtk_accelerator_get_label (r->second.key(), (GdkModifierType) r->second.state())); - bindings.push_back (r->second); } else { keys.push_back (string()); - bindings.push_back (KeyboardKey::null_key()); } + + actions.push_back (*act); } } - + void -Bindings::get_all_actions (std::vector<std::string>& groups, +Bindings::get_all_actions (std::vector<std::string>& names, std::vector<std::string>& paths, - std::vector<std::string>& tooltips, - std::vector<KeyboardKey>& bindings) + std::vector<std::string>& keys) { /* build a reverse map from actions to bindings */ @@ -684,15 +796,14 @@ Bindings::get_all_actions (std::vector<std::string>& groups, action_map->get_actions (actions); for (ActionMap::Actions::const_iterator act = actions.begin(); act != actions.end(); ++act) { - groups.push_back ((*act)->get_name()); + names.push_back ((*act)->get_name()); paths.push_back ((*act)->get_accel_path()); - tooltips.push_back ((*act)->get_tooltip()); ReverseMap::iterator r = rmap.find (*act); if (r != rmap.end()) { - bindings.push_back (r->second); + keys.push_back (gtk_accelerator_get_label (r->second.key(), (GdkModifierType) r->second.state())); } else { - bindings.push_back (KeyboardKey::null_key()); + keys.push_back (string()); } } } @@ -856,6 +967,7 @@ Bindings::remove_bindings_for_state (std::string const& name, Bindings& bindings } std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) { - return out << "Key " << k.key() << " (" << (k.key() > 0 ? gdk_keyval_name (k.key()) : "no-key") << ") state " << k.state(); + char const *gdk_name = gdk_keyval_name (k.key()); + return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state " << k.state(); } |