now with extra-yummy key-release binding semantics, specially for visual state stuff...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 6 May 2008 05:38:24 +0000 (05:38 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 6 May 2008 05:38:24 +0000 (05:38 +0000)
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@3318 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/actions.cc
gtk2_ardour/actions.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/keyboard.cc
gtk2_ardour/keyboard.h
gtk2_ardour/mnemonic-us.bindings.in

index 1f5ff658c9cd8a990d7015b13d57bd585c85c8ee..14713ff4efa0347168d0c74254a4b177ac2c4490 100644 (file)
@@ -157,6 +157,50 @@ struct SortActionsByLabel {
     }
 };
 
+void
+ActionManager::get_all_actions (vector<string>& groups, vector<string>& names, 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));
+                       
+                       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>& keys, vector<AccelKey>& bindings)
 {
@@ -222,6 +266,19 @@ ActionManager::get_widget (const char * name)
        return ui_manager->get_widget (name);
 }
 
+RefPtr<Action>
+ActionManager::get_action (const char* path)
+{
+       GtkAction* _act;
+       RefPtr<Action> act;
+
+       if ((_act = gtk_ui_manager_get_action (ui_manager->gobj(), path)) != 0) {
+               return Glib::wrap (_act, true);
+       }
+
+       return act;
+}
+
 RefPtr<Action>
 ActionManager::get_action (const char* group_name, const char* action_name)
 {
index 832403f01feaebc54332357397eea04f6d272f3d..0ff45a7a10f55fbd38a0fc4075811564a2859a57 100644 (file)
@@ -70,6 +70,7 @@ class ActionManager
 
        static Gtk::Widget* get_widget (const char * name);
        static Glib::RefPtr<Gtk::Action> get_action (const char* group, const char* name);
+       static Glib::RefPtr<Gtk::Action> get_action (const char* path);
 
        static void add_action_group (Glib::RefPtr<Gtk::ActionGroup>);
 
@@ -100,6 +101,10 @@ class ActionManager
                                     std::vector<std::string>& keys, 
                                     std::vector<Gtk::AccelKey>& bindings);
 
+       static void get_all_actions (std::vector<std::string>& groups, 
+                                    std::vector<std::string>& paths, 
+                                    std::vector<Gtk::AccelKey>& bindings);
+
        static void uncheck_toggleaction (const char * actionname);
 };
 
index 9c7fb3a07428aaca49f6af83544334ab568485fb..8f770c7cd51149fe3cbbb5083dcf5279568ebc2e 100644 (file)
@@ -193,53 +193,53 @@ Editor::register_actions ()
        ActionManager::session_sensitive_actions.push_back (act);
        
 
