summaryrefslogtreecommitdiff
path: root/libs/gtkmm2ext
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2015-08-08 08:36:29 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2016-02-22 15:31:24 -0500
commit67e19c177f473807cd6510751bcf4a48574e6088 (patch)
treef44cf815264162afd9d0d4f06c938c4be6cfb06a /libs/gtkmm2ext
parent29b69b0ab4e92b49e171bfeb68af58da43ae766b (diff)
radically change Keyboard/Binding API design to disconnect Gtk::Action lookup from binding definition
We need this because we need binding information/objects before all Actions have been defined.
Diffstat (limited to 'libs/gtkmm2ext')
-rw-r--r--libs/gtkmm2ext/actions.cc204
-rw-r--r--libs/gtkmm2ext/bindings.cc426
-rw-r--r--libs/gtkmm2ext/gtk_ui.cc3
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/actions.h18
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/bindings.h77
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/keyboard.h10
-rw-r--r--libs/gtkmm2ext/keyboard.cc27
7 files changed, 293 insertions, 472 deletions
diff --git a/libs/gtkmm2ext/actions.cc b/libs/gtkmm2ext/actions.cc
index c562816259..7eda4df542 100644
--- a/libs/gtkmm2ext/actions.cc
+++ b/libs/gtkmm2ext/actions.cc
@@ -53,164 +53,6 @@ using namespace Gtkmm2ext;
RefPtr<UIManager> ActionManager::ui_manager;
string ActionManager::unbound_string = "--";
-bool
-ActionManager::lookup_entry (const ustring accel_path, Gtk::AccelKey& key)
-{
- GtkAccelKey gkey;
- bool known = gtk_accel_map_lookup_entry (accel_path.c_str(), &gkey);
-
- if (known) {
- key = AccelKey (gkey.accel_key, Gdk::ModifierType (gkey.accel_mods));
- } else {
- key = AccelKey (GDK_VoidSymbol, Gdk::ModifierType (0));
- }
-
- return known;
-}
-
-struct SortActionsByLabel {
- bool operator() (Glib::RefPtr<Gtk::Action> a, Glib::RefPtr<Gtk::Action> b) {
- ustring astr = a->get_accel_path();
- ustring bstr = b->get_accel_path();
- return astr < bstr;
- }
-};
-
-void
-ActionManager::get_all_actions (vector<string>& groups, vector<string>& names, vector<string>& tooltips, vector<AccelKey>& bindings)
-{
- /* the C++ API for functions used here appears to be broken in
- gtkmm2.6, so we fall back to the C level.
- */
-
- GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj());
- GList* node;
- GList* acts;
-
- for (node = list; node; node = g_list_next (node)) {
-
- GtkActionGroup* group = (GtkActionGroup*) node->data;
-
- /* first pass: collect them all */
-
- typedef std::list<Glib::RefPtr<Gtk::Action> > action_list;
- action_list the_acts;
-
- for (acts = gtk_action_group_list_actions (group); acts; acts = g_list_next (acts)) {
- GtkAction* action = (GtkAction*) acts->data;
- the_acts.push_back (Glib::wrap (action, true));
- }
-
- /* now sort by label */
-
- SortActionsByLabel cmp;
- the_acts.sort (cmp);
-
- for (action_list::iterator a = the_acts.begin(); a != the_acts.end(); ++a) {
-
- string accel_path = (*a)->get_accel_path ();
-
- groups.push_back (gtk_action_group_get_name(group));
- names.push_back (accel_path.substr (accel_path.find_last_of ('/') + 1));
- tooltips.push_back ((*a)->get_tooltip ());
-
- AccelKey key;
- lookup_entry (accel_path, key);
- bindings.push_back (AccelKey (key.get_key(), Gdk::ModifierType (key.get_mod())));
- }
- }
-}
-
-void
-ActionManager::get_all_actions (vector<string>& names, vector<string>& paths, vector<string>& tooltips, vector<string>& keys, vector<AccelKey>& bindings)
-{
- /* the C++ API for functions used here appears to be broken in
- gtkmm2.6, so we fall back to the C level.
- */
-
- GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj());
- GList* node;
- GList* acts;
-
- for (node = list; node; node = g_list_next (node)) {
-
- GtkActionGroup* group = (GtkActionGroup*) node->data;
-
- /* first pass: collect them all */
-
- typedef std::list<Glib::RefPtr<Gtk::Action> > action_list;
- action_list the_acts;
-
- for (acts = gtk_action_group_list_actions (group); acts; acts = g_list_next (acts)) {
- GtkAction* action = (GtkAction*) acts->data;
- the_acts.push_back (Glib::wrap (action, true));
- }
-
- /* now sort by label */
-
- SortActionsByLabel cmp;
- the_acts.sort (cmp);
-
- for (action_list::iterator a = the_acts.begin(); a != the_acts.end(); ++a) {
-
- ustring const label = (*a)->property_label ();
- string const accel_path = (*a)->get_accel_path ();
-
- names.push_back (label);
- paths.push_back (accel_path);
- tooltips.push_back ((*a)->get_tooltip ());
-
- AccelKey key;
- keys.push_back (get_key_representation (accel_path, key));
- bindings.push_back (AccelKey (key.get_key(), Gdk::ModifierType (key.get_mod())));
- }
- }
-}
-
-void
-ActionManager::enable_accelerators ()
-{
- /* the C++ API for functions used here appears to be broken in
- gtkmm2.6, so we fall back to the C level.
- */
-
- GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj());
- GList* node;
- GList* acts;
- string ui_string = "<ui>";
-
- /* get all actions, build a string describing them all as <accelerator
- * action="name"/>
- */
-
- for (node = list; node; node = g_list_next (node)) {
-
- GtkActionGroup* group = (GtkActionGroup*) node->data;
-
- for (acts = gtk_action_group_list_actions (group); acts; acts = g_list_next (acts)) {
- ui_string += "<accelerator action=\"";
-
- /* OK, this is pretty stupid ... there is the full
- * accel path returned by gtk_action_get_accel_path ()
- * but of course the UIManager doesn't use that, but
- * just a name, which is the last component of the
- * path. What a totally ridiculous design.
- */
-
- string fullpath = gtk_action_get_accel_path ((GtkAction*) acts->data);
-
- ui_string += Glib::path_get_basename (fullpath);
- ui_string += "\"/>";
- }
- }
-
- ui_string += "</ui>";
-
- /* and load it */
-
- ui_manager->add_ui_from_string (ui_string);
-}
-
struct ActionState {
GtkAction* action;
bool sensitive;
@@ -278,12 +120,6 @@ ActionManager::disable_active_actions ()
actions_disabled = true;
}
-void
-ActionManager::add_action_group (RefPtr<ActionGroup> grp)
-{
- ui_manager->insert_action_group (grp);
-}
-
Widget*
ActionManager::get_widget (const char * name)
{
@@ -357,32 +193,6 @@ ActionManager::get_action (const char* group_name, const char* action_name)
return act;
}
-RefPtr<Action>
-ActionManager::get_action_from_name (const char* name)
-{
- /* the C++ API for functions used here appears to be broken in
- gtkmm2.6, so we fall back to the C level.
- */
-
- GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj());
- GList* node;
- GList* acts;
-
- for (node = list; node; node = g_list_next (node)) {
-
- GtkActionGroup* group = (GtkActionGroup*) node->data;
-
- for (acts = gtk_action_group_list_actions (group); acts; acts = g_list_next (acts)) {
- GtkAction* action = (GtkAction*) acts->data;
- if (!strcmp (gtk_action_get_name (action), name)) {
- return Glib::wrap (action, true);
- }
- }
- }
-
- return RefPtr<Action>();
-}
-
void
ActionManager::set_sensitive (vector<RefPtr<Action> >& actions, bool state)
{
@@ -452,20 +262,6 @@ ActionManager::set_toggleaction_state (string n, bool s)
delete [] group_name;
}
-string
-ActionManager::get_key_representation (const string& accel_path, AccelKey& key)
-{
- bool known = lookup_entry (accel_path, key);
-
- if (known) {
- uint32_t k = possibly_translate_legal_accelerator_to_real_key (key.get_key());
- key = AccelKey (k, Gdk::ModifierType (key.get_mod()));
- return ui_manager->get_accel_group()->get_label (key.get_key(), Gdk::ModifierType (key.get_mod()));
- }
-
- return unbound_string;
-}
-
void
ActionManager::do_action (const char* group, const char*action)
{
diff --git a/libs/gtkmm2ext/bindings.cc b/libs/gtkmm2ext/bindings.cc
index fc05ec0336..232405bb97 100644
--- a/libs/gtkmm2ext/bindings.cc
+++ b/libs/gtkmm2ext/bindings.cc
@@ -42,8 +42,9 @@ using namespace Gtk;
using namespace Gtkmm2ext;
using namespace PBD;
+ActionMap Gtkmm2ext::Actions; /* global. Gulp */
+list<Bindings*> Bindings::bindings; /* global. Gulp */
uint32_t Bindings::_ignored_state = 0;
-map<string,Bindings*> Bindings::bindings_for_state;
MouseButton::MouseButton (uint32_t state, uint32_t keycode)
{
@@ -228,16 +229,24 @@ KeyboardKey::make_key (const string& str, KeyboardKey& k)
return true;
}
-Bindings::Bindings ()
- : action_map (0)
+Bindings::Bindings (std::string const& name)
+ : _name (name)
+ , _action_map (Actions)
{
+ bindings.push_back (this);
}
Bindings::~Bindings()
{
- if (!_name.empty()) {
- remove_bindings_for_state (_name, *this);
- }
+ bindings.remove (this);
+}
+
+void
+Bindings::set_action_map (ActionMap& actions)
+{
+ _action_map = actions;
+ dissociate ();
+ associate ();
}
bool
@@ -258,14 +267,6 @@ Bindings::empty() const
return empty_keys() && empty_mouse ();
}
-void
-Bindings::set_action_map (ActionMap& am)
-{
- action_map = &am;
- press_bindings.clear ();
- release_bindings.clear ();
-}
-
bool
Bindings::activate (KeyboardKey kb, Operation op)
{
@@ -288,21 +289,118 @@ Bindings::activate (KeyboardKey kb, Operation op)
return false;
}
- /* lets do it ... */
+ RefPtr<Action> action;
+
+ if (!k->second.action) {
+ action = _action_map.find_action (k->second.action_name);
+ }
+
+ if (action) {
+ /* lets do it ... */
+ DEBUG_TRACE (DEBUG::Bindings, string_compose ("binding for %1: %2\n", kb, k->second.action_name));
+ action->activate ();
+ }
- DEBUG_TRACE (DEBUG::Bindings, string_compose ("binding for %1: %2\n", kb, k->second->get_name()));
+ /* return true even if the action could not be found */
- k->second->activate ();
return true;
}
-bool
-Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save)
+void
+Bindings::associate ()
+{
+ KeybindingMap::iterator k;
+
+ 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) {
+ push_to_gtk (k->first, k->second.action);
+ }
+ }
+
+ for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
+ k->second.action = _action_map.find_action (k->second.action_name);
+ /* no working support in GTK for release bindings */
+ }
+
+ 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);
+ }
+
+ for (b = button_release_bindings.begin(); b != button_release_bindings.end(); ++b) {
+ b->second.action = _action_map.find_action (b->second.action_name);
+ }
+}
+
+void
+Bindings::dissociate ()
{
- if (!action_map) {
- return false;
+ KeybindingMap::iterator k;
+
+ for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
+ k->second.action.clear ();
+ }
+ for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
+ k->second.action.clear ();
}
+}
+
+void
+Bindings::push_to_gtk (KeyboardKey kb, RefPtr<Action> 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 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();
+ possibly_translate_keyval_to_make_legal_accelerator (gtk_legal_keyval);
+ KeyboardKey gtk_binding (kb.state(), gtk_legal_keyval);
+
+
+ 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());
+ } else {
+ warning << string_compose (_("There is more than one key binding defined for %1. Both will work, but only the first will be visible in menus"), what->get_accel_path()) << endmsg;
+ }
+
+ 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;
+ }
+}
+
+bool
+Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save)
+{
/* We have to search the existing binding map by both action and
* keybinding, because the following are possible:
*
@@ -312,7 +410,7 @@ Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, boo
* - action is not bound
*/
- RefPtr<Action> action = action_map->find_action (action_name);
+ RefPtr<Action> action = Actions.find_action (action_name);
if (!action) {
return false;
@@ -338,13 +436,13 @@ Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, boo
/* now linear search by action */
for (k = kbm->begin(); k != kbm->end(); ++k) {
- if (k->second == action) {
+ if (k->second.action_name == action_name) {
kbm->erase (k);
break;
}
}
- add (kb, op, action, can_save);
+ add (kb, op, action_name, can_save);
/* for now, this never fails */
@@ -352,7 +450,7 @@ Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, boo
}
void
-Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what, bool can_save)
+Bindings::add (KeyboardKey kb, Operation op, string const& action_name, bool can_save)
{
KeybindingMap* kbm = 0;
@@ -367,59 +465,12 @@ Bindings::add (KeyboardKey kb, Operation op, RefPtr<Action> what, bool can_save)
KeybindingMap::iterator k = kbm->find (kb);
- if (k == kbm->end()) {
- pair<KeyboardKey,RefPtr<Action> > newpair (kb, what);
- kbm->insert (newpair);
- } else {
- 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 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();
- possibly_translate_keyval_to_make_legal_accelerator (gtk_legal_keyval);
- KeyboardKey gtk_binding (kb.state(), gtk_legal_keyval);
+ if (k != kbm->end()) {
+ kbm->erase (k);
+ }
+ KeybindingMap::value_type new_pair (kb, ActionInfo (action_name));
-
- 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());
- } else {
- warning << string_compose (_("There is more than one key binding defined for %1. Both will work, but only the first will be visible in menus"), what->get_accel_path()) << endmsg;
- }
-
- 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;
- }
+ kbm->insert (new_pair).first;
if (can_save) {
Keyboard::keybindings_changed ();
@@ -466,7 +517,7 @@ Bindings::remove (RefPtr<Action> action, Operation op, bool can_save)
}
for (KeybindingMap::iterator k = kbm->begin(); k != kbm->end(); ++k) {
- if (k->second == action) {
+ if (k->second.action == action) {
kbm->erase (k);
break;
}
@@ -498,14 +549,24 @@ Bindings::activate (MouseButton bb, Operation op)
return false;
}
- /* lets do it ... */
+ RefPtr<Action> action;
+
+ if (!b->second.action) {
+ action = _action_map.find_action (b->second.action_name);
+ }
+
+ if (action) {
+ /* lets do it ... */
+ action->activate ();
+ }
- b->second->activate ();
+ /* return true even if the action could not be found */
+
return true;
}
void
-Bindings::add (MouseButton bb, Operation op, RefPtr<Action> what)
+Bindings::add (MouseButton bb, Operation op, string const& action_name)
{
MouseButtonBindingMap* bbm = 0;
@@ -518,15 +579,8 @@ Bindings::add (MouseButton bb, Operation op, RefPtr<Action> what)
break;
}
- MouseButtonBindingMap::iterator b = bbm->find (bb);
-
- if (b == bbm->end()) {
- pair<MouseButton,RefPtr<Action> > newpair (bb, what);
- bbm->insert (newpair);
- // cerr << "Bindings added mouse button " << bb.button() << " w/ " << bb.state() << " => " << what->get_name() << endl;
- } else {
- b->second = what;
- }
+ MouseButtonBindingMap::value_type newpair (bb, ActionInfo (action_name));
+ bbm->insert (newpair);
}
void
@@ -550,23 +604,6 @@ Bindings::remove (MouseButton bb, Operation op)
}
}
-bool
-Bindings::save (const string& path)
-{
- XMLTree tree;
- XMLNode* root = new XMLNode (X_("Bindings"));
- tree.set_root (root);
-
- save (*root);
-
- if (!tree.write (path)) {
- ::g_unlink (path.c_str());
- return false;
- }
-
- return true;
-}
-
void
Bindings::save (XMLNode& root)
{
@@ -581,8 +618,7 @@ Bindings::save (XMLNode& root)
child = new XMLNode (X_("Binding"));
child->add_property (X_("key"), k->first.name());
- string ap = k->second->get_accel_path();
- child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
+ child->add_property (X_("action"), k->second.action_name);
presses->add_child_nocopy (*child);
}
@@ -590,8 +626,7 @@ Bindings::save (XMLNode& root)
XMLNode* child;
child = new XMLNode (X_("Binding"));
child->add_property (X_("button"), k->first.name());
- string ap = k->second->get_accel_path();
- child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
+ child->add_property (X_("action"), k->second.action_name);
presses->add_child_nocopy (*child);
}
@@ -606,8 +641,7 @@ Bindings::save (XMLNode& root)
child = new XMLNode (X_("Binding"));
child->add_property (X_("key"), k->first.name());
- string ap = k->second->get_accel_path();
- child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
+ child->add_property (X_("action"), k->second.action_name);
releases->add_child_nocopy (*child);
}
@@ -615,8 +649,7 @@ Bindings::save (XMLNode& root)
XMLNode* child;
child = new XMLNode (X_("Binding"));
child->add_property (X_("button"), k->first.name());
- string ap = k->second->get_accel_path();
- child->add_property (X_("action"), ap.substr (ap.find ('/') + 1));
+ child->add_property (X_("action"), k->second.action_name);
releases->add_child_nocopy (*child);
}
@@ -625,68 +658,23 @@ Bindings::save (XMLNode& root)
}
bool
-Bindings::load (string const & name)
+Bindings::load (XMLNode const& node)
{
- XMLTree tree;
-
- if (!action_map) {
- return false;
- }
-
- XMLNode const * node = Keyboard::bindings_node();
-
- if (!node) {
- error << string_compose (_("No keyboard binding information when loading bindings for \"%1\""), name) << endmsg;
- return false;
- }
-
- if (!_name.empty()) {
- remove_bindings_for_state (_name, *this);
- }
-
- const XMLNodeList& children (node->children());
- bool found = false;
-
- for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
-
- if ((*i)->name() == X_("Bindings")) {
- XMLProperty const * prop = (*i)->property (X_("name"));
-
- if (!prop) {
- continue;
- }
-
- if (prop->value() == name) {
- found = true;
- node = *i;
- break;
- }
- }
- }
+ const XMLNodeList& children (node.children());
- if (!found) {
- error << string_compose (_("Bindings for \"%1\" not found in keyboard binding node\n"), name) << endmsg;
- return false;
- }
-
press_bindings.clear ();
release_bindings.clear ();
- const XMLNodeList& bindings (node->children());
-
- for (XMLNodeList::const_iterator i = bindings.begin(); i != bindings.end(); ++i) {
+ for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
/* each node could be Press or Release */
- load (**i);
+ load_operation (**i);
}
- _name = name;
- add_bindings_for_state (_name, *this);
-
return true;
}
void
-Bindings::load (const XMLNode& node)
+Bindings::load_operation (XMLNode const& node)
{
if (node.name() == X_("Press") || node.name() == X_("Release")) {
@@ -714,37 +702,18 @@ Bindings::load (const XMLNode& node)
continue;
}
- RefPtr<Action> act;
-
- if (action_map) {
- act = action_map->find_action (ap->value());
- }
-
- if (!act) {
- string::size_type slash = ap->value().find ('/');
- if (slash != string::npos) {
- string group = ap->value().substr (0, slash);
- string action = ap->value().substr (slash+1);
- act = ActionManager::get_action (group.c_str(), action.c_str());
- }
- }
-
- if (!act) {
- continue;
- }
-
if (kp) {
KeyboardKey k;
if (!KeyboardKey::make_key (kp->value(), k)) {
continue;
}
- add (k, op, act);
+ add (k, op, ap->value());
} else {
MouseButton b;
if (!MouseButton::make_button (bp->value(), b)) {
continue;
}
- add (b, op, act);
+ add (b, op, ap->value());
}
}
}
@@ -757,23 +726,19 @@ Bindings::get_all_actions (std::vector<std::string>& paths,
std::vector<std::string>& keys,
std::vector<RefPtr<Action> >& actions)
{
- 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, k->first));
+ 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);
+ _action_map.get_actions (all_actions);
for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
@@ -804,15 +769,16 @@ Bindings::get_all_actions (std::vector<std::string>& names,
ReverseMap rmap;
for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
- rmap.insert (make_pair (k->second, k->first));
+ rmap.insert (make_pair (k->second.action, k->first));
}
/* 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) {
+ 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());
@@ -825,10 +791,32 @@ Bindings::get_all_actions (std::vector<std::string>& names,
}
}
+Bindings*
+Bindings::get_bindings (string const& name)
+{
+ for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
+ if ((*b)->name() == name) {
+ return *b;
+ }
+ }
+
+ return 0;
+}
+
+void
+Bindings::associate_all ()
+{
+ for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
+ (*b)->associate ();
+ }
+}
+
+/*==========================================ACTION MAP =========================================*/
+
void
ActionMap::get_actions (ActionMap::Actions& acts)
{
- for (_ActionMap::iterator a = actions.begin(); a != actions.end(); ++a) {
+ for (_ActionMap::iterator a = _actions.begin(); a != _actions.end(); ++a) {
acts.push_back (a->second);
}
}
@@ -836,9 +824,9 @@ ActionMap::get_actions (ActionMap::Actions& acts)
RefPtr<Action>
ActionMap::find_action (const string& name)
{
- _ActionMap::iterator a = actions.find (name);
+ _ActionMap::iterator a = _actions.find (name);
- if (a != actions.end()) {
+ if (a != _actions.end()) {
return a->second;
}
@@ -849,13 +837,19 @@ RefPtr<ActionGroup>
ActionMap::create_action_group (const string& name)
{
RefPtr<ActionGroup> g = ActionGroup::create (name);
- return g;
-}
-void
-ActionMap::install_action_group (RefPtr<ActionGroup> group)
-{
- ActionManager::ui_manager->insert_action_group (group);
+ /* 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);
+ }
+
+ return g;
}
RefPtr<Action>
@@ -869,7 +863,7 @@ ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const c
fullpath += '/';
fullpath += name;
- if (actions.insert (_ActionMap::value_type (fullpath, act)).second) {
+ if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
group->add (act);
return act;
}
@@ -890,7 +884,7 @@ ActionMap::register_action (RefPtr<ActionGroup> group,
fullpath += '/';
fullpath += name;
- if (actions.insert (_ActionMap::value_type (fullpath, act)).second) {
+ if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
group->add (act, sl);
return act;
}
@@ -914,7 +908,7 @@ ActionMap::register_radio_action (RefPtr<ActionGroup> group,
fullpath += '/';
fullpath += name;
- if (actions.insert (_ActionMap::value_type (fullpath, act)).second) {
+ if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
group->add (act, sl);
return act;
}
@@ -940,7 +934,7 @@ ActionMap::register_radio_action (RefPtr<ActionGroup> group,
fullpath += '/';
fullpath += name;
- if (actions.insert (_ActionMap::value_type (fullpath, act)).second) {
+ if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
group->add (act, sigc::bind (sl, act->gobj()));
return act;
}
@@ -962,7 +956,7 @@ ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
RefPtr<Action> act = ToggleAction::create (name, label);
- if (actions.insert (_ActionMap::value_type (fullpath, act)).second) {
+ if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
group->add (act, sl);
return act;
}
@@ -971,18 +965,6 @@ ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
return RefPtr<Action>();
}
-void
-Bindings::add_bindings_for_state (std::string const& name, Bindings& bindings)
-{
- bindings_for_state.insert (make_pair (name, &bindings));
-}
-
-void
-Bindings::remove_bindings_for_state (std::string const& name, Bindings& bindings)
-{
- bindings_for_state.erase (name);
-}
-
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();
diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc
index 64fef47ca5..6ae50db9a8 100644
--- a/libs/gtkmm2ext/gtk_ui.cc
+++ b/libs/gtkmm2ext/gtk_ui.cc
@@ -365,10 +365,11 @@ UI::set_tip (Widget *w, const gchar *tip, const gchar *hlp)
}
if (action) {
+#warning Paul fix this before you think tabbed is done
Gtk::AccelKey key;
ustring ap = action->get_accel_path();
if (!ap.empty()) {
- string shortcut = ActionManager::get_key_representation (ap, key);
+ string shortcut = string(); // ActionManager::get_key_representation (ap, key);
if (!shortcut.empty()) {
replace_all (shortcut, "<", "");
replace_all (shortcut, ">", "-");
diff --git a/libs/gtkmm2ext/gtkmm2ext/actions.h b/libs/gtkmm2ext/gtkmm2ext/actions.h
index f0f4ffc572..88b9628273 100644
--- a/libs/gtkmm2ext/gtkmm2ext/actions.h
+++ b/libs/gtkmm2ext/gtkmm2ext/actions.h
@@ -45,26 +45,10 @@ namespace ActionManager {
LIBGTKMM2EXT_API extern Gtk::Widget* get_widget (const char * name);
LIBGTKMM2EXT_API extern Glib::RefPtr<Gtk::Action> get_action (const char* group, const char* name);
LIBGTKMM2EXT_API extern Glib::RefPtr<Gtk::Action> get_action (const char* path);
- LIBGTKMM2EXT_API extern Glib::RefPtr<Gtk::Action> get_action_from_name (const char* name);
+
LIBGTKMM2EXT_API extern void do_action (const char* group, const char* name);
LIBGTKMM2EXT_API extern void set_toggle_action (const char* group, const char* name, bool);
- LIBGTKMM2EXT_API extern void add_action_group (Glib::RefPtr<Gtk::ActionGroup>);
- LIBGTKMM2EXT_API extern void enable_accelerators ();
-
- LIBGTKMM2EXT_API extern bool lookup_entry (const Glib::ustring accel_path, Gtk::AccelKey& key);
-
- LIBGTKMM2EXT_API extern void get_all_actions (std::vector<std::string>& names,
- std::vector<std::string>& paths,
- std::vector<std::string>& tooltips,
- std::vector<std::string>& keys,
- std::vector<Gtk::AccelKey>& bindings);
-
- LIBGTKMM2EXT_API extern void get_all_actions (std::vector<std::string>& groups,
- std::vector<std::string>& paths,
- std::vector<std::string>& tooltips,
- std::vector<Gtk::AccelKey>& bindings);
-
LIBGTKMM2EXT_API extern void check_toggleaction (std::string);
LIBGTKMM2EXT_API extern void uncheck_toggleaction (std::string);
LIBGTKMM2EXT_API extern void set_toggleaction_state (std::string, bool);
diff --git a/libs/gtkmm2ext/gtkmm2ext/bindings.h b/libs/gtkmm2ext/gtkmm2ext/bindings.h
index af451e10ed..c586676e3c 100644
--- a/libs/gtkmm2ext/gtkmm2ext/bindings.h
+++ b/libs/gtkmm2ext/gtkmm2ext/bindings.h
@@ -2,7 +2,11 @@
#define __libgtkmm2ext_bindings_h__
#include <map>
+#include <vector>
+#include <list>
+
#include <stdint.h>
+
#include <gdk/gdkkeysyms.h>
#include <gtkmm/action.h>
#include <gtkmm/radioaction.h>
@@ -74,19 +78,13 @@ class LIBGTKMM2EXT_API ActionMap {
~ActionMap() {}
Glib::RefPtr<Gtk::ActionGroup> create_action_group (const std::string& group_name);
- void install_action_group (Glib::RefPtr<Gtk::ActionGroup>);
-
+
Glib::RefPtr<Gtk::Action> register_action (Glib::RefPtr<Gtk::ActionGroup> group, const char* name, const char* label);
Glib::RefPtr<Gtk::Action> register_action (Glib::RefPtr<Gtk::ActionGroup> group,
const char* name, const char* label, sigc::slot<void> sl);
-<<<<<<< HEAD
- Glib::RefPtr<Gtk::Action> register_radio_action (const char* path, Gtk::RadioAction::Group&,
- const char* name, const char* label,
-=======
Glib::RefPtr<Gtk::Action> register_radio_action (Glib::RefPtr<Gtk::ActionGroup> group,
Gtk::RadioAction::Group&,
const char* name, const char* label,
->>>>>>> changes to Bindings and Keyboard API to support (mostly) GTK-free keyboard bindings
sigc::slot<void,GtkAction*> sl,
int value);
Glib::RefPtr<Gtk::Action> register_radio_action (Glib::RefPtr<Gtk::ActionGroup> group,
@@ -100,11 +98,28 @@ class LIBGTKMM2EXT_API ActionMap {
typedef std::vector<Glib::RefPtr<Gtk::Action> > Actions;
void get_actions (Actions&);
-
+
private:
+<<<<<<< HEAD
typedef std::map<std::string, Glib::RefPtr<Gtk::Action> > _ActionMap;
_ActionMap actions;
};
+=======
+ /* hash for faster lookup of actions by name */
+
+ typedef std::map<std::string, Glib::RefPtr<Gtk::Action> > _ActionMap;
+ _ActionMap _actions;
+};
+>>>>>>> radically change Keyboard/Binding API design to disconnect Gtk::Action lookup from binding definition
+
+/* single global action map for entire application.
+ *
+ * Actions are name-spaced by group, and it makes things
+ * much easier if there is a single place to look up
+ * any action.
+ */
+
+LIBGTKMM2EXT_API extern ActionMap Actions;
class LIBGTKMM2EXT_API Bindings {
public:
@@ -113,36 +128,56 @@ class LIBGTKMM2EXT_API Bindings {
Release
};
+<<<<<<< HEAD
Bindings();
+=======
+ struct ActionInfo {
+ ActionInfo (std::string const& name) : action_name (name) {}
+
+ std::string action_name;
+ Glib::RefPtr<Gtk::Action> action;
+ };
+
+ Bindings (std::string const& name);
+>>>>>>> radically change Keyboard/Binding API design to disconnect Gtk::Action lookup from binding definition
~Bindings ();
+ std::string const& name() const { return _name; }
+
+ void associate ();
+ void dissociate ();
+
bool empty() const;
bool empty_keys () const;
bool empty_mouse () const;
- void add (KeyboardKey, Operation, Glib::RefPtr<Gtk::Action>, bool can_save = false);
+ void add (KeyboardKey, Operation, std::string const&, bool can_save = false);
bool replace (KeyboardKey, Operation, std::string const& action_name, bool can_save = true);
void remove (KeyboardKey, Operation, bool can_save = false);
void remove (Glib::RefPtr<Gtk::Action>, Operation, bool can_save = false);
bool activate (KeyboardKey, Operation);
- void add (MouseButton, Operation, Glib::RefPtr<Gtk::Action>);
+ void add (MouseButton, Operation, std::string const&);
void remove (MouseButton, Operation);
bool activate (MouseButton, Operation);
- bool load (const std::string& path);
- void load (const XMLNode& node);
- bool save (const std::string& path);
+ bool load (XMLNode const& node);
+ void load_operation (XMLNode const& node);
void save (XMLNode& root);
+<<<<<<< HEAD
void set_action_map (ActionMap&);
+=======
+>>>>>>> radically change Keyboard/Binding API design to disconnect Gtk::Action lookup from binding definition
static void set_ignored_state (int mask) {
_ignored_state = mask;
}
static uint32_t ignored_state() { return _ignored_state; }
+ void set_action_map (ActionMap&);
+
/* used to list all actions */
void get_all_actions (std::vector<std::string>& names,
std::vector<std::string>& paths,
@@ -155,24 +190,26 @@ class LIBGTKMM2EXT_API Bindings {
std::vector<std::string>& keys,
std::vector<Glib::RefPtr<Gtk::Action> >& actions);
- static std::map<std::string,Bindings*> bindings_for_state;
-
- static void add_bindings_for_state (std::string const &, Bindings&);
- static void remove_bindings_for_state (std::string const &, Bindings&);
+ /* all bindings currently in existence, as grouped into Bindings */
+ static std::list<Bindings*> bindings;
+ static Bindings* get_bindings (std::string const& name);
+ static void associate_all ();
private:
- typedef std::map<KeyboardKey,Glib::RefPtr<Gtk::Action> > KeybindingMap;
+ typedef std::map<KeyboardKey,ActionInfo> KeybindingMap;
std::string _name;
+ ActionMap& _action_map;
KeybindingMap press_bindings;
KeybindingMap release_bindings;
- typedef std::map<MouseButton,Glib::RefPtr<Gtk::Action> > MouseButtonBindingMap;
+ typedef std::map<MouseButton,ActionInfo> MouseButtonBindingMap;
MouseButtonBindingMap button_press_bindings;
MouseButtonBindingMap button_release_bindings;
- ActionMap* action_map;
static uint32_t _ignored_state;
+
+ void push_to_gtk (KeyboardKey, Glib::RefPtr<Gtk::Action>);
};
} // namespace
diff --git a/libs/gtkmm2ext/gtkmm2ext/keyboard.h b/libs/gtkmm2ext/gtkmm2ext/keyboard.h
index 97d42f5cc8..48a1bdcaad 100644
--- a/libs/gtkmm2ext/gtkmm2ext/keyboard.h
+++ b/libs/gtkmm2ext/gtkmm2ext/keyboard.h
@@ -29,6 +29,7 @@
#include <gtkmm/accelkey.h>
#include "pbd/stateful.h"
+#include "pbd/signals.h"
#include "gtkmm2ext/visibility.h"
@@ -38,6 +39,8 @@ namespace Gtk {
namespace Gtkmm2ext {
+class Bindings;
+
class LIBGTKMM2EXT_API Keyboard : public sigc::trackable, PBD::Stateful
{
public:
@@ -170,12 +173,14 @@ class LIBGTKMM2EXT_API Keyboard : public sigc::trackable, PBD::Stateful
static bool load_keybindings (std::string const& path);
static void save_keybindings (std::string const& path);
- static XMLNode const * bindings_node() { return _bindings_node; }
-
int reset_bindings ();
sigc::signal0<void> ZoomVerticalModifierReleased;
+ static std::vector<Bindings*> bindings;
+ static Bindings* get_bindings (std::string const& name);
+ static PBD::Signal0<void> BindingsChanged;
+
protected:
static Keyboard* _the_keyboard;
@@ -196,7 +201,6 @@ class LIBGTKMM2EXT_API Keyboard : public sigc::trackable, PBD::Stateful
static bool can_save_keybindings;
static bool bindings_changed_after_save_became_legal;
static std::string _current_binding_name;
- static XMLNode* _bindings_node;
typedef std::pair<std::string,std::string> two_strings;
diff --git a/libs/gtkmm2ext/keyboard.cc b/libs/gtkmm2ext/keyboard.cc
index b1f5d5561a..1b3f661e60 100644
--- a/libs/gtkmm2ext/keyboard.cc
+++ b/libs/gtkmm2ext/keyboard.cc
@@ -112,7 +112,7 @@ bool Keyboard::bindings_changed_after_save_became_legal = false;
map<string,string> Keyboard::binding_files;
string Keyboard::_current_binding_name;
Gtk::Window* Keyboard::pre_dialog_active_window = 0;
-XMLNode* Keyboard::_bindings_node = 0;
+PBD::Signal0<void> Keyboard::BindingsChanged;
/* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
GdkModifierType Keyboard::RelevantModifierKeyMask;
@@ -643,6 +643,7 @@ Keyboard::keybindings_changed ()
}
Keyboard::save_keybindings ();
+ BindingsChanged (); /* EMIT SIGNAL */
}
void
@@ -697,7 +698,22 @@ Keyboard::read_keybindings (string const & path)
return -1;
}
- _bindings_node = new XMLNode (*tree.root ()); /* copy operation. Sorry */
+ /* toplevel node is "BindingSet; children are "Bindings" */
+
+ XMLNodeList const& children = tree.root()->children();
+
+ for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+ if ((*i)->name() == X_("Bindings")) {
+ XMLProperty const* name = (*i)->property (X_("name"));
+ if (!name) {
+ warning << _("Keyboard binding found without a name") << endmsg;
+ continue;
+ }
+
+ Bindings* b = new Bindings (name->value());
+ b->load (**i);
+ }
+ }
return 0;
}
@@ -709,10 +725,10 @@ Keyboard::store_keybindings (string const & path)
XMLNode* bnode;
int ret = 0;
- for (map<string,Bindings*>::const_iterator c = Bindings::bindings_for_state.begin(); c != Bindings::bindings_for_state.end(); ++c) {
+ for (list<Bindings*>::const_iterator b = Bindings::bindings.begin(); b != Bindings::bindings.end(); ++b) {
bnode = new XMLNode (X_("Bindings"));
- bnode->add_property (X_("name"), c->first);
- c->second->save (*bnode);
+ bnode->add_property (X_("name"), (*b)->name());
+ (*b)->save (*bnode);
node->add_child_nocopy (*bnode);
}
@@ -744,6 +760,7 @@ Keyboard::reset_bindings ()
{
PBD::Unwinder<bool> uw (can_save_keybindings, false);
setup_keybindings ();
+ Bindings::associate_all ();
}
return 0;