LCOV - code coverage report
Current view: top level - gio - gmenu.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 92.4 % 303 280
Test Date: 2024-11-26 05:23:01 Functions: 100.0 % 52 52
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Copyright © 2011 Canonical Ltd.
       3                 :             :  *
       4                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       5                 :             :  *
       6                 :             :  * This library is free software; you can redistribute it and/or
       7                 :             :  * modify it under the terms of the GNU Lesser General Public
       8                 :             :  * License as published by the Free Software Foundation; either
       9                 :             :  * version 2.1 of the License, or (at your option) any later version.
      10                 :             :  *
      11                 :             :  * This library is distributed in the hope that it will be useful, but
      12                 :             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :             :  * Lesser General Public License for more details.
      15                 :             :  *
      16                 :             :  * You should have received a copy of the GNU Lesser General Public
      17                 :             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18                 :             :  *
      19                 :             :  * Author: Ryan Lortie <desrt@desrt.ca>
      20                 :             :  */
      21                 :             : 
      22                 :             : #include "config.h"
      23                 :             : 
      24                 :             : #include "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                 :         222 : 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                 :          37 : g_menu_clear_item (struct item *item)
     445                 :             : {
     446                 :          37 :   if (item->attributes != NULL)
     447                 :          37 :     g_hash_table_unref (item->attributes);
     448                 :          37 :   if (item->links != NULL)
     449                 :          37 :     g_hash_table_unref (item->links);
     450                 :          37 : }
     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                 :          13 : g_menu_finalize (GObject *object)
     507                 :             : {
     508                 :          13 :   GMenu *menu = G_MENU (object);
     509                 :             :   struct item *items;
     510                 :             :   gint n_items;
     511                 :             :   gint i;
     512                 :             : 
     513                 :          13 :   n_items = menu->items->len;
     514                 :          13 :   items = (struct item *) g_array_free (menu->items, FALSE);
     515                 :          40 :   for (i = 0; i < n_items; i++)
     516                 :          27 :     g_menu_clear_item (&items[i]);
     517                 :          13 :   g_free (items);
     518                 :             : 
     519                 :          13 :   G_OBJECT_CLASS (g_menu_parent_class)
     520                 :          13 :     ->finalize (object);
     521                 :          13 : }
     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 2.0-1