provide Tabbable::change_visibility(), which has slightly odd semantics that are...
[ardour.git] / libs / gtkmm2ext / bindings.cc
index 4c9184c0c2fba8495231528f8c8417716ade05cb..667c2cfaaae544160c708c663f11c34b3550dc55 100644 (file)
@@ -43,13 +43,17 @@ using namespace Gtkmm2ext;
 using namespace PBD;
 
 list<Bindings*> Bindings::bindings; /* global. Gulp */
-uint32_t Bindings::_ignored_state = 0;
 list<ActionMap*> ActionMap::action_maps; /* global. Gulp */
 PBD::Signal1<void,Bindings*> Bindings::BindingsChanged;
 
 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
 {
-        uint32_t ignore = Bindings::ignored_state();
+        uint32_t ignore = ~Keyboard::RelevantModifierKeyMask;
+
+        /* this is a slightly wierd test that relies on
+         * gdk_keyval_is_{upper,lower}() returning true for keys that have no
+         * case-sensitivity. This covers mostly non-alphanumeric keys.
+         */
 
         if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
                 /* key is not subject to case, so ignore SHIFT
@@ -138,7 +142,7 @@ MouseButton::name () const
 
 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
 {
-        uint32_t ignore = Bindings::ignored_state();
+        uint32_t ignore = ~Keyboard::RelevantModifierKeyMask;
 
         _val = (state & ~ignore);
         _val <<= 32;
@@ -155,8 +159,20 @@ KeyboardKey::display_label () const
        /* This magically returns a string that will display the right thing
         *  on all platforms, notably the command key on OS X.
         */
-       
-       return gtk_accelerator_get_label (key(), (GdkModifierType) state());
+
+        uint32_t mod = state();
+
+#ifdef __APPLE__
+                /* We use both bits (MOD2|META) for Primary on OS X,
+                 * but we don't want MOD2 showing up in listings.
+                 */
+
+                if (mod & GDK_MOD2_MASK) {
+                        mod &= ~GDK_MOD2_MASK;
+                }
+#endif
+
+       return gtk_accelerator_get_label (key(), (GdkModifierType) mod);
 }
 
 string
@@ -200,7 +216,7 @@ KeyboardKey::name () const
                /* fail! */
                return string();
         }
-               
+
         return str;
 }
 
@@ -227,7 +243,7 @@ KeyboardKey::make_key (const string& str, KeyboardKey& k)
 
         string::size_type lastmod = str.find_last_of ('-');
         guint keyval;
-        
+
         if (lastmod == string::npos) {
                 keyval = gdk_keyval_from_name (str.c_str());
         } else {
@@ -266,7 +282,7 @@ KeyboardKey
 Bindings::get_binding_for_action (RefPtr<Action> action, Operation& op)
 {
        const string action_name = ardour_action_name (action);
-       
+
         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
 
                /* option one: action has already been associated with the
@@ -285,11 +301,11 @@ Bindings::get_binding_for_action (RefPtr<Action> action, Operation& op)
                        k->second.action = _action_map->find_action (action_name);
                        return k->first;
                }
-                
+
         }
 
         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
-               
+
                /* option one: action has already been associated with the
                 * binding
                 */
@@ -306,16 +322,22 @@ Bindings::get_binding_for_action (RefPtr<Action> action, Operation& op)
                         k->second.action = _action_map->find_action (action_name);
                         return k->first;
                 }
-                
+
         }
-        
+
         return KeyboardKey::null_key();
 }
 
 void
 Bindings::set_action_map (ActionMap& actions)
 {
+       if (_action_map) {
+               _action_map->set_bindings (0);
+       }
+
        _action_map = &actions;
+       _action_map->set_bindings (this);
+
        dissociate ();
        associate ();
 }
@@ -351,7 +373,7 @@ Bindings::activate (KeyboardKey kb, Operation op)
                 kbm = &release_bindings;
                 break;
         }
-        
+
         KeybindingMap::iterator k = kbm->find (kb);
 
         if (k == kbm->end()) {
@@ -361,7 +383,7 @@ Bindings::activate (KeyboardKey kb, Operation op)
         }
 
         RefPtr<Action> action;
