LCOV - code coverage report
Current view: top level - glib/gio - gmenu.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 280 303 92.4 %
Date: 2024-04-23 05:16:05 Functions: 52 52 100.0 %
Branches: 68 100 68.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 "gmenu.h"
      25                 :            : 
      26                 :            : #include "gaction.h"
      27                 :            : #include <string.h>
      28                 :            : 
      29                 :            : #include "gicon.h"
      30                 :            : 
      31                 :            : /**
      32                 :            :  * GMenu:
      33                 :            :  *
      34                 :            :  * `GMenu` is a simple implementation of [class@Gio.MenuModel].
      35                 :            :  * You populate a `GMenu` by adding [class@Gio.MenuItem] instances to it.
      36                 :            :  *
      37                 :            :  * There are some convenience functions to allow you to directly
      38                 :            :  * add items (avoiding [class@Gio.MenuItem]) for the common cases. To add
      39                 :            :  * a regular item, use [method@Gio.Menu.insert]. To add a section, use
      40                 :            :  * [method@Gio.Menu.insert_section]. To add a submenu, use
      41                 :            :  * [method@Gio.Menu.insert_submenu].
      42                 :            :  *
      43                 :            :  * Since: 2.32
      44                 :            :  */
      45                 :            : 
      46                 :            : /**
      47                 :            :  * GMenuItem:
      48                 :            :  *
      49                 :            :  * #GMenuItem is an opaque structure type.  You must access it using the
      50                 :            :  * functions below.
      51                 :            :  *
      52                 :            :  * Since: 2.32
      53                 :            :  */
      54                 :            : 
      55                 :            : struct _GMenuItem
      56                 :            : {
      57                 :            :   GObject parent_instance;
      58                 :            : 
      59                 :            :   GHashTable *attributes;
      60                 :            :   GHashTable *links;
      61                 :            :   gboolean    cow;
      62                 :            : };
      63                 :            : 
      64                 :            : typedef GObjectClass GMenuItemClass;
      65                 :            : 
      66                 :            : struct _GMenu
      67                 :            : {
      68                 :            :   GMenuModel parent_instance;
      69                 :            : 
      70                 :            :   GArray   *items;
      71                 :            :   gboolean  mutable;
      72                 :            : };
      73                 :            : 
      74                 :            : typedef GMenuModelClass GMenuClass;
      75                 :            : 
      76   [ +  +  +  -  :        221 : G_DEFINE_TYPE (GMenu, g_menu, G_TYPE_MENU_MODEL)
                   +  + ]
      77   [ +  +  +  -  :        240 : G_DEFINE_TYPE (GMenuItem, g_menu_item, G_TYPE_OBJECT)
                   +  + ]
      78                 :            : 
      79                 :            : struct item
      80                 :            : {
      81                 :            :   GHashTable *attributes;
      82                 :            :   GHashTable *links;
      83                 :            : };
      84                 :            : 
      85                 :            : static gboolean
      86                 :          4 : g_menu_is_mutable (GMenuModel *model)
      87                 :            : {
      88                 :          4 :   GMenu *menu = G_MENU (model);
      89                 :            : 
      90                 :          4 :   return menu->mutable;
      91                 :            : }
      92                 :            : 
      93                 :            : static gint
      94                 :         31 : g_menu_get_n_items (GMenuModel *model)
      95                 :            : {
      96                 :         31 :   GMenu *menu = G_MENU (model);
      97                 :            : 
      98                 :         31 :   return menu->items->len;
      99                 :            : }
     100                 :            : 
     101                 :            : static void
     102                 :         59 : g_menu_get_item_attributes (GMenuModel  *model,
     103                 :            :                             gint         position,
     104                 :            :                             GHashTable **table)
     105                 :            : {
     106                 :         59 :   GMenu *menu = G_MENU (model);
     107                 :            : 
     108                 :         59 :   *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).attributes);
     109                 :         59 : }
     110                 :            : 
     111                 :            : static void
     112                 :         46 : g_menu_get_item_links (GMenuModel  *model,
     113                 :            :                        gint         position,
     114                 :            :                        GHashTable **table)
     115                 :            : {
     116                 :         46 :   GMenu *menu = G_MENU (model);
     117                 :            : 
     118                 :         46 :   *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).links);
     119                 :         46 : }
     120                 :            : 
     121                 :            : /**
     122                 :            :  * g_menu_insert_item:
     123                 :            :  * @menu: a #GMenu
     124                 :            :  * @position: the position at which to insert the item
     125                 :            :  * @item: the #GMenuItem to insert
     126                 :            :  *
     127                 :            :  * Inserts @item into @menu.
     128                 :            :  *
     129                 :            :  * The "insertion" is actually done by copying all of the attribute and
     130                 :            :  * link values of @item and using them to form a new item within @menu.
     131                 :            :  * As such, @item itself is not really inserted, but rather, a menu item
     132                 :            :  * that is exactly the same as the one presently described by @item.
     133                 :            :  *
     134                 :            :  * This means that @item is essentially useless after the insertion
     135                 :            :  * occurs.  Any changes you make to it are ignored unless it is inserted
     136                 :            :  * again (at which point its updated values will be copied).
     137                 :            :  *
     138                 :            :  * You should probably just free @item once you're done.
     139                 :            :  *
     140                 :            :  * There are many convenience functions to take care of common cases.
     141                 :            :  * See g_menu_insert(), g_menu_insert_section() and
     142                 :            :  * g_menu_insert_submenu() as well as "prepend" and "append" variants of
     143                 :            :  * each of these functions.
     144                 :            :  *
     145                 :            :  * Since: 2.32
     146                 :            :  */
     147                 :            : void
     148                 :         37 : g_menu_insert_item (GMenu     *menu,
     149                 :            :                     gint       position,
     150                 :            :                     GMenuItem *item)
     151                 :            : {
     152                 :            :   struct item new_item;
     153                 :            : 
     154                 :         37 :   g_return_if_fail (G_IS_MENU (menu));
     155                 :         37 :   g_return_if_fail (G_IS_MENU_ITEM (item));
     156                 :            : 
     157   [ +  +  +  + ]:         37 :   if (position < 0 || (guint) position > menu->items->len)
     158                 :         27 :     position = menu->items->len;
     159                 :            : 
     160                 :         37 :   new_item.attributes = g_hash_table_ref (item->attributes);
     161                 :         37 :   new_item.links = g_hash_table_ref (item->links);
     162                 :         37 :   item->cow = TRUE;
     163                 :            : 
     164                 :         37 :   g_array_insert_val (menu->items, position, new_item);
     165                 :         37 :   g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
     166                 :            : }
     167                 :            : 
     168                 :            : /**
     169                 :            :  * g_menu_prepend_item:
     170                 :            :  * @menu: a #GMenu
     171                 :            :  * @item: a #GMenuItem to prepend
     172                 :            :  *
     173                 :            :  * Prepends @item to the start of @menu.
     174                 :            :  *
     175                 :            :  * See g_menu_insert_item() for more information.
     176                 :            :  *
     177                 :            :  * Since: 2.32
     178                 :            :  */
     179                 :            : void
     180                 :          1 : g_menu_prepend_item (GMenu     *menu,
     181                 :            :                      GMenuItem *item)
     182                 :            : {
     183                 :          1 :   g_menu_insert_item (menu, 0, item);
     184                 :          1 : }
     185                 :            : 
     186                 :            : /**
     187                 :            :  * g_menu_append_item:
     188                 :            :  * @menu: a #GMenu
     189                 :            :  * @item: a #GMenuItem to append
     190                 :            :  *
     191                 :            :  * Appends @item to the end of @menu.
     192                 :            :  *
     193                 :            :  * See g_menu_insert_item() for more information.
     194                 :            :  *
     195                 :            :  * Since: 2.32
     196                 :            :  */
     197                 :            : void
     198                 :          4 : g_menu_append_item (GMenu     *menu,
     199                 :            :                     GMenuItem *item)
     200                 :            : {
     201                 :          4 :   g_menu_insert_item (menu, -1, item);
     202                 :          4 : }
     203                 :            : 
     204                 :            : /**
     205                 :            :  * g_menu_freeze:
     206                 :            :  * @menu: a #GMenu
     207                 :            :  *
     208                 :            :  * Marks @menu as frozen.
     209                 :            :  *
     210                 :            :  * After the menu is frozen, it is an error to attempt to make any
     211                 :            :  * changes to it.  In effect this means that the #GMenu API must no
     212                 :            :  * longer be used.
     213                 :            :  *
     214                 :            :  * This function causes g_menu_model_is_mutable() to begin returning
     215                 :            :  * %FALSE, which has some positive performance implications.
     216                 :            :  *
     217                 :            :  * Since: 2.32
     218                 :            :  */
     219                 :            : void
     220                 :          1 : g_menu_freeze (GMenu *menu)
     221                 :            : {
     222                 :          1 :   g_return_if_fail (G_IS_MENU (menu));
     223                 :            : 
     224                 :          1 :   menu->mutable = FALSE;
     225                 :            : }
     226                 :            : 
     227                 :            : /**
     228                 :            :  * g_menu_new:
     229                 :            :  *
     230                 :            :  * Creates a new #GMenu.
     231                 :            :  *
     232                 :            :  * The new menu has no items.
     233                 :            :  *
     234                 :            :  * Returns: a new #GMenu
     235                 :            :  *
     236                 :            :  * Since: 2.32
     237                 :            :  */
     238                 :            : GMenu *
     239                 :         12 : g_menu_new (void)
     240                 :            : {
     241                 :         12 :   return g_object_new (G_TYPE_MENU, NULL);
     242                 :            : }
     243                 :            : 
     244                 :            : /**
     245                 :            :  * g_menu_insert:
     246                 :            :  * @menu: a #GMenu
     247                 :            :  * @position: the position at which to insert the item
     248                 :            :  * @label: (nullable): the section label, or %NULL
     249                 :            :  * @detailed_action: (nullable): the detailed action string, or %NULL
     250                 :            :  *
     251                 :            :  * Convenience function for inserting a normal menu item into @menu.
     252                 :            :  * Combine g_menu_item_new() and g_menu_insert_item() for a more flexible
     253                 :            :  * alternative.
     254                 :            :  *
     255                 :            :  * Since: 2.32
     256                 :            :  */
     257                 :            : void
     258                 :         18 : g_menu_insert (GMenu       *menu,
     259                 :            :                gint         position,
     260                 :            :                const gchar *label,
     261                 :            :                const gchar *detailed_action)
     262                 :            : {
     263                 :            :   GMenuItem *menu_item;
     264                 :            : 
     265                 :         18 :   menu_item = g_menu_item_new (label, detailed_action);
     266                 :         18 :   g_menu_insert_item (menu, position, menu_item);
     267                 :         18 :   g_object_unref (menu_item);
     268                 :         18 : }
     269                 :            : 
     270                 :            : /**
     271                 :            :  * g_menu_prepend:
     272                 :            :  * @menu: a #GMenu
     273                 :            :  * @label: (nullable): the section label, or %NULL
     274                 :            :  * @detailed_action: (nullable): the detailed action string, or %NULL
     275                 :            :  *
     276                 :            :  * Convenience function for prepending a normal menu item to the start
     277                 :            :  * of @menu.  Combine g_menu_item_new() and g_menu_insert_item() for a more
     278                 :            :  * flexible alternative.
     279                 :            :  *
     280                 :            :  * Since: 2.32
     281                 :            :  */
     282                 :            : void
     283                 :          1 : g_menu_prepend (GMenu       *menu,
     284                 :            :                 const gchar *label,
     285                 :            :                 const gchar *detailed_action)
     286                 :            : {
     287                 :          1 :   g_menu_insert (menu, 0, label, detailed_action);
     288                 :          1 : }
     289                 :            : 
     290                 :            : /**
     291                 :            :  * g_menu_append:
     292                 :            :  * @menu: a #GMenu
     293                 :            :  * @label: (nullable): the section label, or %NULL
     294                 :            :  * @detailed_action: (nullable): the detailed action string, or %NULL
     295                 :            :  *
     296                 :            :  * Convenience function for appending a normal menu item to the end of
     297                 :            :  * @menu.  Combine g_menu_item_new() and g_menu_insert_item() for a more
     298                 :            :  * flexible alternative.
     299                 :            :  *
     300                 :            :  * Since: 2.32
     301                 :            :  */
     302                 :            : void
     303                 :         15 : g_menu_append (GMenu       *menu,
     304                 :            :                const gchar *label,
     305                 :            :                const gchar *detailed_action)
     306                 :            : {
     307                 :         15 :   g_menu_insert (menu, -1, label, detailed_action);
     308                 :         15 : }
     309                 :            : 
     310                 :            : /**
     311                 :            :  * g_menu_insert_section:
     312                 :            :  * @menu: a #GMenu
     313                 :            :  * @position: the position at which to insert the item
     314                 :            :  * @label: (nullable): the section label, or %NULL
     315                 :            :  * @section: a #GMenuModel with the items of the section
     316                 :            :  *
     317                 :            :  * Convenience function for inserting a section menu item into @menu.
     318                 :            :  * Combine g_menu_item_new_section() and g_menu_insert_item() for a more
     319                 :            :  * flexible alternative.
     320                 :            :  *
     321                 :            :  * Since: 2.32
     322                 :            :  */
     323                 :            : void
     324                 :          5 : g_menu_insert_section (GMenu       *menu,
     325                 :            :                        gint         position,
     326                 :            :                        const gchar *label,
     327                 :            :                        GMenuModel  *section)
     328                 :            : {
     329                 :            :   GMenuItem *menu_item;
     330                 :            : 
     331                 :          5 :   menu_item = g_menu_item_new_section (label, section);
     332                 :          5 :   g_menu_insert_item (menu, position, menu_item);
     333                 :          5 :   g_object_unref (menu_item);
     334                 :          5 : }
     335                 :            : 
     336                 :            : 
     337                 :            : /**
     338                 :            :  * g_menu_prepend_section:
     339                 :            :  * @menu: a #GMenu
     340                 :            :  * @label: (nullable): the section label, or %NULL
     341                 :            :  * @section: a #GMenuModel with the items of the section
     342                 :            :  *
     343                 :            :  * Convenience function for prepending a section menu item to the start
     344                 :            :  * of @menu.  Combine g_menu_item_new_section() and g_menu_insert_item() for
     345                 :            :  * a more flexible alternative.
     346                 :            :  *
     347                 :            :  * Since: 2.32
     348                 :            :  */
     349                 :            : void
     350                 :          1 : g_menu_prepend_section (GMenu       *menu,
     351                 :            :                         const gchar *label,
     352                 :            :                         GMenuModel  *section)
     353                 :            : {
     354                 :          1 :   g_menu_insert_section (menu, 0, label, section);
     355                 :          1 : }
     356                 :            : 
     357                 :            : /**
     358                 :            :  * g_menu_append_section:
     359                 :            :  * @menu: a #GMenu
     360                 :            :  * @label: (nullable): the section label, or %NULL
     361                 :            :  * @section: a #GMenuModel with the items of the section
     362                 :            :  *
     363                 :            :  * Convenience function for appending a section menu item to the end of
     364                 :            :  * @menu.  Combine g_menu_item_new_section() and g_menu_insert_item() for a
     365                 :            :  * more flexible alternative.
     366                 :            :  *
     367                 :            :  * Since: 2.32
     368                 :            :  */
     369                 :            : void
     370                 :          1 : g_menu_append_section (GMenu       *menu,
     371                 :            :                        const gchar *label,
     372                 :            :                        GMenuModel  *section)
     373                 :            : {
     374                 :          1 :   g_menu_insert_section (menu, -1, label, section);
     375                 :          1 : }
     376                 :            : 
     377                 :            : /**
     378                 :            :  * g_menu_insert_submenu:
     379                 :            :  * @menu: a #GMenu
     380                 :            :  * @position: the position at which to insert the item
     381                 :            :  * @label: (nullable): the section label, or %NULL
     382                 :            :  * @submenu: a #GMenuModel with the items of the submenu
     383                 :            :  *
     384                 :            :  * Convenience function for inserting a submenu menu item into @menu.
     385                 :            :  * Combine g_menu_item_new_submenu() and g_menu_insert_item() for a more
     386                 :            :  * flexible alternative.
     387                 :            :  *
     388                 :            :  * Since: 2.32
     389                 :            :  */
     390                 :            : void
     391                 :          5 : g_menu_insert_submenu (GMenu       *menu,
     392                 :            :                        gint         position,
     393                 :            :                        const gchar *label,
     394                 :            :                        GMenuModel  *submenu)
     395                 :            : {
     396                 :            :   GMenuItem *menu_item;
     397                 :            : 
     398                 :          5 :   menu_item = g_menu_item_new_submenu (label, submenu);
     399                 :          5 :   g_menu_insert_item (menu, position, menu_item);
     400                 :          5 :   g_object_unref (menu_item);
     401                 :          5 : }
     402                 :            : 
     403                 :            : /**
     404                 :            :  * g_menu_prepend_submenu:
     405                 :            :  * @menu: a #GMenu
     406                 :            :  * @label: (nullable): the section label, or %NULL
     407                 :            :  * @submenu: a #GMenuModel with the items of the submenu
     408                 :            :  *
     409                 :            :  * Convenience function for prepending a submenu menu item to the start
     410                 :            :  * of @menu.  Combine g_menu_item_new_submenu() and g_menu_insert_item() for
     411                 :            :  * a more flexible alternative.
     412                 :            :  *
     413                 :            :  * Since: 2.32
     414                 :            :  */
     415                 :            : void
     416                 :          1 : g_menu_prepend_submenu (GMenu       *menu,
     417                 :            :                         const gchar *label,
     418                 :            :                         GMenuModel  *submenu)
     419                 :            : {
     420                 :          1 :   g_menu_insert_submenu (menu, 0, label, submenu);
     421                 :          1 : }
     422                 :            : 
     423                 :            : /**
     424                 :            :  * g_menu_append_submenu:
     425                 :            :  * @menu: a #GMenu
     426                 :            :  * @label: (nullable): the section label, or %NULL
     427                 :            :  * @submenu: a #GMenuModel with the items of the submenu
     428                 :            :  *
     429                 :            :  * Convenience function for appending a submenu menu item to the end of
     430                 :            :  * @menu.  Combine g_menu_item_new_submenu() and g_menu_insert_item() for a
     431                 :            :  * more flexible alternative.
     432                 :            :  *
     433                 :            :  * Since: 2.32
     434                 :            :  */
     435                 :            : void
     436                 :          1 : g_menu_append_submenu (GMenu       *menu,
     437                 :            :                        const gchar *label,
     438                 :            :                        GMenuModel  *submenu)
     439                 :            : {
     440                 :          1 :   g_menu_insert_submenu (menu, -1, label, submenu);
     441                 :          1 : }
     442                 :            : 
     443                 :            : static void
     444                 :         35 : g_menu_clear_item (struct item *item)
     445                 :            : {
     446         [ +  - ]:         35 :   if (item->attributes != NULL)
     447                 :         35 :     g_hash_table_unref (item->attributes);
     448         [ +  - ]:         35 :   if (item->links != NULL)
     449                 :         35 :     g_hash_table_unref (item->links);
     450                 :         35 : }
     451                 :            : 
     452                 :            : /**
     453                 :            :  * g_menu_remove:
     454                 :            :  * @menu: a #GMenu
     455                 :            :  * @position: the position of the item to remove
     456                 :            :  *
     457                 :            :  * Removes an item from the menu.
     458                 :            :  *
     459                 :            :  * @position gives the index of the item to remove.
     460                 :            :  *
     461                 :            :  * It is an error if position is not in range the range from 0 to one
     462                 :            :  * less than the number of items in the menu.
     463                 :            :  *
     464                 :            :  * It is not possible to remove items by identity since items are added
     465                 :            :  * to the menu simply by copying their links and attributes (ie:
     466                 :            :  * identity of the item itself is not preserved).
     467                 :            :  *
     468                 :            :  * Since: 2.32
     469                 :            :  */
     470                 :            : void
     471                 :          8 : g_menu_remove (GMenu *menu,
     472                 :            :                gint   position)
     473                 :            : {
     474                 :          8 :   g_return_if_fail (G_IS_MENU (menu));
     475                 :          8 :   g_return_if_fail (0 <= position && (guint) position < menu->items->len);
     476                 :            : 
     477                 :          8 :   g_menu_clear_item (&g_array_index (menu->items, struct item, position));
     478                 :          8 :   g_array_remove_index (menu->items, position);
     479                 :          8 :   g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0);
     480                 :            : }
     481                 :            : 
     482                 :            : /**
     483                 :            :  * g_menu_remove_all:
     484                 :            :  * @menu: a #GMenu
     485                 :            :  *
     486                 :            :  * Removes all items in the menu.
     487                 :            :  *
     488                 :            :  * Since: 2.38
     489                 :            :  **/
     490                 :            : void
     491                 :          2 : g_menu_remove_all (GMenu *menu)
     492                 :            : {
     493                 :            :   gint i, n;
     494                 :            : 
     495                 :          2 :   g_return_if_fail (G_IS_MENU (menu));
     496                 :          2 :   n = menu->items->len;
     497                 :            : 
     498         [ +  + ]:          4 :   for (i = 0; i < n; i++)
     499                 :          2 :     g_menu_clear_item (&g_array_index (menu->items, struct item, i));
     500                 :          2 :   g_array_set_size (menu->items, 0);
     501                 :            : 
     502                 :          2 :   g_menu_model_items_changed (G_MENU_MODEL (menu), 0, n, 0);
     503                 :            : }
     504                 :            : 
     505                 :            : static void
     506                 :         12 : g_menu_finalize (GObject *object)
     507                 :            : {
     508                 :         12 :   GMenu *menu = G_MENU (object);
     509                 :            :   struct item *items;
     510                 :            :   gint n_items;
     511                 :            :   gint i;
     512                 :            : 
     513                 :         12 :   n_items = menu->items->len;
     514                 :         12 :   items = (struct item *) g_array_free (menu->items, FALSE);
     515         [ +  + ]:         37 :   for (i = 0; i < n_items; i++)
     516                 :         25 :     g_menu_clear_item (&items[i]);
     517                 :         12 :   g_free (items);
     518                 :            : 
     519                 :         12 :   G_OBJECT_CLASS (g_menu_parent_class)
     520                 :         12 :     ->finalize (object);
     521                 :         12 : }
     522                 :            : 
     523                 :            : static void
     524                 :         13 : g_menu_init (GMenu *menu)
     525                 :            : {
     526                 :         13 :   menu->items = g_array_new (FALSE, FALSE, sizeof (struct item));
     527                 :         13 :   menu->mutable = TRUE;
     528                 :         13 : }
     529                 :            : 
     530                 :            : static void
     531                 :          3 : g_menu_class_init (GMenuClass *class)
     532                 :            : {
     533                 :          3 :   GMenuModelClass *model_class = G_MENU_MODEL_CLASS (class);
     534                 :          3 :   GObjectClass *object_class = G_OBJECT_CLASS (class);
     535                 :            : 
     536                 :          3 :   object_class->finalize = g_menu_finalize;
     537                 :            : 
     538                 :          3 :   model_class->is_mutable = g_menu_is_mutable;
     539                 :          3 :   model_class->get_n_items = g_menu_get_n_items;
     540                 :          3 :   model_class->get_item_attributes = g_menu_get_item_attributes;
     541                 :          3 :   model_class->get_item_links = g_menu_get_item_links;
     542                 :          3 : }
     543                 :            : 
     544                 :            : 
     545                 :            : static void
     546                 :         83 : g_menu_item_clear_cow (GMenuItem *menu_item)
     547                 :            : {
     548         [ +  + ]:         83 :   if (menu_item->cow)
     549                 :            :     {
     550                 :            :       GHashTableIter iter;
     551                 :            :       GHashTable *new;
     552                 :            :       gpointer key;
     553                 :            :       gpointer val;
     554                 :            : 
     555                 :          3 :       new = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
     556                 :          3 :       g_hash_table_iter_init (&iter, menu_item->attributes);
     557         [ +  + ]:         18 :       while (g_hash_table_iter_next (&iter, &key, &val))
     558                 :         30 :         g_hash_table_insert (new, g_strdup (key), g_variant_ref (val));
     559                 :          3 :       g_hash_table_unref (menu_item->attributes);
     560                 :          3 :       menu_item->attributes = new;
     561                 :            : 
     562                 :          3 :       new = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
     563                 :          3 :       g_hash_table_iter_init (&iter, menu_item->links);
     564         [ +  + ]:          4 :       while (g_hash_table_iter_next (&iter, &key, &val))
     565                 :          2 :         g_hash_table_insert (new, g_strdup (key), g_object_ref (val));
     566                 :          3 :       g_hash_table_unref (menu_item->links);
     567                 :          3 :       menu_item->links = new;
     568                 :            : 
     569                 :          3 :       menu_item->cow = FALSE;
     570                 :            :     }
     571                 :         83 : }
     572                 :            : 
     573                 :            : static void
     574                 :         50 : g_menu_item_finalize (GObject *object)
     575                 :            : {
     576                 :         50 :   GMenuItem *menu_item = G_MENU_ITEM (object);
     577                 :            : 
     578                 :         50 :   g_hash_table_unref (menu_item->attributes);
     579                 :         50 :   g_hash_table_unref (menu_item->links);
     580                 :            : 
     581                 :         50 :   G_OBJECT_CLASS (g_menu_item_parent_class)
     582                 :         50 :     ->finalize (object);
     583                 :         50 : }
     584                 :            : 
     585                 :            : static void
     586                 :         50 : g_menu_item_init (GMenuItem *menu_item)
     587                 :            : {
     588                 :         50 :   menu_item->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
     589                 :         50 :   menu_item->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
     590                 :         50 :   menu_item->cow = FALSE;
     591                 :         50 : }
     592                 :            : 
     593                 :            : static void
     594                 :          4 : g_menu_item_class_init (GMenuItemClass *class)
     595                 :            : {
     596                 :          4 :   class->finalize = g_menu_item_finalize;
     597                 :          4 : }
     598                 :            : 
     599                 :            : /* We treat attribute names the same as GSettings keys:
     600                 :            :  * - only lowercase ascii, digits and '-'
     601                 :            :  * - must start with lowercase
     602                 :            :  * - must not end with '-'
     603                 :            :  * - no consecutive '-'
     604                 :            :  * - not longer than 1024 chars
     605                 :            :  */
     606                 :            : static gboolean
     607                 :         84 : valid_attribute_name (const gchar *name)
     608                 :            : {
     609                 :            :   gint i;
     610                 :            : 
     611         [ -  + ]:         84 :   if (!g_ascii_islower (name[0]))
     612                 :          0 :     return FALSE;
     613                 :            : 
     614         [ +  + ]:        490 :   for (i = 1; name[i]; i++)
     615                 :            :     {
     616         [ +  + ]:        406 :       if (name[i] != '-' &&
     617         [ +  + ]:        404 :           !g_ascii_islower (name[i]) &&
     618         [ -  + ]:          6 :           !g_ascii_isdigit (name[i]))
     619                 :          0 :         return FALSE;
     620                 :            : 
     621   [ +  +  -  + ]:        406 :       if (name[i] == '-' && name[i + 1] == '-')
     622                 :          0 :         return FALSE;
     623                 :            :     }
     624                 :            : 
     625         [ -  + ]:         84 :   if (name[i - 1] == '-')
     626                 :          0 :     return FALSE;
     627                 :            : 
     628         [ -  + ]:         84 :   if (i > 1024)
     629                 :          0 :     return FALSE;
     630                 :            : 
     631                 :         84 :   return TRUE;
     632                 :            : }
     633                 :            : 
     634                 :            : /**
     635                 :            :  * g_menu_item_set_attribute_value:
     636                 :            :  * @menu_item: a #GMenuItem
     637                 :            :  * @attribute: the attribute to set
     638                 :            :  * @value: (nullable): a #GVariant to use as the value, or %NULL
     639                 :            :  *
     640                 :            :  * Sets or unsets an attribute on @menu_item.
     641                 :            :  *
     642                 :            :  * The attribute to set or unset is specified by @attribute. This
     643                 :            :  * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL,
     644                 :            :  * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom
     645                 :            :  * attribute name.
     646                 :            :  * Attribute names are restricted to lowercase characters, numbers
     647                 :            :  * and '-'. Furthermore, the names must begin with a lowercase character,
     648                 :            :  * must not end with a '-', and must not contain consecutive dashes.
     649                 :            :  *
     650                 :            :  * must consist only of lowercase
     651                 :            :  * ASCII characters, digits and '-'.
     652                 :            :  *
     653                 :            :  * If @value is non-%NULL then it is used as the new value for the
     654                 :            :  * attribute.  If @value is %NULL then the attribute is unset. If
     655                 :            :  * the @value #GVariant is floating, it is consumed.
     656                 :            :  *
     657                 :            :  * See also g_menu_item_set_attribute() for a more convenient way to do
     658                 :            :  * the same.
     659                 :            :  *
     660                 :            :  * Since: 2.32
     661                 :            :  */
     662                 :            : void
     663                 :         65 : g_menu_item_set_attribute_value (GMenuItem   *menu_item,
     664                 :            :                                  const gchar *attribute,
     665                 :            :                                  GVariant    *value)
     666                 :            : {
     667                 :         65 :   g_return_if_fail (G_IS_MENU_ITEM (menu_item));
     668                 :         65 :   g_return_if_fail (attribute != NULL);
     669                 :         65 :   g_return_if_fail (valid_attribute_name (attribute));
     670                 :            : 
     671                 :         65 :   g_menu_item_clear_cow (menu_item);
     672                 :            : 
     673         [ +  + ]:         65 :   if (value != NULL)
     674                 :        126 :     g_hash_table_insert (menu_item->attributes, g_strdup (attribute), g_variant_ref_sink (value));
     675                 :            :   else
     676                 :          2 :     g_hash_table_remove (menu_item->attributes, attribute);
     677                 :            : }
     678                 :            : 
     679                 :            : /**
     680                 :            :  * g_menu_item_set_attribute:
     681                 :            :  * @menu_item: a #GMenuItem
     682                 :            :  * @attribute: the attribute to set
     683                 :            :  * @format_string: (nullable): a #GVariant format string, or %NULL
     684                 :            :  * @...: positional parameters, as per @format_string
     685                 :            :  *
     686                 :            :  * Sets or unsets an attribute on @menu_item.
     687                 :            :  *
     688                 :            :  * The attribute to set or unset is specified by @attribute. This
     689                 :            :  * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL,
     690                 :            :  * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom
     691                 :            :  * attribute name.
     692                 :            :  * Attribute names are restricted to lowercase characters, numbers
     693                 :            :  * and '-'. Furthermore, the names must begin with a lowercase character,
     694                 :            :  * must not end with a '-', and must not contain consecutive dashes.
     695                 :            :  *
     696                 :            :  * If @format_string is non-%NULL then the proper position parameters
     697                 :            :  * are collected to create a #GVariant instance to use as the attribute
     698                 :            :  * value.  If it is %NULL then the positional parameterrs are ignored
     699                 :            :  * and the named attribute is unset.
     700                 :            :  *
     701                 :            :  * See also g_menu_item_set_attribute_value() for an equivalent call
     702                 :            :  * that directly accepts a #GVariant.
     703                 :            :  *
     704                 :            :  * Since: 2.32
     705                 :            :  */
     706                 :            : void
     707                 :          5 : g_menu_item_set_attribute (GMenuItem   *menu_item,
     708                 :            :                            const gchar *attribute,
     709                 :            :                            const gchar *format_string,
     710                 :            :                            ...)
     711                 :            : {
     712                 :            :   GVariant *value;
     713                 :            : 
     714         [ +  - ]:          5 :   if (format_string != NULL)
     715                 :            :     {
     716                 :            :       va_list ap;
     717                 :            : 
     718                 :          5 :       va_start (ap, format_string);
     719                 :          5 :       value = g_variant_new_va (format_string, NULL, &ap);
     720                 :          5 :       va_end (ap);
     721                 :            :     }
     722                 :            :   else
     723                 :          0 :     value = NULL;
     724                 :            : 
     725                 :          5 :   g_menu_item_set_attribute_value (menu_item, attribute, value);
     726                 :          5 : }
     727                 :            : 
     728                 :            : /**
     729                 :            :  * g_menu_item_set_link:
     730                 :            :  * @menu_item: a #GMenuItem
     731                 :            :  * @link: type of link to establish or unset
     732                 :            :  * @model: (nullable): the #GMenuModel to link to (or %NULL to unset)
     733                 :            :  *
     734                 :            :  * Creates a link from @menu_item to @model if non-%NULL, or unsets it.
     735                 :            :  *
     736                 :            :  * Links are used to establish a relationship between a particular menu
     737                 :            :  * item and another menu.  For example, %G_MENU_LINK_SUBMENU is used to
     738                 :            :  * associate a submenu with a particular menu item, and %G_MENU_LINK_SECTION
     739                 :            :  * is used to create a section. Other types of link can be used, but there
     740                 :            :  * is no guarantee that clients will be able to make sense of them.
     741                 :            :  * Link types are restricted to lowercase characters, numbers
     742                 :            :  * and '-'. Furthermore, the names must begin with a lowercase character,
     743                 :            :  * must not end with a '-', and must not contain consecutive dashes.
     744                 :            :  *
     745                 :            :  * Since: 2.32
     746                 :            :  */
     747                 :            : void
     748                 :         18 : g_menu_item_set_link (GMenuItem   *menu_item,
     749                 :            :                       const gchar *link,
     750                 :            :                       GMenuModel  *model)
     751                 :            : {
     752                 :         18 :   g_return_if_fail (G_IS_MENU_ITEM (menu_item));
     753                 :         18 :   g_return_if_fail (link != NULL);
     754                 :         18 :   g_return_if_fail (valid_attribute_name (link));
     755                 :            : 
     756                 :         18 :   g_menu_item_clear_cow (menu_item);
     757                 :            : 
     758         [ +  + ]:         18 :   if (model != NULL)
     759                 :         34 :     g_hash_table_insert (menu_item->links, g_strdup (link), g_object_ref (model));
     760                 :            :   else
     761                 :          1 :     g_hash_table_remove (menu_item->links, link);
     762                 :            : }
     763                 :            : 
     764                 :            : /**
     765                 :            :  * g_menu_item_get_attribute_value:
     766                 :            :  * @menu_item: a #GMenuItem
     767                 :            :  * @attribute: the attribute name to query
     768                 :            :  * @expected_type: (nullable): the expected type of the attribute
     769                 :            :  *
     770                 :            :  * Queries the named @attribute on @menu_item.
     771                 :            :  *
     772                 :            :  * If @expected_type is specified and the attribute does not have this
     773                 :            :  * type, %NULL is returned.  %NULL is also returned if the attribute
     774                 :            :  * simply does not exist.
     775                 :            :  *
     776                 :            :  * Returns: (nullable) (transfer full): the attribute value, or %NULL
     777                 :            :  *
     778                 :            :  * Since: 2.34
     779                 :            :  */
     780                 :            : GVariant *
     781                 :          3 : g_menu_item_get_attribute_value (GMenuItem          *menu_item,
     782                 :            :                                  const gchar        *attribute,
     783                 :            :                                  const GVariantType *expected_type)
     784                 :            : {
     785                 :            :   GVariant *value;
     786                 :            : 
     787                 :          3 :   g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
     788                 :          3 :   g_return_val_if_fail (attribute != NULL, NULL);
     789                 :            : 
     790                 :          3 :   value = g_hash_table_lookup (menu_item->attributes, attribute);
     791                 :            : 
     792         [ +  - ]:          3 :   if (value != NULL)
     793                 :            :     {
     794   [ +  -  +  - ]:          3 :       if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
     795                 :          3 :         g_variant_ref (value);
     796                 :            :       else
     797                 :          0 :         value = NULL;
     798                 :            :     }
     799                 :            : 
     800                 :          3 :   return value;
     801                 :            : }
     802                 :            : 
     803                 :            : /**
     804                 :            :  * g_menu_item_get_attribute:
     805                 :            :  * @menu_item: a #GMenuItem
     806                 :            :  * @attribute: the attribute name to query
     807                 :            :  * @format_string: a #GVariant format string
     808                 :            :  * @...: positional parameters, as per @format_string
     809                 :            :  *
     810                 :            :  * Queries the named @attribute on @menu_item.
     811                 :            :  *
     812                 :            :  * If the attribute exists and matches the #GVariantType corresponding
     813                 :            :  * to @format_string then @format_string is used to deconstruct the
     814                 :            :  * value into the positional parameters and %TRUE is returned.
     815                 :            :  *
     816                 :            :  * If the attribute does not exist, or it does exist but has the wrong
     817                 :            :  * type, then the positional parameters are ignored and %FALSE is
     818                 :            :  * returned.
     819                 :            :  *
     820                 :            :  * Returns: %TRUE if the named attribute was found with the expected
     821                 :            :  *     type
     822                 :            :  *
     823                 :            :  * Since: 2.34
     824                 :            :  */
     825                 :            : gboolean
     826                 :          2 : g_menu_item_get_attribute (GMenuItem   *menu_item,
     827                 :            :                            const gchar *attribute,
     828                 :            :                            const gchar *format_string,
     829                 :            :                            ...)
     830                 :            : {
     831                 :            :   GVariant *value;
     832                 :            :   va_list ap;
     833                 :            : 
     834                 :          2 :   g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), FALSE);
     835                 :          2 :   g_return_val_if_fail (attribute != NULL, FALSE);
     836                 :          2 :   g_return_val_if_fail (format_string != NULL, FALSE);
     837                 :            : 
     838                 :          2 :   value = g_hash_table_lookup (menu_item->attributes, attribute);
     839                 :            : 
     840         [ -  + ]:          2 :   if (value == NULL)
     841                 :          0 :     return FALSE;
     842                 :            : 
     843         [ -  + ]:          2 :   if (!g_variant_check_format_string (value, format_string, FALSE))
     844                 :          0 :     return FALSE;
     845                 :            : 
     846                 :          2 :   va_start (ap, format_string);
     847                 :          2 :   g_variant_get_va (value, format_string, NULL, &ap);
     848                 :          2 :   va_end (ap);
     849                 :            : 
     850                 :          2 :   return TRUE;
     851                 :            : }
     852                 :            : 
     853                 :            : /**
     854                 :            :  * g_menu_item_get_link:
     855                 :            :  * @menu_item: a #GMenuItem
     856                 :            :  * @link: the link name to query
     857                 :            :  *
     858                 :            :  * Queries the named @link on @menu_item.
     859                 :            :  *
     860                 :            :  * Returns: (nullable) (transfer full): the link, or %NULL
     861                 :            :  *
     862                 :            :  * Since: 2.34
     863                 :            :  */
     864                 :            : GMenuModel *
     865                 :          1 : g_menu_item_get_link (GMenuItem   *menu_item,
     866                 :            :                       const gchar *link)
     867                 :            : {
     868                 :            :   GMenuModel *model;
     869                 :            : 
     870                 :          1 :   g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
     871                 :          1 :   g_return_val_if_fail (link != NULL, NULL);
     872                 :          1 :   g_return_val_if_fail (valid_attribute_name (link), NULL);
     873                 :            : 
     874                 :          1 :   model = g_hash_table_lookup (menu_item->links, link);
     875                 :            : 
     876         [ +  - ]:          1 :   if (model)
     877                 :          1 :     g_object_ref (model);
     878                 :            : 
     879                 :          1 :   return model;
     880                 :            : }
     881                 :            : 
     882                 :            : /**
     883                 :            :  * g_menu_item_set_label:
     884                 :            :  * @menu_item: a #GMenuItem
     885                 :            :  * @label: (nullable): the label to set, or %NULL to unset
     886                 :            :  *
     887                 :            :  * Sets or unsets the "label" attribute of @menu_item.
     888                 :            :  *
     889                 :            :  * If @label is non-%NULL it is used as the label for the menu item.  If
     890                 :            :  * it is %NULL then the label attribute is unset.
     891                 :            :  *
     892                 :            :  * Since: 2.32
     893                 :            :  */
     894                 :            : void
     895                 :         37 : g_menu_item_set_label (GMenuItem   *menu_item,
     896                 :            :                        const gchar *label)
     897                 :            : {
     898                 :            :   GVariant *value;
     899                 :            : 
     900         [ +  - ]:         37 :   if (label != NULL)
     901                 :         37 :     value = g_variant_new_string (label);
     902                 :            :   else
     903                 :          0 :     value = NULL;
     904                 :            : 
     905                 :         37 :   g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_LABEL, value);
     906                 :         37 : }
     907                 :            : 
     908                 :            : /**
     909                 :            :  * g_menu_item_set_submenu:
     910                 :            :  * @menu_item: a #GMenuItem
     911                 :            :  * @submenu: (nullable): a #GMenuModel, or %NULL
     912                 :            :  *
     913                 :            :  * Sets or unsets the "submenu" link of @menu_item to @submenu.
     914                 :            :  *
     915                 :            :  * If @submenu is non-%NULL, it is linked to.  If it is %NULL then the
     916                 :            :  * link is unset.
     917                 :            :  *
     918                 :            :  * The effect of having one menu appear as a submenu of another is
     919                 :            :  * exactly as it sounds.
     920                 :            :  *
     921                 :            :  * Since: 2.32
     922                 :            :  */
     923                 :            : void
     924                 :          6 : g_menu_item_set_submenu (GMenuItem  *menu_item,
     925                 :            :                          GMenuModel *submenu)
     926                 :            : {
     927                 :          6 :   g_menu_item_set_link (menu_item, G_MENU_LINK_SUBMENU, submenu);
     928                 :          6 : }
     929                 :            : 
     930                 :            : /**
     931                 :            :  * g_menu_item_set_section:
     932                 :            :  * @menu_item: a #GMenuItem
     933                 :            :  * @section: (nullable): a #GMenuModel, or %NULL
     934                 :            :  *
     935                 :            :  * Sets or unsets the "section" link of @menu_item to @section.
     936                 :            :  *
     937                 :            :  * The effect of having one menu appear as a section of another is
     938                 :            :  * exactly as it sounds: the items from @section become a direct part of
     939                 :            :  * the menu that @menu_item is added to.  See g_menu_item_new_section()
     940                 :            :  * for more information about what it means for a menu item to be a
     941                 :            :  * section.
     942                 :            :  *
     943                 :            :  * Since: 2.32
     944                 :            :  */
     945                 :            : void
     946                 :          6 : g_menu_item_set_section (GMenuItem  *menu_item,
     947                 :            :                          GMenuModel *section)
     948                 :            : {
     949                 :          6 :   g_menu_item_set_link (menu_item, G_MENU_LINK_SECTION, section);
     950                 :          6 : }
     951                 :            : 
     952                 :            : /**
     953                 :            :  * g_menu_item_set_action_and_target_value:
     954                 :            :  * @menu_item: a #GMenuItem
     955                 :            :  * @action: (nullable): the name of the action for this item
     956                 :            :  * @target_value: (nullable): a #GVariant to use as the action target
     957                 :            :  *
     958                 :            :  * Sets or unsets the "action" and "target" attributes of @menu_item.
     959                 :            :  *
     960                 :            :  * If @action is %NULL then both the "action" and "target" attributes
     961                 :            :  * are unset (and @target_value is ignored).
     962                 :            :  *
     963                 :            :  * If @action is non-%NULL then the "action" attribute is set.  The
     964                 :            :  * "target" attribute is then set to the value of @target_value if it is
     965                 :            :  * non-%NULL or unset otherwise.
     966                 :            :  *
     967                 :            :  * Normal menu items (ie: not submenu, section or other custom item
     968                 :            :  * types) are expected to have the "action" attribute set to identify
     969                 :            :  * the action that they are associated with.  The state type of the
     970                 :            :  * action help to determine the disposition of the menu item.  See
     971                 :            :  * #GAction and #GActionGroup for an overview of actions.
     972                 :            :  *
     973                 :            :  * In general, clicking on the menu item will result in activation of
     974                 :            :  * the named action with the "target" attribute given as the parameter
     975                 :            :  * to the action invocation.  If the "target" attribute is not set then
     976                 :            :  * the action is invoked with no parameter.
     977                 :            :  *
     978                 :            :  * If the action has no state then the menu item is usually drawn as a
     979                 :            :  * plain menu item (ie: with no additional decoration).
     980                 :            :  *
     981                 :            :  * If the action has a boolean state then the menu item is usually drawn
     982                 :            :  * as a toggle menu item (ie: with a checkmark or equivalent
     983                 :            :  * indication).  The item should be marked as 'toggled' or 'checked'
     984                 :            :  * when the boolean state is %TRUE.
     985                 :            :  *
     986                 :            :  * If the action has a string state then the menu item is usually drawn
     987                 :            :  * as a radio menu item (ie: with a radio bullet or equivalent
     988                 :            :  * indication).  The item should be marked as 'selected' when the string
     989                 :            :  * state is equal to the value of the @target property.
     990                 :            :  *
     991                 :            :  * See g_menu_item_set_action_and_target() or
     992                 :            :  * g_menu_item_set_detailed_action() for two equivalent calls that are
     993                 :            :  * probably more convenient for most uses.
     994                 :            :  *
     995                 :            :  * Since: 2.32
     996                 :            :  */
     997                 :            : void
     998                 :          7 : g_menu_item_set_action_and_target_value (GMenuItem   *menu_item,
     999                 :            :                                          const gchar *action,
    1000                 :            :                                          GVariant    *target_value)
    1001                 :            : {
    1002                 :            :   GVariant *action_value;
    1003                 :            : 
    1004         [ +  - ]:          7 :   if (action != NULL)
    1005                 :            :     {
    1006                 :          7 :       action_value = g_variant_new_string (action);
    1007                 :            :     }
    1008                 :            :   else
    1009                 :            :     {
    1010                 :          0 :       action_value = NULL;
    1011                 :          0 :       target_value = NULL;
    1012                 :            :     }
    1013                 :            : 
    1014                 :          7 :   g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ACTION, action_value);
    1015                 :          7 :   g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_TARGET, target_value);
    1016                 :          7 : }
    1017                 :            : 
    1018                 :            : /**
    1019                 :            :  * g_menu_item_set_action_and_target:
    1020                 :            :  * @menu_item: a #GMenuItem
    1021                 :            :  * @action: (nullable): the name of the action for this item
    1022                 :            :  * @format_string: (nullable): a GVariant format string
    1023                 :            :  * @...: positional parameters, as per @format_string
    1024                 :            :  *
    1025                 :            :  * Sets or unsets the "action" and "target" attributes of @menu_item.
    1026                 :            :  *
    1027                 :            :  * If @action is %NULL then both the "action" and "target" attributes
    1028                 :            :  * are unset (and @format_string is ignored along with the positional
    1029                 :            :  * parameters).
    1030                 :            :  *
    1031                 :            :  * If @action is non-%NULL then the "action" attribute is set.
    1032                 :            :  * @format_string is then inspected.  If it is non-%NULL then the proper
    1033                 :            :  * position parameters are collected to create a #GVariant instance to
    1034                 :            :  * use as the target value.  If it is %NULL then the positional
    1035                 :            :  * parameters are ignored and the "target" attribute is unset.
    1036                 :            :  *
    1037                 :            :  * See also g_menu_item_set_action_and_target_value() for an equivalent
    1038                 :            :  * call that directly accepts a #GVariant.  See
    1039                 :            :  * g_menu_item_set_detailed_action() for a more convenient version that
    1040                 :            :  * works with string-typed targets.
    1041                 :            :  *
    1042                 :            :  * See also g_menu_item_set_action_and_target_value() for a
    1043                 :            :  * description of the semantics of the action and target attributes.
    1044                 :            :  *
    1045                 :            :  * Since: 2.32
    1046                 :            :  */
    1047                 :            : void
    1048                 :          1 : g_menu_item_set_action_and_target (GMenuItem   *menu_item,
    1049                 :            :                                    const gchar *action,
    1050                 :            :                                    const gchar *format_string,
    1051                 :            :                                    ...)
    1052                 :            : {
    1053                 :            :   GVariant *value;
    1054                 :            : 
    1055         [ +  - ]:          1 :   if (format_string != NULL)
    1056                 :            :     {
    1057                 :            :       va_list ap;
    1058                 :            : 
    1059                 :          1 :       va_start (ap, format_string);
    1060                 :          1 :       value = g_variant_new_va (format_string, NULL, &ap);
    1061                 :          1 :       va_end (ap);
    1062                 :            :     }
    1063                 :            :   else
    1064                 :          0 :     value = NULL;
    1065                 :            : 
    1066                 :          1 :   g_menu_item_set_action_and_target_value (menu_item, action, value);
    1067                 :          1 : }
    1068                 :            : 
    1069                 :            : /**
    1070                 :            :  * g_menu_item_set_detailed_action:
    1071                 :            :  * @menu_item: a #GMenuItem
    1072                 :            :  * @detailed_action: the "detailed" action string
    1073                 :            :  *
    1074                 :            :  * Sets the "action" and possibly the "target" attribute of @menu_item.
    1075                 :            :  *
    1076                 :            :  * The format of @detailed_action is the same format parsed by
    1077                 :            :  * g_action_parse_detailed_name().
    1078                 :            :  *
    1079                 :            :  * See g_menu_item_set_action_and_target() or
    1080                 :            :  * g_menu_item_set_action_and_target_value() for more flexible (but
    1081                 :            :  * slightly less convenient) alternatives.
    1082                 :            :  *
    1083                 :            :  * See also g_menu_item_set_action_and_target_value() for a description of
    1084                 :            :  * the semantics of the action and target attributes.
    1085                 :            :  *
    1086                 :            :  * Since: 2.32
    1087                 :            :  */
    1088                 :            : void
    1089                 :          6 : g_menu_item_set_detailed_action (GMenuItem   *menu_item,
    1090                 :            :                                  const gchar *detailed_action)
    1091                 :            : {
    1092                 :          6 :   GError *error = NULL;
    1093                 :            :   GVariant *target;
    1094                 :            :   gchar *name;
    1095                 :            : 
    1096         [ -  + ]:          6 :   if (!g_action_parse_detailed_name (detailed_action, &name, &target, &error))
    1097                 :          0 :     g_error ("g_menu_item_set_detailed_action: %s", error->message);
    1098                 :            : 
    1099                 :          6 :   g_menu_item_set_action_and_target_value (menu_item, name, target);
    1100         [ +  + ]:          6 :   if (target)
    1101                 :          4 :     g_variant_unref (target);
    1102                 :          6 :   g_free (name);
    1103                 :          6 : }
    1104                 :            : 
    1105                 :            : /**
    1106                 :            :  * g_menu_item_new:
    1107                 :            :  * @label: (nullable): the section label, or %NULL
    1108                 :            :  * @detailed_action: (nullable): the detailed action string, or %NULL
    1109                 :            :  *
    1110                 :            :  * Creates a new #GMenuItem.
    1111                 :            :  *
    1112                 :            :  * If @label is non-%NULL it is used to set the "label" attribute of the
    1113                 :            :  * new item.
    1114                 :            :  *
    1115                 :            :  * If @detailed_action is non-%NULL it is used to set the "action" and
    1116                 :            :  * possibly the "target" attribute of the new item.  See
    1117                 :            :  * g_menu_item_set_detailed_action() for more information.
    1118                 :            :  *
    1119                 :            :  * Returns: a new #GMenuItem
    1120                 :            :  *
    1121                 :            :  * Since: 2.32
    1122                 :            :  */
    1123                 :            : GMenuItem *
    1124                 :         36 : g_menu_item_new (const gchar *label,
    1125                 :            :                  const gchar *detailed_action)
    1126                 :            : {
    1127                 :            :   GMenuItem *menu_item;
    1128                 :            : 
    1129                 :         36 :   menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
    1130                 :            : 
    1131         [ +  + ]:         36 :   if (label != NULL)
    1132                 :         25 :     g_menu_item_set_label (menu_item, label);
    1133                 :            : 
    1134         [ +  + ]:         36 :   if (detailed_action != NULL)
    1135                 :          6 :     g_menu_item_set_detailed_action (menu_item, detailed_action);
    1136                 :            : 
    1137                 :         36 :   return menu_item;
    1138                 :            : }
    1139                 :            : 
    1140                 :            : /**
    1141                 :            :  * g_menu_item_new_submenu:
    1142                 :            :  * @label: (nullable): the section label, or %NULL
    1143                 :            :  * @submenu: a #GMenuModel with the items of the submenu
    1144                 :            :  *
    1145                 :            :  * Creates a new #GMenuItem representing a submenu.
    1146                 :            :  *
    1147                 :            :  * This is a convenience API around g_menu_item_new() and
    1148                 :            :  * g_menu_item_set_submenu().
    1149                 :            :  *
    1150                 :            :  * Returns: a new #GMenuItem
    1151                 :            :  *
    1152                 :            :  * Since: 2.32
    1153                 :            :  */
    1154                 :            : GMenuItem *
    1155                 :          6 : g_menu_item_new_submenu (const gchar *label,
    1156                 :            :                          GMenuModel  *submenu)
    1157                 :            : {
    1158                 :            :   GMenuItem *menu_item;
    1159                 :            : 
    1160                 :          6 :   menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
    1161                 :            : 
    1162         [ +  - ]:          6 :   if (label != NULL)
    1163                 :          6 :     g_menu_item_set_label (menu_item, label);
    1164                 :            : 
    1165                 :          6 :   g_menu_item_set_submenu (menu_item, submenu);
    1166                 :            : 
    1167                 :          6 :   return menu_item;
    1168                 :            : }
    1169                 :            : 
    1170                 :            : /**
    1171                 :            :  * g_menu_item_new_section:
    1172                 :            :  * @label: (nullable): the section label, or %NULL
    1173                 :            :  * @section: a #GMenuModel with the items of the section
    1174                 :            :  *
    1175                 :            :  * Creates a new #GMenuItem representing a section.
    1176                 :            :  *
    1177                 :            :  * This is a convenience API around g_menu_item_new() and
    1178                 :            :  * g_menu_item_set_section().
    1179                 :            :  *
    1180                 :            :  * The effect of having one menu appear as a section of another is
    1181                 :            :  * exactly as it sounds: the items from @section become a direct part of
    1182                 :            :  * the menu that @menu_item is added to.
    1183                 :            :  *
    1184                 :            :  * Visual separation is typically displayed between two non-empty
    1185                 :            :  * sections.  If @label is non-%NULL then it will be incorporated into
    1186                 :            :  * this visual indication.  This allows for labeled subsections of a
    1187                 :            :  * menu.
    1188                 :            :  *
    1189                 :            :  * As a simple example, consider a typical "Edit" menu from a simple
    1190                 :            :  * program.  It probably contains an "Undo" and "Redo" item, followed by
    1191                 :            :  * a separator, followed by "Cut", "Copy" and "Paste".
    1192                 :            :  *
    1193                 :            :  * This would be accomplished by creating three #GMenu instances.  The
    1194                 :            :  * first would be populated with the "Undo" and "Redo" items, and the
    1195                 :            :  * second with the "Cut", "Copy" and "Paste" items.  The first and
    1196                 :            :  * second menus would then be added as submenus of the third.  In XML
    1197                 :            :  * format, this would look something like the following:
    1198                 :            :  * |[
    1199                 :            :  * <menu id='edit-menu'>
    1200                 :            :  *   <section>
    1201                 :            :  *     <item label='Undo'/>
    1202                 :            :  *     <item label='Redo'/>
    1203                 :            :  *   </section>
    1204                 :            :  *   <section>
    1205                 :            :  *     <item label='Cut'/>
    1206                 :            :  *     <item label='Copy'/>
    1207                 :            :  *     <item label='Paste'/>
    1208                 :            :  *   </section>
    1209                 :            :  * </menu>
    1210                 :            :  * ]|
    1211                 :            :  *
    1212                 :            :  * The following example is exactly equivalent.  It is more illustrative
    1213                 :            :  * of the exact relationship between the menus and items (keeping in
    1214                 :            :  * mind that the 'link' element defines a new menu that is linked to the
    1215                 :            :  * containing one).  The style of the second example is more verbose and
    1216                 :            :  * difficult to read (and therefore not recommended except for the
    1217                 :            :  * purpose of understanding what is really going on).
    1218                 :            :  * |[
    1219                 :            :  * <menu id='edit-menu'>
    1220                 :            :  *   <item>
    1221                 :            :  *     <link name='section'>
    1222                 :            :  *       <item label='Undo'/>
    1223                 :            :  *       <item label='Redo'/>
    1224                 :            :  *     </link>
    1225                 :            :  *   </item>
    1226                 :            :  *   <item>
    1227                 :            :  *     <link name='section'>
    1228                 :            :  *       <item label='Cut'/>
    1229                 :            :  *       <item label='Copy'/>
    1230                 :            :  *       <item label='Paste'/>
    1231                 :            :  *     </link>
    1232                 :            :  *   </item>
    1233                 :            :  * </menu>
    1234                 :            :  * ]|
    1235                 :            :  *
    1236                 :            :  * Returns: a new #GMenuItem
    1237                 :            :  *
    1238                 :            :  * Since: 2.32
    1239                 :            :  */
    1240                 :            : GMenuItem *
    1241                 :          6 : g_menu_item_new_section (const gchar *label,
    1242                 :            :                          GMenuModel  *section)
    1243                 :            : {
    1244                 :            :   GMenuItem *menu_item;
    1245                 :            : 
    1246                 :          6 :   menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
    1247                 :            : 
    1248         [ +  - ]:          6 :   if (label != NULL)
    1249                 :          6 :     g_menu_item_set_label (menu_item, label);
    1250                 :            : 
    1251                 :          6 :   g_menu_item_set_section (menu_item, section);
    1252                 :            : 
    1253                 :          6 :   return menu_item;
    1254                 :            : }
    1255                 :            : 
    1256                 :            : /**
    1257                 :            :  * g_menu_item_new_from_model:
    1258                 :            :  * @model: a #GMenuModel
    1259                 :            :  * @item_index: the index of an item in @model
    1260                 :            :  *
    1261                 :            :  * Creates a #GMenuItem as an exact copy of an existing menu item in a
    1262                 :            :  * #GMenuModel.
    1263                 :            :  *
    1264                 :            :  * @item_index must be valid (ie: be sure to call
    1265                 :            :  * g_menu_model_get_n_items() first).
    1266                 :            :  *
    1267                 :            :  * Returns: a new #GMenuItem.
    1268                 :            :  *
    1269                 :            :  * Since: 2.34
    1270                 :            :  */
    1271                 :            : GMenuItem *
    1272                 :          1 : g_menu_item_new_from_model (GMenuModel *model,
    1273                 :            :                             gint        item_index)
    1274                 :            : {
    1275                 :          1 :   GMenuModelClass *class = G_MENU_MODEL_GET_CLASS (model);
    1276                 :            :   GMenuItem *menu_item;
    1277                 :            : 
    1278                 :          1 :   menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
    1279                 :            : 
    1280                 :            :   /* With some trickery we can be pretty efficient.
    1281                 :            :    *
    1282                 :            :    * A GMenuModel must either implement iterate_item_attributes() or
    1283                 :            :    * get_item_attributes().  If it implements get_item_attributes() then
    1284                 :            :    * we are in luck -- we can just take a reference on the returned
    1285                 :            :    * hashtable and mark ourselves as copy-on-write.
    1286                 :            :    *
    1287                 :            :    * In the case that the model is based on get_item_attributes (which
    1288                 :            :    * is the case for both GMenu and GDBusMenuModel) then this is
    1289                 :            :    * basically just g_hash_table_ref().
    1290                 :            :    */
    1291         [ +  - ]:          1 :   if (class->get_item_attributes)
    1292                 :            :     {
    1293                 :          1 :       GHashTable *attributes = NULL;
    1294                 :            : 
    1295                 :          1 :       class->get_item_attributes (model, item_index, &attributes);
    1296         [ +  - ]:          1 :       if (attributes)
    1297                 :            :         {
    1298                 :          1 :           g_hash_table_unref (menu_item->attributes);
    1299                 :          1 :           menu_item->attributes = attributes;
    1300                 :          1 :           menu_item->cow = TRUE;
    1301                 :            :         }
    1302                 :            :     }
    1303                 :            :   else
    1304                 :            :     {
    1305                 :            :       GMenuAttributeIter *iter;
    1306                 :            :       const gchar *attribute;
    1307                 :            :       GVariant *value;
    1308                 :            : 
    1309                 :          0 :       iter = g_menu_model_iterate_item_attributes (model, item_index);
    1310         [ #  # ]:          0 :       while (g_menu_attribute_iter_get_next (iter, &attribute, &value))
    1311                 :          0 :         g_hash_table_insert (menu_item->attributes, g_strdup (attribute), value);
    1312                 :          0 :       g_object_unref (iter);
    1313                 :            :     }
    1314                 :            : 
    1315                 :            :   /* Same story for the links... */
    1316         [ +  - ]:          1 :   if (class->get_item_links)
    1317                 :            :     {
    1318                 :          1 :       GHashTable *links = NULL;
    1319                 :            : 
    1320                 :          1 :       class->get_item_links (model, item_index, &links);
    1321         [ +  - ]:          1 :       if (links)
    1322                 :            :         {
    1323                 :          1 :           g_hash_table_unref (menu_item->links);
    1324                 :          1 :           menu_item->links = links;
    1325                 :          1 :           menu_item->cow = TRUE;
    1326                 :            :         }
    1327                 :            :     }
    1328                 :            :   else
    1329                 :            :     {
    1330                 :            :       GMenuLinkIter *iter;
    1331                 :            :       const gchar *link;
    1332                 :            :       GMenuModel *value;
    1333                 :            : 
    1334                 :          0 :       iter = g_menu_model_iterate_item_links (model, item_index);
    1335         [ #  # ]:          0 :       while (g_menu_link_iter_get_next (iter, &link, &value))
    1336                 :          0 :         g_hash_table_insert (menu_item->links, g_strdup (link), value);
    1337                 :          0 :       g_object_unref (iter);
    1338                 :            :     }
    1339                 :            : 
    1340                 :          1 :   return menu_item;
    1341                 :            : }
    1342                 :            : 
    1343                 :            : /**
    1344                 :            :  * g_menu_item_set_icon:
    1345                 :            :  * @menu_item: a #GMenuItem
    1346                 :            :  * @icon: a #GIcon, or %NULL
    1347                 :            :  *
    1348                 :            :  * Sets (or unsets) the icon on @menu_item.
    1349                 :            :  *
    1350                 :            :  * This call is the same as calling g_icon_serialize() and using the
    1351                 :            :  * result as the value to g_menu_item_set_attribute_value() for
    1352                 :            :  * %G_MENU_ATTRIBUTE_ICON.
    1353                 :            :  *
    1354                 :            :  * This API is only intended for use with "noun" menu items; things like
    1355                 :            :  * bookmarks or applications in an "Open With" menu.  Don't use it on
    1356                 :            :  * menu items corresponding to verbs (eg: stock icons for 'Save' or
    1357                 :            :  * 'Quit').
    1358                 :            :  *
    1359                 :            :  * If @icon is %NULL then the icon is unset.
    1360                 :            :  *
    1361                 :            :  * Since: 2.38
    1362                 :            :  **/
    1363                 :            : void
    1364                 :          1 : g_menu_item_set_icon (GMenuItem *menu_item,
    1365                 :            :                       GIcon     *icon)
    1366                 :            : {
    1367                 :            :   GVariant *value;
    1368                 :            : 
    1369                 :          1 :   g_return_if_fail (G_IS_MENU_ITEM (menu_item));
    1370                 :          1 :   g_return_if_fail (icon == NULL || G_IS_ICON (icon));
    1371                 :            : 
    1372         [ +  - ]:          1 :   if (icon != NULL)
    1373                 :          1 :     value = g_icon_serialize (icon);
    1374                 :            :   else
    1375                 :          0 :     value = NULL;
    1376                 :            : 
    1377                 :          1 :   g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ICON, value);
    1378         [ +  - ]:          1 :   if (value)
    1379                 :          1 :     g_variant_unref (value);
    1380                 :            : }

Generated by: LCOV version 1.14