Blame gio/gmenu.c

Packit ae235b
/*
Packit ae235b
 * Copyright © 2011 Canonical Ltd.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful, but
Packit ae235b
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General Public
Packit ae235b
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: Ryan Lortie <desrt@desrt.ca>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include "gmenu.h"
Packit ae235b
Packit ae235b
#include "gaction.h"
Packit ae235b
#include <string.h>
Packit ae235b
Packit ae235b
#include "gicon.h"
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * SECTION:gmenu
Packit ae235b
 * @title: GMenu
Packit ae235b
 * @short_description: A simple implementation of GMenuModel
Packit ae235b
 * @include: gio/gio.h
Packit ae235b
 *
Packit ae235b
 * #GMenu is a simple implementation of #GMenuModel.
Packit ae235b
 * You populate a #GMenu by adding #GMenuItem instances to it.
Packit ae235b
 *
Packit ae235b
 * There are some convenience functions to allow you to directly
Packit ae235b
 * add items (avoiding #GMenuItem) for the common cases. To add
Packit ae235b
 * a regular item, use g_menu_insert(). To add a section, use
Packit ae235b
 * g_menu_insert_section(). To add a submenu, use
Packit ae235b
 * g_menu_insert_submenu().
Packit ae235b
 */
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * GMenu:
Packit ae235b
 *
Packit ae235b
 * #GMenu is an opaque structure type.  You must access it using the
Packit ae235b
 * functions below.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * GMenuItem:
Packit ae235b
 *
Packit ae235b
 * #GMenuItem is an opaque structure type.  You must access it using the
Packit ae235b
 * functions below.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
Packit ae235b
struct _GMenuItem
Packit ae235b
{
Packit ae235b
  GObject parent_instance;
Packit ae235b
Packit ae235b
  GHashTable *attributes;
Packit ae235b
  GHashTable *links;
Packit ae235b
  gboolean    cow;
Packit ae235b
};
Packit ae235b
Packit ae235b
typedef GObjectClass GMenuItemClass;
Packit ae235b
Packit ae235b
struct _GMenu
Packit ae235b
{
Packit ae235b
  GMenuModel parent_instance;
Packit ae235b
Packit ae235b
  GArray   *items;
Packit ae235b
  gboolean  mutable;
Packit ae235b
};
Packit ae235b
Packit ae235b
typedef GMenuModelClass GMenuClass;
Packit ae235b
Packit ae235b
G_DEFINE_TYPE (GMenu, g_menu, G_TYPE_MENU_MODEL)
Packit ae235b
G_DEFINE_TYPE (GMenuItem, g_menu_item, G_TYPE_OBJECT)
Packit ae235b
Packit ae235b
struct item
Packit ae235b
{
Packit ae235b
  GHashTable *attributes;
Packit ae235b
  GHashTable *links;
Packit ae235b
};
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_menu_is_mutable (GMenuModel *model)
Packit ae235b
{
Packit ae235b
  GMenu *menu = G_MENU (model);
Packit ae235b
Packit ae235b
  return menu->mutable;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gint
Packit ae235b
g_menu_get_n_items (GMenuModel *model)
Packit ae235b
{
Packit ae235b
  GMenu *menu = G_MENU (model);
Packit ae235b
Packit ae235b
  return menu->items->len;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_get_item_attributes (GMenuModel  *model,
Packit ae235b
                            gint         position,
Packit ae235b
                            GHashTable **table)
Packit ae235b
{
Packit ae235b
  GMenu *menu = G_MENU (model);
Packit ae235b
Packit ae235b
  *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).attributes);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_get_item_links (GMenuModel  *model,
Packit ae235b
                       gint         position,
Packit ae235b
                       GHashTable **table)
Packit ae235b
{
Packit ae235b
  GMenu *menu = G_MENU (model);
Packit ae235b
Packit ae235b
  *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).links);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_insert_item:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @position: the position at which to insert the item
Packit ae235b
 * @item: the #GMenuItem to insert
Packit ae235b
 *
Packit ae235b
 * Inserts @item into @menu.
Packit ae235b
 *
Packit ae235b
 * The "insertion" is actually done by copying all of the attribute and
Packit ae235b
 * link values of @item and using them to form a new item within @menu.
Packit ae235b
 * As such, @item itself is not really inserted, but rather, a menu item
Packit ae235b
 * that is exactly the same as the one presently described by @item.
Packit ae235b
 *
Packit ae235b
 * This means that @item is essentially useless after the insertion
Packit ae235b
 * occurs.  Any changes you make to it are ignored unless it is inserted
Packit ae235b
 * again (at which point its updated values will be copied).
Packit ae235b
 *
Packit ae235b
 * You should probably just free @item once you're done.
Packit ae235b
 *
Packit ae235b
 * There are many convenience functions to take care of common cases.
Packit ae235b
 * See g_menu_insert(), g_menu_insert_section() and
Packit ae235b
 * g_menu_insert_submenu() as well as "prepend" and "append" variants of
Packit ae235b
 * each of these functions.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_insert_item (GMenu     *menu,
Packit ae235b
                    gint       position,
Packit ae235b
                    GMenuItem *item)
