X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fgtkmm2ext%2Factions.cc;h=25d2ca148cbf6ec19267e6ab4a2ee0564a9147af;hb=58db958839db7c052b95aae86ce9eb6f66ce9854;hp=43a2a24d2d900909ac1a834a869363cc9bf5c2d1;hpb=99c2d589d11114a714a4296c6283b961972cd24d;p=ardour.git diff --git a/libs/gtkmm2ext/actions.cc b/libs/gtkmm2ext/actions.cc index 43a2a24d2d..25d2ca148c 100644 --- a/libs/gtkmm2ext/actions.cc +++ b/libs/gtkmm2ext/actions.cc @@ -21,21 +21,28 @@ #include #include #include +#include #include +#include + #include #include #include +#include #include #include +#include + #include "pbd/error.h" +#include "pbd/stacktrace.h" #include "gtkmm2ext/actions.h" #include "gtkmm2ext/utils.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace Gtk; @@ -44,276 +51,481 @@ 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_toggle_action (RefPtr group, const char * name, const char * label, slot sl) +void +ActionManager::enable_active_actions () { - RefPtr act; + if (!actions_disabled) { + return ; + } - act = ToggleAction::create (name, label); - 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; } -bool -ActionManager::lookup_entry (const ustring accel_path, Gtk::AccelKey& key) +void +ActionManager::disable_active_actions () { - GtkAccelKey gkey; - bool known = gtk_accel_map_lookup_entry (accel_path.c_str(), &gkey); + if (actions_disabled == true ) { + return ; + } + // save all action's states to action_states_to_restore + save_action_states (); - if (known) { - key = AccelKey (gkey.accel_key, Gdk::ModifierType (gkey.accel_mods)); - } else { - key = AccelKey (GDK_VoidSymbol, Gdk::ModifierType (0)); + // 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; +} - return known; +Widget* +ActionManager::get_widget (const char * name) +{ + return ui_manager->get_widget (name); } -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::set_sensitive (vector >& actions, bool state) +{ + // 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; + } + } + } + } +} void -ActionManager::get_all_actions (vector& groups, vector& names, vector& bindings) +ActionManager::check_toggleaction (const string& n) { - /* the C++ API for functions used here appears to be broken in - gtkmm2.6, so we fall back to the C level. - */ + set_toggleaction_state (n, true); +} - GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj()); - GList* node; - GList* acts; +void +ActionManager::uncheck_toggleaction (const string& n) +{ + set_toggleaction_state (n, false); +} - for (node = list; node; node = g_list_next (node)) { +void +ActionManager::set_toggleaction_state (const string& n, bool s) +{ + char const * name = n.c_str (); - GtkActionGroup* group = (GtkActionGroup*) node->data; + const char *last_slash = strrchr (name, '/'); - /* first pass: collect them all */ + if (last_slash == 0) { + fatal << string_compose ("programmer error: %1 %2", "illegal toggle action name", name) << endmsg; + abort(); /*NOTREACHED*/ + return; + } - typedef std::list > action_list; - action_list the_acts; + /* 10 = strlen ("/") */ + size_t len = last_slash - (name + 10); - 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)); + char* group_name = new char[len+1]; + memcpy (group_name, name + 10, len); + group_name[len] = '\0'; + + 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; + } + + delete [] group_name; +} + +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; +} + +void +ActionManager::do_action (const char* group, const char*action) +{ + Glib::RefPtr act = ActionManager::get_action (group, action); + if (act) { + act->activate (); + } +} + +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); +} + +RefPtr +ActionManager::get_action (const string& name, bool or_die) +{ + ActionMap::const_iterator a = actions.find (name); + + if (a != actions.end()) { + return a->second; + } - /* now sort by label */ + if (or_die) { + ::abort (); + } + + cerr << "Failed to find action: [" << name << ']' << endl; + return RefPtr(); +} - SortActionsByLabel cmp; - the_acts.sort (cmp); +RefPtr +ActionManager::get_toggle_action (const string& name, bool or_die) +{ + RefPtr act = get_action (name, or_die); - for (action_list::iterator a = the_acts.begin(); a != the_acts.end(); ++a) { + if (!act) { + return RefPtr(); + } - string accel_path = (*a)->get_accel_path (); + return Glib::RefPtr::cast_dynamic (act); +} - groups.push_back (gtk_action_group_get_name(group)); - names.push_back (accel_path.substr (accel_path.find_last_of ('/') + 1)); +RefPtr +ActionManager::get_radio_action (const string& name, bool or_die) +{ + RefPtr act = get_action (name, or_die); - AccelKey key; - lookup_entry (accel_path, key); - bindings.push_back (AccelKey (key.get_key(), Gdk::ModifierType (key.get_mod()))); - } + if (!act) { + return RefPtr(); } + + return Glib::RefPtr::cast_dynamic (act); } -void -ActionManager::get_all_actions (vector& names, vector& paths, vector& keys, vector& bindings) +RefPtr +ActionManager::get_action (char const * group_name, char const * action_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. - */ + string fullpath (group_name); + fullpath += '/'; + fullpath += action_name; - GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj()); - GList* node; - GList* acts; + ActionMap::const_iterator a = actions.find (fullpath); - for (node = list; node; node = g_list_next (node)) { + if (a != actions.end()) { + return a->second; + } - GtkActionGroup* group = (GtkActionGroup*) node->data; + if (or_die) { + ::abort (); + } - /* first pass: collect them all */ + cerr << "Failed to find action (2): [" << fullpath << ']' << endl; + PBD::stacktrace (std::cerr, 20); + return RefPtr(); +} - typedef std::list > action_list; - action_list the_acts; +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); - 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)); - } + if (!act) { + return RefPtr(); + } - /* now sort by label */ + return Glib::RefPtr::cast_dynamic (act); +} - SortActionsByLabel cmp; - the_acts.sort (cmp); +RefPtr +ActionManager::get_radio_action (char const * group_name, char const * action_name, bool or_die) +{ + RefPtr act = get_action (group_name, action_name, or_die); - for (action_list::iterator a = the_acts.begin(); a != the_acts.end(); ++a) { + if (!act) { + return RefPtr(); + } - string accel_path = (*a)->get_accel_path (); - ustring label = (*a)->property_label(); + return Glib::RefPtr::cast_dynamic (act); +} - names.push_back (label); - paths.push_back (accel_path); - AccelKey key; - keys.push_back (get_key_representation (accel_path, key)); - bindings.push_back (AccelKey (key.get_key(), Gdk::ModifierType (key.get_mod()))); +RefPtr +ActionManager::create_action_group (void * owner, string const & name) +{ + for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) { + if ((*g)->get_name () == name) { + return *g; } } + + RefPtr g = ActionGroup::create (name); + + g->set_data (X_("owner"), owner); + groups.push_back (g); + + /* 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; } -void -ActionManager::add_action_group (RefPtr grp) +RefPtr +ActionManager::register_action (RefPtr group, const char* name, const char* label) { - ui_manager->insert_action_group (grp); + string fullpath; + + RefPtr act = Action::create (name, label); + + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; + + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act); + return act; + } + + /* already registered */ + return RefPtr (); } -Widget* -ActionManager::get_widget (const char * name) +RefPtr +ActionManager::register_action (RefPtr group, + const char* name, const char* label, sigc::slot sl) { - return ui_manager->get_widget (name); + string fullpath; + + RefPtr act = Action::create (name, label); + + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; + + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act, sl); + return act; + } + + /* already registered */ + return RefPtr(); } RefPtr -ActionManager::get_action (const char* path) +ActionManager::register_radio_action (RefPtr group, + Gtk::RadioAction::Group& rgroup, + const char* name, const char* label, + sigc::slot sl) { - GtkAction* _act; - RefPtr act; + string fullpath; + + RefPtr act = RadioAction::create (rgroup, name, label); + RefPtr ract = RefPtr::cast_dynamic(act); - if ((_act = gtk_ui_manager_get_action (ui_manager->gobj(), path)) != 0) { - return Glib::wrap (_act, true); + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; + + 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 (const char* group_name, const char* action_name) +ActionManager::register_radio_action (RefPtr group, + Gtk::RadioAction::Group& rgroup, + const char* name, const char* label, + sigc::slot sl, + int value) { - /* the C++ API for functions used here appears to be broken in - gtkmm2.6, so we fall back to the C level. - */ + 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 (ui_manager == 0) { - return RefPtr (); + if (actions.insert (ActionMap::value_type (fullpath, act)).second) { + group->add (act, sigc::bind (sl, act->gobj())); + return act; } - GList* list = gtk_ui_manager_get_action_groups (ui_manager->gobj()); - GList* node; - RefPtr act; + /* already registered */ - for (node = list; node; node = g_list_next (node)) { + return RefPtr(); +} - GtkActionGroup* _ag = (GtkActionGroup*) node->data; +RefPtr +ActionManager::register_toggle_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) { + fullpath = group->get_name(); + fullpath += '/'; + fullpath += name; - GtkAction* _act; + RefPtr act = ToggleAction::create (name, label); - 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(); } void -ActionManager::set_sensitive (vector >& actions, bool state) +ActionManager::get_actions (void* owner, std::vector >& acts) { - for (vector >::iterator i = actions.begin(); i != actions.end(); ++i) { - (*i)->set_sensitive (state); + for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) { + if (owner) { + Glib::RefPtr group = a->second->property_action_group (); + if (group->get_data (X_("owner")) == owner) { + acts.push_back (a->second); + } + } else { + acts.push_back (a->second); + } } } void -ActionManager::uncheck_toggleaction (string n) +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; - } + Glib::RefPtr act = a->second; - /* 10 = strlen ("/") */ - size_t len = last_slash - (name + 10); + paths.push_back (act->get_accel_path()); + labels.push_back (act->get_label()); + tooltips.push_back (act->get_tooltip()); + acts.push_back (act); - char* group_name = new char[len+1]; - memcpy (group_name, name + 10, len); - group_name[len] = '\0'; + /* foreach binding */ - const char* action_name = last_slash + 1; +#if 0 + Bindings* bindings = (*map)->bindings(); - RefPtr act = get_action (group_name, action_name); - if (act) { - RefPtr tact = RefPtr::cast_dynamic(act); - tact->set_active (false); - } else { - error << string_compose (_("Unknown action name: %1"), name) << endmsg; - } + if (bindings) { - delete [] group_name; -} + KeyboardKey key; + Bindings::Operation op; -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()->name (key.get_key(), Gdk::ModifierType (key.get_mod())); - } - - return unbound_string; + key = bindings->get_binding_for_action (*act, op); + + if (key == KeyboardKey::null_key()) { + keys.push_back (string()); + } else { + keys.push_back (key.display_label()); + } + } else { + keys.push_back (string()); + } + } +#endif + + } }