-        
+
         if (k->second.action) {
                action = k->second.action;
         } else {
@@ -389,14 +411,13 @@ Bindings::associate ()
        if (!_action_map) {
                return;
        }
-       
+
        for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
                k->second.action = _action_map->find_action (k->second.action_name);
                if (k->second.action) {
-                       cerr << "push to GTK " << k->first << ' ' << k->second.action_name << endl;
                        push_to_gtk (k->first, k->second.action);
                } else {
-                       cerr << "didn't find " << k->second.action_name << endl;
+                       cerr << _name << " didn't find " << k->second.action_name << " in " << _action_map->name() << endl;
                }
        }
 
@@ -406,7 +427,7 @@ Bindings::associate ()
        }
 
        MouseButtonBindingMap::iterator b;
-       
+
        for (b = button_press_bindings.begin(); b != button_press_bindings.end(); ++b) {
                b->second.action = _action_map->find_action (b->second.action_name);
        }
@@ -437,14 +458,10 @@ Bindings::push_to_gtk (KeyboardKey kb, RefPtr<Action> what)
          * 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. 
+         * up with all bindings/actions.
          */
 
-       uint32_t gtk_legal_keyval = kb.key();
-       possibly_translate_keyval_to_make_legal_accelerator (gtk_legal_keyval);
-       KeyboardKey gtk_binding (kb.state(), gtk_legal_keyval);
        Gtk::AccelKey gtk_key;
-       
        bool entry_exists = Gtk::AccelMap::lookup_entry (what->get_accel_path(), gtk_key);
 
         if (!entry_exists) {
@@ -460,8 +477,8 @@ Bindings::push_to_gtk (KeyboardKey kb, RefPtr<Action> what)
                 * happens.
                 */
 
-               Gtk::AccelMap::add_entry (what->get_accel_path(), gtk_binding.key(), (Gdk::ModifierType) gtk_binding.state());
-        }
+               Gtk::AccelMap::add_entry (what->get_accel_path(), kb.key(), (Gdk::ModifierType) kb.state());
+        } 
 }
 
 bool
@@ -479,7 +496,7 @@ Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, boo
         *   - key is not used
         *   - action is not bound
         */
-       
+
        RefPtr<Action> action = _action_map->find_action (action_name);
 
         if (!action) {
@@ -515,7 +532,7 @@ Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, boo
         add (kb, op, action_name, can_save);
 
         /* for now, this never fails */
-        
+
         return true;
 }
 
@@ -537,9 +554,9 @@ Bindings::add (KeyboardKey kb, Operation op, string const& action_name, bool can
 
         if (k != kbm->end()) {
                kbm->erase (k);
-        } 
+        }
         KeybindingMap::value_type new_pair (kb, ActionInfo (action_name));
-        
+
         kbm->insert (new_pair).first;
 
         if (can_save) {
@@ -626,7 +643,7 @@ Bindings::activate (MouseButton bb, Operation op)
         }
 
         RefPtr<Action> action;
