(root)/
glib-2.79.0/
gio/
gmenumodel.c
       1  /*
       2   * Copyright © 2011 Canonical Ltd.
       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, but
      12   * 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 Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Author: Ryan Lortie <desrt@desrt.ca>
      20   */
      21  
      22  #include "config.h"
      23  
      24  #include "gmenumodel.h"
      25  
      26  #include "glibintl.h"
      27  #include "gmarshal-internal.h"
      28  
      29  /**
      30   * GMenuModel:
      31   *
      32   * `GMenuModel` represents the contents of a menu — an ordered list of
      33   * menu items. The items are associated with actions, which can be
      34   * activated through them. Items can be grouped in sections, and may
      35   * have submenus associated with them. Both items and sections usually
      36   * have some representation data, such as labels or icons. The type of
      37   * the associated action (ie whether it is stateful, and what kind of
      38   * state it has) can influence the representation of the item.
      39   *
      40   * The conceptual model of menus in `GMenuModel` is hierarchical:
      41   * sections and submenus are again represented by `GMenuModel`s.
      42   * Menus themselves do not define their own roles. Rather, the role
      43   * of a particular `GMenuModel` is defined by the item that references
      44   * it (or, in the case of the ‘root’ menu, is defined by the context
      45   * in which it is used).
      46   *
      47   * As an example, consider the visible portions of this menu:
      48   *
      49   * ## An example menu
      50   *
      51   * ![](menu-example.png)
      52   *
      53   * There are 8 ‘menus’ visible in the screenshot: one menubar, two
      54   * submenus and 5 sections:
      55   *
      56   * - the toplevel menubar (containing 4 items)
      57   * - the View submenu (containing 3 sections)
      58   * - the first section of the View submenu (containing 2 items)
      59   * - the second section of the View submenu (containing 1 item)
      60   * - the final section of the View submenu (containing 1 item)
      61   * - the Highlight Mode submenu (containing 2 sections)
      62   * - the Sources section (containing 2 items)
      63   * - the Markup section (containing 2 items)
      64   *
      65   * The [example](#a-menu-example) illustrates the conceptual connection between
      66   * these 8 menus. Each large block in the figure represents a menu and the
      67   * smaller blocks within the large block represent items in that menu. Some
      68   * items contain references to other menus.
      69   *
      70   * ## A menu example
      71   *
      72   * ![](menu-model.png)
      73   *
      74   * Notice that the separators visible in the [example](#an-example-menu)
      75   * appear nowhere in the [menu model](#a-menu-example). This is because
      76   * separators are not explicitly represented in the menu model. Instead,
      77   * a separator is inserted between any two non-empty sections of a menu.
      78   * Section items can have labels just like any other item. In that case,
      79   * a display system may show a section header instead of a separator.
      80   *
      81   * The motivation for this abstract model of application controls is
      82   * that modern user interfaces tend to make these controls available
      83   * outside the application. Examples include global menus, jumplists,
      84   * dash boards, etc. To support such uses, it is necessary to ‘export’
      85   * information about actions and their representation in menus, which
      86   * is exactly what the action group exporter and the menu model exporter do for
      87   * [iface@Gio.ActionGroup] and [class@Gio.MenuModel]. The client-side
      88   * counterparts to make use of the exported information are
      89   * [class@Gio.DBusActionGroup] and [class@Gio.DBusMenuModel].
      90   *
      91   * The API of `GMenuModel` is very generic, with iterators for the
      92   * attributes and links of an item, see
      93   * [method@Gio.MenuModel.iterate_item_attributes] and
      94   * [method@Gio.MenuModel.iterate_item_links]. The ‘standard’ attributes and
      95   * link types have predefined names: `G_MENU_ATTRIBUTE_LABEL`,
      96   * `G_MENU_ATTRIBUTE_ACTION`, `G_MENU_ATTRIBUTE_TARGET`, `G_MENU_LINK_SECTION`
      97   * and `G_MENU_LINK_SUBMENU`.
      98   *
      99   * Items in a `GMenuModel` represent active controls if they refer to
     100   * an action that can get activated when the user interacts with the
     101   * menu item. The reference to the action is encoded by the string ID
     102   * in the `G_MENU_ATTRIBUTE_ACTION` attribute. An action ID uniquely
     103   * identifies an action in an action group. Which action group(s) provide
     104   * actions depends on the context in which the menu model is used.
     105   * E.g. when the model is exported as the application menu of a
     106   * [class@Gtk.Application], actions can be application-wide or window-specific
     107   * (and thus come from two different action groups). By convention, the
     108   * application-wide actions have names that start with `app.`, while the
     109   * names of window-specific actions start with `win.`.
     110   *
     111   * While a wide variety of stateful actions is possible, the following
     112   * is the minimum that is expected to be supported by all users of exported
     113   * menu information:
     114   * - an action with no parameter type and no state
     115   * - an action with no parameter type and boolean state
     116   * - an action with string parameter type and string state
     117   *
     118   * ## Stateless
     119   *
     120   * A stateless action typically corresponds to an ordinary menu item.
     121   *
     122   * Selecting such a menu item will activate the action (with no parameter).
     123   *
     124   * ## Boolean State
     125   *
     126   * An action with a boolean state will most typically be used with a ‘toggle’
     127   * or ‘switch’ menu item. The state can be set directly, but activating the
     128   * action (with no parameter) results in the state being toggled.
     129   *
     130   * Selecting a toggle menu item will activate the action. The menu item should
     131   * be rendered as ‘checked’ when the state is true.
     132   *
     133   * ## String Parameter and State
     134   *
     135   * Actions with string parameters and state will most typically be used to
     136   * represent an enumerated choice over the items available for a group of
     137   * radio menu items. Activating the action with a string parameter is
     138   * equivalent to setting that parameter as the state.
     139   *
     140   * Radio menu items, in addition to being associated with the action, will
     141   * have a target value. Selecting that menu item will result in activation
     142   * of the action with the target value as the parameter. The menu item should
     143   * be rendered as ‘selected’ when the state of the action is equal to the
     144   * target value of the menu item.
     145   *
     146   * Since: 2.32
     147   */
     148  
     149  /**
     150   * GMenuAttributeIter:
     151   *
     152   * #GMenuAttributeIter is an opaque structure type.  You must access it
     153   * using the functions below.
     154   *
     155   * Since: 2.32
     156   */
     157  
     158  /**
     159   * GMenuLinkIter:
     160   *
     161   * #GMenuLinkIter is an opaque structure type.  You must access it using
     162   * the functions below.
     163   *
     164   * Since: 2.32
     165   */
     166  
     167  typedef struct
     168  {
     169    GMenuLinkIter parent_instance;
     170    GHashTableIter iter;
     171    GHashTable *table;
     172  } GMenuLinkHashIter;
     173  
     174  typedef GMenuLinkIterClass GMenuLinkHashIterClass;
     175  
     176  static GType g_menu_link_hash_iter_get_type (void);
     177  
     178  G_DEFINE_TYPE (GMenuLinkHashIter, g_menu_link_hash_iter, G_TYPE_MENU_LINK_ITER)
     179  
     180  static gboolean
     181  g_menu_link_hash_iter_get_next (GMenuLinkIter  *link_iter,
     182                                  const gchar   **out_name,
     183                                  GMenuModel    **value)
     184  {
     185    GMenuLinkHashIter *iter = (GMenuLinkHashIter *) link_iter;
     186    gpointer keyptr, valueptr;
     187  
     188    if (!g_hash_table_iter_next (&iter->iter, &keyptr, &valueptr))
     189      return FALSE;
     190  
     191    *out_name = keyptr;
     192    *value = g_object_ref (valueptr);
     193  
     194    return TRUE;
     195  }
     196  
     197  static void
     198  g_menu_link_hash_iter_finalize (GObject *object)
     199  {
     200    GMenuLinkHashIter *iter = (GMenuLinkHashIter *) object;
     201  
     202    g_hash_table_unref (iter->table);
     203  
     204    G_OBJECT_CLASS (g_menu_link_hash_iter_parent_class)
     205      ->finalize (object);
     206  }
     207  
     208  static void
     209  g_menu_link_hash_iter_init (GMenuLinkHashIter *iter)
     210  {
     211  }
     212  
     213  static void
     214  g_menu_link_hash_iter_class_init (GMenuLinkHashIterClass *class)
     215  {
     216    GObjectClass *object_class = G_OBJECT_CLASS (class);
     217  
     218    object_class->finalize = g_menu_link_hash_iter_finalize;
     219    class->get_next = g_menu_link_hash_iter_get_next;
     220  }
     221  
     222  
     223  typedef struct
     224  {
     225    GMenuAttributeIter parent_instance;
     226    GHashTableIter iter;
     227    GHashTable *table;
     228  } GMenuAttributeHashIter;
     229  
     230  typedef GMenuAttributeIterClass GMenuAttributeHashIterClass;
     231  
     232  static GType g_menu_attribute_hash_iter_get_type (void);
     233  
     234  G_DEFINE_TYPE (GMenuAttributeHashIter, g_menu_attribute_hash_iter, G_TYPE_MENU_ATTRIBUTE_ITER)
     235  
     236  static gboolean
     237  g_menu_attribute_hash_iter_get_next (GMenuAttributeIter  *attr_iter,
     238                                       const gchar        **name,
     239                                       GVariant           **value)
     240  {
     241    GMenuAttributeHashIter *iter = (GMenuAttributeHashIter *) attr_iter;
     242    gpointer keyptr, valueptr;
     243  
     244    if (!g_hash_table_iter_next (&iter->iter, &keyptr, &valueptr))
     245      return FALSE;
     246  
     247    *name = keyptr;
     248  
     249    *value = g_variant_ref (valueptr);
     250  
     251    return TRUE;
     252  }
     253  
     254  static void
     255  g_menu_attribute_hash_iter_finalize (GObject *object)
     256  {
     257    GMenuAttributeHashIter *iter = (GMenuAttributeHashIter *) object;
     258  
     259    g_hash_table_unref (iter->table);
     260  
     261    G_OBJECT_CLASS (g_menu_attribute_hash_iter_parent_class)
     262      ->finalize (object);
     263  }
     264  
     265  static void
     266  g_menu_attribute_hash_iter_init (GMenuAttributeHashIter *iter)
     267  {
     268  }
     269  
     270  static void
     271  g_menu_attribute_hash_iter_class_init (GMenuAttributeHashIterClass *class)
     272  {
     273    GObjectClass *object_class = G_OBJECT_CLASS (class);
     274  
     275    object_class->finalize = g_menu_attribute_hash_iter_finalize;
     276    class->get_next = g_menu_attribute_hash_iter_get_next;
     277  }
     278  
     279  G_DEFINE_ABSTRACT_TYPE (GMenuModel, g_menu_model, G_TYPE_OBJECT)
     280  
     281  
     282  static guint g_menu_model_items_changed_signal;
     283  
     284  static GMenuAttributeIter *
     285  g_menu_model_real_iterate_item_attributes (GMenuModel *model,
     286                                             gint        item_index)
     287  {
     288    GHashTable *table = NULL;
     289    GMenuAttributeIter *result;
     290  
     291    G_MENU_MODEL_GET_CLASS (model)->get_item_attributes (model, item_index, &table);
     292  
     293    if (table)
     294      {
     295        GMenuAttributeHashIter *iter = g_object_new (g_menu_attribute_hash_iter_get_type (), NULL);
     296        g_hash_table_iter_init (&iter->iter, table);
     297        iter->table = g_hash_table_ref (table);
     298        result = G_MENU_ATTRIBUTE_ITER (iter);
     299      }
     300    else
     301      {
     302        g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_attributes() "
     303                    "and fails to return valid values from get_item_attributes()",
     304                    G_OBJECT_TYPE_NAME (model));
     305        result = NULL;
     306      }
     307  
     308    if (table != NULL)
     309      g_hash_table_unref (table);
     310  
     311    return result;
     312  }
     313  
     314  static GVariant *
     315  g_menu_model_real_get_item_attribute_value (GMenuModel         *model,
     316                                              gint                item_index,
     317                                              const gchar        *attribute,
     318                                              const GVariantType *expected_type)
     319  {
     320    GHashTable *table = NULL;
     321    GVariant *value = NULL;
     322  
     323    G_MENU_MODEL_GET_CLASS (model)
     324      ->get_item_attributes (model, item_index, &table);
     325  
     326    if (table != NULL)
     327      {
     328        value = g_hash_table_lookup (table, attribute);
     329  
     330        if (value != NULL)
     331          {
     332            if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
     333              value = g_variant_ref (value);
     334            else
     335              value = NULL;
     336          }
     337      }
     338    else
     339      g_assert_not_reached ();
     340  
     341    if (table != NULL)
     342      g_hash_table_unref (table);
     343  
     344    return value;
     345  }
     346  
     347  static GMenuLinkIter *
     348  g_menu_model_real_iterate_item_links (GMenuModel *model,
     349                                        gint        item_index)
     350  {
     351    GHashTable *table = NULL;
     352    GMenuLinkIter *result;
     353  
     354    G_MENU_MODEL_GET_CLASS (model)
     355      ->get_item_links (model, item_index, &table);
     356  
     357    if (table)
     358      {
     359        GMenuLinkHashIter *iter = g_object_new (g_menu_link_hash_iter_get_type (), NULL);
     360        g_hash_table_iter_init (&iter->iter, table);
     361        iter->table = g_hash_table_ref (table);
     362        result = G_MENU_LINK_ITER (iter);
     363      }
     364    else
     365      {
     366        g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_links() "
     367                    "and fails to return valid values from get_item_links()",
     368                    G_OBJECT_TYPE_NAME (model));
     369        result = NULL;
     370      }
     371  
     372    if (table != NULL)
     373      g_hash_table_unref (table);
     374  
     375    return result;
     376  }
     377  
     378  static GMenuModel *
     379  g_menu_model_real_get_item_link (GMenuModel  *model,
     380                                   gint         item_index,
     381                                   const gchar *link)
     382  {
     383    GHashTable *table = NULL;
     384    GMenuModel *value = NULL;
     385  
     386    G_MENU_MODEL_GET_CLASS (model)
     387      ->get_item_links (model, item_index, &table);
     388  
     389    if (table != NULL)
     390      value = g_hash_table_lookup (table, link);
     391    else
     392      g_assert_not_reached ();
     393  
     394    if (value != NULL)
     395      g_object_ref (value);
     396  
     397    if (table != NULL)
     398      g_hash_table_unref (table);
     399  
     400    return value;
     401  }
     402  
     403  static void
     404  g_menu_model_init (GMenuModel *model)
     405  {
     406  }
     407  
     408  static void
     409  g_menu_model_class_init (GMenuModelClass *class)
     410  {
     411    class->iterate_item_attributes = g_menu_model_real_iterate_item_attributes;
     412    class->get_item_attribute_value = g_menu_model_real_get_item_attribute_value;
     413    class->iterate_item_links = g_menu_model_real_iterate_item_links;
     414    class->get_item_link = g_menu_model_real_get_item_link;
     415  
     416    /**
     417     * GMenuModel::items-changed:
     418     * @model: the #GMenuModel that is changing
     419     * @position: the position of the change
     420     * @removed: the number of items removed
     421     * @added: the number of items added
     422     *
     423     * Emitted when a change has occurred to the menu.
     424     *
     425     * The only changes that can occur to a menu is that items are removed
     426     * or added.  Items may not change (except by being removed and added
     427     * back in the same location).  This signal is capable of describing
     428     * both of those changes (at the same time).
     429     *
     430     * The signal means that starting at the index @position, @removed
     431     * items were removed and @added items were added in their place.  If
     432     * @removed is zero then only items were added.  If @added is zero
     433     * then only items were removed.
     434     *
     435     * As an example, if the menu contains items a, b, c, d (in that
     436     * order) and the signal (2, 1, 3) occurs then the new composition of
     437     * the menu will be a, b, _, _, _, d (with each _ representing some
     438     * new item).
     439     *
     440     * Signal handlers may query the model (particularly the added items)
     441     * and expect to see the results of the modification that is being
     442     * reported.  The signal is emitted after the modification.
     443     **/
     444    g_menu_model_items_changed_signal =
     445      g_signal_new (I_("items-changed"), G_TYPE_MENU_MODEL,
     446                    G_SIGNAL_RUN_LAST, 0, NULL, NULL,
     447                    _g_cclosure_marshal_VOID__INT_INT_INT,
     448                    G_TYPE_NONE,
     449                    3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
     450    g_signal_set_va_marshaller (g_menu_model_items_changed_signal,
     451                                G_TYPE_FROM_CLASS (class),
     452                                _g_cclosure_marshal_VOID__INT_INT_INTv);
     453  }
     454  
     455  /**
     456   * g_menu_model_is_mutable:
     457   * @model: a #GMenuModel
     458   *
     459   * Queries if @model is mutable.
     460   *
     461   * An immutable #GMenuModel will never emit the #GMenuModel::items-changed
     462   * signal. Consumers of the model may make optimisations accordingly.
     463   *
     464   * Returns: %TRUE if the model is mutable (ie: "items-changed" may be
     465   *     emitted).
     466   *
     467   * Since: 2.32
     468   */
     469  gboolean
     470  g_menu_model_is_mutable (GMenuModel *model)
     471  {
     472    return G_MENU_MODEL_GET_CLASS (model)
     473      ->is_mutable (model);
     474  }
     475  
     476  /**
     477   * g_menu_model_get_n_items:
     478   * @model: a #GMenuModel
     479   *
     480   * Query the number of items in @model.
     481   *
     482   * Returns: the number of items
     483   *
     484   * Since: 2.32
     485   */
     486  gint
     487  g_menu_model_get_n_items (GMenuModel *model)
     488  {
     489    return G_MENU_MODEL_GET_CLASS (model)
     490      ->get_n_items (model);
     491  }
     492  
     493  /**
     494   * g_menu_model_iterate_item_attributes:
     495   * @model: a #GMenuModel
     496   * @item_index: the index of the item
     497   *
     498   * Creates a #GMenuAttributeIter to iterate over the attributes of
     499   * the item at position @item_index in @model.
     500   *
     501   * You must free the iterator with g_object_unref() when you are done.
     502   *
     503   * Returns: (transfer full): a new #GMenuAttributeIter
     504   *
     505   * Since: 2.32
     506   */
     507  GMenuAttributeIter *
     508  g_menu_model_iterate_item_attributes (GMenuModel *model,
     509                                        gint        item_index)
     510  {
     511    return G_MENU_MODEL_GET_CLASS (model)
     512      ->iterate_item_attributes (model, item_index);
     513  }
     514  
     515  /**
     516   * g_menu_model_get_item_attribute_value:
     517   * @model: a #GMenuModel
     518   * @item_index: the index of the item
     519   * @attribute: the attribute to query
     520   * @expected_type: (nullable): the expected type of the attribute, or
     521   *     %NULL
     522   *
     523   * Queries the item at position @item_index in @model for the attribute
     524   * specified by @attribute.
     525   *
     526   * If @expected_type is non-%NULL then it specifies the expected type of
     527   * the attribute.  If it is %NULL then any type will be accepted.
     528   *
     529   * If the attribute exists and matches @expected_type (or if the
     530   * expected type is unspecified) then the value is returned.
     531   *
     532   * If the attribute does not exist, or does not match the expected type
     533   * then %NULL is returned.
     534   *
     535   * Returns: (nullable) (transfer full): the value of the attribute
     536   *
     537   * Since: 2.32
     538   */
     539  GVariant *
     540  g_menu_model_get_item_attribute_value (GMenuModel         *model,
     541                                         gint                item_index,
     542                                         const gchar        *attribute,
     543                                         const GVariantType *expected_type)
     544  {
     545    return G_MENU_MODEL_GET_CLASS (model)
     546      ->get_item_attribute_value (model, item_index, attribute, expected_type);
     547  }
     548  
     549  /**
     550   * g_menu_model_get_item_attribute:
     551   * @model: a #GMenuModel
     552   * @item_index: the index of the item
     553   * @attribute: the attribute to query
     554   * @format_string: a #GVariant format string
     555   * @...: positional parameters, as per @format_string
     556   *
     557   * Queries item at position @item_index in @model for the attribute
     558   * specified by @attribute.
     559   *
     560   * If the attribute exists and matches the #GVariantType corresponding
     561   * to @format_string then @format_string is used to deconstruct the
     562   * value into the positional parameters and %TRUE is returned.
     563   *
     564   * If the attribute does not exist, or it does exist but has the wrong
     565   * type, then the positional parameters are ignored and %FALSE is
     566   * returned.
     567   *
     568   * This function is a mix of g_menu_model_get_item_attribute_value() and
     569   * g_variant_get(), followed by a g_variant_unref().  As such,
     570   * @format_string must make a complete copy of the data (since the
     571   * #GVariant may go away after the call to g_variant_unref()).  In
     572   * particular, no '&' characters are allowed in @format_string.
     573   *
     574   * Returns: %TRUE if the named attribute was found with the expected
     575   *     type
     576   *
     577   * Since: 2.32
     578   */
     579  gboolean
     580  g_menu_model_get_item_attribute (GMenuModel  *model,
     581                                   gint         item_index,
     582                                   const gchar *attribute,
     583                                   const gchar *format_string,
     584                                   ...)
     585  {
     586    GVariant *value;
     587    va_list ap;
     588  
     589    value = g_menu_model_get_item_attribute_value (model, item_index, attribute, NULL);
     590  
     591    if (value == NULL)
     592      return FALSE;
     593  
     594    if (!g_variant_check_format_string (value, format_string, TRUE))
     595      {
     596        g_variant_unref (value);
     597        return FALSE;
     598      }
     599  
     600    va_start (ap, format_string);
     601    g_variant_get_va (value, format_string, NULL, &ap);
     602    g_variant_unref (value);
     603    va_end (ap);
     604  
     605    return TRUE;
     606  }
     607  
     608  /**
     609   * g_menu_model_iterate_item_links:
     610   * @model: a #GMenuModel
     611   * @item_index: the index of the item
     612   *
     613   * Creates a #GMenuLinkIter to iterate over the links of the item at
     614   * position @item_index in @model.
     615   *
     616   * You must free the iterator with g_object_unref() when you are done.
     617   *
     618   * Returns: (transfer full): a new #GMenuLinkIter
     619   *
     620   * Since: 2.32
     621   */
     622  GMenuLinkIter *
     623  g_menu_model_iterate_item_links (GMenuModel *model,
     624                                   gint        item_index)
     625  {
     626    return G_MENU_MODEL_GET_CLASS (model)
     627      ->iterate_item_links (model, item_index);
     628  }
     629  
     630  /**
     631   * g_menu_model_get_item_link:
     632   * @model: a #GMenuModel
     633   * @item_index: the index of the item
     634   * @link: the link to query
     635   *
     636   * Queries the item at position @item_index in @model for the link
     637   * specified by @link.
     638   *
     639   * If the link exists, the linked #GMenuModel is returned.  If the link
     640   * does not exist, %NULL is returned.
     641   *
     642   * Returns: (nullable) (transfer full): the linked #GMenuModel, or %NULL
     643   *
     644   * Since: 2.32
     645   */
     646  GMenuModel *
     647  g_menu_model_get_item_link (GMenuModel *model,
     648                              gint        item_index,
     649                              const gchar *link)
     650  {
     651    return G_MENU_MODEL_GET_CLASS (model)
     652      ->get_item_link (model, item_index, link);
     653  }
     654  
     655  /**
     656   * g_menu_model_items_changed:
     657   * @model: a #GMenuModel
     658   * @position: the position of the change
     659   * @removed: the number of items removed
     660   * @added: the number of items added
     661   *
     662   * Requests emission of the #GMenuModel::items-changed signal on @model.
     663   *
     664   * This function should never be called except by #GMenuModel
     665   * subclasses.  Any other calls to this function will very likely lead
     666   * to a violation of the interface of the model.
     667   *
     668   * The implementation should update its internal representation of the
     669   * menu before emitting the signal.  The implementation should further
     670   * expect to receive queries about the new state of the menu (and
     671   * particularly added menu items) while signal handlers are running.
     672   *
     673   * The implementation must dispatch this call directly from a mainloop
     674   * entry and not in response to calls -- particularly those from the
     675   * #GMenuModel API.  Said another way: the menu must not change while
     676   * user code is running without returning to the mainloop.
     677   *
     678   * Since: 2.32
     679   */
     680  void
     681  g_menu_model_items_changed (GMenuModel *model,
     682                              gint        position,
     683                              gint        removed,
     684                              gint        added)
     685  {
     686    g_signal_emit (model, g_menu_model_items_changed_signal, 0, position, removed, added);
     687  }
     688  
     689  struct _GMenuAttributeIterPrivate
     690  {
     691    GQuark name;
     692    GVariant *value;
     693    gboolean valid;
     694  };
     695  
     696  G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GMenuAttributeIter, g_menu_attribute_iter, G_TYPE_OBJECT)
     697  
     698  /**
     699   * g_menu_attribute_iter_get_next:
     700   * @iter: a #GMenuAttributeIter
     701   * @out_name: (out) (optional) (transfer none): the type of the attribute
     702   * @value: (out) (optional) (transfer full): the attribute value
     703   *
     704   * This function combines g_menu_attribute_iter_next() with
     705   * g_menu_attribute_iter_get_name() and g_menu_attribute_iter_get_value().
     706   *
     707   * First the iterator is advanced to the next (possibly first) attribute.
     708   * If that fails, then %FALSE is returned and there are no other
     709   * effects.
     710   *
     711   * If successful, @name and @value are set to the name and value of the
     712   * attribute that has just been advanced to.  At this point,
     713   * g_menu_attribute_iter_get_name() and g_menu_attribute_iter_get_value() will
     714   * return the same values again.
     715   *
     716   * The value returned in @name remains valid for as long as the iterator
     717   * remains at the current position.  The value returned in @value must
     718   * be unreffed using g_variant_unref() when it is no longer in use.
     719   *
     720   * Returns: %TRUE on success, or %FALSE if there is no additional
     721   *     attribute
     722   *
     723   * Since: 2.32
     724   */
     725  gboolean
     726  g_menu_attribute_iter_get_next (GMenuAttributeIter  *iter,
     727                                  const gchar        **out_name,
     728                                  GVariant           **value)
     729  {
     730    const gchar *name;
     731  
     732    if (iter->priv->value)
     733      {
     734        g_variant_unref (iter->priv->value);
     735        iter->priv->value = NULL;
     736      }
     737  
     738    iter->priv->valid = G_MENU_ATTRIBUTE_ITER_GET_CLASS (iter)
     739      ->get_next (iter, &name, &iter->priv->value);
     740  
     741    if (iter->priv->valid)
     742      {
     743        iter->priv->name = g_quark_from_string (name);
     744        if (out_name)
     745          *out_name = g_quark_to_string (iter->priv->name);
     746  
     747        if (value)
     748          *value = g_variant_ref (iter->priv->value);
     749      }
     750  
     751    return iter->priv->valid;
     752  }
     753  
     754  /**
     755   * g_menu_attribute_iter_next:
     756   * @iter: a #GMenuAttributeIter
     757   *
     758   * Attempts to advance the iterator to the next (possibly first)
     759   * attribute.
     760   *
     761   * %TRUE is returned on success, or %FALSE if there are no more
     762   * attributes.
     763   *
     764   * You must call this function when you first acquire the iterator
     765   * to advance it to the first attribute (and determine if the first
     766   * attribute exists at all).
     767   *
     768   * Returns: %TRUE on success, or %FALSE when there are no more attributes
     769   *
     770   * Since: 2.32
     771   */
     772  gboolean
     773  g_menu_attribute_iter_next (GMenuAttributeIter *iter)
     774  {
     775    return g_menu_attribute_iter_get_next (iter, NULL, NULL);
     776  }
     777  
     778  /**
     779   * g_menu_attribute_iter_get_name:
     780   * @iter: a #GMenuAttributeIter
     781   *
     782   * Gets the name of the attribute at the current iterator position, as
     783   * a string.
     784   *
     785   * The iterator is not advanced.
     786   *
     787   * Returns: the name of the attribute
     788   *
     789   * Since: 2.32
     790   */
     791  const gchar *
     792  g_menu_attribute_iter_get_name (GMenuAttributeIter *iter)
     793  {
     794    g_return_val_if_fail (iter->priv->valid, 0);
     795  
     796    return g_quark_to_string (iter->priv->name);
     797  }
     798  
     799  /**
     800   * g_menu_attribute_iter_get_value:
     801   * @iter: a #GMenuAttributeIter
     802   *
     803   * Gets the value of the attribute at the current iterator position.
     804   *
     805   * The iterator is not advanced.
     806   *
     807   * Returns: (transfer full): the value of the current attribute
     808   *
     809   * Since: 2.32
     810   */
     811  GVariant *
     812  g_menu_attribute_iter_get_value (GMenuAttributeIter *iter)
     813  {
     814    g_return_val_if_fail (iter->priv->valid, NULL);
     815  
     816    return g_variant_ref (iter->priv->value);
     817  }
     818  
     819  static void
     820  g_menu_attribute_iter_finalize (GObject *object)
     821  {
     822    GMenuAttributeIter *iter = G_MENU_ATTRIBUTE_ITER (object);
     823  
     824    if (iter->priv->value)
     825      g_variant_unref (iter->priv->value);
     826  
     827    G_OBJECT_CLASS (g_menu_attribute_iter_parent_class)
     828      ->finalize (object);
     829  }
     830  
     831  static void
     832  g_menu_attribute_iter_init (GMenuAttributeIter *iter)
     833  {
     834    iter->priv = g_menu_attribute_iter_get_instance_private (iter);
     835  }
     836  
     837  static void
     838  g_menu_attribute_iter_class_init (GMenuAttributeIterClass *class)
     839  {
     840    GObjectClass *object_class = G_OBJECT_CLASS (class);
     841  
     842    object_class->finalize = g_menu_attribute_iter_finalize;
     843  }
     844  
     845  struct _GMenuLinkIterPrivate
     846  {
     847    GQuark name;
     848    GMenuModel *value;
     849    gboolean valid;
     850  };
     851  
     852  G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GMenuLinkIter, g_menu_link_iter, G_TYPE_OBJECT)
     853  
     854  /**
     855   * g_menu_link_iter_get_next:
     856   * @iter: a #GMenuLinkIter
     857   * @out_link: (out) (optional) (transfer none): the name of the link
     858   * @value: (out) (optional) (transfer full): the linked #GMenuModel
     859   *
     860   * This function combines g_menu_link_iter_next() with
     861   * g_menu_link_iter_get_name() and g_menu_link_iter_get_value().
     862   *
     863   * First the iterator is advanced to the next (possibly first) link.
     864   * If that fails, then %FALSE is returned and there are no other effects.
     865   *
     866   * If successful, @out_link and @value are set to the name and #GMenuModel
     867   * of the link that has just been advanced to.  At this point,
     868   * g_menu_link_iter_get_name() and g_menu_link_iter_get_value() will return the
     869   * same values again.
     870   *
     871   * The value returned in @out_link remains valid for as long as the iterator
     872   * remains at the current position.  The value returned in @value must
     873   * be unreffed using g_object_unref() when it is no longer in use.
     874   *
     875   * Returns: %TRUE on success, or %FALSE if there is no additional link
     876   *
     877   * Since: 2.32
     878   */
     879  gboolean
     880  g_menu_link_iter_get_next (GMenuLinkIter  *iter,
     881                             const gchar   **out_link,
     882                             GMenuModel    **value)
     883  {
     884    const gchar *name;
     885  
     886    if (iter->priv->value)
     887      {
     888        g_object_unref (iter->priv->value);
     889        iter->priv->value = NULL;
     890      }
     891  
     892    iter->priv->valid = G_MENU_LINK_ITER_GET_CLASS (iter)
     893      ->get_next (iter, &name, &iter->priv->value);
     894  
     895    if (iter->priv->valid)
     896      {
     897        g_assert (name != NULL);
     898  
     899        iter->priv->name = g_quark_from_string (name);
     900        if (out_link)
     901          *out_link = g_quark_to_string (iter->priv->name);
     902  
     903        if (value)
     904          *value = g_object_ref (iter->priv->value);
     905      }
     906  
     907    return iter->priv->valid;
     908  }
     909  
     910  /**
     911   * g_menu_link_iter_next:
     912   * @iter: a #GMenuLinkIter
     913   *
     914   * Attempts to advance the iterator to the next (possibly first)
     915   * link.
     916   *
     917   * %TRUE is returned on success, or %FALSE if there are no more links.
     918   *
     919   * You must call this function when you first acquire the iterator to
     920   * advance it to the first link (and determine if the first link exists
     921   * at all).
     922   *
     923   * Returns: %TRUE on success, or %FALSE when there are no more links
     924   *
     925   * Since: 2.32
     926   */
     927  gboolean
     928  g_menu_link_iter_next (GMenuLinkIter *iter)
     929  {
     930    return g_menu_link_iter_get_next (iter, NULL, NULL);
     931  }
     932  
     933  /**
     934   * g_menu_link_iter_get_name:
     935   * @iter: a #GMenuLinkIter
     936   *
     937   * Gets the name of the link at the current iterator position.
     938   *
     939   * The iterator is not advanced.
     940   *
     941   * Returns: the type of the link
     942   *
     943   * Since: 2.32
     944   */
     945  const gchar *
     946  g_menu_link_iter_get_name (GMenuLinkIter *iter)
     947  {
     948    g_return_val_if_fail (iter->priv->valid, 0);
     949  
     950    return g_quark_to_string (iter->priv->name);
     951  }
     952  
     953  /**
     954   * g_menu_link_iter_get_value:
     955   * @iter: a #GMenuLinkIter
     956   *
     957   * Gets the linked #GMenuModel at the current iterator position.
     958   *
     959   * The iterator is not advanced.
     960   *
     961   * Returns: (transfer full): the #GMenuModel that is linked to
     962   *
     963   * Since: 2.32
     964   */
     965  GMenuModel *
     966  g_menu_link_iter_get_value (GMenuLinkIter *iter)
     967  {
     968    g_return_val_if_fail (iter->priv->valid, NULL);
     969  
     970    return g_object_ref (iter->priv->value);
     971  }
     972  
     973  static void
     974  g_menu_link_iter_finalize (GObject *object)
     975  {
     976    GMenuLinkIter *iter = G_MENU_LINK_ITER (object);
     977  
     978    if (iter->priv->value)
     979      g_object_unref (iter->priv->value);
     980  
     981    G_OBJECT_CLASS (g_menu_link_iter_parent_class)
     982      ->finalize (object);
     983  }
     984  
     985  static void
     986  g_menu_link_iter_init (GMenuLinkIter *iter)
     987  {
     988    iter->priv = g_menu_link_iter_get_instance_private (iter);
     989  }
     990  
     991  static void
     992  g_menu_link_iter_class_init (GMenuLinkIterClass *class)
     993  {
     994    GObjectClass *object_class = G_OBJECT_CLASS (class);
     995  
     996    object_class->finalize = g_menu_link_iter_finalize;
     997  }