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