Updated FSF's address
[platform/upstream/glib.git] / gio / gmenumodel.c
1 /*
2  * Copyright © 2011 Canonical Ltd.
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author: Ryan Lortie <desrt@desrt.ca>
18  */
19
20 #include "config.h"
21
22 #include "gmenumodel.h"
23
24 /**
25  * SECTION:gmenumodel
26  * @title: GMenuModel
27  * @short_description: An abstract class representing the contents of a menu
28  * @include: gio/gio.h
29  * @see_also: #GActionGroup
30  *
31  * #GMenuModel represents the contents of a menu -- an ordered list of
32  * menu items. The items are associated with actions, which can be
33  * activated through them. Items can be grouped in sections, and may
34  * have submenus associated with them. Both items and sections usually
35  * have some representation data, such as labels or icons. The type of
36  * the associated action (ie whether it is stateful, and what kind of
37  * state it has) can influence the representation of the item.
38  *
39  * The conceptual model of menus in #GMenuModel is hierarchical:
40  * sections and submenus are again represented by #GMenuModels.
41  * Menus themselves do not define their own roles. Rather, the role
42  * of a particular #GMenuModel is defined by the item that references
43  * it (or, in the case of the 'root' menu, is defined by the context
44  * in which it is used).
45  *
46  * As an example, consider the visible portions of the menu in
47  * <xref linkend="menu-example"/>.
48  *
49  * <figure id="menu-example">
50  *   <title>An example menu</title>
51  *   <graphic fileref="menu-example.png" format="PNG"></graphic>
52  * </figure>
53  *
54  * There are 8 "menus" visible in the screenshot: one menubar, two
55  * submenus and 5 sections:
56  * <itemizedlist>
57  * <listitem>the toplevel menubar (containing 4 items)</listitem>
58  * <listitem>the View submenu (containing 3 sections)</listitem>
59  * <listitem>the first section of the View submenu (containing 2 items)</listitem>
60  * <listitem>the second section of the View submenu (containing 1 item)</listitem>
61  * <listitem>the final section of the View submenu (containing 1 item)</listitem>
62  * <listitem>the Highlight Mode submenu (containing 2 sections)</listitem>
63  * <listitem>the Sources section (containing 2 items)</listitem>
64  * <listitem>the Markup section (containing 2 items)</listitem>
65  * </itemizedlist>
66  *
67  * <xref linkend="menu-model"/> illustrates the conceptual connection between
68  * these 8 menus. Each large block in the figure represents a menu and the
69  * smaller blocks within the large block represent items in that menu. Some
70  * items contain references to other menus.
71  *
72  * <figure id="menu-model">
73  *   <title>A menu model</title>
74  *   <graphic fileref="menu-model.png" format="PNG"></graphic>
75  * </figure>
76  *
77  * Notice that the separators visible in <xref linkend="menu-example"/>
78  * appear nowhere in <xref linkend="menu-model"/>. This is because
79  * separators are not explicitly represented in the menu model. Instead,
80  * a separator is inserted between any two non-empty sections of a menu.
81  * Section items can have labels just like any other item. In that case,
82  * a display system may show a section header instead of a separator.
83  *
84  * The motivation for this abstract model of application controls is
85  * that modern user interfaces tend to make these controls available
86  * outside the application. Examples include global menus, jumplists,
87  * dash boards, etc. To support such uses, it is necessary to 'export'
88  * information about actions and their representation in menus, which
89  * is exactly what the
90  * <link linkend="gio-GActionGroup-exporter">GActionGroup exporter</link>
91  * and the
92  * <link linkend="gio-GMenuModel-exporter">GMenuModel exporter</link>
93  * do for #GActionGroup and #GMenuModel. The client-side counterparts
94  * to make use of the exported information are #GDBusActionGroup and
95  * #GDBusMenuModel.
96  *
97  * The API of #GMenuModel is very generic, with iterators for the
98  * attributes and links of an item, see g_menu_model_iterate_item_attributes()
99  * and g_menu_model_iterate_item_links(). The 'standard' attributes and
100  * link types have predefined names: %G_MENU_ATTRIBUTE_LABEL,
101  * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, %G_MENU_LINK_SECTION
102  * and %G_MENU_LINK_SUBMENU.
103  *
104  * Items in a #GMenuModel represent active controls if they refer to
105  * an action that can get activated when the user interacts with the
106  * menu item. The reference to the action is encoded by the string id
107  * in the %G_MENU_ATTRIBUTE_ACTION attribute. An action id uniquely
108  * identifies an action in an action group. Which action group(s) provide
109  * actions depends on the context in which the menu model is used.
110  * E.g. when the model is exported as the application menu of a
111  * #GtkApplication, actions can be application-wide or window-specific
112  * (and thus come from two different action groups). By convention, the
113  * application-wide actions have names that start with "app.", while the
114  * names of window-specific actions start with "win.".
115  *
116  * While a wide variety of stateful actions is possible, the following
117  * is the minimum that is expected to be supported by all users of exported
118  * menu information:
119  * <itemizedlist>
120  * <listitem>an action with no parameter type and no state</listitem>
121  * <listitem>an action with no parameter type and boolean state</listitem>
122  * <listitem>an action with string parameter type and string state</listitem>
123  * </itemizedlist>
124  *
125  * <formalpara><title>Stateless</title>
126  * <para>
127  * A stateless action typically corresponds to an ordinary menu item.
128  * </para>
129  * <para>
130  * Selecting such a menu item will activate the action (with no parameter).
131  * </para>
132  * </formalpara>
133  *
134  * <formalpara><title>Boolean State</title>
135  * <para>
136  * An action with a boolean state will most typically be used with a "toggle"
137  * or "switch" menu item. The state can be set directly, but activating the
138  * action (with no parameter) results in the state being toggled.
139  * </para>
140  * <para>
141  * Selecting a toggle menu item will activate the action. The menu item should
142  * be rendered as "checked" when the state is true.
143  * </para>
144  * </formalpara>
145  *
146  * <formalpara><title>String Parameter and State</title>
147  * <para>
148  * Actions with string parameters and state will most typically be used to
149  * represent an enumerated choice over the items available for a group of
150  * radio menu items. Activating the action with a string parameter is
151  * equivalent to setting that parameter as the state.
152  * </para>
153  * <para>
154  * Radio menu items, in addition to being associated with the action, will
155  * have a target value. Selecting that menu item will result in activation
156  * of the action with the target value as the parameter. The menu item should
157  * be rendered as "selected" when the state of the action is equal to the
158  * target value of the menu item.
159  * </para>
160  * </formalpara>
161  */
162
163 /**
164  * GMenuModel:
165  *
166  * #GMenuModel is an opaque structure type.  You must access it using the
167  * functions below.
168  *
169  * Since: 2.32
170  */
171
172 /**
173  * GMenuAttributeIter:
174  *
175  * #GMenuAttributeIter is an opaque structure type.  You must access it
176  * using the functions below.
177  *
178  * Since: 2.32
179  */
180
181 /**
182  * GMenuLinkIter:
183  *
184  * #GMenuLinkIter is an opaque structure type.  You must access it using
185  * the functions below.
186  *
187  * Since: 2.32
188  */
189
190 typedef struct
191 {
192   GMenuLinkIter parent_instance;
193   GHashTableIter iter;
194   GHashTable *table;
195 } GMenuLinkHashIter;
196
197 typedef GMenuLinkIterClass GMenuLinkHashIterClass;
198
199 static GType g_menu_link_hash_iter_get_type (void);
200
201 G_DEFINE_TYPE (GMenuLinkHashIter, g_menu_link_hash_iter, G_TYPE_MENU_LINK_ITER)
202
203 static gboolean
204 g_menu_link_hash_iter_get_next (GMenuLinkIter  *link_iter,
205                                 const gchar   **out_name,
206                                 GMenuModel    **value)
207 {
208   GMenuLinkHashIter *iter = (GMenuLinkHashIter *) link_iter;
209   gpointer keyptr, valueptr;
210
211   if (!g_hash_table_iter_next (&iter->iter, &keyptr, &valueptr))
212     return FALSE;
213
214   *out_name = keyptr;
215   *value = g_object_ref (valueptr);
216
217   return TRUE;
218 }
219
220 static void
221 g_menu_link_hash_iter_finalize (GObject *object)
222 {
223   GMenuLinkHashIter *iter = (GMenuLinkHashIter *) object;
224
225   g_hash_table_unref (iter->table);
226
227   G_OBJECT_CLASS (g_menu_link_hash_iter_parent_class)
228     ->finalize (object);
229 }
230
231 static void
232 g_menu_link_hash_iter_init (GMenuLinkHashIter *iter)
233 {
234 }
235
236 static void
237 g_menu_link_hash_iter_class_init (GMenuLinkHashIterClass *class)
238 {
239   GObjectClass *object_class = G_OBJECT_CLASS (class);
240
241   object_class->finalize = g_menu_link_hash_iter_finalize;
242   class->get_next = g_menu_link_hash_iter_get_next;
243 }
244
245
246 typedef struct
247 {
248   GMenuAttributeIter parent_instance;
249   GHashTableIter iter;
250   GHashTable *table;
251 } GMenuAttributeHashIter;
252
253 typedef GMenuAttributeIterClass GMenuAttributeHashIterClass;
254
255 static GType g_menu_attribute_hash_iter_get_type (void);
256
257 G_DEFINE_TYPE (GMenuAttributeHashIter, g_menu_attribute_hash_iter, G_TYPE_MENU_ATTRIBUTE_ITER)
258
259 static gboolean
260 g_menu_attribute_hash_iter_get_next (GMenuAttributeIter  *attr_iter,
261                                      const gchar        **name,
262                                      GVariant           **value)
263 {
264   GMenuAttributeHashIter *iter = (GMenuAttributeHashIter *) attr_iter;
265   gpointer keyptr, valueptr;
266
267   if (!g_hash_table_iter_next (&iter->iter, &keyptr, &valueptr))
268     return FALSE;
269
270   *name = keyptr;
271
272   *value = g_variant_ref (valueptr);
273
274   return TRUE;
275 }
276
277 static void
278 g_menu_attribute_hash_iter_finalize (GObject *object)
279 {
280   GMenuAttributeHashIter *iter = (GMenuAttributeHashIter *) object;
281
282   g_hash_table_unref (iter->table);
283
284   G_OBJECT_CLASS (g_menu_attribute_hash_iter_parent_class)
285     ->finalize (object);
286 }
287
288 static void
289 g_menu_attribute_hash_iter_init (GMenuAttributeHashIter *iter)
290 {
291 }
292
293 static void
294 g_menu_attribute_hash_iter_class_init (GMenuAttributeHashIterClass *class)
295 {
296   GObjectClass *object_class = G_OBJECT_CLASS (class);
297
298   object_class->finalize = g_menu_attribute_hash_iter_finalize;
299   class->get_next = g_menu_attribute_hash_iter_get_next;
300 }
301
302 G_DEFINE_ABSTRACT_TYPE (GMenuModel, g_menu_model, G_TYPE_OBJECT)
303
304
305 static guint g_menu_model_items_changed_signal;
306
307 static GMenuAttributeIter *
308 g_menu_model_real_iterate_item_attributes (GMenuModel *model,
309                                            gint        item_index)
310 {
311   GHashTable *table = NULL;
312   GMenuAttributeIter *result;
313
314   G_MENU_MODEL_GET_CLASS (model)->get_item_attributes (model, item_index, &table);
315
316   if (table)
317     {
318       GMenuAttributeHashIter *iter = g_object_new (g_menu_attribute_hash_iter_get_type (), NULL);
319       g_hash_table_iter_init (&iter->iter, table);
320       iter->table = g_hash_table_ref (table);
321       result = G_MENU_ATTRIBUTE_ITER (iter);
322     }
323   else
324     {
325       g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_attributes() "
326                   "and fails to return sane values from get_item_attributes()",
327                   G_OBJECT_TYPE_NAME (model));
328       result = NULL;
329     }
330
331   if (table != NULL)
332     g_hash_table_unref (table);
333
334   return result;
335 }
336
337 static GVariant *
338 g_menu_model_real_get_item_attribute_value (GMenuModel         *model,
339                                             gint                item_index,
340                                             const gchar        *attribute,
341                                             const GVariantType *expected_type)
342 {
343   GHashTable *table = NULL;
344   GVariant *value = NULL;
345
346   G_MENU_MODEL_GET_CLASS (model)
347     ->get_item_attributes (model, item_index, &table);
348
349   if (table != NULL)
350     {
351       value = g_hash_table_lookup (table, attribute);
352
353       if (value != NULL)
354         {
355           if (expected_type == NULL || g_variant_is_of_type (value, expected_type))
356             value = g_variant_ref (value);
357           else
358             value = NULL;
359         }
360     }
361   else
362     g_assert_not_reached ();
363
364   if (table != NULL)
365     g_hash_table_unref (table);
366
367   return value;
368 }
369
370 static GMenuLinkIter *
371 g_menu_model_real_iterate_item_links (GMenuModel *model,
372                                       gint        item_index)
373 {
374   GHashTable *table = NULL;
375   GMenuLinkIter *result;
376
377   G_MENU_MODEL_GET_CLASS (model)
378     ->get_item_links (model, item_index, &table);
379
380   if (table)
381     {
382       GMenuLinkHashIter *iter = g_object_new (g_menu_link_hash_iter_get_type (), NULL);
383       g_hash_table_iter_init (&iter->iter, table);
384       iter->table = g_hash_table_ref (table);
385       result = G_MENU_LINK_ITER (iter);
386     }
387   else
388     {
389       g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_links() "
390                   "and fails to return sane values from get_item_links()",
391                   G_OBJECT_TYPE_NAME (model));
392       result = NULL;
393     }
394
395   if (table != NULL)
396     g_hash_table_unref (table);
397
398   return result;
399 }
400
401 static GMenuModel *
402 g_menu_model_real_get_item_link (GMenuModel  *model,
403                                  gint         item_index,
404                                  const gchar *link)
405 {
406   GHashTable *table = NULL;
407   GMenuModel *value = NULL;
408
409   G_MENU_MODEL_GET_CLASS (model)
410     ->get_item_links (model, item_index, &table);
411
412   if (table != NULL)
413     value = g_hash_table_lookup (table, link);
414   else
415     g_assert_not_reached ();
416
417   if (value != NULL)
418     g_object_ref (value);
419
420   if (table != NULL)
421     g_hash_table_unref (table);
422
423   return value;
424 }
425
426 static void
427 g_menu_model_init (GMenuModel *model)
428 {
429 }
430
431 static void
432 g_menu_model_class_init (GMenuModelClass *class)
433 {
434   class->iterate_item_attributes = g_menu_model_real_iterate_item_attributes;
435   class->get_item_attribute_value = g_menu_model_real_get_item_attribute_value;
436   class->iterate_item_links = g_menu_model_real_iterate_item_links;
437   class->get_item_link = g_menu_model_real_get_item_link;
438
439   /**
440    * GMenuModel::items-changed:
441    * @model: the #GMenuModel that is changing
442    * @position: the position of the change
443    * @removed: the number of items removed
444    * @added: the number of items added
445    *
446    * Emitted when a change has occured to the menu.
447    *
448    * The only changes that can occur to a menu is that items are removed
449    * or added.  Items may not change (except by being removed and added
450    * back in the same location).  This signal is capable of describing
451    * both of those changes (at the same time).
452    *
453    * The signal means that starting at the index @position, @removed
454    * items were removed and @added items were added in their place.  If
455    * @removed is zero then only items were added.  If @added is zero
456    * then only items were removed.
457    *
458    * As an example, if the menu contains items a, b, c, d (in that
459    * order) and the signal (2, 1, 3) occurs then the new composition of
460    * the menu will be a, b, _, _, _, d (with each _ representing some
461    * new item).
462    *
463    * Signal handlers may query the model (particularly the added items)
464    * and expect to see the results of the modification that is being
465    * reported.  The signal is emitted after the modification.
466    **/
467   g_menu_model_items_changed_signal =
468     g_signal_new ("items-changed", G_TYPE_MENU_MODEL,
469                   G_SIGNAL_RUN_LAST, 0, NULL, NULL,
470                   g_cclosure_marshal_generic, G_TYPE_NONE,
471                   3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
472 }
473
474 /**
475  * g_menu_model_is_mutable:
476  * @model: a #GMenuModel
477  *
478  * Queries if @model is mutable.
479  *
480  * An immutable #GMenuModel will never emit the #GMenuModel::items-changed
481  * signal. Consumers of the model may make optimisations accordingly.
482  *
483  * Returns: %TRUE if the model is mutable (ie: "items-changed" may be
484  *     emitted).
485  *
486  * Since: 2.32
487  */
488 gboolean
489 g_menu_model_is_mutable (GMenuModel *model)
490 {
491   return G_MENU_MODEL_GET_CLASS (model)
492     ->is_mutable (model);
493 }
494
495 /**
496  * g_menu_model_get_n_items:
497  * @model: a #GMenuModel
498  *
499  * Query the number of items in @model.
500  *
501  * Returns: the number of items
502  *
503  * Since: 2.32
504  */
505 gint
506 g_menu_model_get_n_items (GMenuModel *model)
507 {
508   return G_MENU_MODEL_GET_CLASS (model)
509     ->get_n_items (model);
510 }
511
512 /**
513  * g_menu_model_iterate_item_attributes:
514  * @model: a #GMenuModel
515  * @item_index: the index of the item
516  *
517  * Creates a #GMenuAttributeIter to iterate over the attributes of
518  * the item at position @item_index in @model.
519  *
520  * You must free the iterator with g_object_unref() when you are done.
521  *
522  * Returns: (transfer full): a new #GMenuAttributeIter
523  *
524  * Since: 2.32
525  */
526 GMenuAttributeIter *
527 g_menu_model_iterate_item_attributes (GMenuModel *model,
528                                       gint        item_index)
529 {
530   return G_MENU_MODEL_GET_CLASS (model)
531     ->iterate_item_attributes (model, item_index);
532 }
533
534 /**
535  * g_menu_model_get_item_attribute_value:
536  * @model: a #GMenuModel
537  * @item_index: the index of the item
538  * @attribute: the attribute to query
539  * @expected_type: (allow-none): the expected type of the attribute, or
540  *     %NULL
541  *
542  * Queries the item at position @item_index in @model for the attribute
543  * specified by @attribute.
544  *
545  * If @expected_type is non-%NULL then it specifies the expected type of
546  * the attribute.  If it is %NULL then any type will be accepted.
547  *
548  * If the attribute exists and matches @expected_type (or if the
549  * expected type is unspecified) then the value is returned.
550  *
551  * If the attribute does not exist, or does not match the expected type
552  * then %NULL is returned.
553  *
554  * Returns: (transfer full): the value of the attribute
555  *
556  * Since: 2.32
557  */
558 GVariant *
559 g_menu_model_get_item_attribute_value (GMenuModel         *model,
560                                        gint                item_index,
561                                        const gchar        *attribute,
562                                        const GVariantType *expected_type)
563 {
564   return G_MENU_MODEL_GET_CLASS (model)
565     ->get_item_attribute_value (model, item_index, attribute, expected_type);
566 }
567
568 /**
569  * g_menu_model_get_item_attribute:
570  * @model: a #GMenuModel
571  * @item_index: the index of the item
572  * @attribute: the attribute to query
573  * @format_string: a #GVariant format string
574  * @...: positional parameters, as per @format_string
575  *
576  * Queries item at position @item_index in @model for the attribute
577  * specified by @attribute.
578  *
579  * If the attribute exists and matches the #GVariantType corresponding
580  * to @format_string then @format_string is used to deconstruct the
581  * value into the positional parameters and %TRUE is returned.
582  *
583  * If the attribute does not exist, or it does exist but has the wrong
584  * type, then the positional parameters are ignored and %FALSE is
585  * returned.
586  *
587  * This function is a mix of g_menu_model_get_item_attribute_value() and
588  * g_variant_get(), followed by a g_variant_unref().  As such,
589  * @format_string must make a complete copy of the data (since the
590  * #GVariant may go away after the call to g_variant_unref()).  In
591  * particular, no '&amp;' characters are allowed in @format_string.
592  *
593  * Returns: %TRUE if the named attribute was found with the expected
594  *     type
595  *
596  * Since: 2.32
597  */
598 gboolean
599 g_menu_model_get_item_attribute (GMenuModel  *model,
600                                  gint         item_index,
601                                  const gchar *attribute,
602                                  const gchar *format_string,
603                                  ...)
604 {
605   GVariant *value;
606   va_list ap;
607
608   value = g_menu_model_get_item_attribute_value (model, item_index, attribute, NULL);
609
610   if (value == NULL)
611     return FALSE;
612
613   if (!g_variant_check_format_string (value, format_string, TRUE))
614     {
615       g_variant_unref (value);
616       return FALSE;
617     }
618
619   va_start (ap, format_string);
620   g_variant_get_va (value, format_string, NULL, &ap);
621   g_variant_unref (value);
622   va_end (ap);
623
624   return TRUE;
625 }
626
627 /**
628  * g_menu_model_iterate_item_links:
629  * @model: a #GMenuModel
630  * @item_index: the index of the item
631  *
632  * Creates a #GMenuLinkIter to iterate over the links of the item at
633  * position @item_index in @model.
634  *
635  * You must free the iterator with g_object_unref() when you are done.
636  *
637  * Returns: (transfer full): a new #GMenuLinkIter
638  *
639  * Since: 2.32
640  */
641 GMenuLinkIter *
642 g_menu_model_iterate_item_links (GMenuModel *model,
643                                  gint        item_index)
644 {
645   return G_MENU_MODEL_GET_CLASS (model)
646     ->iterate_item_links (model, item_index);
647 }
648
649 /**
650  * g_menu_model_get_item_link:
651  * @model: a #GMenuModel
652  * @item_index: the index of the item
653  * @link: the link to query
654  *
655  * Queries the item at position @item_index in @model for the link
656  * specified by @link.
657  *
658  * If the link exists, the linked #GMenuModel is returned.  If the link
659  * does not exist, %NULL is returned.
660  *
661  * Returns: (transfer full): the linked #GMenuModel, or %NULL
662  *
663  * Since: 2.32
664  */
665 GMenuModel *
666 g_menu_model_get_item_link (GMenuModel *model,
667                             gint        item_index,
668                             const gchar *link)
669 {
670   return G_MENU_MODEL_GET_CLASS (model)
671     ->get_item_link (model, item_index, link);
672 }
673
674 /**
675  * g_menu_model_items_changed:
676  * @model: a #GMenuModel
677  * @position: the position of the change
678  * @removed: the number of items removed
679  * @added: the number of items added
680  *
681  * Requests emission of the #GMenuModel::items-changed signal on @model.
682  *
683  * This function should never be called except by #GMenuModel
684  * subclasses.  Any other calls to this function will very likely lead
685  * to a violation of the interface of the model.
686  *
687  * The implementation should update its internal representation of the
688  * menu before emitting the signal.  The implementation should further
689  * expect to receive queries about the new state of the menu (and
690  * particularly added menu items) while signal handlers are running.
691  *
692  * The implementation must dispatch this call directly from a mainloop
693  * entry and not in response to calls -- particularly those from the
694  * #GMenuModel API.  Said another way: the menu must not change while
695  * user code is running without returning to the mainloop.
696  *
697  * Since: 2.32
698  */
699 void
700 g_menu_model_items_changed (GMenuModel *model,
701                             gint        position,
702                             gint        removed,
703                             gint        added)
704 {
705   g_signal_emit (model, g_menu_model_items_changed_signal, 0, position, removed, added);
706 }
707
708 struct _GMenuAttributeIterPrivate
709 {
710   GQuark name;
711   GVariant *value;
712   gboolean valid;
713 };
714
715 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GMenuAttributeIter, g_menu_attribute_iter, G_TYPE_OBJECT)
716
717 /**
718  * g_menu_attribute_iter_get_next:
719  * @iter: a #GMenuAttributeIter
720  * @out_name: (out) (allow-none) (transfer none): the type of the attribute
721  * @value: (out) (allow-none) (transfer full): the attribute value
722  *
723  * This function combines g_menu_attribute_iter_next() with
724  * g_menu_attribute_iter_get_name() and g_menu_attribute_iter_get_value().
725  *
726  * First the iterator is advanced to the next (possibly first) attribute.
727  * If that fails, then %FALSE is returned and there are no other
728  * effects.
729  *
730  * If successful, @name and @value are set to the name and value of the
731  * attribute that has just been advanced to.  At this point,
732  * g_menu_attribute_iter_get_name() and g_menu_attribute_iter_get_value() will
733  * return the same values again.
734  *
735  * The value returned in @name remains valid for as long as the iterator
736  * remains at the current position.  The value returned in @value must
737  * be unreffed using g_variant_unref() when it is no longer in use.
738  *
739  * Returns: %TRUE on success, or %FALSE if there is no additional
740  *     attribute
741  *
742  * Since: 2.32
743  */
744 gboolean
745 g_menu_attribute_iter_get_next (GMenuAttributeIter  *iter,
746                                 const gchar        **out_name,
747                                 GVariant           **value)
748 {
749   const gchar *name;
750
751   if (iter->priv->value)
752     {
753       g_variant_unref (iter->priv->value);
754       iter->priv->value = NULL;
755     }
756
757   iter->priv->valid = G_MENU_ATTRIBUTE_ITER_GET_CLASS (iter)
758     ->get_next (iter, &name, &iter->priv->value);
759
760   if (iter->priv->valid)
761     {
762       iter->priv->name = g_quark_from_string (name);
763       if (out_name)
764         *out_name = g_quark_to_string (iter->priv->name);
765
766       if (value)
767         *value = g_variant_ref (iter->priv->value);
768     }
769
770   return iter->priv->valid;
771 }
772
773 /**
774  * g_menu_attribute_iter_next:
775  * @iter: a #GMenuAttributeIter
776  *
777  * Attempts to advance the iterator to the next (possibly first)
778  * attribute.
779  *
780  * %TRUE is returned on success, or %FALSE if there are no more
781  * attributes.
782  *
783  * You must call this function when you first acquire the iterator
784  * to advance it to the first attribute (and determine if the first
785  * attribute exists at all).
786  *
787  * Returns: %TRUE on success, or %FALSE when there are no more attributes
788  *
789  * Since: 2.32
790  */
791 gboolean
792 g_menu_attribute_iter_next (GMenuAttributeIter *iter)
793 {
794   return g_menu_attribute_iter_get_next (iter, NULL, NULL);
795 }
796
797 /**
798  * g_menu_attribute_iter_get_name:
799  * @iter: a #GMenuAttributeIter
800  *
801  * Gets the name of the attribute at the current iterator position, as
802  * a string.
803  *
804  * The iterator is not advanced.
805  *
806  * Returns: the name of the attribute
807  *
808  * Since: 2.32
809  */
810 const gchar *
811 g_menu_attribute_iter_get_name (GMenuAttributeIter *iter)
812 {
813   g_return_val_if_fail (iter->priv->valid, 0);
814
815   return g_quark_to_string (iter->priv->name);
816 }
817
818 /**
819  * g_menu_attribute_iter_get_value:
820  * @iter: a #GMenuAttributeIter
821  *
822  * Gets the value of the attribute at the current iterator position.
823  *
824  * The iterator is not advanced.
825  *
826  * Returns: (transfer full): the value of the current attribute
827  *
828  * Since: 2.32
829  */
830 GVariant *
831 g_menu_attribute_iter_get_value (GMenuAttributeIter *iter)
832 {
833   g_return_val_if_fail (iter->priv->valid, NULL);
834
835   return g_variant_ref (iter->priv->value);
836 }
837
838 static void
839 g_menu_attribute_iter_finalize (GObject *object)
840 {
841   GMenuAttributeIter *iter = G_MENU_ATTRIBUTE_ITER (object);
842
843   if (iter->priv->value)
844     g_variant_unref (iter->priv->value);
845
846   G_OBJECT_CLASS (g_menu_attribute_iter_parent_class)
847     ->finalize (object);
848 }
849
850 static void
851 g_menu_attribute_iter_init (GMenuAttributeIter *iter)
852 {
853   iter->priv = g_menu_attribute_iter_get_instance_private (iter);
854 }
855
856 static void
857 g_menu_attribute_iter_class_init (GMenuAttributeIterClass *class)
858 {
859   GObjectClass *object_class = G_OBJECT_CLASS (class);
860
861   object_class->finalize = g_menu_attribute_iter_finalize;
862 }
863
864 struct _GMenuLinkIterPrivate
865 {
866   GQuark name;
867   GMenuModel *value;
868   gboolean valid;
869 };
870
871 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GMenuLinkIter, g_menu_link_iter, G_TYPE_OBJECT)
872
873 /**
874  * g_menu_link_iter_get_next:
875  * @iter: a #GMenuLinkIter
876  * @out_link: (out) (allow-none) (transfer none): the name of the link
877  * @value: (out) (allow-none) (transfer full): the linked #GMenuModel
878  *
879  * This function combines g_menu_link_iter_next() with
880  * g_menu_link_iter_get_name() and g_menu_link_iter_get_value().
881  *
882  * First the iterator is advanced to the next (possibly first) link.
883  * If that fails, then %FALSE is returned and there are no other effects.
884  *
885  * If successful, @out_link and @value are set to the name and #GMenuModel
886  * of the link that has just been advanced to.  At this point,
887  * g_menu_link_iter_get_name() and g_menu_link_iter_get_value() will return the
888  * same values again.
889  *
890  * The value returned in @out_link remains valid for as long as the iterator
891  * remains at the current position.  The value returned in @value must
892  * be unreffed using g_object_unref() when it is no longer in use.
893  *
894  * Returns: %TRUE on success, or %FALSE if there is no additional link
895  *
896  * Since: 2.32
897  */
898 gboolean
899 g_menu_link_iter_get_next (GMenuLinkIter  *iter,
900                            const gchar   **out_link,
901                            GMenuModel    **value)
902 {
903   const gchar *name;
904
905   if (iter->priv->value)
906     {
907       g_object_unref (iter->priv->value);
908       iter->priv->value = NULL;
909     }
910
911   iter->priv->valid = G_MENU_LINK_ITER_GET_CLASS (iter)
912     ->get_next (iter, &name, &iter->priv->value);
913
914   if (iter->priv->valid)
915     {
916       g_assert (name != NULL);
917
918       iter->priv->name = g_quark_from_string (name);
919       if (out_link)
920         *out_link = g_quark_to_string (iter->priv->name);
921
922       if (value)
923         *value = g_object_ref (iter->priv->value);
924     }
925
926   return iter->priv->valid;
927 }
928
929 /**
930  * g_menu_link_iter_next:
931  * @iter: a #GMenuLinkIter
932  *
933  * Attempts to advance the iterator to the next (possibly first)
934  * link.
935  *
936  * %TRUE is returned on success, or %FALSE if there are no more links.
937  *
938  * You must call this function when you first acquire the iterator to
939  * advance it to the first link (and determine if the first link exists
940  * at all).
941  *
942  * Returns: %TRUE on success, or %FALSE when there are no more links
943  *
944  * Since: 2.32
945  */
946 gboolean
947 g_menu_link_iter_next (GMenuLinkIter *iter)
948 {
949   return g_menu_link_iter_get_next (iter, NULL, NULL);
950 }
951
952 /**
953  * g_menu_link_iter_get_name:
954  * @iter: a #GMenuLinkIter
955  *
956  * Gets the name of the link at the current iterator position.
957  *
958  * The iterator is not advanced.
959  *
960  * Returns: the type of the link
961  *
962  * Since: 2.32
963  */
964 const gchar *
965 g_menu_link_iter_get_name (GMenuLinkIter *iter)
966 {
967   g_return_val_if_fail (iter->priv->valid, 0);
968
969   return g_quark_to_string (iter->priv->name);
970 }
971
972 /**
973  * g_menu_link_iter_get_value:
974  * @iter: a #GMenuLinkIter
975  *
976  * Gets the linked #GMenuModel at the current iterator position.
977  *
978  * The iterator is not advanced.
979  *
980  * Returns: (transfer full): the #GMenuModel that is linked to
981  *
982  * Since: 2.32
983  */
984 GMenuModel *
985 g_menu_link_iter_get_value (GMenuLinkIter *iter)
986 {
987   g_return_val_if_fail (iter->priv->valid, NULL);
988
989   return g_object_ref (iter->priv->value);
990 }
991
992 static void
993 g_menu_link_iter_finalize (GObject *object)
994 {
995   GMenuLinkIter *iter = G_MENU_LINK_ITER (object);
996
997   if (iter->priv->value)
998     g_object_unref (iter->priv->value);
999
1000   G_OBJECT_CLASS (g_menu_link_iter_parent_class)
1001     ->finalize (object);
1002 }
1003
1004 static void
1005 g_menu_link_iter_init (GMenuLinkIter *iter)
1006 {
1007   iter->priv = g_menu_link_iter_get_instance_private (iter);
1008 }
1009
1010 static void
1011 g_menu_link_iter_class_init (GMenuLinkIterClass *class)
1012 {
1013   GObjectClass *object_class = G_OBJECT_CLASS (class);
1014
1015   object_class->finalize = g_menu_link_iter_finalize;
1016 }