-       act = ActionManager::register_action (editor_actions, "save-visual-state-1", _("Save View 1"), bind (mem_fun (*this, &Editor::save_visual_state), 0));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-1", _("Save View 1"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 0));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-1", _("Goto View 1"), bind (mem_fun (*this, &Editor::goto_visual_state), 0));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-1", _("Goto View 1"), bind (mem_fun (*this, &Editor::start_visual_state_op), 0));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-2", _("Save View 2"), bind (mem_fun (*this, &Editor::save_visual_state), 1));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-2", _("Save View 2"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 1));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-2", _("Goto View 2"), bind (mem_fun (*this, &Editor::goto_visual_state), 1));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-2", _("Goto View 2"), bind (mem_fun (*this, &Editor::start_visual_state_op), 1));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-3", _("Save View 3"), bind (mem_fun (*this, &Editor::save_visual_state), 2));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-3", _("Save View 3"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 2));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-3", _("Goto View 3"), bind (mem_fun (*this, &Editor::goto_visual_state), 2));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-3", _("Goto View 3"), bind (mem_fun (*this, &Editor::start_visual_state_op), 2));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-4", _("Save View 4"), bind (mem_fun (*this, &Editor::save_visual_state), 3));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-4", _("Save View 4"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 3));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-4", _("Goto View 4"), bind (mem_fun (*this, &Editor::goto_visual_state), 3));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-4", _("Goto View 4"), bind (mem_fun (*this, &Editor::start_visual_state_op), 3));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-5", _("Save View 5"), bind (mem_fun (*this, &Editor::save_visual_state), 4));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-5", _("Save View 5"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 4));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-5", _("Goto View 5"), bind (mem_fun (*this, &Editor::goto_visual_state), 4));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-5", _("Goto View 5"), bind (mem_fun (*this, &Editor::start_visual_state_op), 4));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-6", _("Save View 6"), bind (mem_fun (*this, &Editor::save_visual_state), 5));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-6", _("Save View 6"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 5));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-6", _("Goto View 6"), bind (mem_fun (*this, &Editor::goto_visual_state), 5));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-6", _("Goto View 6"), bind (mem_fun (*this, &Editor::start_visual_state_op), 5));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-7", _("Save View 7"), bind (mem_fun (*this, &Editor::save_visual_state), 6));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-7", _("Save View 7"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 6));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-7", _("Goto View 7"), bind (mem_fun (*this, &Editor::goto_visual_state), 6));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-7", _("Goto View 7"), bind (mem_fun (*this, &Editor::start_visual_state_op), 6));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-8", _("Save View 8"), bind (mem_fun (*this, &Editor::save_visual_state), 7));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-8", _("Save View 8"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 7));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-8", _("Goto View 8"), bind (mem_fun (*this, &Editor::goto_visual_state), 7));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-8", _("Goto View 8"), bind (mem_fun (*this, &Editor::start_visual_state_op), 7));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-9", _("Save View 9"), bind (mem_fun (*this, &Editor::save_visual_state), 8));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-9", _("Save View 9"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 8));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-9", _("Goto View 9"), bind (mem_fun (*this, &Editor::goto_visual_state), 8));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-9", _("Goto View 9"), bind (mem_fun (*this, &Editor::start_visual_state_op), 8));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-10", _("Save View 10"), bind (mem_fun (*this, &Editor::save_visual_state), 9));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-10", _("Save View 10"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 9));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-10", _("Goto View 10"), bind (mem_fun (*this, &Editor::goto_visual_state), 9));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-10", _("Goto View 10"), bind (mem_fun (*this, &Editor::start_visual_state_op), 9));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-11", _("Save View 11"), bind (mem_fun (*this, &Editor::save_visual_state), 10));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-11", _("Save View 11"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 10));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-11", _("Goto View 11"), bind (mem_fun (*this, &Editor::goto_visual_state), 10));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-11", _("Goto View 11"), bind (mem_fun (*this, &Editor::start_visual_state_op), 10));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "save-visual-state-12", _("Save View 12"), bind (mem_fun (*this, &Editor::save_visual_state), 11));
+       act = ActionManager::register_action (editor_actions, "save-visual-state-12", _("Save View 12"), bind (mem_fun (*this, &Editor::cancel_visual_state_op), 11));
        ActionManager::session_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (editor_actions, "goto-visual-state-12", _("Goto View 12"), bind (mem_fun (*this, &Editor::goto_visual_state), 11));
+       act = ActionManager::register_action (editor_actions, "goto-visual-state-12", _("Goto View 12"), bind (mem_fun (*this, &Editor::start_visual_state_op), 11));
        ActionManager::session_sensitive_actions.push_back (act);
 
 
index 407947d90b0d37f831630530d512240b8a8b5643..76ad82cd9f4cf84f4b4791be2fd4393d9a4d08d7 100644 (file)
@@ -5926,7 +5926,7 @@ Editor::save_visual_state (uint32_t n)
 void
 Editor::goto_visual_state (uint32_t n)
 {
-       if (visual_states.size() < n) {
+       if (visual_states.size() <= n) {
                return;
        }
 
@@ -5941,25 +5941,31 @@ void
 Editor::start_visual_state_op (uint32_t n)
 {
        if (visual_state_op_connection.empty()) {
-               visual_state_op_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::end_visual_state_op), n), 2000);
-       } else {
-               cancel_visual_state_op (n);
+               cerr << "START pending op, for " << n << endl;
+               visual_state_op_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::end_visual_state_op), n), 1000);
        }
 }
 
 void
 Editor::cancel_visual_state_op (uint32_t n)
 {
-       
-       visual_state_op_connection.disconnect();
-       goto_visual_state (n);
+       if (!visual_state_op_connection.empty()) {
+               cerr << "CANCEL pending op, and goto " << n << endl;
+               visual_state_op_connection.disconnect();
+               goto_visual_state (n);
+       } else {
+               cerr << "NOTHING TO DO\n";
+       }
 }
 
 bool
 Editor::end_visual_state_op (uint32_t n)
 {
+       cerr << "TIMEOUT HIT, saveing visual state " << n << endl;
        visual_state_op_connection.disconnect();
        save_visual_state (n);
+       cerr << "vsop empty ? " << visual_state_op_connection.empty() << endl;
+       
        // FLASH SCREEN OR SOMETHING
        return false; // do not call again
 }
