more changes to Bindings, Keyboard APIs
[ardour.git] / libs / gtkmm2ext / bindings.cc
1 /*
2     Copyright (C) 2012 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 <iostream>
21
22 #include "pbd/gstdio_compat.h"
23 #include <gtkmm/accelmap.h>
24 #include <gtkmm/uimanager.h>
25
26 #include "pbd/convert.h"
27 #include "pbd/debug.h"
28 #include "pbd/error.h"
29 #include "pbd/xml++.h"
30
31 #include "gtkmm2ext/actions.h"
32 #include "gtkmm2ext/bindings.h"
33 #include "gtkmm2ext/debug.h"
34 #include "gtkmm2ext/keyboard.h"
35 #include "gtkmm2ext/utils.h"
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace Glib;
41 using namespace Gtk;
42 using namespace Gtkmm2ext;
43 using namespace PBD;
44
45 list<Bindings*> Bindings::bindings; /* global. Gulp */
46 uint32_t Bindings::_ignored_state = 0;
47 list<ActionMap*> ActionMap::action_maps; /* global. Gulp */
48 PBD::Signal1<void,Bindings*> Bindings::BindingsChanged;
49
50 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
51 {
52         uint32_t ignore = Bindings::ignored_state();
53
54         if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
55                 /* key is not subject to case, so ignore SHIFT
56                  */
57                 ignore |= GDK_SHIFT_MASK;
58         }
59
60         _val = (state & ~ignore);
61         _val <<= 32;
62         _val |= keycode;
63 };
64
65 bool
66 MouseButton::make_button (const string& str, MouseButton& b)
67 {
68         int s = 0;
69
70         if (str.find ("Primary") != string::npos) {
71                 s |= Keyboard::PrimaryModifier;
72         }
73
74         if (str.find ("Secondary") != string::npos) {
75                 s |= Keyboard::SecondaryModifier;
76         }
77
78         if (str.find ("Tertiary") != string::npos) {
79                 s |= Keyboard::TertiaryModifier;
80         }
81
82         if (str.find ("Level4") != string::npos) {
83                 s |= Keyboard::Level4Modifier;
84         }
85
86         string::size_type lastmod = str.find_last_of ('-');
87         uint32_t button_number;
88
89         if (lastmod == string::npos) {
90                 button_number = PBD::atoi (str);
91         } else {
92                 button_number = PBD::atoi (str.substr (lastmod+1));
93         }
94
95         b = MouseButton (s, button_number);
96         return true;
97 }
98
99 string
100 MouseButton::name () const
101 {
102         int s = state();
103
104         string str;
105
106         if (s & Keyboard::PrimaryModifier) {
107                 str += "Primary";
108         }
109         if (s & Keyboard::SecondaryModifier) {
110                 if (!str.empty()) {
111                         str += '-';
112                 }
113                 str += "Secondary";
114         }
115         if (s & Keyboard::TertiaryModifier) {
116                 if (!str.empty()) {
117                         str += '-';
118                 }
119                 str += "Tertiary";
120         }
121         if (s & Keyboard::Level4Modifier) {
122                 if (!str.empty()) {
123                         str += '-';
124                 }
125                 str += "Level4";
126         }
127
128         if (!str.empty()) {
129                 str += '-';
130         }
131
132         char buf[16];
133         snprintf (buf, sizeof (buf), "%u", button());
134         str += buf;
135
136         return str;
137 }
138
139 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
140 {
141         uint32_t ignore = Bindings::ignored_state();
142
143         _val = (state & ~ignore);
144         _val <<= 32;
145         _val |= keycode;
146 }
147
148 string
149 KeyboardKey::display_label () const
150 {
151         if (key() == 0) {
152                 return string();
153         }
154
155         /* This magically returns a string that will display the right thing
156          *  on all platforms, notably the command key on OS X.
157          */
158         
159         return gtk_accelerator_get_label (key(), (GdkModifierType) state());
160 }
161
162 string
163 KeyboardKey::name () const
164 {
165         int s = state();
166
167         string str;
168
169         if (s & Keyboard::PrimaryModifier) {
170                 str += "Primary";
171         }
172         if (s & Keyboard::SecondaryModifier) {
173                 if (!str.empty()) {
174                         str += '-';
175                 }
176                 str += "Secondary";
177         }
178         if (s & Keyboard::TertiaryModifier) {
179                 if (!str.empty()) {
180                         str += '-';
181                 }
182                 str += "Tertiary";
183         }
184         if (s & Keyboard::Level4Modifier) {
185                 if (!str.empty()) {
186                         str += '-';
187                 }
188                 str += "Level4";
189         }
190
191         if (!str.empty()) {
192                 str += '-';
193         }
194
195         char const *gdk_name = gdk_keyval_name (key());
196
197         if (gdk_name) {
198                 str += gdk_name;
199         } else {
200                 /* fail! */
201                 return string();
202         }
203                 
204         return str;
205 }
206
207 bool
208 KeyboardKey::make_key (const string& str, KeyboardKey& k)
209 {
210         int s = 0;
211
212         if (str.find ("Primary") != string::npos) {
213                 s |= Keyboard::PrimaryModifier;
214         }
215
216         if (str.find ("Secondary") != string::npos) {
217                 s |= Keyboard::SecondaryModifier;
218         }
219
220         if (str.find ("Tertiary") != string::npos) {
221                 s |= Keyboard::TertiaryModifier;
222         }
223
224         if (str.find ("Level4") != string::npos) {
225                 s |= Keyboard::Level4Modifier;
226         }
227
228         string::size_type lastmod = str.find_last_of ('-');
229         guint keyval;
230         
231         if (lastmod == string::npos) {
232                 keyval = gdk_keyval_from_name (str.c_str());
233         } else {
234                 keyval = gdk_keyval_from_name (str.substr (lastmod+1).c_str());
235         }
236
237         if (keyval == GDK_VoidSymbol || keyval == 0) {
238                 return false;
239         }
240
241         k = KeyboardKey (s, keyval);
242
243         return true;
244 }
245
246 Bindings::Bindings (std::string const& name)
247         : _name (name)
248         , _action_map (0)
249 {
250         bindings.push_back (this);
251 }
252
253 Bindings::~Bindings()
254 {
255         bindings.remove (this);
256 }
257
258 string
259 Bindings::ardour_action_name (RefPtr<Action> action)
260 {
261         /* Skip "<Actions>/" */
262         return action->get_accel_path ().substr (10);
263 }
264
265 KeyboardKey
266 Bindings::get_binding_for_action (RefPtr<Action> action, Operation& op)
267 {
268         const string action_name = ardour_action_name (action);
269         
270         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
271
272                 /* option one: action has already been associated with the
273                  * binding
274                  */
275
276                 if (k->second.action == action) {
277                         return k->first;
278                 }
279
280                 /* option two: action name matches, so lookup the action,
281                  * setup the association while we're here, and return the binding.
282                  */
283
284                 if (_action_map && k->second.action_name == action_name) {
285                         k->second.action = _action_map->find_action (action_name);
286                         return k->first;
287                 }
288                  
289         }
290
291         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
292                 
293                 /* option one: action has already been associated with the
294                  * binding
295                  */
296
297                 if (k->second.action == action) {
298                         return k->first;
299                 }
300
301                 /* option two: action name matches, so lookup the action,
302                  * setup the association while we're here, and return the binding.
303                  */
304
305                 if (_action_map && k->second.action_name == action_name) {
306                          k->second.action = _action_map->find_action (action_name);
307                          return k->first;
308                  }
309                  
310         }
311         
312         return KeyboardKey::null_key();
313 }
314
315 void
316 Bindings::set_action_map (ActionMap& actions)
317 {
318         _action_map = &actions;
319         dissociate ();
320         associate ();
321 }
322
323 bool
324 Bindings::empty_keys() const
325 {
326         return press_bindings.empty() && release_bindings.empty();
327 }
328
329 bool
330 Bindings::empty_mouse () const
331 {
332         return button_press_bindings.empty() && button_release_bindings.empty();
333 }
334
335 bool
336 Bindings::empty() const
337 {
338         return empty_keys() && empty_mouse ();
339 }
340
341 bool
342 Bindings::activate (KeyboardKey kb, Operation op)
343 {
344         KeybindingMap* kbm = 0;
345
346         switch (op) {
347         case Press:
348                 kbm = &press_bindings;
349                 break;
350         case Release:
351                 kbm = &release_bindings;
352                 break;
353         }
354         
355         KeybindingMap::iterator k = kbm->find (kb);
356
357         if (k == kbm->end()) {
358                 /* no entry for this key in the state map */
359                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("no binding for %1\n", kb));
360                 return false;
361         }
362
363         RefPtr<Action> action;
364         
365         if (k->second.action) {
366                 action = k->second.action;
367         } else {
368                 if (_action_map) {
369                         action = _action_map->find_action (k->second.action_name);
370                 }
371         }
372
373         if (action) {
374                 /* lets do it ... */
375                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("binding for %1: %2\n", kb, k->second.action_name));
376                 action->activate ();
377         }
378
379         /* return true even if the action could not be found */
380
381         return true;
382 }
383
384 void
385 Bindings::associate ()
386 {
387         KeybindingMap::iterator k;
388
389         if (!_action_map) {
390                 return;
391         }
392         
393         for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
394                 k->second.action = _action_map->find_action (k->second.action_name);
395                 if (k->second.action) {
396                         cerr << "push to GTK " << k->first << ' ' << k->second.action_name << endl;
397                         push_to_gtk (k->first, k->second.action);
398                 } else {
399                         cerr << "didn't find " << k->second.action_name << endl;
400                 }
401         }
402
403         for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
404                 k->second.action = _action_map->find_action (k->second.action_name);
405                 /* no working support in GTK for release bindings */
406         }
407
408         MouseButtonBindingMap::iterator b;
409         
410         for (b = button_press_bindings.begin(); b != button_press_bindings.end(); ++b) {
411                 b->second.action = _action_map->find_action (b->second.action_name);
412         }
413
414         for (b = button_release_bindings.begin(); b != button_release_bindings.end(); ++b) {
415                 b->second.action = _action_map->find_action (b->second.action_name);
416         }
417 }
418
419 void
420 Bindings::dissociate ()
421 {
422         KeybindingMap::iterator k;
423
424         for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
425                 k->second.action.clear ();
426         }
427         for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
428                 k->second.action.clear ();
429         }
430 }
431
432 void
433 Bindings::push_to_gtk (KeyboardKey kb, RefPtr<Action> what)
434 {
435         /* GTK has the useful feature of showing key bindings for actions in
436          * menus. As of August 2015, we have no interest in trying to
437          * reimplement this functionality, so we will use it even though we no
438          * longer use GTK accelerators for handling key events. To do this, we
439          * need to make sure that there is a fully populated GTK AccelMap set
440          * up with all bindings/actions. 
441          */
442
443         uint32_t gtk_legal_keyval = kb.key();
444         possibly_translate_keyval_to_make_legal_accelerator (gtk_legal_keyval);
445         KeyboardKey gtk_binding (kb.state(), gtk_legal_keyval);
446         Gtk::AccelKey gtk_key;
447         
448         bool entry_exists = Gtk::AccelMap::lookup_entry (what->get_accel_path(), gtk_key);
449
450         if (!entry_exists) {
451
452                 /* there is a trick happening here. It turns out that
453                  * gtk_accel_map_add_entry() performs no validation checks on
454                  * the accelerator keyval. This means we can use it to define
455                  * ANY accelerator, even if they violate GTK's rules
456                  * (e.g. about not using navigation keys). This works ONLY when
457                  * the entry in the GTK accelerator map has not already been
458                  * added. The entries will be added by the GTK UIManager when
459                  * building menus, so this code must be called before that
460                  * happens.
461                  */
462
463                 Gtk::AccelMap::add_entry (what->get_accel_path(), gtk_binding.key(), (Gdk::ModifierType) gtk_binding.state());
464         }
465 }
466
467 bool
468 Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save)
469 {
470         if (!_action_map) {
471                 return false;
472         }
473
474         /* We have to search the existing binding map by both action and
475          * keybinding, because the following are possible:
476          *
477          *   - key is already used for a different action
478          *   - action has a different binding
479          *   - key is not used
480          *   - action is not bound
481          */
482         
483         RefPtr<Action> action = _action_map->find_action (action_name);
484
485         if (!action) {
486                 return false;
487         }
488
489         KeybindingMap* kbm = 0;
490
491         switch (op) {
492         case Press:
493                 kbm = &press_bindings;
494                 break;
495         case Release:
496                 kbm = &release_bindings;
497                 break;
498         }
499
500         KeybindingMap::iterator k = kbm->find (kb);
501
502         if (k != kbm->end()) {
503                 kbm->erase (k);
504         }
505
506         /* now linear search by action */
507
508         for (k = kbm->begin(); k != kbm->end(); ++k) {
509                 if (k->second.action_name == action_name) {
510                         kbm->erase (k);
511                         break;
512                 }
513         }
514
515         add (kb, op, action_name, can_save);
516
517         /* for now, this never fails */
518         
519         return true;
520 }
521
522 void
523 Bindings::add (KeyboardKey kb, Operation op, string const& action_name, bool can_save)
524 {
525         KeybindingMap* kbm = 0;
526
527         switch (op) {
528         case Press:
529                 kbm = &press_bindings;
530                 break;
531         case Release:
532                 kbm = &release_bindings;
533                 break;
534         }
535
536         KeybindingMap::iterator k = kbm->find (kb);
537
538         if (k != kbm->end()) {
539                 kbm->erase (k);
540         } 
541         KeybindingMap::value_type new_pair (kb, ActionInfo (action_name));
542         
543         kbm->insert (new_pair).first;
544
545         if (can_save) {
546                 Keyboard::keybindings_changed ();
547         }
548
549         BindingsChanged (this); /* EMIT SIGNAL */
550 }
551
552 void
553 Bindings::remove (KeyboardKey kb, Operation op, bool can_save)
554 {
555         KeybindingMap* kbm = 0;
556
557         switch (op) {
558         case Press:
559                 kbm = &press_bindings;
560                 break;
561         case Release:
562                 kbm = &release_bindings;
563                 break;
564         }
565
566         KeybindingMap::iterator k = kbm->find (kb);
567
568         if (k != kbm->end()) {
569                 kbm->erase (k);
570         }
571
572         if (can_save) {
573                 Keyboard::keybindings_changed ();
574         }
575
576         BindingsChanged (this); /* EMIT SIGNAL */
577 }
578
579 void
580 Bindings::remove (RefPtr<Action> action, Operation op, bool can_save)
581 {
582         KeybindingMap* kbm = 0;
583
584         switch (op) {
585         case Press:
586                 kbm = &press_bindings;
587                 break;
588         case Release:
589                 kbm = &release_bindings;
590                 break;
591         }
592
593         for (KeybindingMap::iterator k = kbm->begin(); k != kbm->end(); ++k) {
594                 if (k->second.action == action) {
595                         kbm->erase (k);
596                         break;
597                 }
598         }
599
600         if (can_save) {
601                 Keyboard::keybindings_changed ();
602         }
603
604         BindingsChanged (this); /* EMIT SIGNAL */
605 }
606
607 bool
608 Bindings::activate (MouseButton bb, Operation op)
609 {
610         MouseButtonBindingMap* bbm = 0;
611
612         switch (op) {
613         case Press:
614                 bbm = &button_press_bindings;
615                 break;
616         case Release:
617                 bbm = &button_release_bindings;
618                 break;
619         }
620
621         MouseButtonBindingMap::iterator b = bbm->find (bb);
622
623         if (b == bbm->end()) {
624                 /* no entry for this key in the state map */
625                 return false;
626         }
627
628         RefPtr<Action> action;
629         
630         if (b->second.action) {
631                 action = b->second.action;
632         } else {
633                 if (_action_map) {
634                         action = _action_map->find_action (b->second.action_name);
635                 }
636         }
637
638         if (action) {
639                 /* lets do it ... */
640                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("activating action %1\n", ardour_action_name (action)));
641                 action->activate ();
642         }
643
644         /* return true even if the action could not be found */
645
646         return true;
647 }
648
649 void
650 Bindings::add (MouseButton bb, Operation op, string const& action_name)
651 {
652         MouseButtonBindingMap* bbm = 0;
653
654         switch (op) {
655         case Press:
656                 bbm = &button_press_bindings;
657                 break;
658         case Release:
659                 bbm = &button_release_bindings;
660                 break;
661         }
662
663         MouseButtonBindingMap::value_type newpair (bb, ActionInfo (action_name));
664         bbm->insert (newpair);
665 }
666
667 void
668 Bindings::remove (MouseButton bb, Operation op)
669 {
670         MouseButtonBindingMap* bbm = 0;
671
672         switch (op) {
673         case Press:
674                 bbm = &button_press_bindings;
675                 break;
676         case Release:
677                 bbm = &button_release_bindings;
678                 break;
679         }
680
681         MouseButtonBindingMap::iterator b = bbm->find (bb);
682
683         if (b != bbm->end()) {
684                 bbm->erase (b);
685         }
686 }
687
688 void
689 Bindings::save (XMLNode& root)
690 {
691         XMLNode* presses = new XMLNode (X_("Press"));
692
693         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
694                 XMLNode* child;
695
696                 if (k->first.name().empty()) {
697                         continue;
698                 }
699
700                 child = new XMLNode (X_("Binding"));
701                 child->add_property (X_("key"), k->first.name());
702                 child->add_property (X_("action"), k->second.action_name);
703                 presses->add_child_nocopy (*child);
704         }
705
706         for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
707                 XMLNode* child;
708                 child = new XMLNode (X_("Binding"));
709                 child->add_property (X_("button"), k->first.name());
710                 child->add_property (X_("action"), k->second.action_name);
711                 presses->add_child_nocopy (*child);
712         }
713
714         XMLNode* releases = new XMLNode (X_("Release"));
715
716         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
717                 XMLNode* child;
718
719                 if (k->first.name().empty()) {
720                         continue;
721                 }
722
723                 child = new XMLNode (X_("Binding"));
724                 child->add_property (X_("key"), k->first.name());
725                 child->add_property (X_("action"), k->second.action_name);
726                 releases->add_child_nocopy (*child);
727         }
728
729         for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
730                 XMLNode* child;
731                 child = new XMLNode (X_("Binding"));
732                 child->add_property (X_("button"), k->first.name());
733                 child->add_property (X_("action"), k->second.action_name);
734                 releases->add_child_nocopy (*child);
735         }
736
737         root.add_child_nocopy (*presses);
738         root.add_child_nocopy (*releases);
739 }
740
741 bool
742 Bindings::load (XMLNode const& node)
743 {
744         const XMLNodeList& children (node.children());
745         
746         press_bindings.clear ();
747         release_bindings.clear ();
748
749         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
750                 /* each node could be Press or Release */
751                 load_operation (**i);
752         }
753
754         return true;
755 }
756
757 void
758 Bindings::load_operation (XMLNode const& node)
759 {
760         if (node.name() == X_("Press") || node.name() == X_("Release")) {
761
762                 Operation op;
763
764                 if (node.name() == X_("Press")) {
765                         op = Press;
766                 } else {
767                         op = Release;
768                 }
769
770                 const XMLNodeList& children (node.children());
771
772                 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
773
774                         XMLProperty* ap;
775                         XMLProperty* kp;
776                         XMLProperty* bp;
777
778                         ap = (*p)->property ("action");
779                         kp = (*p)->property ("key");
780                         bp = (*p)->property ("button");
781
782                         if (!ap || (!kp && !bp)) {
783                                 continue;
784                         }
785
786                         if (kp) {
787                                 KeyboardKey k;
788                                 if (!KeyboardKey::make_key (kp->value(), k)) {
789                                         continue;
790                                 }
791                                 add (k, op, ap->value());
792                         } else {
793                                 MouseButton b;
794                                 if (!MouseButton::make_button (bp->value(), b)) {
795                                         continue;
796                                 }
797                                 add (b, op, ap->value());
798                         }
799                 }
800         }
801 }
802
803 void
804 Bindings::get_all_actions (std::vector<std::string>& paths,
805                            std::vector<std::string>& labels,
806                            std::vector<std::string>& tooltips,
807                            std::vector<std::string>& keys,
808                            std::vector<RefPtr<Action> >& actions)
809 {
810         if (!_action_map) {
811                 return;
812         }
813
814         /* build a reverse map from actions to bindings */
815
816         typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
817         ReverseMap rmap;
818
819         for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
820                 rmap.insert (make_pair (k->second.action, k->first));
821         }
822
823         /* get a list of all actions */
824
825         ActionMap::Actions all_actions;
826         _action_map->get_actions (all_actions);
827         
828         for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
829
830                 paths.push_back ((*act)->get_accel_path());
831                 labels.push_back ((*act)->get_label());
832                 tooltips.push_back ((*act)->get_tooltip());
833
834                 ReverseMap::iterator r = rmap.find (*act);
835
836                 if (r != rmap.end()) {
837                         keys.push_back (r->second.display_label());
838                 } else {
839                         keys.push_back (string());
840                 }
841
842                 actions.push_back (*act);
843         }
844 }
845
846 void
847 Bindings::get_all_actions (std::vector<std::string>& names,
848                            std::vector<std::string>& paths,
849                            std::vector<std::string>& keys)
850 {
851         if (!_action_map) {
852                 return;
853         }
854
855         /* build a reverse map from actions to bindings */
856
857         typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
858         ReverseMap rmap;
859
860         for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
861                 rmap.insert (make_pair (k->second.action, k->first));
862         }
863
864         /* get a list of all actions */
865
866         ActionMap::Actions all_actions;
867         _action_map->get_actions (all_actions);
868         
869         for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
870                 
871                 names.push_back ((*act)->get_name());
872                 paths.push_back ((*act)->get_accel_path());
873
874                 ReverseMap::iterator r = rmap.find (*act);
875                 if (r != rmap.end()) {
876                         keys.push_back (r->second.display_label());
877                 } else {
878                         keys.push_back (string());
879                 }
880         }
881 }
882
883 Bindings*
884 Bindings::get_bindings (string const& name, ActionMap& map)
885 {
886         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
887                 if ((*b)->name() == name) {
888                         (*b)->set_action_map (map);
889                         return *b;
890                 }
891         }
892
893         return 0;
894 }
895
896 void
897 Bindings::associate_all ()
898 {
899         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
900                 (*b)->associate ();
901         }
902 }
903
904 /*==========================================ACTION MAP =========================================*/
905
906 void
907 ActionMap::get_actions (ActionMap::Actions& acts)
908 {
909         for (_ActionMap::iterator a = _actions.begin(); a != _actions.end(); ++a) {
910                 acts.push_back (a->second);
911         }
912 }
913
914 RefPtr<Action>
915 ActionMap::find_action (const string& name)
916 {
917         _ActionMap::iterator a = _actions.find (name);
918
919         if (a != _actions.end()) {
920                 return a->second;
921         }
922
923         return RefPtr<Action>();
924 }
925
926 RefPtr<ActionGroup>
927 ActionMap::create_action_group (const string& name)
928 {
929         RefPtr<ActionGroup> g = ActionGroup::create (name);
930
931         /* this is one of the places where our own Action management code
932            has to touch the GTK one, because we want the GtkUIManager to
933            be able to create widgets (particularly Menus) from our actions.
934            
935            This is a a necessary step for that to happen.
936         */
937         
938         if (g) {
939                 ActionManager::ui_manager->insert_action_group (g);
940         }
941
942         return g;
943 }
944
945 RefPtr<Action> 
946 ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
947 {
948         string fullpath;
949
950         RefPtr<Action> act = Action::create (name, label);
951
952         fullpath = group->get_name();
953         fullpath += '/';
954         fullpath += name;
955         
956         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
957                 group->add (act);
958                 return act;
959         }
960
961         /* already registered */
962         return RefPtr<Action> ();
963 }
964
965 RefPtr<Action> 
966 ActionMap::register_action (RefPtr<ActionGroup> group,
967                             const char* name, const char* label, sigc::slot<void> sl)
968 {
969         string fullpath;
970
971         RefPtr<Action> act = Action::create (name, label);
972
973         fullpath = group->get_name();
974         fullpath += '/';
975         fullpath += name;
976
977         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
978                 group->add (act, sl);
979                 return act;
980         }
981
982         /* already registered */
983         return RefPtr<Action>();
984 }
985
986 RefPtr<Action> 
987 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
988                                   Gtk::RadioAction::Group& rgroup,
989                                   const char* name, const char* label, 
990                                   sigc::slot<void> sl)
991 {
992         string fullpath;
993
994         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
995         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
996         
997         fullpath = group->get_name();
998         fullpath += '/';
999         fullpath += name;
1000
1001         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1002                 group->add (act, sl);
1003                 return act;
1004         }
1005
1006         /* already registered */
1007         return RefPtr<Action>();
1008 }
1009
1010 RefPtr<Action> 
1011 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1012                                   Gtk::RadioAction::Group& rgroup,
1013                                   const char* name, const char* label, 
1014                                   sigc::slot<void,GtkAction*> sl,
1015                                   int value)
1016 {
1017         string fullpath;
1018
1019         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1020         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1021         ract->property_value() = value;
1022
1023         fullpath = group->get_name();
1024         fullpath += '/';
1025         fullpath += name;
1026
1027         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1028                 group->add (act, sigc::bind (sl, act->gobj()));
1029                 return act;
1030         }
1031
1032         /* already registered */
1033
1034         return RefPtr<Action>();
1035 }
1036
1037 RefPtr<Action> 
1038 ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
1039                                    const char* name, const char* label, sigc::slot<void> sl)
1040 {
1041         string fullpath;
1042
1043         fullpath = group->get_name();
1044         fullpath += '/';
1045         fullpath += name;
1046
1047         RefPtr<Action> act = ToggleAction::create (name, label);
1048
1049         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1050                 group->add (act, sl);
1051                 return act;
1052         }
1053
1054         /* already registered */
1055         return RefPtr<Action>();
1056 }
1057
1058 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) {
1059         char const *gdk_name = gdk_keyval_name (k.key());
1060         return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state " << k.state();
1061 }
1062