X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgmenu.c;h=fe82ba7a04dbc84011420614a8d296e8baa1f2a6;hb=a3d86afa81ff34ce797a3928fd619ead219a37af;hp=40485f523e560807bf59d86261229791e6d8c86c;hpb=58a8c02dfb2b003d4bb104dbe622b31c816107bc;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gmenu.c b/gio/gmenu.c index 40485f5..fe82ba7 100644 --- a/gio/gmenu.c +++ b/gio/gmenu.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. + * License along with this library; if not, see . * * Author: Ryan Lortie */ @@ -23,12 +21,16 @@ #include "gmenu.h" +#include "gaction.h" #include +#include "gicon.h" + /** * SECTION:gmenu * @title: GMenu * @short_description: A simple implementation of GMenuModel + * @include: gio/gio.h * * #GMenu is a simple implementation of #GMenuModel. * You populate a #GMenu by adding #GMenuItem instances to it. @@ -38,9 +40,6 @@ * a regular item, use g_menu_insert(). To add a section, use * g_menu_insert_section(). To add a submenu, use * g_menu_insert_submenu(). - * - * Often it is more convenient to create a #GMenu from an XML - * fragment, using GMenu Markup. */ /** @@ -48,14 +47,18 @@ * * #GMenu is an opaque structure type. You must access it using the * functions below. - **/ + * + * Since: 2.32 + */ /** * GMenuItem: * * #GMenuItem is an opaque structure type. You must access it using the * functions below. - **/ + * + * Since: 2.32 + */ struct _GMenuItem { @@ -146,7 +149,9 @@ g_menu_get_item_links (GMenuModel *model, * See g_menu_insert(), g_menu_insert_section() and * g_menu_insert_submenu() as well as "prepend" and "append" variants of * each of these functions. - **/ + * + * Since: 2.32 + */ void g_menu_insert_item (GMenu *menu, gint position, @@ -176,7 +181,9 @@ g_menu_insert_item (GMenu *menu, * Prepends @item to the start of @menu. * * See g_menu_insert_item() for more information. - **/ + * + * Since: 2.32 + */ void g_menu_prepend_item (GMenu *menu, GMenuItem *item) @@ -192,7 +199,9 @@ g_menu_prepend_item (GMenu *menu, * Appends @item to the end of @menu. * * See g_menu_insert_item() for more information. - **/ + * + * Since: 2.32 + */ void g_menu_append_item (GMenu *menu, GMenuItem *item) @@ -212,7 +221,9 @@ g_menu_append_item (GMenu *menu, * * This function causes g_menu_model_is_mutable() to begin returning * %FALSE, which has some positive performance implications. - **/ + * + * Since: 2.32 + */ void g_menu_freeze (GMenu *menu) { @@ -229,7 +240,9 @@ g_menu_freeze (GMenu *menu) * The new menu has no items. * * Returns: a new #GMenu - **/ + * + * Since: 2.32 + */ GMenu * g_menu_new (void) { @@ -244,9 +257,11 @@ g_menu_new (void) * @detailed_action: (allow-none): the detailed action string, or %NULL * * Convenience function for inserting a normal menu item into @menu. - * Combine g_menu_new() and g_menu_insert_item() for a more flexible + * Combine g_menu_item_new() and g_menu_insert_item() for a more flexible * alternative. - **/ + * + * Since: 2.32 + */ void g_menu_insert (GMenu *menu, gint position, @@ -267,9 +282,11 @@ g_menu_insert (GMenu *menu, * @detailed_action: (allow-none): the detailed action string, or %NULL * * Convenience function for prepending a normal menu item to the start - * of @menu. Combine g_menu_new() and g_menu_insert_item() for a more + * of @menu. Combine g_menu_item_new() and g_menu_insert_item() for a more * flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_prepend (GMenu *menu, const gchar *label, @@ -285,9 +302,11 @@ g_menu_prepend (GMenu *menu, * @detailed_action: (allow-none): the detailed action string, or %NULL * * Convenience function for appending a normal menu item to the end of - * @menu. Combine g_menu_new() and g_menu_insert_item() for a more + * @menu. Combine g_menu_item_new() and g_menu_insert_item() for a more * flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_append (GMenu *menu, const gchar *label, @@ -304,9 +323,11 @@ g_menu_append (GMenu *menu, * @section: a #GMenuModel with the items of the section * * Convenience function for inserting a section menu item into @menu. - * Combine g_menu_new_section() and g_menu_insert_item() for a more + * Combine g_menu_item_new_section() and g_menu_insert_item() for a more * flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_insert_section (GMenu *menu, gint position, @@ -328,9 +349,11 @@ g_menu_insert_section (GMenu *menu, * @section: a #GMenuModel with the items of the section * * Convenience function for prepending a section menu item to the start - * of @menu. Combine g_menu_new_section() and g_menu_insert_item() for + * of @menu. Combine g_menu_item_new_section() and g_menu_insert_item() for * a more flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_prepend_section (GMenu *menu, const gchar *label, @@ -346,9 +369,11 @@ g_menu_prepend_section (GMenu *menu, * @section: a #GMenuModel with the items of the section * * Convenience function for appending a section menu item to the end of - * @menu. Combine g_menu_new_section() and g_menu_insert_item() for a + * @menu. Combine g_menu_item_new_section() and g_menu_insert_item() for a * more flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_append_section (GMenu *menu, const gchar *label, @@ -365,9 +390,11 @@ g_menu_append_section (GMenu *menu, * @submenu: a #GMenuModel with the items of the submenu * * Convenience function for inserting a submenu menu item into @menu. - * Combine g_menu_new_submenu() and g_menu_insert_item() for a more + * Combine g_menu_item_new_submenu() and g_menu_insert_item() for a more * flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_insert_submenu (GMenu *menu, gint position, @@ -388,9 +415,11 @@ g_menu_insert_submenu (GMenu *menu, * @submenu: a #GMenuModel with the items of the submenu * * Convenience function for prepending a submenu menu item to the start - * of @menu. Combine g_menu_new_submenu() and g_menu_insert_item() for + * of @menu. Combine g_menu_item_new_submenu() and g_menu_insert_item() for * a more flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_prepend_submenu (GMenu *menu, const gchar *label, @@ -406,9 +435,11 @@ g_menu_prepend_submenu (GMenu *menu, * @submenu: a #GMenuModel with the items of the submenu * * Convenience function for appending a submenu menu item to the end of - * @menu. Combine g_menu_new_submenu() and g_menu_insert_item() for a + * @menu. Combine g_menu_item_new_submenu() and g_menu_insert_item() for a * more flexible alternative. - **/ + * + * Since: 2.32 + */ void g_menu_append_submenu (GMenu *menu, const gchar *label, @@ -422,7 +453,7 @@ g_menu_clear_item (struct item *item) { if (item->attributes != NULL) g_hash_table_unref (item->attributes); - if (item->links != NULL); + if (item->links != NULL) g_hash_table_unref (item->links); } @@ -441,7 +472,9 @@ g_menu_clear_item (struct item *item) * It is not possible to remove items by identity since items are added * to the menu simply by copying their links and attributes (ie: * identity of the item itself is not preserved). - **/ + * + * Since: 2.32 + */ void g_menu_remove (GMenu *menu, gint position) @@ -454,6 +487,29 @@ g_menu_remove (GMenu *menu, g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0); } +/** + * g_menu_remove_all: + * @menu: a #GMenu + * + * Removes all items in the menu. + * + * Since: 2.38 + **/ +void +g_menu_remove_all (GMenu *menu) +{ + gint i, n; + + g_return_if_fail (G_IS_MENU (menu)); + n = menu->items->len; + + for (i = 0; i < n; i++) + g_menu_clear_item (&g_array_index (menu->items, struct item, i)); + g_array_set_size (menu->items, 0); + + g_menu_model_items_changed (G_MENU_MODEL (menu), 0, n, 0); +} + static void g_menu_finalize (GObject *object) { @@ -548,6 +604,41 @@ g_menu_item_class_init (GMenuItemClass *class) class->finalize = g_menu_item_finalize; } +/* We treat attribute names the same as GSettings keys: + * - only lowercase ascii, digits and '-' + * - must start with lowercase + * - must not end with '-' + * - no consecutive '-' + * - not longer than 1024 chars + */ +static gboolean +valid_attribute_name (const gchar *name) +{ + gint i; + + if (!g_ascii_islower (name[0])) + return FALSE; + + for (i = 1; name[i]; i++) + { + if (name[i] != '-' && + !g_ascii_islower (name[i]) && + !g_ascii_isdigit (name[i])) + return FALSE; + + if (name[i] == '-' && name[i + 1] == '-') + return FALSE; + } + + if (name[i - 1] == '-') + return FALSE; + + if (i > 1024) + return FALSE; + + return TRUE; +} + /** * g_menu_item_set_attribute_value: * @menu_item: a #GMenuItem @@ -556,14 +647,26 @@ g_menu_item_class_init (GMenuItemClass *class) * * Sets or unsets an attribute on @menu_item. * - * The attribute to set or unset is specified by @attribute. + * The attribute to set or unset is specified by @attribute. This + * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL, + * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom + * attribute name. + * Attribute names are restricted to lowercase characters, numbers + * and '-'. Furthermore, the names must begin with a lowercase character, + * must not end with a '-', and must not contain consecutive dashes. + * + * must consist only of lowercase + * ASCII characters, digits and '-'. * * If @value is non-%NULL then it is used as the new value for the - * attribute. If @value is %NULL then the attribute is unset. + * attribute. If @value is %NULL then the attribute is unset. If + * the @value #GVariant is floating, it is consumed. * * See also g_menu_item_set_attribute() for a more convenient way to do * the same. - **/ + * + * Since: 2.32 + */ void g_menu_item_set_attribute_value (GMenuItem *menu_item, const gchar *attribute, @@ -571,6 +674,7 @@ g_menu_item_set_attribute_value (GMenuItem *menu_item, { g_return_if_fail (G_IS_MENU_ITEM (menu_item)); g_return_if_fail (attribute != NULL); + g_return_if_fail (valid_attribute_name (attribute)); g_menu_item_clear_cow (menu_item); @@ -589,7 +693,13 @@ g_menu_item_set_attribute_value (GMenuItem *menu_item, * * Sets or unsets an attribute on @menu_item. * - * The attribute to set or unset is specified by @attribute. + * The attribute to set or unset is specified by @attribute. This + * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL, + * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom + * attribute name. + * Attribute names are restricted to lowercase characters, numbers + * and '-'. Furthermore, the names must begin with a lowercase character, + * must not end with a '-', and must not contain consecutive dashes. * * If @format_string is non-%NULL then the proper position parameters * are collected to create a #GVariant instance to use as the attribute @@ -598,7 +708,9 @@ g_menu_item_set_attribute_value (GMenuItem *menu_item, * * See also g_menu_item_set_attribute_value() for an equivalent call * that directly accepts a #GVariant. - **/ + * + * Since: 2.32 + */ void g_menu_item_set_attribute (GMenuItem *menu_item, const gchar *attribute, @@ -627,11 +739,18 @@ g_menu_item_set_attribute (GMenuItem *menu_item, * @link: type of link to establish or unset * @model: (allow-none): the #GMenuModel to link to (or %NULL to unset) * - * Creates a link from @menu_item to @link if non-%NULL, or unsets it. + * Creates a link from @menu_item to @model if non-%NULL, or unsets it. * * Links are used to establish a relationship between a particular menu * item and another menu. For example, %G_MENU_LINK_SUBMENU is used to - * associate a submenu with a particular menu item. + * associate a submenu with a particular menu item, and %G_MENU_LINK_SECTION + * is used to create a section. Other types of link can be used, but there + * is no guarantee that clients will be able to make sense of them. + * Link types are restricted to lowercase characters, numbers + * and '-'. Furthermore, the names must begin with a lowercase character, + * must not end with a '-', and must not contain consecutive dashes. + * + * Since: 2.32 */ void g_menu_item_set_link (GMenuItem *menu_item, @@ -640,6 +759,7 @@ g_menu_item_set_link (GMenuItem *menu_item, { g_return_if_fail (G_IS_MENU_ITEM (menu_item)); g_return_if_fail (link != NULL); + g_return_if_fail (valid_attribute_name (link)); g_menu_item_clear_cow (menu_item); @@ -650,6 +770,124 @@ g_menu_item_set_link (GMenuItem *menu_item, } /** + * g_menu_item_get_attribute_value: + * @menu_item: a #GMenuItem + * @attribute: the attribute name to query + * @expected_type: (allow-none): the expected type of the attribute + * + * Queries the named @attribute on @menu_item. + * + * If @expected_type is specified and the attribute does not have this + * type, %NULL is returned. %NULL is also returned if the attribute + * simply does not exist. + * + * Returns: (transfer full): the attribute value, or %NULL + * + * Since: 2.34 + */ +GVariant * +g_menu_item_get_attribute_value (GMenuItem *menu_item, + const gchar *attribute, + const GVariantType *expected_type) +{ + GVariant *value; + + g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL); + g_return_val_if_fail (attribute != NULL, NULL); + + value = g_hash_table_lookup (menu_item->attributes, attribute); + + if (value != NULL) + { + if (expected_type == NULL || g_variant_is_of_type (value, expected_type)) + g_variant_ref (value); + else + value = NULL; + } + + return value; +} + +/** + * g_menu_item_get_attribute: + * @menu_item: a #GMenuItem + * @attribute: the attribute name to query + * @format_string: a #GVariant format string + * @...: positional parameters, as per @format_string + * + * Queries the named @attribute on @menu_item. + * + * If the attribute exists and matches the #GVariantType corresponding + * to @format_string then @format_string is used to deconstruct the + * value into the positional parameters and %TRUE is returned. + * + * If the attribute does not exist, or it does exist but has the wrong + * type, then the positional parameters are ignored and %FALSE is + * returned. + * + * Returns: %TRUE if the named attribute was found with the expected + * type + * + * Since: 2.34 + */ +gboolean +g_menu_item_get_attribute (GMenuItem *menu_item, + const gchar *attribute, + const gchar *format_string, + ...) +{ + GVariant *value; + va_list ap; + + g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), FALSE); + g_return_val_if_fail (attribute != NULL, FALSE); + g_return_val_if_fail (format_string != NULL, FALSE); + + value = g_hash_table_lookup (menu_item->attributes, attribute); + + if (value == NULL) + return FALSE; + + if (!g_variant_check_format_string (value, format_string, FALSE)) + return FALSE; + + va_start (ap, format_string); + g_variant_get_va (value, format_string, NULL, &ap); + va_end (ap); + + return TRUE; +} + +/** + * g_menu_item_get_link: + * @menu_item: a #GMenuItem + * @link: the link name to query + * + * Queries the named @link on @menu_item. + * + * Returns: (transfer full): the link, or %NULL + * + * Since: 2.34 + */ +GMenuModel * +g_menu_item_get_link (GMenuItem *menu_item, + const gchar *link) +{ + GMenuModel *model; + + g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL); + g_return_val_if_fail (link != NULL, NULL); + g_return_val_if_fail (valid_attribute_name (link), NULL); + + model = g_hash_table_lookup (menu_item->links, link); + + if (model) + g_object_ref (model); + + return model; +} + +/** * g_menu_item_set_label: * @menu_item: a #GMenuItem * @label: (allow-none): the label to set, or %NULL to unset @@ -658,7 +896,9 @@ g_menu_item_set_link (GMenuItem *menu_item, * * If @label is non-%NULL it is used as the label for the menu item. If * it is %NULL then the label attribute is unset. - **/ + * + * Since: 2.32 + */ void g_menu_item_set_label (GMenuItem *menu_item, const gchar *label) @@ -685,7 +925,9 @@ g_menu_item_set_label (GMenuItem *menu_item, * * The effect of having one menu appear as a submenu of another is * exactly as it sounds. - **/ + * + * Since: 2.32 + */ void g_menu_item_set_submenu (GMenuItem *menu_item, GMenuModel *submenu) @@ -705,7 +947,9 @@ g_menu_item_set_submenu (GMenuItem *menu_item, * the menu that @menu_item is added to. See g_menu_item_new_section() * for more information about what it means for a menu item to be a * section. - **/ + * + * Since: 2.32 + */ void g_menu_item_set_section (GMenuItem *menu_item, GMenuModel *section) @@ -755,6 +999,8 @@ g_menu_item_set_section (GMenuItem *menu_item, * See g_menu_item_set_action_and_target() or * g_menu_item_set_detailed_action() for two equivalent calls that are * probably more convenient for most uses. + * + * Since: 2.32 */ void g_menu_item_set_action_and_target_value (GMenuItem *menu_item, @@ -803,6 +1049,8 @@ g_menu_item_set_action_and_target_value (GMenuItem *menu_item, * * See also g_menu_item_set_action_and_target_value() for a * description of the semantics of the action and target attributes. + * + * Since: 2.32 */ void g_menu_item_set_action_and_target (GMenuItem *menu_item, @@ -833,42 +1081,33 @@ g_menu_item_set_action_and_target (GMenuItem *menu_item, * * Sets the "action" and possibly the "target" attribute of @menu_item. * - * If @detailed_action contains a double colon ("::") then it is used as - * a separator between an action name and a target string. In this - * case, this call is equivalent to calling - * g_menu_item_set_action_and_target() with the part before the "::" and - * g_menu_item_set_target_value() with a string-type #GVariant - * containing the part following the "::". - * - * If @detailed_action doesn't contain "::" then the action is set to - * the given string (verbatim) and the target value is unset. + * The format of @detailed_action is the same format parsed by + * g_action_parse_detailed_name(). * * See g_menu_item_set_action_and_target() or * g_menu_item_set_action_and_target_value() for more flexible (but * slightly less convenient) alternatives. * - * See also g_menu_set_action_and_target_value() for a description of + * See also g_menu_item_set_action_and_target_value() for a description of * the semantics of the action and target attributes. - **/ + * + * Since: 2.32 + */ void g_menu_item_set_detailed_action (GMenuItem *menu_item, const gchar *detailed_action) { - const gchar *sep; - - sep = strstr (detailed_action, "::"); + GError *error = NULL; + GVariant *target; + gchar *name; - if (sep != NULL) - { - gchar *action; + if (!g_action_parse_detailed_name (detailed_action, &name, &target, &error)) + g_error ("g_menu_item_set_detailed_action: %s", error->message); - action = g_strndup (detailed_action, sep - detailed_action); - g_menu_item_set_action_and_target (menu_item, action, "s", sep + 2); - g_free (action); - } - - else - g_menu_item_set_action_and_target_value (menu_item, detailed_action, NULL); + g_menu_item_set_action_and_target_value (menu_item, name, target); + if (target) + g_variant_unref (target); + g_free (name); } /** @@ -886,7 +1125,9 @@ g_menu_item_set_detailed_action (GMenuItem *menu_item, * g_menu_item_set_detailed_action() for more information. * * Returns: a new #GMenuItem - **/ + * + * Since: 2.32 + */ GMenuItem * g_menu_item_new (const gchar *label, const gchar *detailed_action) @@ -915,7 +1156,9 @@ g_menu_item_new (const gchar *label, * g_menu_item_set_submenu(). * * Returns: a new #GMenuItem - **/ + * + * Since: 2.32 + */ GMenuItem * g_menu_item_new_submenu (const gchar *label, GMenuModel *submenu) @@ -960,8 +1203,7 @@ g_menu_item_new_submenu (const gchar *label, * second with the "Cut", "Copy" and "Paste" items. The first and * second menus would then be added as submenus of the third. In XML * format, this would look something like the following: - * - * *
* @@ -973,7 +1215,7 @@ g_menu_item_new_submenu (const gchar *label, * *
* - * ]]>
+ * ]| * * The following example is exactly equivalent. It is more illustrative * of the exact relationship between the menus and items (keeping in @@ -981,8 +1223,7 @@ g_menu_item_new_submenu (const gchar *label, * containing one). The style of the second example is more verbose and * difficult to read (and therefore not recommended except for the * purpose of understanding what is really going on). - * - * * * @@ -998,10 +1239,12 @@ g_menu_item_new_submenu (const gchar *label, * * * - * ]]> + * ]| * * Returns: a new #GMenuItem - **/ + * + * Since: 2.32 + */ GMenuItem * g_menu_item_new_section (const gchar *label, GMenuModel *section) @@ -1017,3 +1260,129 @@ g_menu_item_new_section (const gchar *label, return menu_item; } + +/** + * g_menu_item_new_from_model: + * @model: a #GMenuModel + * @item_index: the index of an item in @model + * + * Creates a #GMenuItem as an exact copy of an existing menu item in a + * #GMenuModel. + * + * @item_index must be valid (ie: be sure to call + * g_menu_model_get_n_items() first). + * + * Returns: a new #GMenuItem. + * + * Since: 2.34 + */ +GMenuItem * +g_menu_item_new_from_model (GMenuModel *model, + gint item_index) +{ + GMenuModelClass *class = G_MENU_MODEL_GET_CLASS (model); + GMenuItem *menu_item; + + menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL); + + /* With some trickery we can be pretty efficient. + * + * A GMenuModel must either implement iterate_item_attributes() or + * get_item_attributes(). If it implements get_item_attributes() then + * we are in luck -- we can just take a reference on the returned + * hashtable and mark ourselves as copy-on-write. + * + * In the case that the model is based on get_item_attributes (which + * is the case for both GMenu and GDBusMenuModel) then this is + * basically just g_hash_table_ref(). + */ + if (class->get_item_attributes) + { + GHashTable *attributes = NULL; + + class->get_item_attributes (model, item_index, &attributes); + if (attributes) + { + g_hash_table_unref (menu_item->attributes); + menu_item->attributes = attributes; + menu_item->cow = TRUE; + } + } + else + { + GMenuAttributeIter *iter; + const gchar *attribute; + GVariant *value; + + iter = g_menu_model_iterate_item_attributes (model, item_index); + while (g_menu_attribute_iter_get_next (iter, &attribute, &value)) + g_hash_table_insert (menu_item->attributes, g_strdup (attribute), value); + g_object_unref (iter); + } + + /* Same story for the links... */ + if (class->get_item_links) + { + GHashTable *links = NULL; + + class->get_item_links (model, item_index, &links); + if (links) + { + g_hash_table_unref (menu_item->links); + menu_item->links = links; + menu_item->cow = TRUE; + } + } + else + { + GMenuLinkIter *iter; + const gchar *link; + GMenuModel *value; + + iter = g_menu_model_iterate_item_links (model, item_index); + while (g_menu_link_iter_get_next (iter, &link, &value)) + g_hash_table_insert (menu_item->links, g_strdup (link), value); + g_object_unref (iter); + } + + return menu_item; +} + +/** + * g_menu_item_set_icon: + * @menu_item: a #GMenuItem + * @icon: a #GIcon, or %NULL + * + * Sets (or unsets) the icon on @menu_item. + * + * This call is the same as calling g_icon_serialize() and using the + * result as the value to g_menu_item_set_attribute_value() for + * %G_MENU_ATTRIBUTE_ICON. + * + * This API is only intended for use with "noun" menu items; things like + * bookmarks or applications in an "Open With" menu. Don't use it on + * menu items corresponding to verbs (eg: stock icons for 'Save' or + * 'Quit'). + * + * If @icon is %NULL then the icon is unset. + * + * Since: 2.38 + **/ +void +g_menu_item_set_icon (GMenuItem *menu_item, + GIcon *icon) +{ + GVariant *value; + + g_return_if_fail (G_IS_MENU_ITEM (menu_item)); + g_return_if_fail (G_IS_ICON (icon)); + + if (icon != NULL) + value = g_icon_serialize (icon); + else + value = NULL; + + g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ICON, value); + if (value) + g_variant_unref (value); +}