-        
+
         if (b->second.action) {
                action = b->second.action;
         } else {
@@ -742,7 +759,7 @@ bool
 Bindings::load (XMLNode const& node)
 {
         const XMLNodeList& children (node.children());
-        
+
         press_bindings.clear ();
         release_bindings.clear ();
 
@@ -824,7 +841,7 @@ Bindings::get_all_actions (std::vector<std::string>& paths,
 
        ActionMap::Actions all_actions;
        _action_map->get_actions (all_actions);
-       
+
        for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
 
                paths.push_back ((*act)->get_accel_path());
@@ -843,43 +860,6 @@ Bindings::get_all_actions (std::vector<std::string>& paths,
        }
 }
 
-void
-Bindings::get_all_actions (std::vector<std::string>& names,
-                           std::vector<std::string>& paths,
-                           std::vector<std::string>& keys)
-{
-       if (!_action_map) {
-               return;
-       }
-
-       /* build a reverse map from actions to bindings */
-
-       typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
-       ReverseMap rmap;
-
-       for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
-               rmap.insert (make_pair (k->second.action, k->first));
-       }
-
-       /* get a list of all actions */
-
-       ActionMap::Actions all_actions;
-       _action_map->get_actions (all_actions);
-       
-       for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
-               
-               names.push_back ((*act)->get_name());
-               paths.push_back ((*act)->get_accel_path());
-
-               ReverseMap::iterator r = rmap.find (*act);
-               if (r != rmap.end()) {
-                       keys.push_back (r->second.display_label());
-               } else {
-                       keys.push_back (string());
-               }
-       }
-}
-
 Bindings*
 Bindings::get_bindings (string const& name, ActionMap& map)
 {
@@ -903,6 +883,24 @@ Bindings::associate_all ()
 
 /*==========================================ACTION MAP =========================================*/
 
+ActionMap::ActionMap (string const & name)
+       : _name (name)
+       , _bindings (0)
+{
+       action_maps.push_back (this);
+}
+
+ActionMap::~ActionMap ()
+{
+       action_maps.remove (this);
+}
+
+void
+ActionMap::set_bindings (Bindings* b)
+{
+       _bindings = b;
+}
+
 void
 ActionMap::get_actions (ActionMap::Actions& acts)
 {
@@ -931,10 +929,10 @@ ActionMap::create_action_group (const string& name)
        /* this is one of the places where our own Action management code
           has to touch the GTK one, because we want the GtkUIManager to
           be able to create widgets (particularly Menus) from our actions.
-          
+
           This is a a necessary step for that to happen.
        */
-       
+
        if (g) {
                ActionManager::ui_manager->insert_action_group (g);
        }
@@ -942,7 +940,7 @@ ActionMap::create_action_group (const string& name)
        return g;
 }
 
-RefPtr<Action> 
+RefPtr<Action>
 ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
 {
         string fullpath;
@@ -952,7 +950,7 @@ ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const c
         fullpath = group->get_name();
         fullpath += '/';
         fullpath += name;
-        
+
         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
                group->add (act);
                return act;
@@ -962,7 +960,7 @@ ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const c
         return RefPtr<Action> ();
 }
 
-RefPtr<Action> 
+RefPtr<Action>
 ActionMap::register_action (RefPtr<ActionGroup> group,
                             const char* name, const char* label, sigc::slot<void> sl)
 {
@@ -983,17 +981,17 @@ ActionMap::register_action (RefPtr<ActionGroup> group,
         return RefPtr<Action>();
 }
 
-RefPtr<Action> 
+RefPtr<Action>
 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
                                   Gtk::RadioAction::Group& rgroup,
-                                  const char* name, const char* label, 
+                                  const char* name, const char* label,
                                   sigc::slot<void> sl)
 {
         string fullpath;
 
         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
-        
+
         fullpath = group->get_name();
         fullpath += '/';
         fullpath += name;
@@ -1007,10 +1005,10 @@ ActionMap::register_radio_action (RefPtr<ActionGroup> group,
         return RefPtr<Action>();
 }
 
-RefPtr<Action> 
+RefPtr<Action>
 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
                                   Gtk::RadioAction::Group& rgroup,
-                                  const char* name, const char* label, 
+                                  const char* name, const char* label,
                                   sigc::slot<void,GtkAction*> sl,
                                   int value)
 {
@@ -1034,7 +1032,7 @@ ActionMap::register_radio_action (RefPtr<ActionGroup> group,
         return RefPtr<Action>();
 }
 
-RefPtr<Action> 
+RefPtr<Action>
 ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
                                    const char* name, const char* label, sigc::slot<void> sl)
 {
@@ -1055,8 +1053,49 @@ ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
         return RefPtr<Action>();
 }
 
+void
+ActionMap::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<RefPtr<Action> >& actions)
+{
+       for (list<ActionMap*>::const_iterator map = action_maps.begin(); map != action_maps.end(); ++map) {
+
+               ActionMap::Actions these_actions;
+               (*map)->get_actions (these_actions);
+
+               for (ActionMap::Actions::const_iterator act = these_actions.begin(); act != these_actions.end(); ++act) {
+
+                       paths.push_back ((*act)->get_accel_path());
+                       labels.push_back ((*act)->get_label());
+                       tooltips.push_back ((*act)->get_tooltip());
+                       actions.push_back (*act);
+
+                       Bindings* bindings = (*map)->bindings();
+
+                       if (bindings) {
+
+                               KeyboardKey key;
+                               Bindings::Operation op;
+
+                               key = bindings->get_binding_for_action (*act, op);
+
+                               if (key == KeyboardKey::null_key()) {
+                                       keys.push_back (string());
+                               } else {
+                                       keys.push_back (key.display_label());
+                               }
+                       } else {
+                               keys.push_back (string());
+                       }
+               }
+
+               these_actions.clear ();
+       }
+}
+
 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) {
        char const *gdk_name = gdk_keyval_name (k.key());
-       return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state " << k.state();
+       return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state " << hex << k.state() << dec;
 }
-