X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fgtkmm2ext%2Factions.cc;h=edf092d909a0b4a4b800f1ff2bcf6abc05a58968;hb=ab61c6837f6aed0179e098c83a81445fba1bab9a;hp=200308a254b3bdbafae9b32ed89af930eaf3b115;hpb=86343b6c15a3a43f082802484d2bc813d34db821;p=ardour.git diff --git a/libs/gtkmm2ext/actions.cc b/libs/gtkmm2ext/actions.cc index 200308a254..edf092d909 100644 --- a/libs/gtkmm2ext/actions.cc +++ b/libs/gtkmm2ext/actions.cc @@ -21,8 +21,11 @@ #include #include #include +#include #include +#include + #include #include #include @@ -31,12 +34,14 @@ #include #include +#include + #include "pbd/error.h" #include "gtkmm2ext/actions.h" #include "gtkmm2ext/utils.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace Gtk; @@ -45,383 +50,464 @@ using namespace sigc; using namespace PBD; using namespace Gtkmm2ext; +typedef std::map > ActionMap; +static ActionMap actions; +typedef std::vector > ActionGroups; +static ActionGroups groups; + RefPtr ActionManager::ui_manager; -string ActionManager::unbound_string = "--"; +string ActionManager::unbound_string = X_("--"); +struct ActionState { + GtkAction* action; + bool sensitive; + ActionState (GtkAction* a, bool s) : action (a), sensitive (s) {} +}; -RefPtr -ActionManager::register_action (RefPtr group, const char * name, const char * label, slot sl) -{ - RefPtr act; +typedef std::vector ActionStates; - act = Action::create (name, label); - group->add (act, sl); +static ActionStates action_states_to_restore; +static bool actions_disabled = false; - return act; +void +ActionManager::init () +{ + ui_manager = UIManager::create (); } -RefPtr -ActionManager::register_action (RefPtr group, const char * name, const char * label) +void +ActionManager::save_action_states () { - RefPtr act; + for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) { - act = Action::create (name, label); - group->add (act); + /* the C++ API for functions used here appears to be broken in + gtkmm2.6, so we fall back to the C level. + */ - return act; -} + GtkActionGroup* group = (*g)->gobj(); + for (GList* acts = gtk_action_group_list_actions (group); acts; acts = g_list_next (acts)) { + GtkAction* action = (GtkAction*) acts->data; + action_states_to_restore.push_back (ActionState (action, gtk_action_get_sensitive (action))); + } + } +} -RefPtr -ActionManager::register_radio_action (RefPtr group, RadioAction::Group& rgroup, const char * name, const char * label, slot sl) +void +ActionManager::set_sensitive (Glib::RefPtr group, bool yn) { - RefPtr act; + /* the C++ API for functions used here appears to be broken in + gtkmm2.6, so we fall back to the C level. + */ - act = RadioAction::create (rgroup, name, label); - group->add (act, sl); + GtkActionGroup* grp = group->gobj(); - return act; + for (GList* acts = gtk_action_group_list_actions (grp); acts; acts = g_list_next (acts)) { + GtkAction* action = (GtkAction*) acts->data; + gtk_action_set_sensitive (action, yn); + } } -RefPtr -ActionManager::register_radio_action ( - RefPtr group, RadioAction::Group& rgroup, string const & name, string const & label, string const & tooltip, slot sl - ) +void +ActionManager::enable_active_actions () { - RefPtr act; + if (!actions_disabled) { + return ; + } - act = RadioAction::create (rgroup, name, label, tooltip); - group->add (act, sl); + for (ActionStates::iterator i = action_states_to_restore.begin(); i != action_states_to_restore.end(); ++i) { + if ((*i).action && (*i).sensitive) { + gtk_action_set_sensitive ((*i).action, true); + } + } - return act; + action_states_to_restore.clear (); + actions_disabled = false; } -RefPtr -ActionManager::register_toggle_action (RefPtr group, const char * name, const char * label, slot sl) +void +ActionManager::disable_active_actions () { - RefPtr act; - - act = ToggleAction::create (name, label); - group->add (act, sl); + if (actions_disabled == true ) { + return ; + } + // save all action's states to action_states_to_restore + save_action_states (); - return act; + // set all action's states disabled + for (ActionStates::iterator i = action_states_to_restore.begin(); i != action_states_to_restore.end(); ++i) { + if ((*i).sensitive) { + gtk_action_set_sensitive ((*i).action, false); + } + } + actions_disabled = true; } -RefPtr -ActionManager::register_toggle_action (RefPtr group, string const & name, string const & label, string const & tooltip, slot sl) +Widget* +ActionManager::get_widget (const char * name) { - RefPtr act; - - act = ToggleAction::create (name, label, tooltip); - group->add (act, sl); - - return act; + return ui_manager->get_widget (name); } -bool -ActionManager::lookup_entry (const ustring accel_path, Gtk::AccelKey& key) +void +ActionManager::set_sensitive (vector >& actions, bool state) { - 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)); + // if actions weren't disabled + if (!actions_disabled) { + for (vector >::iterator i = actions.begin(); i != actions.end(); ++i) { + (*i)->set_sensitive (state); + } } + else { + // actions were disabled + // so we should just set necessary action's states in action_states_to_restore + for (vector >::iterator i = actions.begin(); i != actions.end(); ++i) { + // go through action_states_to_restore and set state of actions + for (ActionStates::iterator j = action_states_to_restore.begin(); j != action_states_to_restore.end(); ++j) { + // all actions should have their individual name, so we can use it for comparison + if (gtk_action_get_name ((*j).action) == (*i)->get_name ()) { + (*j).sensitive = state; + } + } + } + } +} - return known; +void +ActionManager::check_toggleaction (const string& n) +{ + set_toggleaction_state (n, true); } -struct SortActionsByLabel { - bool operator() (Glib::RefPtr a, Glib::RefPtr b) { - ustring astr = a->get_accel_path(); - ustring bstr = b->get_accel_path(); - return astr < bstr; - } -}; +void +ActionManager::uncheck_toggleaction (const string& n) +{ + set_toggleaction_state (n, false); +} void -ActionManager::get_all_actions (vector& groups, vector& names, vector& tooltips, vector& bindings) +ActionManager::set_toggleaction_state (const string& n, bool s) { - /* the C++ API for functions used here appears to be broken in - gtkmm2.6, so we fall back to the C level. - */ + char const * name = n.c_str (); - GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj()); - GList* node; - GList* acts; + const char *last_slash = strrchr (name, '/'); - for (node = list; node; node = g_list_next (node)) { + if (last_slash == 0) { + fatal << string_compose ("programmer error: %1 %2", "illegal toggle action name", name) << endmsg; + abort(); /*NOTREACHED*/ + return; + } - GtkActionGroup* group = (GtkActionGroup*) node->data; + /* 10 = strlen ("/") */ + size_t len = last_slash - (name + 10); - /* first pass: collect them all */ + char* group_name = new char[len+1]; + memcpy (group_name, name + 10, len); + group_name[len] = '\0'; - typedef std::list > action_list; - action_list the_acts; + const char* action_name = last_slash + 1; + if (!set_toggleaction_state (group_name, action_name, s)) { + error << string_compose (_("Unknown action name: %1/%2"), group_name, action_name) << endmsg; + } - 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)); - } + delete [] group_name; +} - /* now sort by label */ +bool +ActionManager::set_toggleaction_state (const char* group_name, const char* action_name, bool s) +{ + RefPtr act = get_action (group_name, action_name); + if (act) { + RefPtr tact = RefPtr::cast_dynamic(act); + if (tact) { + tact->set_active (s); + return true; + } + } + return false; +} - SortActionsByLabel cmp; - the_acts.sort (cmp); +void +ActionManager::do_action (const char* group, const char*action) +{ + Glib::RefPtr act = ActionManager::get_action (group, action); + if (act) { + act->activate (); + } +} - for (action_list::iterator a = the_acts.begin(); a != the_acts.end(); ++a) { +void +ActionManager::set_toggle_action (const char* group, const char*action, bool yn) +{ + Glib::RefPtr tact = ActionManager::get_toggle_action (group, action); + tact->set_active (yn); +} - string accel_path = (*a)->get_accel_path (); +RefPtr +ActionManager::get_action (const string& name, bool or_die) +{ + ActionMap::const_iterator a = actions.find (name); - 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 ()); + if (a != actions.end()) { + return a->second; + } - AccelKey key; - lookup_entry (accel_path, key); - bindings.push_back (AccelKey (key.get_key(), Gdk::ModifierType (key.get_mod()))); - } + if (or_die) { + ::abort (); } + + cerr << "Failed to find action: [" << name << ']' << endl; + return RefPtr(); } -void -ActionManager::get_all_actions (vector& names, vector& paths, vector& tooltips, vector& keys, vector& bindings) +RefPtr +ActionManager::get_toggle_action (const string& name, bool or_die) { - /* the C++ API for functions used here appears to be broken in - gtkmm2.6, so we fall back to the C level. - */ + RefPtr act = get_action (name, or_die); - GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj()); - GList* node; - GList* acts; + if (!act) { + return RefPtr(); + } - for (node = list; node; node = g_list_next (node)) { + return Glib::RefPtr::cast_dynamic (act); +} - GtkActionGroup* group = (GtkActionGroup*) node->data; +RefPtr +ActionManager::get_radio_action (const string& name, bool or_die) +{ + RefPtr act = get_action (name, or_die); - /* first pass: collect them all */ + if (!act) { + return RefPtr(); + } - typedef std::list > action_list; - action_list the_acts; + return Glib::RefPtr::cast_dynamic (act); +} - 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)); - } +RefPtr +ActionManager::get_action (char const * group_name, char const * action_name, bool or_die) +{ + string fullpath (group_name); + fullpath += '/'; + fullpath += action_name; - /* now sort by label */ + ActionMap::const_iterator a = actions.find (fullpath); - SortActionsByLabel cmp; - the_acts.sort (cmp); + if (a != actions.end()) { + return a->second; + } - for (action_list::iterator a = the_acts.begin(); a != the_acts.end(); ++a) { + if (or_die) { + ::abort (); + } - ustring const label = (*a)->property_label (); - string const accel_path = (*a)->get_accel_path (); + cerr << "Failed to find action (2): [" << fullpath << ']' << endl; + return RefPtr(); +} - names.push_back (label); - paths.push_back (accel_path); - tooltips.push_back ((*a)->get_tooltip ()); +RefPtr +ActionManager::get_toggle_action (char const * group_name, char const * action_name, bool or_die) +{ + RefPtr act = get_action (group_name, action_name, or_die); - AccelKey key; - keys.push_back (get_key_representation (accel_path, key)); - bindings.push_back (AccelKey (key.get_key(), Gdk::ModifierType (key.get_mod()))); - } + if (!act) { + return RefPtr(); } -} -void -ActionManager::add_action_group (RefPtr grp) -{ - ui_manager->insert_action_group (grp); + return Glib::RefPtr::cast_dynamic (act); } -Widget* -ActionManager::get_widget (const char * name) +RefPtr +ActionManager::get_radio_action (char const * group_name, char const * action_name, bool or_die) { - return ui_manager->get_widget (name); + RefPtr act = get_action (group_name, action_name, or_die); + + if (!act) { + return RefPtr(); + } + + return Glib::RefPtr::cast_dynamic (act); } -RefPtr -ActionManager::get_action (const char* path) + +RefPtr +ActionManager::create_action_group (string const & name) { - if (!path) { - return RefPtr(); + for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) { + if ((*g)->get_name () == name) { + return *g; + } } - /* Skip / in path */ + RefPtr g = ActionGroup::create (name); - int len = strlen (path); + groups.push_back (g); - if (len < 3) { - /* shortest possible path: "a/b" */ - return RefPtr(); - } + /* 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. - if (len > 10 && !strncmp (path, "/", 10 )) { - path = path+10; - } else if (path[0] == '/') { - path++; - } + This is a a necessary step for that to happen. + */ - vector copy(len+1); - strcpy (©[0], path); - char* slash = strchr (©[0], '/'); - if (!slash) { - return RefPtr (); + if (g) { + ActionManager::ui_manager->insert_action_group (g); } - *slash = '\0'; - return get_action (©[0], ++slash); - + return g; } RefPtr -ActionManager::get_action (const char* group_name, const char* action_name) +ActionManager::register_action (RefPtr group, const char* name, const char* label) { - /* the C++ API for functions used here appears to be broken in - gtkmm2.6, so we fall back to the C level. - */ + string fullpath; - if (ui_manager == 0) { - return RefPtr (); - } + RefPtr act = Action::create (name, label); - GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj()); - GList* node; - RefPtr act; + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; - for (node = list; node; node = g_list_next (node)) { + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act); + return act; + } - GtkActionGroup* _ag = (GtkActionGroup*) node->data; + /* already registered */ + return RefPtr (); +} + +RefPtr +ActionManager::register_action (RefPtr group, + const char* name, const char* label, sigc::slot sl) +{ + string fullpath; - if (strcmp (group_name, gtk_action_group_get_name (_ag)) == 0) { + RefPtr act = Action::create (name, label); - GtkAction* _act; + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; - if ((_act = gtk_action_group_get_action (_ag, action_name)) != 0) { - act = Glib::wrap (_act, true); - break; - } - } + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act, sl); + return act; } - return act; + /* already registered */ + return RefPtr(); } RefPtr -ActionManager::get_action_from_name (const char* name) +ActionManager::register_radio_action (RefPtr group, + Gtk::RadioAction::Group& rgroup, + const char* name, const char* label, + sigc::slot sl) { - /* the C++ API for functions used here appears to be broken in - gtkmm2.6, so we fall back to the C level. - */ + string fullpath; - GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj()); - GList* node; - GList* acts; + RefPtr act = RadioAction::create (rgroup, name, label); + RefPtr ract = RefPtr::cast_dynamic(act); - for (node = list; node; node = g_list_next (node)) { + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; - 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); - } - } + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act, sl); + return act; } + /* already registered */ return RefPtr(); } -void -ActionManager::set_sensitive (vector >& actions, bool state) +RefPtr +ActionManager::register_radio_action (RefPtr group, + Gtk::RadioAction::Group& rgroup, + const char* name, const char* label, + sigc::slot sl, + int value) { - for (vector >::iterator i = actions.begin(); i != actions.end(); ++i) { - (*i)->set_sensitive (state); + string fullpath; + + RefPtr act = RadioAction::create (rgroup, name, label); + RefPtr ract = RefPtr::cast_dynamic(act); + ract->property_value() = value; + + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; + + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act, sigc::bind (sl, act->gobj())); + return act; } -} -void -ActionManager::check_toggleaction (string n) -{ - set_toggleaction_state (n, true); + /* already registered */ + + return RefPtr(); } -void -ActionManager::uncheck_toggleaction (string n) +RefPtr +ActionManager::register_toggle_action (RefPtr group, + const char* name, const char* label, sigc::slot sl) { - set_toggleaction_state (n, false); + string fullpath; + + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; + + RefPtr act = ToggleAction::create (name, label); + + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act, sl); + return act; + } + + /* already registered */ + return RefPtr(); } void -ActionManager::set_toggleaction_state (string n, bool s) +ActionManager::get_all_actions (std::vector& paths, + std::vector& labels, + std::vector& tooltips, + std::vector& keys, + std::vector >& acts) { - char const * name = n.c_str (); - - const char *last_slash = strrchr (name, '/'); + for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) { - if (last_slash == 0) { - fatal << string_compose ("programmer error: %1 %2", "illegal toggle action name", name) << endmsg; - /*NOTREACHED*/ - return; - } - - /* 10 = strlen ("/") */ - size_t len = last_slash - (name + 10); + Glib::RefPtr act = a->second; - char* group_name = new char[len+1]; - memcpy (group_name, name + 10, len); - group_name[len] = '\0'; + paths.push_back (act->get_accel_path()); + labels.push_back (act->get_label()); + tooltips.push_back (act->get_tooltip()); + acts.push_back (act); - const char* action_name = last_slash + 1; + /* foreach binding */ - RefPtr act = get_action (group_name, action_name); - if (act) { - RefPtr tact = RefPtr::cast_dynamic(act); - tact->set_active (s); - } else { - error << string_compose (_("Unknown action name: %1"), name) << endmsg; - } +#if 0 + Bindings* bindings = (*map)->bindings(); - delete [] group_name; -} + if (bindings) { -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; -} + KeyboardKey key; + Bindings::Operation op; -void -ActionManager::do_action (const char* group, const char*action) -{ - Glib::RefPtr act = ActionManager::get_action (group, action); - if (act) { - act->activate (); - } -} + key = bindings->get_binding_for_action (*act, op); -void -ActionManager::set_toggle_action (const char* group, const char*action, bool yn) -{ - Glib::RefPtr act = ActionManager::get_action (group, action); - if (act) { - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic (act); - if (tact) { - tact->set_active (yn); + if (key == KeyboardKey::null_key()) { + keys.push_back (string()); + } else { + keys.push_back (key.display_label()); + } + } else { + keys.push_back (string()); + } } +#endif + } } -