index 0899e1f3545a9e32fa2a97fb73072521a6ae956f..44066715db16ad58b4bb52cdd2b19d56414687be 100644 (file)
@@ -17,6 +17,7 @@
 
 */
 
+#include <vector>
 #include <ardour/ardour.h>
 
 #include "ardour_ui.h"
 #include "keyboard.h"
 #include "gui_thread.h"
 #include "opts.h"
+#include "actions.h"
 
 #include "i18n.h"
 
 using namespace PBD;
 using namespace ARDOUR;
+using namespace Gtk;
+using namespace std;
 
 #define KBD_DEBUG 0
 bool debug_keyboard = false;
@@ -73,7 +77,8 @@ bool         Keyboard::_some_magic_widget_has_focus = false;
 std::string Keyboard::user_keybindings_path;
 bool Keyboard::can_save_keybindings = false;
 map<string,string> Keyboard::binding_files;
-std::string Keyboard::_current_binding_name = _("Unknown");
+string Keyboard::_current_binding_name = _("Unknown");
+map<AccelKey,pair<string,string>,Keyboard::AccelKeyLess> Keyboard::release_keys;
 
 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
 
@@ -183,6 +188,7 @@ gint
 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
 {
        uint32_t keyval;
+       bool ret = false;
 
 #if 0
        cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
@@ -212,7 +218,23 @@ Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
                if (find (state.begin(), state.end(), keyval) == state.end()) {
                        state.push_back (keyval);
                        sort (state.begin(), state.end());
-               } 
+
+               } else {
+
+                       /* key is already down. if its also used for release,
+                          prevent auto-repeat events.
+                       */
+
+                       for (map<AccelKey,two_strings,AccelKeyLess>::iterator k = release_keys.begin(); k != release_keys.end(); ++k) {
+
+                               const AccelKey& ak (k->first);
+                               
+                               if (keyval == ak.get_key() && (Gdk::ModifierType)(event->state | Gdk::RELEASE_MASK) == ak.get_mod()) {
+                                       ret = true;
+                                       break;
+                               }
+                       }
+               }
 
        } else if (event->type == GDK_KEY_RELEASE) {
 
@@ -223,6 +245,20 @@ Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
                        sort (state.begin(), state.end());
                } 
 
+               for (map<AccelKey,two_strings,AccelKeyLess>::iterator k = release_keys.begin(); k != release_keys.end(); ++k) {
+
+                       const AccelKey& ak (k->first);
+                       two_strings ts (k->second);
+
+                       if (keyval == ak.get_key() && (Gdk::ModifierType)(event->state | Gdk::RELEASE_MASK) == ak.get_mod()) {
+                               Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (ts.first.c_str(), ts.second.c_str());
+                               if (act) {
+                                       act->activate();
+                                       ret = true;
+                               }
+                               break;
+                       }
+               }
        }
 
        if (event->type == GDK_KEY_RELEASE && event->keyval == GDK_w && modifier_state_equals (event->state, PrimaryModifier)) {
@@ -232,7 +268,7 @@ Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
                }
        }
 
-       return false;
+       return ret;
 }
 
 bool
@@ -552,13 +588,35 @@ Keyboard::load_keybindings (string path)
                        }
                }
 
-               return true;
 
        } catch (...) {
                error << string_compose (_("Ardour key bindings file not found at \"%1\" or contains errors."), path)
                      << endmsg;
                return false;
        }
+
+       /* now find all release-driven bindings */
+
+       vector<string> groups;
+       vector<string> names;
+       vector<AccelKey> bindings;
+       
+       ActionManager::get_all_actions (groups, names, bindings);
+       
+       vector<string>::iterator g;
+       vector<AccelKey>::iterator b;
+       vector<string>::iterator n;
+
+       release_keys.clear ();
+
+       for (n = names.begin(), b = bindings.begin(), g = groups.begin(); n != names.end(); ++n, ++b, ++g) {
+               if ((*b).get_mod() & Gdk::RELEASE_MASK) {
+                       cerr << "Action: " << (*n) << " bound to release of " << (*g) << '+' << (*n) << endl;
+                       release_keys.insert (pair<AccelKey,two_strings> (*b, two_strings (*g, *n)));
+               }
+       }
+
+       return true;
 }
 
 