Packit ae235b
{
Packit ae235b
  struct item new_item;
Packit ae235b
Packit ae235b
  g_return_if_fail (G_IS_MENU (menu));
Packit ae235b
  g_return_if_fail (G_IS_MENU_ITEM (item));
Packit ae235b
Packit ae235b
  if (position < 0 || position > menu->items->len)
Packit ae235b
    position = menu->items->len;
Packit ae235b
Packit ae235b
  new_item.attributes = g_hash_table_ref (item->attributes);
Packit ae235b
  new_item.links = g_hash_table_ref (item->links);
Packit ae235b
  item->cow = TRUE;
Packit ae235b
Packit ae235b
  g_array_insert_val (menu->items, position, new_item);
Packit ae235b
  g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_prepend_item:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @item: a #GMenuItem to prepend
Packit ae235b
 *
Packit ae235b
 * Prepends @item to the start of @menu.
Packit ae235b
 *
Packit ae235b
 * See g_menu_insert_item() for more information.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_prepend_item (GMenu     *menu,
Packit ae235b
                     GMenuItem *item)
Packit ae235b
{
Packit ae235b
  g_menu_insert_item (menu, 0, item);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_append_item:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @item: a #GMenuItem to append
Packit ae235b
 *
Packit ae235b
 * Appends @item to the end of @menu.
Packit ae235b
 *
Packit ae235b
 * See g_menu_insert_item() for more information.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_append_item (GMenu     *menu,
Packit ae235b
                    GMenuItem *item)
Packit ae235b
{
Packit ae235b
  g_menu_insert_item (menu, -1, item);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_freeze:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 *
Packit ae235b
 * Marks @menu as frozen.
Packit ae235b
 *
Packit ae235b
 * After the menu is frozen, it is an error to attempt to make any
Packit ae235b
 * changes to it.  In effect this means that the #GMenu API must no
Packit ae235b
 * longer be used.
Packit ae235b
 *
Packit ae235b
 * This function causes g_menu_model_is_mutable() to begin returning
Packit ae235b
 * %FALSE, which has some positive performance implications.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_freeze (GMenu *menu)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (G_IS_MENU (menu));
Packit ae235b
Packit ae235b
  menu->mutable = FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_new:
Packit ae235b
 *
Packit ae235b
 * Creates a new #GMenu.
Packit ae235b
 *
Packit ae235b
 * The new menu has no items.
Packit ae235b
 *
Packit ae235b
 * Returns: a new #GMenu
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
GMenu *
Packit ae235b
g_menu_new (void)
Packit ae235b
{
Packit ae235b
  return g_object_new (G_TYPE_MENU, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_insert:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @position: the position at which to insert the item
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @detailed_action: (nullable): the detailed action string, or %NULL
Packit ae235b
 *
Packit ae235b
 * Convenience function for inserting a normal menu item into @menu.
Packit ae235b
 * Combine g_menu_item_new() and g_menu_insert_item() for a more flexible
Packit ae235b
 * alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_insert (GMenu       *menu,
Packit ae235b
               gint         position,
Packit ae235b
               const gchar *label,
Packit ae235b
               const gchar *detailed_action)
Packit ae235b
{
Packit ae235b
  GMenuItem *menu_item;
Packit ae235b
Packit ae235b
  menu_item = g_menu_item_new (label, detailed_action);
Packit ae235b
  g_menu_insert_item (menu, position, menu_item);
Packit ae235b
  g_object_unref (menu_item);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_prepend:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @detailed_action: (nullable): the detailed action string, or %NULL
Packit ae235b
 *
Packit ae235b
 * Convenience function for prepending a normal menu item to the start
Packit ae235b
 * of @menu.  Combine g_menu_item_new() and g_menu_insert_item() for a more
Packit ae235b
 * flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_prepend (GMenu       *menu,
Packit ae235b
                const gchar *label,
Packit ae235b
                const gchar *detailed_action)
Packit ae235b
{
Packit ae235b
  g_menu_insert (menu, 0, label, detailed_action);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_append:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @detailed_action: (nullable): the detailed action string, or %NULL
Packit ae235b
 *
Packit ae235b
 * Convenience function for appending a normal menu item to the end of
Packit ae235b
 * @menu.  Combine g_menu_item_new() and g_menu_insert_item() for a more
Packit ae235b
 * flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_append (GMenu       *menu,
Packit ae235b
               const gchar *label,
Packit ae235b
               const gchar *detailed_action)
Packit ae235b
{
Packit ae235b
  g_menu_insert (menu, -1, label, detailed_action);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_insert_section:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @position: the position at which to insert the item
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @section: a #GMenuModel with the items of the section
Packit ae235b
 *
Packit ae235b
 * Convenience function for inserting a section menu item into @menu.
Packit ae235b
 * Combine g_menu_item_new_section() and g_menu_insert_item() for a more
Packit ae235b
 * flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_insert_section (GMenu       *menu,
Packit ae235b
                       gint         position,
Packit ae235b
                       const gchar *label,
Packit ae235b
                       GMenuModel  *section)
Packit ae235b
{
Packit ae235b
  GMenuItem *menu_item;
Packit ae235b
Packit ae235b
  menu_item = g_menu_item_new_section (label, section);
Packit ae235b
  g_menu_insert_item (menu, position, menu_item);
Packit ae235b
  g_object_unref (menu_item);
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_prepend_section:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @section: a #GMenuModel with the items of the section
Packit ae235b
 *
Packit ae235b
 * Convenience function for prepending a section menu item to the start
Packit ae235b
 * of @menu.  Combine g_menu_item_new_section() and g_menu_insert_item() for
Packit ae235b
 * a more flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_prepend_section (GMenu       *menu,
Packit ae235b
                        const gchar *label,
Packit ae235b
                        GMenuModel  *section)
Packit ae235b
{
Packit ae235b
  g_menu_insert_section (menu, 0, label, section);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_append_section:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @section: a #GMenuModel with the items of the section
Packit ae235b
 *
Packit ae235b
 * Convenience function for appending a section menu item to the end of
Packit ae235b
 * @menu.  Combine g_menu_item_new_section() and g_menu_insert_item() for a
Packit ae235b
 * more flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_append_section (GMenu       *menu,
Packit ae235b
                       const gchar *label,
Packit ae235b
                       GMenuModel  *section)
Packit ae235b
{
Packit ae235b
  g_menu_insert_section (menu, -1, label, section);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_insert_submenu:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @position: the position at which to insert the item
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @submenu: a #GMenuModel with the items of the submenu
Packit ae235b
 *
Packit ae235b
 * Convenience function for inserting a submenu menu item into @menu.
Packit ae235b
 * Combine g_menu_item_new_submenu() and g_menu_insert_item() for a more
Packit ae235b
 * flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_insert_submenu (GMenu       *menu,
Packit ae235b
                       gint         position,
Packit ae235b
                       const gchar *label,
Packit ae235b
                       GMenuModel  *submenu)
Packit ae235b
{
Packit ae235b
  GMenuItem *menu_item;
Packit ae235b
Packit ae235b
  menu_item = g_menu_item_new_submenu (label, submenu);
Packit ae235b
  g_menu_insert_item (menu, position, menu_item);
Packit ae235b
  g_object_unref (menu_item);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_prepend_submenu:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @submenu: a #GMenuModel with the items of the submenu
Packit ae235b
 *
Packit ae235b
 * Convenience function for prepending a submenu menu item to the start
Packit ae235b
 * of @menu.  Combine g_menu_item_new_submenu() and g_menu_insert_item() for
Packit ae235b
 * a more flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_prepend_submenu (GMenu       *menu,
Packit ae235b
                        const gchar *label,
Packit ae235b
                        GMenuModel  *submenu)
Packit ae235b
{
Packit ae235b
  g_menu_insert_submenu (menu, 0, label, submenu);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_append_submenu:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @submenu: a #GMenuModel with the items of the submenu
Packit ae235b
 *
Packit ae235b
 * Convenience function for appending a submenu menu item to the end of
Packit ae235b
 * @menu.  Combine g_menu_item_new_submenu() and g_menu_insert_item() for a
Packit ae235b
 * more flexible alternative.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_append_submenu (GMenu       *menu,
Packit ae235b
                       const gchar *label,
Packit ae235b
                       GMenuModel  *submenu)
Packit ae235b
{
Packit ae235b
  g_menu_insert_submenu (menu, -1, label, submenu);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_clear_item (struct item *item)
Packit ae235b
{
Packit ae235b
  if (item->attributes != NULL)
Packit ae235b
    g_hash_table_unref (item->attributes);
Packit ae235b
  if (item->links != NULL)
Packit ae235b
    g_hash_table_unref (item->links);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_remove:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 * @position: the position of the item to remove
Packit ae235b
 *
Packit ae235b
 * Removes an item from the menu.
Packit ae235b
 *
Packit ae235b
 * @position gives the index of the item to remove.
Packit ae235b
 *
Packit ae235b
 * It is an error if position is not in range the range from 0 to one
Packit ae235b
 * less than the number of items in the menu.
Packit ae235b
 *
Packit ae235b
 * It is not possible to remove items by identity since items are added
Packit ae235b
 * to the menu simply by copying their links and attributes (ie:
Packit ae235b
 * identity of the item itself is not preserved).
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_remove (GMenu *menu,
Packit ae235b
               gint   position)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (G_IS_MENU (menu));
Packit ae235b
  g_return_if_fail (0 <= position && position < menu->items->len);
Packit ae235b
Packit ae235b
  g_menu_clear_item (&g_array_index (menu->items, struct item, position));
Packit ae235b
  g_array_remove_index (menu->items, position);
Packit ae235b
  g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_remove_all:
Packit ae235b
 * @menu: a #GMenu
Packit ae235b
 *
Packit ae235b
 * Removes all items in the menu.
Packit ae235b
 *
Packit ae235b
 * Since: 2.38
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_menu_remove_all (GMenu *menu)
Packit ae235b
{
Packit ae235b
  gint i, n;
Packit ae235b
Packit ae235b
  g_return_if_fail (G_IS_MENU (menu));
Packit ae235b
  n = menu->items->len;
Packit ae235b
Packit ae235b
  for (i = 0; i < n; i++)
Packit ae235b
    g_menu_clear_item (&g_array_index (menu->items, struct item, i));
Packit ae235b
  g_array_set_size (menu->items, 0);
Packit ae235b
Packit ae235b
  g_menu_model_items_changed (G_MENU_MODEL (menu), 0, n, 0);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_finalize (GObject *object)
Packit ae235b
{
Packit ae235b
  GMenu *menu = G_MENU (object);
Packit ae235b
  struct item *items;
Packit ae235b
  gint n_items;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  n_items = menu->items->len;
Packit ae235b
  items = (struct item *) g_array_free (menu->items, FALSE);
Packit ae235b
  for (i = 0; i < n_items; i++)
Packit ae235b
    g_menu_clear_item (&items[i]);
Packit ae235b
  g_free (items);
Packit ae235b
Packit ae235b
  G_OBJECT_CLASS (g_menu_parent_class)
Packit ae235b
    ->finalize (object);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_init (GMenu *menu)
Packit ae235b
{
Packit ae235b
  menu->items = g_array_new (FALSE, FALSE, sizeof (struct item));
Packit ae235b
  menu->mutable = TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_class_init (GMenuClass *class)
Packit ae235b
{
Packit ae235b
  GMenuModelClass *model_class = G_MENU_MODEL_CLASS (class);
Packit ae235b
  GObjectClass *object_class = G_OBJECT_CLASS (class);
Packit ae235b
Packit ae235b
  object_class->finalize = g_menu_finalize;
Packit ae235b
Packit ae235b
  model_class->is_mutable = g_menu_is_mutable;
Packit ae235b
  model_class->get_n_items = g_menu_get_n_items;
Packit ae235b
  model_class->get_item_attributes = g_menu_get_item_attributes;
Packit ae235b
  model_class->get_item_links = g_menu_get_item_links;
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_item_clear_cow (GMenuItem *menu_item)
Packit ae235b
{
Packit ae235b
  if (menu_item->cow)
Packit ae235b
    {
Packit ae235b
      GHashTableIter iter;
Packit ae235b
      GHashTable *new;
Packit ae235b
      gpointer key;
Packit ae235b
      gpointer val;
Packit ae235b
Packit ae235b
      new = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
Packit ae235b
      g_hash_table_iter_init (&iter, menu_item->attributes);
Packit ae235b
      while (g_hash_table_iter_next (&iter, &key, &val))
Packit ae235b
        g_hash_table_insert (new, g_strdup (key), g_variant_ref (val));
Packit ae235b
      g_hash_table_unref (menu_item->attributes);
Packit ae235b
      menu_item->attributes = new;
Packit ae235b
Packit ae235b
      new = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
Packit ae235b
      g_hash_table_iter_init (&iter, menu_item->links);
Packit ae235b
      while (g_hash_table_iter_next (&iter, &key, &val))
Packit ae235b
        g_hash_table_insert (new, g_strdup (key), g_object_ref (val));
Packit ae235b
      g_hash_table_unref (menu_item->links);
Packit ae235b
      menu_item->links = new;
Packit ae235b
Packit ae235b
      menu_item->cow = FALSE;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_item_finalize (GObject *object)
Packit ae235b
{
Packit ae235b
  GMenuItem *menu_item = G_MENU_ITEM (object);
Packit ae235b
Packit ae235b
  g_hash_table_unref (menu_item->attributes);
Packit ae235b
  g_hash_table_unref (menu_item->links);
Packit ae235b
Packit ae235b
  G_OBJECT_CLASS (g_menu_item_parent_class)
Packit ae235b
    ->finalize (object);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_item_init (GMenuItem *menu_item)
Packit ae235b
{
Packit ae235b
  menu_item->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
Packit ae235b
  menu_item->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
Packit ae235b
  menu_item->cow = FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_menu_item_class_init (GMenuItemClass *class)
Packit ae235b
{
Packit ae235b
  class->finalize = g_menu_item_finalize;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* We treat attribute names the same as GSettings keys:
Packit ae235b
 * - only lowercase ascii, digits and '-'
Packit ae235b
 * - must start with lowercase
Packit ae235b
 * - must not end with '-'
Packit ae235b
 * - no consecutive '-'
Packit ae235b
 * - not longer than 1024 chars
Packit ae235b
 */
Packit ae235b
static gboolean
Packit ae235b
valid_attribute_name (const gchar *name)
Packit ae235b
{
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  if (!g_ascii_islower (name[0]))
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  for (i = 1; name[i]; i++)
Packit ae235b
    {
Packit ae235b
      if (name[i] != '-' &&
Packit ae235b
          !g_ascii_islower (name[i]) &&
Packit ae235b
          !g_ascii_isdigit (name[i]))
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      if (name[i] == '-' && name[i + 1] == '-')
Packit ae235b
        return FALSE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (name[i - 1] == '-')
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  if (i > 1024)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_attribute_value:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @attribute: the attribute to set
Packit ae235b
 * @value: (nullable): a #GVariant to use as the value, or %NULL
Packit ae235b
 *
Packit ae235b
 * Sets or unsets an attribute on @menu_item.
Packit ae235b
 *
Packit ae235b
 * The attribute to set or unset is specified by @attribute. This
Packit ae235b
 * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL,
Packit ae235b
 * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom
Packit ae235b
 * attribute name.
Packit ae235b
 * Attribute names are restricted to lowercase characters, numbers
Packit ae235b
 * and '-'. Furthermore, the names must begin with a lowercase character,
Packit ae235b
 * must not end with a '-', and must not contain consecutive dashes.
Packit ae235b
 *
Packit ae235b
 * must consist only of lowercase
Packit ae235b
 * ASCII characters, digits and '-'.
Packit ae235b
 *
Packit ae235b
 * If @value is non-%NULL then it is used as the new value for the
Packit ae235b
 * attribute.  If @value is %NULL then the attribute is unset. If
Packit ae235b
 * the @value #GVariant is floating, it is consumed.
Packit ae235b
 *
Packit ae235b
 * See also g_menu_item_set_attribute() for a more convenient way to do
Packit ae235b
 * the same.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_attribute_value (GMenuItem   *menu_item,
Packit ae235b
                                 const gchar *attribute,
Packit ae235b
                                 GVariant    *value)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (G_IS_MENU_ITEM (menu_item));
Packit ae235b
  g_return_if_fail (attribute != NULL);
Packit ae235b
  g_return_if_fail (valid_attribute_name (attribute));
Packit ae235b
Packit ae235b
  g_menu_item_clear_cow (menu_item);
Packit ae235b
Packit ae235b
  if (value != NULL)
Packit ae235b
    g_hash_table_insert (menu_item->attributes, g_strdup (attribute), g_variant_ref_sink (value));
Packit ae235b
  else
Packit ae235b
    g_hash_table_remove (menu_item->attributes, attribute);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_attribute:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @attribute: the attribute to set
Packit ae235b
 * @format_string: (nullable): a #GVariant format string, or %NULL
Packit ae235b
 * @...: positional parameters, as per @format_string
Packit ae235b
 *
Packit ae235b
 * Sets or unsets an attribute on @menu_item.
Packit ae235b
 *
Packit ae235b
 * The attribute to set or unset is specified by @attribute. This
Packit ae235b
 * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL,
Packit ae235b
 * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom
Packit ae235b
 * attribute name.
Packit ae235b
 * Attribute names are restricted to lowercase characters, numbers
Packit ae235b
 * and '-'. Furthermore, the names must begin with a lowercase character,
Packit ae235b
 * must not end with a '-', and must not contain consecutive dashes.
Packit ae235b
 *
Packit ae235b
 * If @format_string is non-%NULL then the proper position parameters
Packit ae235b
 * are collected to create a #GVariant instance to use as the attribute
Packit ae235b
 * value.  If it is %NULL then the positional parameterrs are ignored
Packit ae235b
 * and the named attribute is unset.
Packit ae235b
 *
Packit ae235b
 * See also g_menu_item_set_attribute_value() for an equivalent call
Packit ae235b
 * that directly accepts a #GVariant.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_attribute (GMenuItem   *menu_item,
Packit ae235b
                           const gchar *attribute,
Packit ae235b
                           const gchar *format_string,
Packit ae235b
                           ...)
Packit ae235b
{
Packit ae235b
  GVariant *value;
Packit ae235b
Packit ae235b
  if (format_string != NULL)
Packit ae235b
    {
Packit ae235b
      va_list ap;
Packit ae235b
Packit ae235b
      va_start (ap, format_string);
Packit ae235b
      value = g_variant_new_va (format_string, NULL, &ap);
Packit ae235b
      va_end (ap);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    value = NULL;
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute_value (menu_item, attribute, value);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_link:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @link: type of link to establish or unset
Packit ae235b
 * @model: (nullable): the #GMenuModel to link to (or %NULL to unset)
Packit ae235b
 *
Packit ae235b
 * Creates a link from @menu_item to @model if non-%NULL, or unsets it.
Packit ae235b
 *
Packit ae235b
 * Links are used to establish a relationship between a particular menu
Packit ae235b
 * item and another menu.  For example, %G_MENU_LINK_SUBMENU is used to
Packit ae235b
 * associate a submenu with a particular menu item, and %G_MENU_LINK_SECTION
Packit ae235b
 * is used to create a section. Other types of link can be used, but there
Packit ae235b
 * is no guarantee that clients will be able to make sense of them.
Packit ae235b
 * Link types are restricted to lowercase characters, numbers
Packit ae235b
 * and '-'. Furthermore, the names must begin with a lowercase character,
Packit ae235b
 * must not end with a '-', and must not contain consecutive dashes.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_link (GMenuItem   *menu_item,
Packit ae235b
                      const gchar *link,
Packit ae235b
                      GMenuModel  *model)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (G_IS_MENU_ITEM (menu_item));
Packit ae235b
  g_return_if_fail (link != NULL);
Packit ae235b
  g_return_if_fail (valid_attribute_name (link));
Packit ae235b
Packit ae235b
  g_menu_item_clear_cow (menu_item);
Packit ae235b
Packit ae235b
  if (model != NULL)
Packit ae235b
    g_hash_table_insert (menu_item->links, g_strdup (link), g_object_ref (model));
Packit ae235b
  else
Packit ae235b
    g_hash_table_remove (menu_item->links, link);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_get_attribute_value:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @attribute: the attribute name to query
Packit ae235b
 * @expected_type: (nullable): the expected type of the attribute
Packit ae235b
 *
Packit ae235b
 * Queries the named @attribute on @menu_item.
Packit ae235b
 *
Packit ae235b
 * If @expected_type is specified and the attribute does not have this
Packit ae235b
 * type, %NULL is returned.  %NULL is also returned if the attribute
Packit ae235b
 * simply does not exist.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): the attribute value, or %NULL
Packit ae235b
 *
Packit ae235b
 * Since: 2.34
Packit ae235b
 */
Packit ae235b
GVariant *
Packit ae235b
g_menu_item_get_attribute_value (GMenuItem          *menu_item,
Packit ae235b
                                 const gchar        *attribute,
Packit ae235b
                                 const GVariantType *expected_type)
Packit ae235b
{
Packit ae235b
  GVariant *value;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
Packit ae235b
  g_return_val_if_fail (attribute != NULL, NULL);
Packit ae235b
Packit ae235b
  value = g_hash_table_lookup (menu_item->attributes, attribute);
Packit ae235b
Packit ae235b
  if (value != NULL)
Packit ae235b
    {
Packit ae235b
      if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
Packit ae235b
        g_variant_ref (value);
Packit ae235b
      else
Packit ae235b
        value = NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return value;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_get_attribute:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @attribute: the attribute name to query
Packit ae235b
 * @format_string: a #GVariant format string
Packit ae235b
 * @...: positional parameters, as per @format_string
Packit ae235b
 *
Packit ae235b
 * Queries the named @attribute on @menu_item.
Packit ae235b
 *
Packit ae235b
 * If the attribute exists and matches the #GVariantType corresponding
Packit ae235b
 * to @format_string then @format_string is used to deconstruct the
Packit ae235b
 * value into the positional parameters and %TRUE is returned.
Packit ae235b
 *
Packit ae235b
 * If the attribute does not exist, or it does exist but has the wrong
Packit ae235b
 * type, then the positional parameters are ignored and %FALSE is
Packit ae235b
 * returned.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if the named attribute was found with the expected
Packit ae235b
 *     type
Packit ae235b
 *
Packit ae235b
 * Since: 2.34
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_menu_item_get_attribute (GMenuItem   *menu_item,
Packit ae235b
                           const gchar *attribute,
Packit ae235b
                           const gchar *format_string,
Packit ae235b
                           ...)
Packit ae235b
{
Packit ae235b
  GVariant *value;
Packit ae235b
  va_list ap;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), FALSE);
Packit ae235b
  g_return_val_if_fail (attribute != NULL, FALSE);
Packit ae235b
  g_return_val_if_fail (format_string != NULL, FALSE);
Packit ae235b
Packit ae235b
  value = g_hash_table_lookup (menu_item->attributes, attribute);
Packit ae235b
Packit ae235b
  if (value == NULL)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  if (!g_variant_check_format_string (value, format_string, FALSE))
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  va_start (ap, format_string);
Packit ae235b
  g_variant_get_va (value, format_string, NULL, &ap);
Packit ae235b
  va_end (ap);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_get_link:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @link: the link name to query
Packit ae235b
 *
Packit ae235b
 * Queries the named @link on @menu_item.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): the link, or %NULL
Packit ae235b
 *
Packit ae235b
 * Since: 2.34
Packit ae235b
 */
Packit ae235b
GMenuModel *
Packit ae235b
g_menu_item_get_link (GMenuItem   *menu_item,
Packit ae235b
                      const gchar *link)
Packit ae235b
{
Packit ae235b
  GMenuModel *model;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
Packit ae235b
  g_return_val_if_fail (link != NULL, NULL);
Packit ae235b
  g_return_val_if_fail (valid_attribute_name (link), NULL);
Packit ae235b
Packit ae235b
  model = g_hash_table_lookup (menu_item->links, link);
Packit ae235b
Packit ae235b
  if (model)
Packit ae235b
    g_object_ref (model);
Packit ae235b
Packit ae235b
  return model;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_label:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @label: (nullable): the label to set, or %NULL to unset
Packit ae235b
 *
Packit ae235b
 * Sets or unsets the "label" attribute of @menu_item.
Packit ae235b
 *
Packit ae235b
 * If @label is non-%NULL it is used as the label for the menu item.  If
Packit ae235b
 * it is %NULL then the label attribute is unset.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_label (GMenuItem   *menu_item,
Packit ae235b
                       const gchar *label)
Packit ae235b
{
Packit ae235b
  GVariant *value;
Packit ae235b
Packit ae235b
  if (label != NULL)
Packit ae235b
    value = g_variant_new_string (label);
Packit ae235b
  else
Packit ae235b
    value = NULL;
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_LABEL, value);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_submenu:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @submenu: (nullable): a #GMenuModel, or %NULL
Packit ae235b
 *
Packit ae235b
 * Sets or unsets the "submenu" link of @menu_item to @submenu.
Packit ae235b
 *
Packit ae235b
 * If @submenu is non-%NULL, it is linked to.  If it is %NULL then the
Packit ae235b
 * link is unset.
Packit ae235b
 *
Packit ae235b
 * The effect of having one menu appear as a submenu of another is
Packit ae235b
 * exactly as it sounds.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_submenu (GMenuItem  *menu_item,
Packit ae235b
                         GMenuModel *submenu)
Packit ae235b
{
Packit ae235b
  g_menu_item_set_link (menu_item, G_MENU_LINK_SUBMENU, submenu);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_section:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @section: (nullable): a #GMenuModel, or %NULL
Packit ae235b
 *
Packit ae235b
 * Sets or unsets the "section" link of @menu_item to @section.
Packit ae235b
 *
Packit ae235b
 * The effect of having one menu appear as a section of another is
Packit ae235b
 * exactly as it sounds: the items from @section become a direct part of
Packit ae235b
 * the menu that @menu_item is added to.  See g_menu_item_new_section()
Packit ae235b
 * for more information about what it means for a menu item to be a
Packit ae235b
 * section.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_section (GMenuItem  *menu_item,
Packit ae235b
                         GMenuModel *section)
Packit ae235b
{
Packit ae235b
  g_menu_item_set_link (menu_item, G_MENU_LINK_SECTION, section);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_action_and_target_value:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @action: (nullable): the name of the action for this item
Packit ae235b
 * @target_value: (nullable): a #GVariant to use as the action target
Packit ae235b
 *
Packit ae235b
 * Sets or unsets the "action" and "target" attributes of @menu_item.
Packit ae235b
 *
Packit ae235b
 * If @action is %NULL then both the "action" and "target" attributes
Packit ae235b
 * are unset (and @target_value is ignored).
Packit ae235b
 *
Packit ae235b
 * If @action is non-%NULL then the "action" attribute is set.  The
Packit ae235b
 * "target" attribute is then set to the value of @target_value if it is
Packit ae235b
 * non-%NULL or unset otherwise.
Packit ae235b
 *
Packit ae235b
 * Normal menu items (ie: not submenu, section or other custom item
Packit ae235b
 * types) are expected to have the "action" attribute set to identify
Packit ae235b
 * the action that they are associated with.  The state type of the
Packit ae235b
 * action help to determine the disposition of the menu item.  See
Packit ae235b
 * #GAction and #GActionGroup for an overview of actions.
Packit ae235b
 *
Packit ae235b
 * In general, clicking on the menu item will result in activation of
Packit ae235b
 * the named action with the "target" attribute given as the parameter
Packit ae235b
 * to the action invocation.  If the "target" attribute is not set then
Packit ae235b
 * the action is invoked with no parameter.
Packit ae235b
 *
Packit ae235b
 * If the action has no state then the menu item is usually drawn as a
Packit ae235b
 * plain menu item (ie: with no additional decoration).
Packit ae235b
 *
Packit ae235b
 * If the action has a boolean state then the menu item is usually drawn
Packit ae235b
 * as a toggle menu item (ie: with a checkmark or equivalent
Packit ae235b
 * indication).  The item should be marked as 'toggled' or 'checked'
Packit ae235b
 * when the boolean state is %TRUE.
Packit ae235b
 *
Packit ae235b
 * If the action has a string state then the menu item is usually drawn
Packit ae235b
 * as a radio menu item (ie: with a radio bullet or equivalent
Packit ae235b
 * indication).  The item should be marked as 'selected' when the string
Packit ae235b
 * state is equal to the value of the @target property.
Packit ae235b
 *
Packit ae235b
 * See g_menu_item_set_action_and_target() or
Packit ae235b
 * g_menu_item_set_detailed_action() for two equivalent calls that are
Packit ae235b
 * probably more convenient for most uses.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_action_and_target_value (GMenuItem   *menu_item,
Packit ae235b
                                         const gchar *action,
Packit ae235b
                                         GVariant    *target_value)
Packit ae235b
{
Packit ae235b
  GVariant *action_value;
Packit ae235b
Packit ae235b
  if (action != NULL)
Packit ae235b
    {
Packit ae235b
      action_value = g_variant_new_string (action);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      action_value = NULL;
Packit ae235b
      target_value = NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ACTION, action_value);
Packit ae235b
  g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_TARGET, target_value);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_action_and_target:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @action: (nullable): the name of the action for this item
Packit ae235b
 * @format_string: (nullable): a GVariant format string
Packit ae235b
 * @...: positional parameters, as per @format_string
Packit ae235b
 *
Packit ae235b
 * Sets or unsets the "action" and "target" attributes of @menu_item.
Packit ae235b
 *
Packit ae235b
 * If @action is %NULL then both the "action" and "target" attributes
Packit ae235b
 * are unset (and @format_string is ignored along with the positional
Packit ae235b
 * parameters).
Packit ae235b
 *
Packit ae235b
 * If @action is non-%NULL then the "action" attribute is set.
Packit ae235b
 * @format_string is then inspected.  If it is non-%NULL then the proper
Packit ae235b
 * position parameters are collected to create a #GVariant instance to
Packit ae235b
 * use as the target value.  If it is %NULL then the positional
Packit ae235b
 * parameters are ignored and the "target" attribute is unset.
Packit ae235b
 *
Packit ae235b
 * See also g_menu_item_set_action_and_target_value() for an equivalent
Packit ae235b
 * call that directly accepts a #GVariant.  See
Packit ae235b
 * g_menu_item_set_detailed_action() for a more convenient version that
Packit ae235b
 * works with string-typed targets.
Packit ae235b
 *
Packit ae235b
 * See also g_menu_item_set_action_and_target_value() for a
Packit ae235b
 * description of the semantics of the action and target attributes.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_action_and_target (GMenuItem   *menu_item,
Packit ae235b
                                   const gchar *action,
Packit ae235b
                                   const gchar *format_string,
Packit ae235b
                                   ...)
Packit ae235b
{
Packit ae235b
  GVariant *value;
Packit ae235b
Packit ae235b
  if (format_string != NULL)
Packit ae235b
    {
Packit ae235b
      va_list ap;
Packit ae235b
Packit ae235b
      va_start (ap, format_string);
Packit ae235b
      value = g_variant_new_va (format_string, NULL, &ap);
Packit ae235b
      va_end (ap);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    value = NULL;
Packit ae235b
Packit ae235b
  g_menu_item_set_action_and_target_value (menu_item, action, value);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_detailed_action:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @detailed_action: the "detailed" action string
Packit ae235b
 *
Packit ae235b
 * Sets the "action" and possibly the "target" attribute of @menu_item.
Packit ae235b
 *
Packit ae235b
 * The format of @detailed_action is the same format parsed by
Packit ae235b
 * g_action_parse_detailed_name().
Packit ae235b
 *
Packit ae235b
 * See g_menu_item_set_action_and_target() or
Packit ae235b
 * g_menu_item_set_action_and_target_value() for more flexible (but
Packit ae235b
 * slightly less convenient) alternatives.
Packit ae235b
 *
Packit ae235b
 * See also g_menu_item_set_action_and_target_value() for a description of
Packit ae235b
 * the semantics of the action and target attributes.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_menu_item_set_detailed_action (GMenuItem   *menu_item,
Packit ae235b
                                 const gchar *detailed_action)
Packit ae235b
{
Packit ae235b
  GError *error = NULL;
Packit ae235b
  GVariant *target;
Packit ae235b
  gchar *name;
Packit ae235b
Packit ae235b
  if (!g_action_parse_detailed_name (detailed_action, &name, &target, &error))
Packit ae235b
    g_error ("g_menu_item_set_detailed_action: %s", error->message);
Packit ae235b
Packit ae235b
  g_menu_item_set_action_and_target_value (menu_item, name, target);
Packit ae235b
  if (target)
Packit ae235b
    g_variant_unref (target);
Packit ae235b
  g_free (name);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_new:
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @detailed_action: (nullable): the detailed action string, or %NULL
Packit ae235b
 *
Packit ae235b
 * Creates a new #GMenuItem.
Packit ae235b
 *
Packit ae235b
 * If @label is non-%NULL it is used to set the "label" attribute of the
Packit ae235b
 * new item.
Packit ae235b
 *
Packit ae235b
 * If @detailed_action is non-%NULL it is used to set the "action" and
Packit ae235b
 * possibly the "target" attribute of the new item.  See
Packit ae235b
 * g_menu_item_set_detailed_action() for more information.
Packit ae235b
 *
Packit ae235b
 * Returns: a new #GMenuItem
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
GMenuItem *
Packit ae235b
g_menu_item_new (const gchar *label,
Packit ae235b
                 const gchar *detailed_action)
Packit ae235b
{
Packit ae235b
  GMenuItem *menu_item;
Packit ae235b
Packit ae235b
  menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
Packit ae235b
Packit ae235b
  if (label != NULL)
Packit ae235b
    g_menu_item_set_label (menu_item, label);
Packit ae235b
Packit ae235b
  if (detailed_action != NULL)
Packit ae235b
    g_menu_item_set_detailed_action (menu_item, detailed_action);
Packit ae235b
Packit ae235b
  return menu_item;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_new_submenu:
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @submenu: a #GMenuModel with the items of the submenu
Packit ae235b
 *
Packit ae235b
 * Creates a new #GMenuItem representing a submenu.
Packit ae235b
 *
Packit ae235b
 * This is a convenience API around g_menu_item_new() and
Packit ae235b
 * g_menu_item_set_submenu().
Packit ae235b
 *
Packit ae235b
 * Returns: a new #GMenuItem
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
GMenuItem *
Packit ae235b
g_menu_item_new_submenu (const gchar *label,
Packit ae235b
                         GMenuModel  *submenu)
Packit ae235b
{
Packit ae235b
  GMenuItem *menu_item;
Packit ae235b
Packit ae235b
  menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
Packit ae235b
Packit ae235b
  if (label != NULL)
Packit ae235b
    g_menu_item_set_label (menu_item, label);
Packit ae235b
Packit ae235b
  g_menu_item_set_submenu (menu_item, submenu);
Packit ae235b
Packit ae235b
  return menu_item;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_new_section:
Packit ae235b
 * @label: (nullable): the section label, or %NULL
Packit ae235b
 * @section: a #GMenuModel with the items of the section
Packit ae235b
 *
Packit ae235b
 * Creates a new #GMenuItem representing a section.
Packit ae235b
 *
Packit ae235b
 * This is a convenience API around g_menu_item_new() and
Packit ae235b
 * g_menu_item_set_section().
Packit ae235b
 *
Packit ae235b
 * The effect of having one menu appear as a section of another is
Packit ae235b
 * exactly as it sounds: the items from @section become a direct part of
Packit ae235b
 * the menu that @menu_item is added to.
Packit ae235b
 *
Packit ae235b
 * Visual separation is typically displayed between two non-empty
Packit ae235b
 * sections.  If @label is non-%NULL then it will be encorporated into
Packit ae235b
 * this visual indication.  This allows for labeled subsections of a
Packit ae235b
 * menu.
Packit ae235b
 *
Packit ae235b
 * As a simple example, consider a typical "Edit" menu from a simple
Packit ae235b
 * program.  It probably contains an "Undo" and "Redo" item, followed by
Packit ae235b
 * a separator, followed by "Cut", "Copy" and "Paste".
Packit ae235b
 *
Packit ae235b
 * This would be accomplished by creating three #GMenu instances.  The
Packit ae235b
 * first would be populated with the "Undo" and "Redo" items, and the
Packit ae235b
 * second with the "Cut", "Copy" and "Paste" items.  The first and
Packit ae235b
 * second menus would then be added as submenus of the third.  In XML
Packit ae235b
 * format, this would look something like the following:
Packit ae235b
 * |[
Packit ae235b
 * <menu id='edit-menu'>
Packit ae235b
 *   <section>
Packit ae235b
 *     <item label='Undo'/>
Packit ae235b
 *     <item label='Redo'/>
Packit ae235b
 *   </section>
Packit ae235b
 *   <section>
Packit ae235b
 *     <item label='Cut'/>
Packit ae235b
 *     <item label='Copy'/>
Packit ae235b
 *     <item label='Paste'/>
Packit ae235b
 *   </section>
Packit ae235b
 * </menu>
Packit ae235b
 * ]|
Packit ae235b
 *
Packit ae235b
 * The following example is exactly equivalent.  It is more illustrative
Packit ae235b
 * of the exact relationship between the menus and items (keeping in
Packit ae235b
 * mind that the 'link' element defines a new menu that is linked to the
Packit ae235b
 * containing one).  The style of the second example is more verbose and
Packit ae235b
 * difficult to read (and therefore not recommended except for the
Packit ae235b
 * purpose of understanding what is really going on).
Packit ae235b
 * |[
Packit ae235b
 * <menu id='edit-menu'>
Packit ae235b
 *   <item>
Packit ae235b
 *     <link name='section'>
Packit ae235b
 *       <item label='Undo'/>
Packit ae235b
 *       <item label='Redo'/>
Packit ae235b
 *     </link>
Packit ae235b
 *   </item>
Packit ae235b
 *   <item>
Packit ae235b
 *     <link name='section'>
Packit ae235b
 *       <item label='Cut'/>
Packit ae235b
 *       <item label='Copy'/>
Packit ae235b
 *       <item label='Paste'/>
Packit ae235b
 *     </link>
Packit ae235b
 *   </item>
Packit ae235b
 * </menu>
Packit ae235b
 * ]|
Packit ae235b
 *
Packit ae235b
 * Returns: a new #GMenuItem
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
GMenuItem *
Packit ae235b
g_menu_item_new_section (const gchar *label,
Packit ae235b
                         GMenuModel  *section)
Packit ae235b
{
Packit ae235b
  GMenuItem *menu_item;
Packit ae235b
Packit ae235b
  menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
Packit ae235b
Packit ae235b
  if (label != NULL)
Packit ae235b
    g_menu_item_set_label (menu_item, label);
Packit ae235b
Packit ae235b
  g_menu_item_set_section (menu_item, section);
Packit ae235b
Packit ae235b
  return menu_item;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_new_from_model:
Packit ae235b
 * @model: a #GMenuModel
Packit ae235b
 * @item_index: the index of an item in @model
Packit ae235b
 *
Packit ae235b
 * Creates a #GMenuItem as an exact copy of an existing menu item in a
Packit ae235b
 * #GMenuModel.
Packit ae235b
 *
Packit ae235b
 * @item_index must be valid (ie: be sure to call
Packit ae235b
 * g_menu_model_get_n_items() first).
Packit ae235b
 *
Packit ae235b
 * Returns: a new #GMenuItem.
Packit ae235b
 *
Packit ae235b
 * Since: 2.34
Packit ae235b
 */
Packit ae235b
GMenuItem *
Packit ae235b
g_menu_item_new_from_model (GMenuModel *model,
Packit ae235b
                            gint        item_index)
Packit ae235b
{
Packit ae235b
  GMenuModelClass *class = G_MENU_MODEL_GET_CLASS (model);
Packit ae235b
  GMenuItem *menu_item;
Packit ae235b
Packit ae235b
  menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
Packit ae235b
Packit ae235b
  /* With some trickery we can be pretty efficient.
Packit ae235b
   *
Packit ae235b
   * A GMenuModel must either implement iterate_item_attributes() or
Packit ae235b
   * get_item_attributes().  If it implements get_item_attributes() then
Packit ae235b
   * we are in luck -- we can just take a reference on the returned
Packit ae235b
   * hashtable and mark ourselves as copy-on-write.
Packit ae235b
   *
Packit ae235b
   * In the case that the model is based on get_item_attributes (which
Packit ae235b
   * is the case for both GMenu and GDBusMenuModel) then this is
Packit ae235b
   * basically just g_hash_table_ref().
Packit ae235b
   */
Packit ae235b
  if (class->get_item_attributes)
Packit ae235b
    {
Packit ae235b
      GHashTable *attributes = NULL;
Packit ae235b
Packit ae235b
      class->get_item_attributes (model, item_index, &attributes);
Packit ae235b
      if (attributes)
Packit ae235b
        {
Packit ae235b
          g_hash_table_unref (menu_item->attributes);
Packit ae235b
          menu_item->attributes = attributes;
Packit ae235b
          menu_item->cow = TRUE;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      GMenuAttributeIter *iter;
Packit ae235b
      const gchar *attribute;
Packit ae235b
      GVariant *value;
Packit ae235b
Packit ae235b
      iter = g_menu_model_iterate_item_attributes (model, item_index);
Packit ae235b
      while (g_menu_attribute_iter_get_next (iter, &attribute, &value))
Packit ae235b
        g_hash_table_insert (menu_item->attributes, g_strdup (attribute), value);
Packit ae235b
      g_object_unref (iter);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* Same story for the links... */
Packit ae235b
  if (class->get_item_links)
Packit ae235b
    {
Packit ae235b
      GHashTable *links = NULL;
Packit ae235b
Packit ae235b
      class->get_item_links (model, item_index, &links);
Packit ae235b
      if (links)
Packit ae235b
        {
Packit ae235b
          g_hash_table_unref (menu_item->links);
Packit ae235b
          menu_item->links = links;
Packit ae235b
          menu_item->cow = TRUE;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      GMenuLinkIter *iter;
Packit ae235b
      const gchar *link;
Packit ae235b
      GMenuModel *value;
Packit ae235b
Packit ae235b
      iter = g_menu_model_iterate_item_links (model, item_index);
Packit ae235b
      while (g_menu_link_iter_get_next (iter, &link, &value))
Packit ae235b
        g_hash_table_insert (menu_item->links, g_strdup (link), value);
Packit ae235b
      g_object_unref (iter);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return menu_item;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_menu_item_set_icon:
Packit ae235b
 * @menu_item: a #GMenuItem
Packit ae235b
 * @icon: a #GIcon, or %NULL
Packit ae235b
 *
Packit ae235b
 * Sets (or unsets) the icon on @menu_item.
Packit ae235b
 *
Packit ae235b
 * This call is the same as calling g_icon_serialize() and using the
Packit ae235b
 * result as the value to g_menu_item_set_attribute_value() for
Packit ae235b
 * %G_MENU_ATTRIBUTE_ICON.
Packit ae235b
 *
Packit ae235b
 * This API is only intended for use with "noun" menu items; things like
Packit ae235b
 * bookmarks or applications in an "Open With" menu.  Don't use it on
Packit ae235b
 * menu items corresponding to verbs (eg: stock icons for 'Save' or
Packit ae235b
 * 'Quit').
Packit ae235b
 *
Packit ae235b
 * If @icon is %NULL then the icon is unset.
Packit ae235b
 *
Packit ae235b
 * Since: 2.38
Packit ae235b
 **/
Packit ae235b
void
Packit ae235b
g_menu_item_set_icon (GMenuItem *menu_item,
Packit ae235b
                      GIcon     *icon)
Packit ae235b
{
Packit ae235b
  GVariant *value;
Packit ae235b
Packit ae235b
  g_return_if_fail (G_IS_MENU_ITEM (menu_item));
Packit ae235b
  g_return_if_fail (icon == NULL || G_IS_ICON (icon));
Packit ae235b
Packit ae235b
  if (icon != NULL)
Packit ae235b
    value = g_icon_serialize (icon);
Packit ae235b
  else
Packit ae235b
    value = NULL;
Packit ae235b
Packit ae235b
  g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ICON, value);
Packit ae235b
  if (value)
Packit ae235b
    g_variant_unref (value);
Packit ae235b
}