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

Generated by: LCOV version 2.0-1