index 25955935f3ecf9ffb5e23801f8507d2a6debc778..175208a4349882ccb7d4a766516e4a19229bac02 100644 (file)
 #ifndef __ardour_keyboard_h__
 #define __ardour_keyboard_h__
 
+#include <map>
 #include <vector>
 #include <string>
 
 #include <sigc++/signal.h>
 #include <gtk/gtk.h>
 #include <gtkmm/window.h>
+#include <gtkmm/accelkey.h>
 
 #include <ardour/types.h>
 #include <pbd/stateful.h>
 
 #include "selection.h"
 
-using std::vector;
 using std::string;
 
 class Keyboard : public sigc::trackable, Stateful
@@ -44,7 +45,7 @@ class Keyboard : public sigc::trackable, Stateful
        XMLNode& get_state (void);
        int set_state (const XMLNode&);
 
-       typedef vector<uint32_t> State;
+       typedef std::vector<uint32_t> State;
        typedef uint32_t ModifierMask;
 
        static uint32_t PrimaryModifier;
@@ -121,6 +122,16 @@ class Keyboard : public sigc::trackable, Stateful
        static std::string current_binding_name () { return _current_binding_name; }
        static std::map<std::string,std::string> binding_files;
 
+       struct AccelKeyLess {
+           bool operator() (const Gtk::AccelKey a, const Gtk::AccelKey b) const {
+                   if (a.get_key() != b.get_key()) {
+                           return a.get_key() < b.get_key();
+                   } else {
+                           return a.get_mod() < b.get_mod();
+                   }
+           }
+       };
+
   private:
        static Keyboard* _the_keyboard;
 
@@ -137,6 +148,10 @@ class Keyboard : public sigc::trackable, Stateful
        static bool can_save_keybindings;
        static std::string _current_binding_name;
 
+       typedef std::pair<std::string,std::string> two_strings;
+
+       static std::map<Gtk::AccelKey,two_strings,AccelKeyLess> release_keys;
+
        static gint _snooper (GtkWidget*, GdkEventKey*, gpointer);
        gint snooper (GtkWidget*, GdkEventKey*);
 
index c2ac948d80cdc042e5ed9a4d3edb06d5e7b75ad4..4fb546f0a3173c5949a545d42c0719f6f1842618 100644 (file)
 (gtk_accel_path "<Actions>/Editor/goto-visual-state-11" "<%PRIMARY%>F11")
 (gtk_accel_path "<Actions>/Editor/goto-visual-state-12" "<%PRIMARY%>F12")
 
-(gtk_accel_path "<Actions>/Editor/save-visual-state-1" "<%PRIMARY%><%SECONDARY%>F1")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-2" "<%PRIMARY%><%SECONDARY%>F2")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-3" "<%PRIMARY%><%SECONDARY%>F3")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-4" "<%PRIMARY%><%SECONDARY%>F4")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-5" "<%PRIMARY%><%SECONDARY%>F5")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-6" "<%PRIMARY%><%SECONDARY%>F6")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-7" "<%PRIMARY%><%SECONDARY%>F7")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-8" "<%PRIMARY%><%SECONDARY%>F8")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-9" "<%PRIMARY%><%SECONDARY%>F9")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-10" "<%PRIMARY%><%SECONDARY%>F10")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-11" "<%PRIMARY%><%SECONDARY%>F11")
-(gtk_accel_path "<Actions>/Editor/save-visual-state-12" "<%PRIMARY%><%SECONDARY%>F12")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-1" "<release><%PRIMARY%>F1")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-2" "<release><%PRIMARY%>F2")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-3" "<release><%PRIMARY%>F3")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-4" "<release><%PRIMARY%>F4")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-5" "<release><%PRIMARY%>F5")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-6" "<release><%PRIMARY%>F6")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-7" "<release><%PRIMARY%>F7")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-8" "<release><%PRIMARY%>F8")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-9" "<release><%PRIMARY%>F9")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-10" "<release><%PRIMARY%>F10")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-11" "<release><%PRIMARY%>F11")
+(gtk_accel_path "<Actions>/Editor/save-visual-state-12" "<release><%PRIMARY%>F12")
 
 
 ;; numbers