(root)/
glib-2.79.0/
gio/
gactionmap.c
       1  /*
       2   * Copyright © 2010 Codethink Limited
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General
      17   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Authors: Ryan Lortie <desrt@desrt.ca>
      20   */
      21  
      22  #include "config.h"
      23  
      24  #include "gsimpleaction.h"
      25  #include "gactionmap.h"
      26  #include "gaction.h"
      27  
      28  /**
      29   * GActionMap:
      30   *
      31   * `GActionMap` is an interface for action containers.
      32   *
      33   * The `GActionMap` interface is implemented by [iface@Gio.ActionGroup]
      34   * implementations that operate by containing a number of named
      35   * [iface@Gio.Action] instances, such as [class@Gio.SimpleActionGroup].
      36   *
      37   * One useful application of this interface is to map the
      38   * names of actions from various action groups to unique,
      39   * prefixed names (e.g. by prepending "app." or "win.").
      40   * This is the motivation for the 'Map' part of the interface
      41   * name.
      42   *
      43   * Since: 2.32
      44   */
      45  
      46  /**
      47   * GActionMapInterface:
      48   * @lookup_action: the virtual function pointer for g_action_map_lookup_action()
      49   * @add_action: the virtual function pointer for g_action_map_add_action()
      50   * @remove_action: the virtual function pointer for g_action_map_remove_action()
      51   *
      52   * The virtual function table for #GActionMap.
      53   *
      54   * Since: 2.32
      55   **/
      56  
      57  G_DEFINE_INTERFACE (GActionMap, g_action_map, G_TYPE_OBJECT)
      58  
      59  static void
      60  g_action_map_default_init (GActionMapInterface *iface)
      61  {
      62  }
      63  
      64  /**
      65   * g_action_map_lookup_action:
      66   * @action_map: a #GActionMap
      67   * @action_name: the name of an action
      68   *
      69   * Looks up the action with the name @action_name in @action_map.
      70   *
      71   * If no such action exists, returns %NULL.
      72   *
      73   * Returns: (nullable) (transfer none): a #GAction, or %NULL
      74   *
      75   * Since: 2.32
      76   */
      77  GAction *
      78  g_action_map_lookup_action (GActionMap  *action_map,
      79                              const gchar *action_name)
      80  {
      81    return G_ACTION_MAP_GET_IFACE (action_map)
      82      ->lookup_action (action_map, action_name);
      83  }
      84  
      85  /**
      86   * g_action_map_add_action:
      87   * @action_map: a #GActionMap
      88   * @action: a #GAction
      89   *
      90   * Adds an action to the @action_map.
      91   *
      92   * If the action map already contains an action with the same name
      93   * as @action then the old action is dropped from the action map.
      94   *
      95   * The action map takes its own reference on @action.
      96   *
      97   * Since: 2.32
      98   */
      99  void
     100  g_action_map_add_action (GActionMap *action_map,
     101                           GAction    *action)
     102  {
     103    G_ACTION_MAP_GET_IFACE (action_map)->add_action (action_map, action);
     104  }
     105  
     106  /**
     107   * g_action_map_remove_action:
     108   * @action_map: a #GActionMap
     109   * @action_name: the name of the action
     110   *
     111   * Removes the named action from the action map.
     112   *
     113   * If no action of this name is in the map then nothing happens.
     114   *
     115   * Since: 2.32
     116   */
     117  void
     118  g_action_map_remove_action (GActionMap  *action_map,
     119                              const gchar *action_name)
     120  {
     121    G_ACTION_MAP_GET_IFACE (action_map)->remove_action (action_map, action_name);
     122  }
     123  
     124  /**
     125   * GActionEntry:
     126   * @name: the name of the action
     127   * @activate: the callback to connect to the "activate" signal of the
     128   *            action.  Since GLib 2.40, this can be %NULL for stateful
     129   *            actions, in which case the default handler is used.  For
     130   *            boolean-stated actions with no parameter, this is a
     131   *            toggle.  For other state types (and parameter type equal
     132   *            to the state type) this will be a function that
     133   *            just calls @change_state (which you should provide).
     134   * @parameter_type: the type of the parameter that must be passed to the
     135   *                  activate function for this action, given as a single
     136   *                  GVariant type string (or %NULL for no parameter)
     137   * @state: the initial state for this action, given in
     138   *         [GVariant text format][gvariant-text].  The state is parsed
     139   *         with no extra type information, so type tags must be added to
     140   *         the string if they are necessary.  Stateless actions should
     141   *         give %NULL here.
     142   * @change_state: the callback to connect to the "change-state" signal
     143   *                of the action.  All stateful actions should provide a
     144   *                handler here; stateless actions should not.
     145   *
     146   * This struct defines a single action.  It is for use with
     147   * g_action_map_add_action_entries().
     148   *
     149   * The order of the items in the structure are intended to reflect
     150   * frequency of use.  It is permissible to use an incomplete initialiser
     151   * in order to leave some of the later values as %NULL.  All values
     152   * after @name are optional.  Additional optional fields may be added in
     153   * the future.
     154   *
     155   * See g_action_map_add_action_entries() for an example.
     156   **/
     157  
     158  /**
     159   * g_action_map_add_action_entries:
     160   * @action_map: a #GActionMap
     161   * @entries: (array length=n_entries) (element-type GActionEntry): a pointer to
     162   *           the first item in an array of #GActionEntry structs
     163   * @n_entries: the length of @entries, or -1 if @entries is %NULL-terminated
     164   * @user_data: the user data for signal connections
     165   *
     166   * A convenience function for creating multiple #GSimpleAction instances
     167   * and adding them to a #GActionMap.
     168   *
     169   * Each action is constructed as per one #GActionEntry.
     170   *
     171   * |[<!-- language="C" -->
     172   * static void
     173   * activate_quit (GSimpleAction *simple,
     174   *                GVariant      *parameter,
     175   *                gpointer       user_data)
     176   * {
     177   *   exit (0);
     178   * }
     179   *
     180   * static void
     181   * activate_print_string (GSimpleAction *simple,
     182   *                        GVariant      *parameter,
     183   *                        gpointer       user_data)
     184   * {
     185   *   g_print ("%s\n", g_variant_get_string (parameter, NULL));
     186   * }
     187   *
     188   * static GActionGroup *
     189   * create_action_group (void)
     190   * {
     191   *   const GActionEntry entries[] = {
     192   *     { "quit",         activate_quit              },
     193   *     { "print-string", activate_print_string, "s" }
     194   *   };
     195   *   GSimpleActionGroup *group;
     196   *
     197   *   group = g_simple_action_group_new ();
     198   *   g_action_map_add_action_entries (G_ACTION_MAP (group), entries, G_N_ELEMENTS (entries), NULL);
     199   *
     200   *   return G_ACTION_GROUP (group);
     201   * }
     202   * ]|
     203   *
     204   * Since: 2.32
     205   */
     206  void
     207  g_action_map_add_action_entries (GActionMap         *action_map,
     208                                   const GActionEntry *entries,
     209                                   gint                n_entries,
     210                                   gpointer            user_data)
     211  {
     212    g_return_if_fail (G_IS_ACTION_MAP (action_map));
     213    g_return_if_fail (entries != NULL || n_entries == 0);
     214  
     215    for (int i = 0; n_entries < 0 ? entries[i].name != NULL : i < n_entries; i++)
     216      {
     217        const GActionEntry *entry = &entries[i];
     218        const GVariantType *parameter_type;
     219        GSimpleAction *action;
     220  
     221        if (entry->parameter_type)
     222          {
     223            if (!g_variant_type_string_is_valid (entry->parameter_type))
     224              {
     225                g_critical ("g_action_map_add_entries: the type "
     226                            "string '%s' given as the parameter type for "
     227                            "action '%s' is not a valid GVariant type "
     228                            "string.  This action will not be added.",
     229                            entry->parameter_type, entry->name);
     230                return;
     231              }
     232  
     233            parameter_type = G_VARIANT_TYPE (entry->parameter_type);
     234          }
     235        else
     236          parameter_type = NULL;
     237  
     238        if (entry->state)
     239          {
     240            GError *error = NULL;
     241            GVariant *state;
     242  
     243            state = g_variant_parse (NULL, entry->state, NULL, NULL, &error);
     244            if (state == NULL)
     245              {
     246                g_critical ("g_action_map_add_entries: GVariant could "
     247                            "not parse the state value given for action '%s' "
     248                            "('%s'): %s.  This action will not be added.",
     249                            entry->name, entry->state, error->message);
     250                g_error_free (error);
     251                continue;
     252              }
     253  
     254            action = g_simple_action_new_stateful (entry->name,
     255                                                   parameter_type,
     256                                                   state);
     257  
     258            g_variant_unref (state);
     259          }
     260        else
     261          {
     262            action = g_simple_action_new (entry->name,
     263                                          parameter_type);
     264          }
     265  
     266        if (entry->activate != NULL)
     267          g_signal_connect (action, "activate",
     268                            G_CALLBACK (entry->activate), user_data);
     269  
     270        if (entry->change_state != NULL)
     271          g_signal_connect (action, "change-state",
     272                            G_CALLBACK (entry->change_state), user_data);
     273  
     274        g_action_map_add_action (action_map, G_ACTION (action));
     275        g_object_unref (action);
     276      }
     277  }
     278  
     279  /**
     280   * g_action_map_remove_action_entries:
     281   * @action_map: The #GActionMap
     282   * @entries: (array length=n_entries) (element-type GActionEntry): a pointer to
     283   *           the first item in an array of #GActionEntry structs
     284   * @n_entries: the length of @entries, or -1 if @entries is %NULL-terminated
     285   *
     286   * Remove actions from a #GActionMap. This is meant as the reverse of
     287   * g_action_map_add_action_entries().
     288   *
     289   *
     290   * |[<!-- language="C" -->
     291   * static const GActionEntry entries[] = {
     292   *     { "quit",         activate_quit              },
     293   *     { "print-string", activate_print_string, "s" }
     294   * };
     295   *
     296   * void
     297   * add_actions (GActionMap *map)
     298   * {
     299   *   g_action_map_add_action_entries (map, entries, G_N_ELEMENTS (entries), NULL);
     300   * }
     301   *
     302   * void
     303   * remove_actions (GActionMap *map)
     304   * {
     305   *   g_action_map_remove_action_entries (map, entries, G_N_ELEMENTS (entries));
     306   * }
     307   * ]|
     308   *
     309   * Since: 2.78
     310   */
     311  void
     312  g_action_map_remove_action_entries (GActionMap         *action_map,
     313                                      const GActionEntry  entries[],
     314                                      gint                n_entries)
     315  {
     316    g_return_if_fail (G_IS_ACTION_MAP (action_map));
     317    g_return_if_fail (entries != NULL || n_entries == 0);
     318  
     319    for (int i = 0; n_entries < 0 ? entries[i].name != NULL : i < n_entries; i++)
     320      g_action_map_remove_action (action_map, entries[i].name);
     321  }