GSettings: properly support 'extends'
[glib.git] / gio / gmenu.c
blob39c267a9784ca4ef5121f69cd1f5ad0c33bc5bf6
1 /*
2 * Copyright © 2011 Canonical Ltd.
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
19 * Author: Ryan Lortie <desrt@desrt.ca>
22 #include "config.h"
24 #include "gmenu.h"
26 #include "gaction.h"
27 #include <string.h>
29 #include "gicon.h"
31 /**
32 * SECTION:gmenu
33 * @title: GMenu
34 * @short_description: A simple implementation of GMenuModel
36 * #GMenu is a simple implementation of #GMenuModel.
37 * You populate a #GMenu by adding #GMenuItem instances to it.
39 * There are some convenience functions to allow you to directly
40 * add items (avoiding #GMenuItem) for the common cases. To add
41 * a regular item, use g_menu_insert(). To add a section, use
42 * g_menu_insert_section(). To add a submenu, use
43 * g_menu_insert_submenu().
46 /**
47 * GMenu:
49 * #GMenu is an opaque structure type. You must access it using the
50 * functions below.
52 * Since: 2.32
55 /**
56 * GMenuItem:
58 * #GMenuItem is an opaque structure type. You must access it using the
59 * functions below.
61 * Since: 2.32
64 struct _GMenuItem
66 GObject parent_instance;
68 GHashTable *attributes;
69 GHashTable *links;
70 gboolean cow;
73 typedef GObjectClass GMenuItemClass;
75 struct _GMenu
77 GMenuModel parent_instance;
79 GArray *items;
80 gboolean mutable;
83 typedef GMenuModelClass GMenuClass;
85 G_DEFINE_TYPE (GMenu, g_menu, G_TYPE_MENU_MODEL)
86 G_DEFINE_TYPE (GMenuItem, g_menu_item, G_TYPE_OBJECT)
88 struct item
90 GHashTable *attributes;
91 GHashTable *links;
94 static gboolean
95 g_menu_is_mutable (GMenuModel *model)
97 GMenu *menu = G_MENU (model);
99 return menu->mutable;
102 static gint
103 g_menu_get_n_items (GMenuModel *model)
105 GMenu *menu = G_MENU (model);
107 return menu->items->len;
110 static void
111 g_menu_get_item_attributes (GMenuModel *model,
112 gint position,
113 GHashTable **table)
115 GMenu *menu = G_MENU (model);
117 *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).attributes);
120 static void
121 g_menu_get_item_links (GMenuModel *model,
122 gint position,
123 GHashTable **table)
125 GMenu *menu = G_MENU (model);
127 *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).links);
131 * g_menu_insert_item:
132 * @menu: a #GMenu
133 * @position: the position at which to insert the item
134 * @item: the #GMenuItem to insert
136 * Inserts @item into @menu.
138 * The "insertion" is actually done by copying all of the attribute and
139 * link values of @item and using them to form a new item within @menu.
140 * As such, @item itself is not really inserted, but rather, a menu item
141 * that is exactly the same as the one presently described by @item.
143 * This means that @item is essentially useless after the insertion
144 * occurs. Any changes you make to it are ignored unless it is inserted
145 * again (at which point its updated values will be copied).
147 * You should probably just free @item once you're done.
149 * There are many convenience functions to take care of common cases.
150 * See g_menu_insert(), g_menu_insert_section() and
151 * g_menu_insert_submenu() as well as "prepend" and "append" variants of
152 * each of these functions.
154 * Since: 2.32
156 void
157 g_menu_insert_item (GMenu *menu,
158 gint position,
159 GMenuItem *item)
161 struct item new_item;
163 g_return_if_fail (G_IS_MENU (menu));
164 g_return_if_fail (G_IS_MENU_ITEM (item));
166 if (position < 0 || position > menu->items->len)
167 position = menu->items->len;
169 new_item.attributes = g_hash_table_ref (item->attributes);
170 new_item.links = g_hash_table_ref (item->links);
171 item->cow = TRUE;
173 g_array_insert_val (menu->items, position, new_item);
174 g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
178 * g_menu_prepend_item:
179 * @menu: a #GMenu
180 * @item: a #GMenuItem to prepend
182 * Prepends @item to the start of @menu.
184 * See g_menu_insert_item() for more information.
186 * Since: 2.32
188 void
189 g_menu_prepend_item (GMenu *menu,
190 GMenuItem *item)
192 g_menu_insert_item (menu, 0, item);
196 * g_menu_append_item:
197 * @menu: a #GMenu
198 * @item: a #GMenuItem to append
200 * Appends @item to the end of @menu.
202 * See g_menu_insert_item() for more information.
204 * Since: 2.32
206 void
207 g_menu_append_item (GMenu *menu,
208 GMenuItem *item)
210 g_menu_insert_item (menu, -1, item);
214 * g_menu_freeze:
215 * @menu: a #GMenu
217 * Marks @menu as frozen.
219 * After the menu is frozen, it is an error to attempt to make any
220 * changes to it. In effect this means that the #GMenu API must no
221 * longer be used.
223 * This function causes g_menu_model_is_mutable() to begin returning
224 * %FALSE, which has some positive performance implications.
226 * Since: 2.32
228 void
229 g_menu_freeze (GMenu *menu)
231 g_return_if_fail (G_IS_MENU (menu));
233 menu->mutable = FALSE;
237 * g_menu_new:
239 * Creates a new #GMenu.
241 * The new menu has no items.
243 * Returns: a new #GMenu
245 * Since: 2.32
247 GMenu *
248 g_menu_new (void)
250 return g_object_new (G_TYPE_MENU, NULL);
254 * g_menu_insert:
255 * @menu: a #GMenu
256 * @position: the position at which to insert the item
257 * @label: (allow-none): the section label, or %NULL
258 * @detailed_action: (allow-none): the detailed action string, or %NULL
260 * Convenience function for inserting a normal menu item into @menu.
261 * Combine g_menu_item_new() and g_menu_insert_item() for a more flexible
262 * alternative.
264 * Since: 2.32
266 void
267 g_menu_insert (GMenu *menu,
268 gint position,
269 const gchar *label,
270 const gchar *detailed_action)
272 GMenuItem *menu_item;
274 menu_item = g_menu_item_new (label, detailed_action);
275 g_menu_insert_item (menu, position, menu_item);
276 g_object_unref (menu_item);
280 * g_menu_prepend:
281 * @menu: a #GMenu
282 * @label: (allow-none): the section label, or %NULL
283 * @detailed_action: (allow-none): the detailed action string, or %NULL
285 * Convenience function for prepending a normal menu item to the start
286 * of @menu. Combine g_menu_item_new() and g_menu_insert_item() for a more
287 * flexible alternative.
289 * Since: 2.32
291 void
292 g_menu_prepend (GMenu *menu,
293 const gchar *label,
294 const gchar *detailed_action)
296 g_menu_insert (menu, 0, label, detailed_action);
300 * g_menu_append:
301 * @menu: a #GMenu
302 * @label: (allow-none): the section label, or %NULL
303 * @detailed_action: (allow-none): the detailed action string, or %NULL
305 * Convenience function for appending a normal menu item to the end of
306 * @menu. Combine g_menu_item_new() and g_menu_insert_item() for a more
307 * flexible alternative.
309 * Since: 2.32
311 void
312 g_menu_append (GMenu *menu,
313 const gchar *label,
314 const gchar *detailed_action)
316 g_menu_insert (menu, -1, label, detailed_action);
320 * g_menu_insert_section:
321 * @menu: a #GMenu
322 * @position: the position at which to insert the item
323 * @label: (allow-none): the section label, or %NULL
324 * @section: a #GMenuModel with the items of the section
326 * Convenience function for inserting a section menu item into @menu.
327 * Combine g_menu_item_new_section() and g_menu_insert_item() for a more
328 * flexible alternative.
330 * Since: 2.32
332 void
333 g_menu_insert_section (GMenu *menu,
334 gint position,
335 const gchar *label,
336 GMenuModel *section)
338 GMenuItem *menu_item;
340 menu_item = g_menu_item_new_section (label, section);
341 g_menu_insert_item (menu, position, menu_item);
342 g_object_unref (menu_item);
347 * g_menu_prepend_section:
348 * @menu: a #GMenu
349 * @label: (allow-none): the section label, or %NULL
350 * @section: a #GMenuModel with the items of the section
352 * Convenience function for prepending a section menu item to the start
353 * of @menu. Combine g_menu_item_new_section() and g_menu_insert_item() for
354 * a more flexible alternative.
356 * Since: 2.32
358 void
359 g_menu_prepend_section (GMenu *menu,
360 const gchar *label,
361 GMenuModel *section)
363 g_menu_insert_section (menu, 0, label, section);
367 * g_menu_append_section:
368 * @menu: a #GMenu
369 * @label: (allow-none): the section label, or %NULL
370 * @section: a #GMenuModel with the items of the section
372 * Convenience function for appending a section menu item to the end of
373 * @menu. Combine g_menu_item_new_section() and g_menu_insert_item() for a
374 * more flexible alternative.
376 * Since: 2.32
378 void
379 g_menu_append_section (GMenu *menu,
380 const gchar *label,
381 GMenuModel *section)
383 g_menu_insert_section (menu, -1, label, section);
387 * g_menu_insert_submenu:
388 * @menu: a #GMenu
389 * @position: the position at which to insert the item
390 * @label: (allow-none): the section label, or %NULL
391 * @submenu: a #GMenuModel with the items of the submenu
393 * Convenience function for inserting a submenu menu item into @menu.
394 * Combine g_menu_item_new_submenu() and g_menu_insert_item() for a more
395 * flexible alternative.
397 * Since: 2.32
399 void
400 g_menu_insert_submenu (GMenu *menu,
401 gint position,
402 const gchar *label,
403 GMenuModel *submenu)
405 GMenuItem *menu_item;
407 menu_item = g_menu_item_new_submenu (label, submenu);
408 g_menu_insert_item (menu, position, menu_item);
409 g_object_unref (menu_item);
413 * g_menu_prepend_submenu:
414 * @menu: a #GMenu
415 * @label: (allow-none): the section label, or %NULL
416 * @submenu: a #GMenuModel with the items of the submenu
418 * Convenience function for prepending a submenu menu item to the start
419 * of @menu. Combine g_menu_item_new_submenu() and g_menu_insert_item() for
420 * a more flexible alternative.
422 * Since: 2.32
424 void
425 g_menu_prepend_submenu (GMenu *menu,
426 const gchar *label,
427 GMenuModel *submenu)
429 g_menu_insert_submenu (menu, 0, label, submenu);
433 * g_menu_append_submenu:
434 * @menu: a #GMenu
435 * @label: (allow-none): the section label, or %NULL
436 * @submenu: a #GMenuModel with the items of the submenu
438 * Convenience function for appending a submenu menu item to the end of
439 * @menu. Combine g_menu_item_new_submenu() and g_menu_insert_item() for a
440 * more flexible alternative.
442 * Since: 2.32
444 void
445 g_menu_append_submenu (GMenu *menu,
446 const gchar *label,
447 GMenuModel *submenu)
449 g_menu_insert_submenu (menu, -1, label, submenu);
452 static void
453 g_menu_clear_item (struct item *item)
455 if (item->attributes != NULL)
456 g_hash_table_unref (item->attributes);
457 if (item->links != NULL)
458 g_hash_table_unref (item->links);
462 * g_menu_remove:
463 * @menu: a #GMenu
464 * @position: the position of the item to remove
466 * Removes an item from the menu.
468 * @position gives the index of the item to remove.
470 * It is an error if position is not in range the range from 0 to one
471 * less than the number of items in the menu.
473 * It is not possible to remove items by identity since items are added
474 * to the menu simply by copying their links and attributes (ie:
475 * identity of the item itself is not preserved).
477 * Since: 2.32
479 void
480 g_menu_remove (GMenu *menu,
481 gint position)
483 g_return_if_fail (G_IS_MENU (menu));
484 g_return_if_fail (0 <= position && position < menu->items->len);
486 g_menu_clear_item (&g_array_index (menu->items, struct item, position));
487 g_array_remove_index (menu->items, position);
488 g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0);
492 * g_menu_remove_all:
493 * @menu: a #GMenu
495 * Removes all items in the menu.
497 * Since: 2.38
499 void
500 g_menu_remove_all (GMenu *menu)
502 gint i, n;
504 g_return_if_fail (G_IS_MENU (menu));
505 n = menu->items->len;
507 for (i = 0; i < n; i++)
508 g_menu_clear_item (&g_array_index (menu->items, struct item, i));
509 g_array_set_size (menu->items, 0);
511 g_menu_model_items_changed (G_MENU_MODEL (menu), 0, n, 0);
514 static void
515 g_menu_finalize (GObject *object)
517 GMenu *menu = G_MENU (object);
518 struct item *items;
519 gint n_items;
520 gint i;
522 n_items = menu->items->len;
523 items = (struct item *) g_array_free (menu->items, FALSE);
524 for (i = 0; i < n_items; i++)
525 g_menu_clear_item (&items[i]);
526 g_free (items);
528 G_OBJECT_CLASS (g_menu_parent_class)
529 ->finalize (object);
532 static void
533 g_menu_init (GMenu *menu)
535 menu->items = g_array_new (FALSE, FALSE, sizeof (struct item));
536 menu->mutable = TRUE;
539 static void
540 g_menu_class_init (GMenuClass *class)
542 GMenuModelClass *model_class = G_MENU_MODEL_CLASS (class);
543 GObjectClass *object_class = G_OBJECT_CLASS (class);
545 object_class->finalize = g_menu_finalize;
547 model_class->is_mutable = g_menu_is_mutable;
548 model_class->get_n_items = g_menu_get_n_items;
549 model_class->get_item_attributes = g_menu_get_item_attributes;
550 model_class->get_item_links = g_menu_get_item_links;
554 static void
555 g_menu_item_clear_cow (GMenuItem *menu_item)
557 if (menu_item->cow)
559 GHashTableIter iter;
560 GHashTable *new;
561 gpointer key;
562 gpointer val;
564 new = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
565 g_hash_table_iter_init (&iter, menu_item->attributes);
566 while (g_hash_table_iter_next (&iter, &key, &val))
567 g_hash_table_insert (new, g_strdup (key), g_variant_ref (val));
568 g_hash_table_unref (menu_item->attributes);
569 menu_item->attributes = new;
571 new = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
572 g_hash_table_iter_init (&iter, menu_item->links);
573 while (g_hash_table_iter_next (&iter, &key, &val))
574 g_hash_table_insert (new, g_strdup (key), g_object_ref (val));
575 g_hash_table_unref (menu_item->links);
576 menu_item->links = new;
578 menu_item->cow = FALSE;
582 static void
583 g_menu_item_finalize (GObject *object)
585 GMenuItem *menu_item = G_MENU_ITEM (object);
587 g_hash_table_unref (menu_item->attributes);
588 g_hash_table_unref (menu_item->links);
590 G_OBJECT_CLASS (g_menu_item_parent_class)
591 ->finalize (object);
594 static void
595 g_menu_item_init (GMenuItem *menu_item)
597 menu_item->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
598 menu_item->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
599 menu_item->cow = FALSE;
602 static void
603 g_menu_item_class_init (GMenuItemClass *class)
605 class->finalize = g_menu_item_finalize;
608 /* We treat attribute names the same as GSettings keys:
609 * - only lowercase ascii, digits and '-'
610 * - must start with lowercase
611 * - must not end with '-'
612 * - no consecutive '-'
613 * - not longer than 1024 chars
615 static gboolean
616 valid_attribute_name (const gchar *name)
618 gint i;
620 if (!g_ascii_islower (name[0]))
621 return FALSE;
623 for (i = 1; name[i]; i++)
625 if (name[i] != '-' &&
626 !g_ascii_islower (name[i]) &&
627 !g_ascii_isdigit (name[i]))
628 return FALSE;
630 if (name[i] == '-' && name[i + 1] == '-')
631 return FALSE;
634 if (name[i - 1] == '-')
635 return FALSE;
637 if (i > 1024)
638 return FALSE;
640 return TRUE;
644 * g_menu_item_set_attribute_value:
645 * @menu_item: a #GMenuItem
646 * @attribute: the attribute to set
647 * @value: (allow-none): a #GVariant to use as the value, or %NULL
649 * Sets or unsets an attribute on @menu_item.
651 * The attribute to set or unset is specified by @attribute. This
652 * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL,
653 * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom
654 * attribute name.
655 * Attribute names are restricted to lowercase characters, numbers
656 * and '-'. Furthermore, the names must begin with a lowercase character,
657 * must not end with a '-', and must not contain consecutive dashes.
659 * must consist only of lowercase
660 * ASCII characters, digits and '-'.
662 * If @value is non-%NULL then it is used as the new value for the
663 * attribute. If @value is %NULL then the attribute is unset. If
664 * the @value #GVariant is floating, it is consumed.
666 * See also g_menu_item_set_attribute() for a more convenient way to do
667 * the same.
669 * Since: 2.32
671 void
672 g_menu_item_set_attribute_value (GMenuItem *menu_item,
673 const gchar *attribute,
674 GVariant *value)
676 g_return_if_fail (G_IS_MENU_ITEM (menu_item));
677 g_return_if_fail (attribute != NULL);
678 g_return_if_fail (valid_attribute_name (attribute));
680 g_menu_item_clear_cow (menu_item);
682 if (value != NULL)
683 g_hash_table_insert (menu_item->attributes, g_strdup (attribute), g_variant_ref_sink (value));
684 else
685 g_hash_table_remove (menu_item->attributes, attribute);
689 * g_menu_item_set_attribute:
690 * @menu_item: a #GMenuItem
691 * @attribute: the attribute to set
692 * @format_string: (allow-none): a #GVariant format string, or %NULL
693 * @...: positional parameters, as per @format_string
695 * Sets or unsets an attribute on @menu_item.
697 * The attribute to set or unset is specified by @attribute. This
698 * can be one of the standard attribute names %G_MENU_ATTRIBUTE_LABEL,
699 * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, or a custom
700 * attribute name.
701 * Attribute names are restricted to lowercase characters, numbers
702 * and '-'. Furthermore, the names must begin with a lowercase character,
703 * must not end with a '-', and must not contain consecutive dashes.
705 * If @format_string is non-%NULL then the proper position parameters
706 * are collected to create a #GVariant instance to use as the attribute
707 * value. If it is %NULL then the positional parameterrs are ignored
708 * and the named attribute is unset.
710 * See also g_menu_item_set_attribute_value() for an equivalent call
711 * that directly accepts a #GVariant.
713 * Since: 2.32
715 void
716 g_menu_item_set_attribute (GMenuItem *menu_item,
717 const gchar *attribute,
718 const gchar *format_string,
719 ...)
721 GVariant *value;
723 if (format_string != NULL)
725 va_list ap;
727 va_start (ap, format_string);
728 value = g_variant_new_va (format_string, NULL, &ap);
729 va_end (ap);
731 else
732 value = NULL;
734 g_menu_item_set_attribute_value (menu_item, attribute, value);
738 * g_menu_item_set_link:
739 * @menu_item: a #GMenuItem
740 * @link: type of link to establish or unset
741 * @model: (allow-none): the #GMenuModel to link to (or %NULL to unset)
743 * Creates a link from @menu_item to @model if non-%NULL, or unsets it.
745 * Links are used to establish a relationship between a particular menu
746 * item and another menu. For example, %G_MENU_LINK_SUBMENU is used to
747 * associate a submenu with a particular menu item, and %G_MENU_LINK_SECTION
748 * is used to create a section. Other types of link can be used, but there
749 * is no guarantee that clients will be able to make sense of them.
750 * Link types are restricted to lowercase characters, numbers
751 * and '-'. Furthermore, the names must begin with a lowercase character,
752 * must not end with a '-', and must not contain consecutive dashes.
754 * Since: 2.32
756 void
757 g_menu_item_set_link (GMenuItem *menu_item,
758 const gchar *link,
759 GMenuModel *model)
761 g_return_if_fail (G_IS_MENU_ITEM (menu_item));
762 g_return_if_fail (link != NULL);
763 g_return_if_fail (valid_attribute_name (link));
765 g_menu_item_clear_cow (menu_item);
767 if (model != NULL)
768 g_hash_table_insert (menu_item->links, g_strdup (link), g_object_ref (model));
769 else
770 g_hash_table_remove (menu_item->links, link);
774 * g_menu_item_get_attribute_value:
775 * @menu_item: a #GMenuItem
776 * @attribute: the attribute name to query
777 * @expected_type: (allow-none): the expected type of the attribute
779 * Queries the named @attribute on @menu_item.
781 * If @expected_type is specified and the attribute does not have this
782 * type, %NULL is returned. %NULL is also returned if the attribute
783 * simply does not exist.
785 * Returns: (transfer full): the attribute value, or %NULL
787 * Since: 2.34
789 GVariant *
790 g_menu_item_get_attribute_value (GMenuItem *menu_item,
791 const gchar *attribute,
792 const GVariantType *expected_type)
794 GVariant *value;
796 g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
797 g_return_val_if_fail (attribute != NULL, NULL);
799 value = g_hash_table_lookup (menu_item->attributes, attribute);
801 if (value != NULL)
803 if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
804 g_variant_ref (value);
805 else
806 value = NULL;
809 return value;
813 * g_menu_item_get_attribute:
814 * @menu_item: a #GMenuItem
815 * @attribute: the attribute name to query
816 * @format_string: a #GVariant format string
817 * @...: positional parameters, as per @format_string
819 * Queries the named @attribute on @menu_item.
821 * If the attribute exists and matches the #GVariantType corresponding
822 * to @format_string then @format_string is used to deconstruct the
823 * value into the positional parameters and %TRUE is returned.
825 * If the attribute does not exist, or it does exist but has the wrong
826 * type, then the positional parameters are ignored and %FALSE is
827 * returned.
829 * Returns: %TRUE if the named attribute was found with the expected
830 * type
832 * Since: 2.34
834 gboolean
835 g_menu_item_get_attribute (GMenuItem *menu_item,
836 const gchar *attribute,
837 const gchar *format_string,
838 ...)
840 GVariant *value;
841 va_list ap;
843 g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), FALSE);
844 g_return_val_if_fail (attribute != NULL, FALSE);
845 g_return_val_if_fail (format_string != NULL, FALSE);
847 value = g_hash_table_lookup (menu_item->attributes, attribute);
849 if (value == NULL)
850 return FALSE;
852 if (!g_variant_check_format_string (value, format_string, FALSE))
853 return FALSE;
855 va_start (ap, format_string);
856 g_variant_get_va (value, format_string, NULL, &ap);
857 va_end (ap);
859 return TRUE;
863 * g_menu_item_get_link:
864 * @menu_item: a #GMenuItem
865 * @link: the link name to query
867 * Queries the named @link on @menu_item.
869 * Returns: (transfer full): the link, or %NULL
871 * Since: 2.34
873 GMenuModel *
874 g_menu_item_get_link (GMenuItem *menu_item,
875 const gchar *link)
877 GMenuModel *model;
879 g_return_val_if_fail (G_IS_MENU_ITEM (menu_item), NULL);
880 g_return_val_if_fail (link != NULL, NULL);
881 g_return_val_if_fail (valid_attribute_name (link), NULL);
883 model = g_hash_table_lookup (menu_item->links, link);
885 if (model)
886 g_object_ref (model);
888 return model;
892 * g_menu_item_set_label:
893 * @menu_item: a #GMenuItem
894 * @label: (allow-none): the label to set, or %NULL to unset
896 * Sets or unsets the "label" attribute of @menu_item.
898 * If @label is non-%NULL it is used as the label for the menu item. If
899 * it is %NULL then the label attribute is unset.
901 * Since: 2.32
903 void
904 g_menu_item_set_label (GMenuItem *menu_item,
905 const gchar *label)
907 GVariant *value;
909 if (label != NULL)
910 value = g_variant_new_string (label);
911 else
912 value = NULL;
914 g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_LABEL, value);
918 * g_menu_item_set_submenu:
919 * @menu_item: a #GMenuItem
920 * @submenu: (allow-none): a #GMenuModel, or %NULL
922 * Sets or unsets the "submenu" link of @menu_item to @submenu.
924 * If @submenu is non-%NULL, it is linked to. If it is %NULL then the
925 * link is unset.
927 * The effect of having one menu appear as a submenu of another is
928 * exactly as it sounds.
930 * Since: 2.32
932 void
933 g_menu_item_set_submenu (GMenuItem *menu_item,
934 GMenuModel *submenu)
936 g_menu_item_set_link (menu_item, G_MENU_LINK_SUBMENU, submenu);
940 * g_menu_item_set_section:
941 * @menu_item: a #GMenuItem
942 * @section: (allow-none): a #GMenuModel, or %NULL
944 * Sets or unsets the "section" link of @menu_item to @section.
946 * The effect of having one menu appear as a section of another is
947 * exactly as it sounds: the items from @section become a direct part of
948 * the menu that @menu_item is added to. See g_menu_item_new_section()
949 * for more information about what it means for a menu item to be a
950 * section.
952 * Since: 2.32
954 void
955 g_menu_item_set_section (GMenuItem *menu_item,
956 GMenuModel *section)
958 g_menu_item_set_link (menu_item, G_MENU_LINK_SECTION, section);
962 * g_menu_item_set_action_and_target_value:
963 * @menu_item: a #GMenuItem
964 * @action: (allow-none): the name of the action for this item
965 * @target_value: (allow-none): a #GVariant to use as the action target
967 * Sets or unsets the "action" and "target" attributes of @menu_item.
969 * If @action is %NULL then both the "action" and "target" attributes
970 * are unset (and @target_value is ignored).
972 * If @action is non-%NULL then the "action" attribute is set. The
973 * "target" attribute is then set to the value of @target_value if it is
974 * non-%NULL or unset otherwise.
976 * Normal menu items (ie: not submenu, section or other custom item
977 * types) are expected to have the "action" attribute set to identify
978 * the action that they are associated with. The state type of the
979 * action help to determine the disposition of the menu item. See
980 * #GAction and #GActionGroup for an overview of actions.
982 * In general, clicking on the menu item will result in activation of
983 * the named action with the "target" attribute given as the parameter
984 * to the action invocation. If the "target" attribute is not set then
985 * the action is invoked with no parameter.
987 * If the action has no state then the menu item is usually drawn as a
988 * plain menu item (ie: with no additional decoration).
990 * If the action has a boolean state then the menu item is usually drawn
991 * as a toggle menu item (ie: with a checkmark or equivalent
992 * indication). The item should be marked as 'toggled' or 'checked'
993 * when the boolean state is %TRUE.
995 * If the action has a string state then the menu item is usually drawn
996 * as a radio menu item (ie: with a radio bullet or equivalent
997 * indication). The item should be marked as 'selected' when the string
998 * state is equal to the value of the @target property.
1000 * See g_menu_item_set_action_and_target() or
1001 * g_menu_item_set_detailed_action() for two equivalent calls that are
1002 * probably more convenient for most uses.
1004 * Since: 2.32
1006 void
1007 g_menu_item_set_action_and_target_value (GMenuItem *menu_item,
1008 const gchar *action,
1009 GVariant *target_value)
1011 GVariant *action_value;
1013 if (action != NULL)
1015 action_value = g_variant_new_string (action);
1017 else
1019 action_value = NULL;
1020 target_value = NULL;
1023 g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ACTION, action_value);
1024 g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_TARGET, target_value);
1028 * g_menu_item_set_action_and_target:
1029 * @menu_item: a #GMenuItem
1030 * @action: (allow-none): the name of the action for this item
1031 * @format_string: (allow-none): a GVariant format string
1032 * @...: positional parameters, as per @format_string
1034 * Sets or unsets the "action" and "target" attributes of @menu_item.
1036 * If @action is %NULL then both the "action" and "target" attributes
1037 * are unset (and @format_string is ignored along with the positional
1038 * parameters).
1040 * If @action is non-%NULL then the "action" attribute is set.
1041 * @format_string is then inspected. If it is non-%NULL then the proper
1042 * position parameters are collected to create a #GVariant instance to
1043 * use as the target value. If it is %NULL then the positional
1044 * parameters are ignored and the "target" attribute is unset.
1046 * See also g_menu_item_set_action_and_target_value() for an equivalent
1047 * call that directly accepts a #GVariant. See
1048 * g_menu_item_set_detailed_action() for a more convenient version that
1049 * works with string-typed targets.
1051 * See also g_menu_item_set_action_and_target_value() for a
1052 * description of the semantics of the action and target attributes.
1054 * Since: 2.32
1056 void
1057 g_menu_item_set_action_and_target (GMenuItem *menu_item,
1058 const gchar *action,
1059 const gchar *format_string,
1060 ...)
1062 GVariant *value;
1064 if (format_string != NULL)
1066 va_list ap;
1068 va_start (ap, format_string);
1069 value = g_variant_new_va (format_string, NULL, &ap);
1070 va_end (ap);
1072 else
1073 value = NULL;
1075 g_menu_item_set_action_and_target_value (menu_item, action, value);
1079 * g_menu_item_set_detailed_action:
1080 * @menu_item: a #GMenuItem
1081 * @detailed_action: the "detailed" action string
1083 * Sets the "action" and possibly the "target" attribute of @menu_item.
1085 * The format of @detailed_action is the same format parsed by
1086 * g_action_parse_detailed_name().
1088 * See g_menu_item_set_action_and_target() or
1089 * g_menu_item_set_action_and_target_value() for more flexible (but
1090 * slightly less convenient) alternatives.
1092 * See also g_menu_item_set_action_and_target_value() for a description of
1093 * the semantics of the action and target attributes.
1095 * Since: 2.32
1097 void
1098 g_menu_item_set_detailed_action (GMenuItem *menu_item,
1099 const gchar *detailed_action)
1101 GError *error = NULL;
1102 GVariant *target;
1103 gchar *name;
1105 if (!g_action_parse_detailed_name (detailed_action, &name, &target, &error))
1106 g_error ("g_menu_item_set_detailed_action: %s", error->message);
1108 g_menu_item_set_action_and_target_value (menu_item, name, target);
1109 if (target)
1110 g_variant_unref (target);
1111 g_free (name);
1115 * g_menu_item_new:
1116 * @label: (allow-none): the section label, or %NULL
1117 * @detailed_action: (allow-none): the detailed action string, or %NULL
1119 * Creates a new #GMenuItem.
1121 * If @label is non-%NULL it is used to set the "label" attribute of the
1122 * new item.
1124 * If @detailed_action is non-%NULL it is used to set the "action" and
1125 * possibly the "target" attribute of the new item. See
1126 * g_menu_item_set_detailed_action() for more information.
1128 * Returns: a new #GMenuItem
1130 * Since: 2.32
1132 GMenuItem *
1133 g_menu_item_new (const gchar *label,
1134 const gchar *detailed_action)
1136 GMenuItem *menu_item;
1138 menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
1140 if (label != NULL)
1141 g_menu_item_set_label (menu_item, label);
1143 if (detailed_action != NULL)
1144 g_menu_item_set_detailed_action (menu_item, detailed_action);
1146 return menu_item;
1150 * g_menu_item_new_submenu:
1151 * @label: (allow-none): the section label, or %NULL
1152 * @submenu: a #GMenuModel with the items of the submenu
1154 * Creates a new #GMenuItem representing a submenu.
1156 * This is a convenience API around g_menu_item_new() and
1157 * g_menu_item_set_submenu().
1159 * Returns: a new #GMenuItem
1161 * Since: 2.32
1163 GMenuItem *
1164 g_menu_item_new_submenu (const gchar *label,
1165 GMenuModel *submenu)
1167 GMenuItem *menu_item;
1169 menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
1171 if (label != NULL)
1172 g_menu_item_set_label (menu_item, label);
1174 g_menu_item_set_submenu (menu_item, submenu);
1176 return menu_item;
1180 * g_menu_item_new_section:
1181 * @label: (allow-none): the section label, or %NULL
1182 * @section: a #GMenuModel with the items of the section
1184 * Creates a new #GMenuItem representing a section.
1186 * This is a convenience API around g_menu_item_new() and
1187 * g_menu_item_set_section().
1189 * The effect of having one menu appear as a section of another is
1190 * exactly as it sounds: the items from @section become a direct part of
1191 * the menu that @menu_item is added to.
1193 * Visual separation is typically displayed between two non-empty
1194 * sections. If @label is non-%NULL then it will be encorporated into
1195 * this visual indication. This allows for labeled subsections of a
1196 * menu.
1198 * As a simple example, consider a typical "Edit" menu from a simple
1199 * program. It probably contains an "Undo" and "Redo" item, followed by
1200 * a separator, followed by "Cut", "Copy" and "Paste".
1202 * This would be accomplished by creating three #GMenu instances. The
1203 * first would be populated with the "Undo" and "Redo" items, and the
1204 * second with the "Cut", "Copy" and "Paste" items. The first and
1205 * second menus would then be added as submenus of the third. In XML
1206 * format, this would look something like the following:
1208 * <informalexample><programlisting><![CDATA[
1209 * <menu id='edit-menu'>
1210 * <section>
1211 * <item label='Undo'/>
1212 * <item label='Redo'/>
1213 * </section>
1214 * <section>
1215 * <item label='Cut'/>
1216 * <item label='Copy'/>
1217 * <item label='Paste'/>
1218 * </section>
1219 * </menu>
1220 * ]]></programlisting></informalexample>
1222 * The following example is exactly equivalent. It is more illustrative
1223 * of the exact relationship between the menus and items (keeping in
1224 * mind that the 'link' element defines a new menu that is linked to the
1225 * containing one). The style of the second example is more verbose and
1226 * difficult to read (and therefore not recommended except for the
1227 * purpose of understanding what is really going on).
1229 * <informalexample><programlisting><![CDATA[
1230 * <menu id='edit-menu'>
1231 * <item>
1232 * <link name='section'>
1233 * <item label='Undo'/>
1234 * <item label='Redo'/>
1235 * </link>
1236 * </item>
1237 * <item>
1238 * <link name='section'>
1239 * <item label='Cut'/>
1240 * <item label='Copy'/>
1241 * <item label='Paste'/>
1242 * </link>
1243 * </item>
1244 * </menu>
1245 * ]]></programlisting></informalexample>
1247 * Returns: a new #GMenuItem
1249 * Since: 2.32
1251 GMenuItem *
1252 g_menu_item_new_section (const gchar *label,
1253 GMenuModel *section)
1255 GMenuItem *menu_item;
1257 menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
1259 if (label != NULL)
1260 g_menu_item_set_label (menu_item, label);
1262 g_menu_item_set_section (menu_item, section);
1264 return menu_item;
1268 * g_menu_item_new_from_model:
1269 * @model: a #GMenuModel
1270 * @item_index: the index of an item in @model
1272 * Creates a #GMenuItem as an exact copy of an existing menu item in a
1273 * #GMenuModel.
1275 * @item_index must be valid (ie: be sure to call
1276 * g_menu_model_get_n_items() first).
1278 * Returns: a new #GMenuItem.
1280 * Since: 2.34
1282 GMenuItem *
1283 g_menu_item_new_from_model (GMenuModel *model,
1284 gint item_index)
1286 GMenuModelClass *class = G_MENU_MODEL_GET_CLASS (model);
1287 GMenuItem *menu_item;
1289 menu_item = g_object_new (G_TYPE_MENU_ITEM, NULL);
1291 /* With some trickery we can be pretty efficient.
1293 * A GMenuModel must either implement iterate_item_attributes() or
1294 * get_item_attributes(). If it implements get_item_attributes() then
1295 * we are in luck -- we can just take a reference on the returned
1296 * hashtable and mark ourselves as copy-on-write.
1298 * In the case that the model is based on get_item_attributes (which
1299 * is the case for both GMenu and GDBusMenuModel) then this is
1300 * basically just g_hash_table_ref().
1302 if (class->get_item_attributes)
1304 GHashTable *attributes = NULL;
1306 class->get_item_attributes (model, item_index, &attributes);
1307 if (attributes)
1309 g_hash_table_unref (menu_item->attributes);
1310 menu_item->attributes = attributes;
1311 menu_item->cow = TRUE;
1314 else
1316 GMenuAttributeIter *iter;
1317 const gchar *attribute;
1318 GVariant *value;
1320 iter = g_menu_model_iterate_item_attributes (model, item_index);
1321 while (g_menu_attribute_iter_get_next (iter, &attribute, &value))
1322 g_hash_table_insert (menu_item->attributes, g_strdup (attribute), value);
1323 g_object_unref (iter);
1326 /* Same story for the links... */
1327 if (class->get_item_links)
1329 GHashTable *links = NULL;
1331 class->get_item_links (model, item_index, &links);
1332 if (links)
1334 g_hash_table_unref (menu_item->links);
1335 menu_item->links = links;
1336 menu_item->cow = TRUE;
1339 else
1341 GMenuLinkIter *iter;
1342 const gchar *link;
1343 GMenuModel *value;
1345 iter = g_menu_model_iterate_item_links (model, item_index);
1346 while (g_menu_link_iter_get_next (iter, &link, &value))
1347 g_hash_table_insert (menu_item->links, g_strdup (link), value);
1348 g_object_unref (iter);
1351 return menu_item;
1355 * g_menu_item_set_icon:
1356 * @menu_item: a #GMenuItem
1357 * @icon: a #GIcon, or %NULL
1359 * Sets (or unsets) the icon on @menu_item.
1361 * This call is the same as calling g_icon_serialize() and using the
1362 * result as the value to g_menu_item_set_attribute_value() for
1363 * %G_MENU_ATTRIBUTE_ICON.
1365 * This API is only intended for use with "noun" menu items; things like
1366 * bookmarks or applications in an "Open With" menu. Don't use it on
1367 * menu items corresponding to verbs (eg: stock icons for 'Save' or
1368 * 'Quit').
1370 * If @icon is %NULL then the icon is unset.
1372 * Since: 2.38
1374 void
1375 g_menu_item_set_icon (GMenuItem *menu_item,
1376 GIcon *icon)
1378 GVariant *value;
1380 g_return_if_fail (G_IS_MENU_ITEM (menu_item));
1381 g_return_if_fail (G_IS_ICON (icon));
1383 if (icon != NULL)
1384 value = g_icon_serialize (icon);
1385 else
1386 value = NULL;
1388 g_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ICON, value);
1389 if (value)
1390 g_variant_unref (value);