LCOV - code coverage report
Current view: top level - gio - gmenumodel.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 88.3 % 213 188
Test Date: 2024-11-26 05:23:01 Functions: 94.3 % 53 50
Branches: - 0 0

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

Generated by: LCOV version 2.0-1