]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenuitem.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkmenuitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but 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
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24
25 #include "config.h"
26
27 #include <string.h>
28
29 #include "gtkaccellabel.h"
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkmenuprivate.h"
33 #include "gtkmenushellprivate.h"
34 #include "gtkmenuitemprivate.h"
35 #include "gtkmenubar.h"
36 #include "gtkmenuprivate.h"
37 #include "gtkseparatormenuitem.h"
38 #include "gtkprivate.h"
39 #include "gtkbuildable.h"
40 #include "gtkactivatable.h"
41 #include "gtkwidgetprivate.h"
42 #include "gtkintl.h"
43 #include "gtksettings.h"
44 #include "gtktypebuiltins.h"
45 #include "a11y/gtkmenuitemaccessible.h"
46 #include "deprecated/gtktearoffmenuitem.h"
47
48 /**
49  * SECTION:gtkmenuitem
50  * @Short_description: The widget used for item in menus
51  * @Title: GtkMenuItem
52  * @See_also: #GtkBin, #GtkMenuShell
53  *
54  * The #GtkMenuItem widget and the derived widgets are the only valid
55  * childs for menus. Their function is to correctly handle highlighting,
56  * alignment, events and submenus.
57  *
58  * As it derives from #GtkBin it can hold any valid child widget, altough
59  * only a few are really useful.
60  *
61  * <refsect2 id="GtkMenuItem-BUILDER-UI">
62  * <title>GtkMenuItem as GtkBuildable</title>
63  * The GtkMenuItem implementation of the GtkBuildable interface
64  * supports adding a submenu by specifying "submenu" as the "type"
65  * attribute of a &lt;child&gt; element.
66  * <example>
67  * <title>A UI definition fragment with submenus</title>
68  * <programlisting><![CDATA[
69  * <object class="GtkMenuItem">
70  *   <child type="submenu">
71  *     <object class="GtkMenu"/>
72  *   </child>
73  * </object>
74  * ]]></programlisting>
75  * </example>
76  * </refsect2>
77  */
78
79
80 enum {
81   ACTIVATE,
82   ACTIVATE_ITEM,
83   TOGGLE_SIZE_REQUEST,
84   TOGGLE_SIZE_ALLOCATE,
85   SELECT,
86   DESELECT,
87   LAST_SIGNAL
88 };
89
90 enum {
91   PROP_0,
92   PROP_RIGHT_JUSTIFIED,
93   PROP_SUBMENU,
94   PROP_ACCEL_PATH,
95   PROP_LABEL,
96   PROP_USE_UNDERLINE,
97
98   /* activatable properties */
99   PROP_ACTIVATABLE_RELATED_ACTION,
100   PROP_ACTIVATABLE_USE_ACTION_APPEARANCE,
101
102   PROP_ACTION_NAME,
103   PROP_ACTION_TARGET
104 };
105
106
107 static void gtk_menu_item_dispose        (GObject          *object);
108 static void gtk_menu_item_set_property   (GObject          *object,
109                                           guint             prop_id,
110                                           const GValue     *value,
111                                           GParamSpec       *pspec);
112 static void gtk_menu_item_get_property   (GObject          *object,
113                                           guint             prop_id,
114                                           GValue           *value,
115                                           GParamSpec       *pspec);
116 static void gtk_menu_item_destroy        (GtkWidget        *widget);
117 static void gtk_menu_item_size_allocate  (GtkWidget        *widget,
118                                           GtkAllocation    *allocation);
119 static void gtk_menu_item_realize        (GtkWidget        *widget);
120 static void gtk_menu_item_unrealize      (GtkWidget        *widget);
121 static void gtk_menu_item_map            (GtkWidget        *widget);
122 static void gtk_menu_item_unmap          (GtkWidget        *widget);
123 static gboolean gtk_menu_item_enter      (GtkWidget        *widget,
124                                           GdkEventCrossing *event);
125 static gboolean gtk_menu_item_leave      (GtkWidget        *widget,
126                                           GdkEventCrossing *event);
127 static gboolean gtk_menu_item_draw       (GtkWidget        *widget,
128                                           cairo_t          *cr);
129 static void gtk_menu_item_parent_set     (GtkWidget        *widget,
130                                           GtkWidget        *previous_parent);
131
132
133 static void gtk_real_menu_item_select               (GtkMenuItem *item);
134 static void gtk_real_menu_item_deselect             (GtkMenuItem *item);
135 static void gtk_real_menu_item_activate             (GtkMenuItem *item);
136 static void gtk_real_menu_item_activate_item        (GtkMenuItem *item);
137 static void gtk_real_menu_item_toggle_size_request  (GtkMenuItem *menu_item,
138                                                      gint        *requisition);
139 static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
140                                                      gint         allocation);
141 static gboolean gtk_menu_item_mnemonic_activate     (GtkWidget   *widget,
142                                                      gboolean     group_cycling);
143
144 static void gtk_menu_item_ensure_label   (GtkMenuItem      *menu_item);
145 static gint gtk_menu_item_popup_timeout  (gpointer          data);
146 static void gtk_menu_item_position_menu  (GtkMenu          *menu,
147                                           gint             *x,
148                                           gint             *y,
149                                           gboolean         *push_in,
150                                           gpointer          user_data);
151 static void gtk_menu_item_show_all       (GtkWidget        *widget);
152 static void gtk_menu_item_forall         (GtkContainer    *container,
153                                           gboolean         include_internals,
154                                           GtkCallback      callback,
155                                           gpointer         callback_data);
156 static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget,
157                                                   guint      signal_id);
158
159 static void gtk_real_menu_item_set_label (GtkMenuItem     *menu_item,
160                                           const gchar     *label);
161 static const gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item);
162
163 static void gtk_menu_item_get_preferred_width            (GtkWidget           *widget,
164                                                           gint                *minimum_size,
165                                                           gint                *natural_size);
166 static void gtk_menu_item_get_preferred_height           (GtkWidget           *widget,
167                                                           gint                *minimum_size,
168                                                           gint                *natural_size);
169 static void gtk_menu_item_get_preferred_height_for_width (GtkWidget           *widget,
170                                                           gint                 for_size,
171                                                           gint                *minimum_size,
172                                                           gint                *natural_size);
173
174 static void gtk_menu_item_buildable_interface_init (GtkBuildableIface   *iface);
175 static void gtk_menu_item_buildable_add_child      (GtkBuildable        *buildable,
176                                                     GtkBuilder          *builder,
177                                                     GObject             *child,
178                                                     const gchar         *type);
179 static void gtk_menu_item_buildable_custom_finished(GtkBuildable        *buildable,
180                                                     GtkBuilder          *builder,
181                                                     GObject             *child,
182                                                     const gchar         *tagname,
183                                                     gpointer             user_data);
184
185 static void gtk_menu_item_actionable_interface_init  (GtkActionableInterface *iface);
186 static void gtk_menu_item_activatable_interface_init (GtkActivatableIface  *iface);
187 static void gtk_menu_item_update                     (GtkActivatable       *activatable,
188                                                       GtkAction            *action,
189                                                       const gchar          *property_name);
190 static void gtk_menu_item_sync_action_properties     (GtkActivatable       *activatable,
191                                                       GtkAction            *action);
192 static void gtk_menu_item_set_related_action         (GtkMenuItem          *menu_item, 
193                                                       GtkAction            *action);
194 static void gtk_menu_item_set_use_action_appearance  (GtkMenuItem          *menu_item, 
195                                                       gboolean              use_appearance);
196
197 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
198
199 static GtkBuildableIface *parent_buildable_iface;
200
201 G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_BIN,
202                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
203                                                 gtk_menu_item_buildable_interface_init)
204                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
205                                                 gtk_menu_item_activatable_interface_init)
206                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE,
207                                                 gtk_menu_item_actionable_interface_init))
208
209 static void
210 gtk_menu_item_set_action_name (GtkActionable *actionable,
211                                const gchar   *action_name)
212 {
213   GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable);
214
215   if (!menu_item->priv->action_helper)
216     menu_item->priv->action_helper = gtk_action_helper_new (actionable);
217
218   gtk_action_helper_set_action_name (menu_item->priv->action_helper, action_name);
219 }
220
221 static void
222 gtk_menu_item_set_action_target_value (GtkActionable *actionable,
223                                        GVariant      *action_target)
224 {
225   GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable);
226
227   if (!menu_item->priv->action_helper)
228     menu_item->priv->action_helper = gtk_action_helper_new (actionable);
229
230   gtk_action_helper_set_action_target_value (menu_item->priv->action_helper, action_target);
231 }
232
233 static const gchar *
234 gtk_menu_item_get_action_name (GtkActionable *actionable)
235 {
236   GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable);
237
238   return gtk_action_helper_get_action_name (menu_item->priv->action_helper);
239 }
240
241 static GVariant *
242 gtk_menu_item_get_action_target_value (GtkActionable *actionable)
243 {
244   GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable);
245
246   return gtk_action_helper_get_action_target_value (menu_item->priv->action_helper);
247 }
248
249 static void
250 gtk_menu_item_actionable_interface_init (GtkActionableInterface *iface)
251 {
252   iface->set_action_name = gtk_menu_item_set_action_name;
253   iface->get_action_name = gtk_menu_item_get_action_name;
254   iface->set_action_target_value = gtk_menu_item_set_action_target_value;
255   iface->get_action_target_value = gtk_menu_item_get_action_target_value;
256 }
257
258 static void
259 gtk_menu_item_class_init (GtkMenuItemClass *klass)
260 {
261   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
262   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
263   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
264
265   gobject_class->dispose = gtk_menu_item_dispose;
266   gobject_class->set_property = gtk_menu_item_set_property;
267   gobject_class->get_property = gtk_menu_item_get_property;
268
269   widget_class->destroy = gtk_menu_item_destroy;
270   widget_class->size_allocate = gtk_menu_item_size_allocate;
271   widget_class->draw = gtk_menu_item_draw;
272   widget_class->realize = gtk_menu_item_realize;
273   widget_class->unrealize = gtk_menu_item_unrealize;
274   widget_class->map = gtk_menu_item_map;
275   widget_class->unmap = gtk_menu_item_unmap;
276   widget_class->enter_notify_event = gtk_menu_item_enter;
277   widget_class->leave_notify_event = gtk_menu_item_leave;
278   widget_class->show_all = gtk_menu_item_show_all;
279   widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate;
280   widget_class->parent_set = gtk_menu_item_parent_set;
281   widget_class->can_activate_accel = gtk_menu_item_can_activate_accel;
282   widget_class->get_preferred_width = gtk_menu_item_get_preferred_width;
283   widget_class->get_preferred_height = gtk_menu_item_get_preferred_height;
284   widget_class->get_preferred_height_for_width = gtk_menu_item_get_preferred_height_for_width;
285
286   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_MENU_ITEM_ACCESSIBLE);
287
288   container_class->forall = gtk_menu_item_forall;
289
290   klass->activate = gtk_real_menu_item_activate;
291   klass->activate_item = gtk_real_menu_item_activate_item;
292   klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
293   klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
294   klass->set_label = gtk_real_menu_item_set_label;
295   klass->get_label = gtk_real_menu_item_get_label;
296   klass->select = gtk_real_menu_item_select;
297   klass->deselect = gtk_real_menu_item_deselect;
298
299   klass->hide_on_activate = TRUE;
300
301   /**
302    * GtkMenuItem::activate:
303    * @menuitem: the object which received the signal.
304    *
305    * Emitted when the item is activated.
306    */
307   menu_item_signals[ACTIVATE] =
308     g_signal_new (I_("activate"),
309                   G_OBJECT_CLASS_TYPE (gobject_class),
310                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
311                   G_STRUCT_OFFSET (GtkMenuItemClass, activate),
312                   NULL, NULL,
313                   _gtk_marshal_VOID__VOID,
314                   G_TYPE_NONE, 0);
315   widget_class->activate_signal = menu_item_signals[ACTIVATE];
316
317   /**
318    * GtkMenuItem::activate-item:
319    * @menuitem: the object which received the signal.
320    *
321    * Emitted when the item is activated, but also if the menu item has a
322    * submenu. For normal applications, the relevant signal is
323    * #GtkMenuItem::activate.
324    */
325   menu_item_signals[ACTIVATE_ITEM] =
326     g_signal_new (I_("activate-item"),
327                   G_OBJECT_CLASS_TYPE (gobject_class),
328                   G_SIGNAL_RUN_FIRST,
329                   G_STRUCT_OFFSET (GtkMenuItemClass, activate_item),
330                   NULL, NULL,
331                   _gtk_marshal_VOID__VOID,
332                   G_TYPE_NONE, 0);
333
334   menu_item_signals[TOGGLE_SIZE_REQUEST] =
335     g_signal_new (I_("toggle-size-request"),
336                   G_OBJECT_CLASS_TYPE (gobject_class),
337                   G_SIGNAL_RUN_FIRST,
338                   G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request),
339                   NULL, NULL,
340                   _gtk_marshal_VOID__POINTER,
341                   G_TYPE_NONE, 1,
342                   G_TYPE_POINTER);
343
344   menu_item_signals[TOGGLE_SIZE_ALLOCATE] =
345     g_signal_new (I_("toggle-size-allocate"),
346                   G_OBJECT_CLASS_TYPE (gobject_class),
347                   G_SIGNAL_RUN_FIRST,
348                   G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate),
349                   NULL, NULL,
350                   _gtk_marshal_VOID__INT,
351                   G_TYPE_NONE, 1,
352                   G_TYPE_INT);
353
354   menu_item_signals[SELECT] =
355     g_signal_new (I_("select"),
356                   G_OBJECT_CLASS_TYPE (gobject_class),
357                   G_SIGNAL_RUN_FIRST,
358                   G_STRUCT_OFFSET (GtkMenuItemClass, select),
359                   NULL, NULL,
360                   _gtk_marshal_VOID__VOID,
361                   G_TYPE_NONE, 0);
362
363   menu_item_signals[DESELECT] =
364     g_signal_new (I_("deselect"),
365                   G_OBJECT_CLASS_TYPE (gobject_class),
366                   G_SIGNAL_RUN_FIRST,
367                   G_STRUCT_OFFSET (GtkMenuItemClass, deselect),
368                   NULL, NULL,
369                   _gtk_marshal_VOID__VOID,
370                   G_TYPE_NONE, 0);
371
372   /**
373    * GtkMenuItem:right-justified:
374    *
375    * Sets whether the menu item appears justified
376    * at the right side of a menu bar.
377    *
378    * Since: 2.14
379    */
380   g_object_class_install_property (gobject_class,
381                                    PROP_RIGHT_JUSTIFIED,
382                                    g_param_spec_boolean ("right-justified",
383                                                          P_("Right Justified"),
384                                                          P_("Sets whether the menu item appears justified at the right side of a menu bar"),
385                                                          FALSE,
386                                                          GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
387
388   /**
389    * GtkMenuItem:submenu:
390    *
391    * The submenu attached to the menu item, or %NULL if it has none.
392    *
393    * Since: 2.12
394    */
395   g_object_class_install_property (gobject_class,
396                                    PROP_SUBMENU,
397                                    g_param_spec_object ("submenu",
398                                                         P_("Submenu"),
399                                                         P_("The submenu attached to the menu item, or NULL if it has none"),
400                                                         GTK_TYPE_MENU,
401                                                         GTK_PARAM_READWRITE));
402
403   /**
404    * GtkMenuItem:accel-path:
405    *
406    * Sets the accelerator path of the menu item, through which runtime
407    * changes of the menu item's accelerator caused by the user can be
408    * identified and saved to persistant storage.
409    *
410    * Since: 2.14
411    */
412   g_object_class_install_property (gobject_class,
413                                    PROP_ACCEL_PATH,
414                                    g_param_spec_string ("accel-path",
415                                                         P_("Accel Path"),
416                                                         P_("Sets the accelerator path of the menu item"),
417                                                         NULL,
418                                                         GTK_PARAM_READWRITE));
419
420   /**
421    * GtkMenuItem:label:
422    *
423    * The text for the child label.
424    *
425    * Since: 2.16
426    */
427   g_object_class_install_property (gobject_class,
428                                    PROP_LABEL,
429                                    g_param_spec_string ("label",
430                                                         P_("Label"),
431                                                         P_("The text for the child label"),
432                                                         "",
433                                                         GTK_PARAM_READWRITE));
434
435   /**
436    * GtkMenuItem:use-underline:
437    *
438    * %TRUE if underlines in the text indicate mnemonics.
439    *
440    * Since: 2.16
441    */
442   g_object_class_install_property (gobject_class,
443                                    PROP_USE_UNDERLINE,
444                                    g_param_spec_boolean ("use-underline",
445                                                          P_("Use underline"),
446                                                          P_("If set, an underline in the text indicates "
447                                                             "the next character should be used for the "
448                                                             "mnemonic accelerator key"),
449                                                          FALSE,
450                                                          GTK_PARAM_READWRITE));
451
452   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
453   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
454
455   g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
456   g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");
457
458   gtk_widget_class_install_style_property_parser (widget_class,
459                                                   g_param_spec_enum ("selected-shadow-type",
460                                                                      "Selected Shadow Type",
461                                                                      "Shadow type when item is selected",
462                                                                      GTK_TYPE_SHADOW_TYPE,
463                                                                      GTK_SHADOW_NONE,
464                                                                      GTK_PARAM_READABLE),
465                                                   gtk_rc_property_parse_enum);
466
467   /**
468    * GtkMenuItem:horizontal-padding:
469    *
470    * Padding to left and right of the menu item.
471    *
472    * Deprecated: 3.8: use the standard padding CSS property (through objects
473    *   like #GtkStyleContext and #GtkCssProvider); the value of this style
474    *   property is ignored.
475    */
476   gtk_widget_class_install_style_property (widget_class,
477                                            g_param_spec_int ("horizontal-padding",
478                                                              "Horizontal Padding",
479                                                              "Padding to left and right of the menu item",
480                                                              0,
481                                                              G_MAXINT,
482                                                              0,
483                                                              GTK_PARAM_READABLE |
484                                                              G_PARAM_DEPRECATED));
485
486   gtk_widget_class_install_style_property (widget_class,
487                                            g_param_spec_int ("toggle-spacing",
488                                                              "Icon Spacing",
489                                                              "Space between icon and label",
490                                                              0,
491                                                              G_MAXINT,
492                                                              5,
493                                                              GTK_PARAM_READABLE));
494
495   gtk_widget_class_install_style_property (widget_class,
496                                            g_param_spec_int ("arrow-spacing",
497                                                              "Arrow Spacing",
498                                                              "Space between label and arrow",
499                                                              0,
500                                                              G_MAXINT,
501                                                              10,
502                                                              GTK_PARAM_READABLE));
503
504   gtk_widget_class_install_style_property (widget_class,
505                                            g_param_spec_float ("arrow-scaling",
506                                                                P_("Arrow Scaling"),
507                                                                P_("Amount of space used up by arrow, relative to the menu item's font size"),
508                                                                0.0, 2.0, 0.8,
509                                                                GTK_PARAM_READABLE));
510
511   /**
512    * GtkMenuItem:width-chars:
513    *
514    * The minimum desired width of the menu item in characters.
515    *
516    * Since: 2.14
517    */
518   gtk_widget_class_install_style_property (widget_class,
519                                            g_param_spec_int ("width-chars",
520                                                              P_("Width in Characters"),
521                                                              P_("The minimum desired width of the menu item in characters"),
522                                                              0, G_MAXINT, 12,
523                                                              GTK_PARAM_READABLE));
524
525   g_type_class_add_private (klass, sizeof (GtkMenuItemPrivate));
526 }
527
528 static void
529 gtk_menu_item_init (GtkMenuItem *menu_item)
530 {
531   GtkStyleContext *context;
532   GtkMenuItemPrivate *priv;
533
534   priv = G_TYPE_INSTANCE_GET_PRIVATE (menu_item,
535                                       GTK_TYPE_MENU_ITEM,
536                                       GtkMenuItemPrivate);
537   menu_item->priv = priv;
538
539   gtk_widget_set_has_window (GTK_WIDGET (menu_item), FALSE);
540
541   priv->action = NULL;
542   priv->use_action_appearance = TRUE;
543   
544   menu_item->priv->submenu = NULL;
545   menu_item->priv->toggle_size = 0;
546   menu_item->priv->accelerator_width = 0;
547   if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
548     priv->submenu_direction = GTK_DIRECTION_LEFT;
549   else
550     priv->submenu_direction = GTK_DIRECTION_RIGHT;
551   priv->submenu_placement = GTK_TOP_BOTTOM;
552   priv->right_justify = FALSE;
553   priv->use_action_appearance = TRUE;
554   priv->timer = 0;
555   priv->action = NULL;
556
557   context = gtk_widget_get_style_context (GTK_WIDGET (menu_item));
558   gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUITEM);
559 }
560
561 /**
562  * gtk_menu_item_new:
563  *
564  * Creates a new #GtkMenuItem.
565  *
566  * Returns: the newly created #GtkMenuItem
567  */
568 GtkWidget*
569 gtk_menu_item_new (void)
570 {
571   return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
572 }
573
574 /**
575  * gtk_menu_item_new_with_label:
576  * @label: the text for the label
577  *
578  * Creates a new #GtkMenuItem whose child is a #GtkLabel.
579  *
580  * Returns: the newly created #GtkMenuItem
581  */
582 GtkWidget*
583 gtk_menu_item_new_with_label (const gchar *label)
584 {
585   return g_object_new (GTK_TYPE_MENU_ITEM,
586                        "label", label,
587                        NULL);
588 }
589
590
591 /**
592  * gtk_menu_item_new_with_mnemonic:
593  * @label: The text of the button, with an underscore in front of the
594  *     mnemonic character
595  *
596  * Creates a new #GtkMenuItem containing a label.
597  *
598  * The label will be created using gtk_label_new_with_mnemonic(),
599  * so underscores in @label indicate the mnemonic for the menu item.
600  *
601  * Returns: a new #GtkMenuItem
602  */
603 GtkWidget*
604 gtk_menu_item_new_with_mnemonic (const gchar *label)
605 {
606   return g_object_new (GTK_TYPE_MENU_ITEM,
607                        "use-underline", TRUE,
608                        "label", label,
609                        NULL);
610 }
611
612 static void
613 gtk_menu_item_dispose (GObject *object)
614 {
615   GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
616   GtkMenuItemPrivate *priv = menu_item->priv;
617
618   g_clear_object (&priv->action_helper);
619
620   if (priv->action)
621     {
622       gtk_action_disconnect_accelerator (priv->action);
623       gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), NULL);
624       priv->action = NULL;
625     }
626   G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object);
627 }
628
629 static void
630 gtk_menu_item_do_set_right_justified (GtkMenuItem *menu_item,
631                                       gboolean     right_justified)
632 {
633   GtkMenuItemPrivate *priv = menu_item->priv;
634
635   right_justified = right_justified != FALSE;
636
637   if (priv->right_justify != right_justified)
638     {
639       priv->right_justify = right_justified;
640       gtk_widget_queue_resize (GTK_WIDGET (menu_item));
641     }
642 }
643
644 static void
645 gtk_menu_item_set_property (GObject      *object,
646                             guint         prop_id,
647                             const GValue *value,
648                             GParamSpec   *pspec)
649 {
650   GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
651
652   switch (prop_id)
653     {
654     case PROP_RIGHT_JUSTIFIED:
655       gtk_menu_item_do_set_right_justified (menu_item, g_value_get_boolean (value));
656       break;
657     case PROP_SUBMENU:
658       gtk_menu_item_set_submenu (menu_item, g_value_get_object (value));
659       break;
660     case PROP_ACCEL_PATH:
661       gtk_menu_item_set_accel_path (menu_item, g_value_get_string (value));
662       break;
663     case PROP_LABEL:
664       gtk_menu_item_set_label (menu_item, g_value_get_string (value));
665       break;
666     case PROP_USE_UNDERLINE:
667       gtk_menu_item_set_use_underline (menu_item, g_value_get_boolean (value));
668       break;
669     case PROP_ACTIVATABLE_RELATED_ACTION:
670       gtk_menu_item_set_related_action (menu_item, g_value_get_object (value));
671       break;
672     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
673       gtk_menu_item_set_use_action_appearance (menu_item, g_value_get_boolean (value));
674       break;
675     case PROP_ACTION_NAME:
676       gtk_menu_item_set_action_name (GTK_ACTIONABLE (menu_item), g_value_get_string (value));
677       break;
678     case PROP_ACTION_TARGET:
679       gtk_menu_item_set_action_target_value (GTK_ACTIONABLE (menu_item), g_value_get_variant (value));
680       break;
681     default:
682       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
683       break;
684     }
685 }
686
687 static void
688 gtk_menu_item_get_property (GObject    *object,
689                             guint       prop_id,
690                             GValue     *value,
691                             GParamSpec *pspec)
692 {
693   GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
694   GtkMenuItemPrivate *priv = menu_item->priv;
695
696   switch (prop_id)
697     {
698     case PROP_RIGHT_JUSTIFIED:
699       g_value_set_boolean (value, menu_item->priv->right_justify);
700       break;
701     case PROP_SUBMENU:
702       g_value_set_object (value, gtk_menu_item_get_submenu (menu_item));
703       break;
704     case PROP_ACCEL_PATH:
705       g_value_set_string (value, gtk_menu_item_get_accel_path (menu_item));
706       break;
707     case PROP_LABEL:
708       g_value_set_string (value, gtk_menu_item_get_label (menu_item));
709       break;
710     case PROP_USE_UNDERLINE:
711       g_value_set_boolean (value, gtk_menu_item_get_use_underline (menu_item));
712       break;
713     case PROP_ACTIVATABLE_RELATED_ACTION:
714       g_value_set_object (value, priv->action);
715       break;
716     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
717       g_value_set_boolean (value, priv->use_action_appearance);
718       break;
719     case PROP_ACTION_NAME:
720       g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper));
721       break;
722     case PROP_ACTION_TARGET:
723       g_value_set_variant (value, gtk_action_helper_get_action_target_value (priv->action_helper));
724       break;
725     default:
726       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
727       break;
728     }
729 }
730
731 static void
732 gtk_menu_item_destroy (GtkWidget *widget)
733 {
734   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
735   GtkMenuItemPrivate *priv = menu_item->priv;
736
737   if (priv->submenu)
738     gtk_widget_destroy (priv->submenu);
739
740   GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->destroy (widget);
741 }
742
743 static void
744 gtk_menu_item_detacher (GtkWidget *widget,
745                         GtkMenu   *menu)
746 {
747   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
748   GtkMenuItemPrivate *priv = menu_item->priv;
749
750   g_return_if_fail (priv->submenu == (GtkWidget*) menu);
751
752   priv->submenu = NULL;
753 }
754
755 static void
756 get_arrow_size (GtkWidget *widget,
757                 GtkWidget *child,
758                 gint      *size,
759                 gint      *spacing)
760 {
761   PangoContext     *context;
762   PangoFontMetrics *metrics;
763   gfloat            arrow_scaling;
764   gint              arrow_spacing;
765
766   g_assert (size);
767
768   gtk_widget_style_get (widget,
769                         "arrow-scaling", &arrow_scaling,
770                         "arrow-spacing", &arrow_spacing,
771                         NULL);
772
773   if (spacing != NULL)
774     *spacing = arrow_spacing;
775
776   context = gtk_widget_get_pango_context (child);
777
778   metrics = pango_context_get_metrics (context,
779                                        pango_context_get_font_description (context),
780                                        pango_context_get_language (context));
781
782   *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
783                          pango_font_metrics_get_descent (metrics)));
784
785   pango_font_metrics_unref (metrics);
786
787   *size = *size * arrow_scaling;
788 }
789
790
791 static void
792 gtk_menu_item_accel_width_foreach (GtkWidget *widget,
793                                    gpointer   data)
794 {
795   guint *width = data;
796
797   if (GTK_IS_ACCEL_LABEL (widget))
798     {
799       guint w;
800
801       w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
802       *width = MAX (*width, w);
803     }
804   else if (GTK_IS_CONTAINER (widget))
805     gtk_container_foreach (GTK_CONTAINER (widget),
806                            gtk_menu_item_accel_width_foreach,
807                            data);
808 }
809
810 static gint
811 get_minimum_width (GtkWidget *widget)
812 {
813   PangoContext *context;
814   PangoFontMetrics *metrics;
815   gint width;
816   gint width_chars;
817
818   context = gtk_widget_get_pango_context (widget);
819
820   metrics = pango_context_get_metrics (context,
821                                        pango_context_get_font_description (context),
822                                        pango_context_get_language (context));
823
824   width = pango_font_metrics_get_approximate_char_width (metrics);
825
826   pango_font_metrics_unref (metrics);
827
828   gtk_widget_style_get (widget, "width-chars", &width_chars, NULL);
829
830   return PANGO_PIXELS (width_chars * width);
831 }
832
833 static void
834 gtk_menu_item_get_preferred_width (GtkWidget *widget,
835                                    gint      *minimum_size,
836                                    gint      *natural_size)
837 {
838   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
839   GtkMenuItemPrivate *priv = menu_item->priv;
840   GtkBin *bin;
841   GtkWidget *child;
842   GtkWidget *parent;
843   guint accel_width;
844   guint border_width;
845   gint  min_width, nat_width;
846   GtkStyleContext *context;
847   GtkStateFlags state;
848   GtkBorder padding;
849
850   min_width = nat_width = 0;
851   bin = GTK_BIN (widget);
852   parent = gtk_widget_get_parent (widget);
853
854   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
855
856   context = gtk_widget_get_style_context (widget);
857   state = gtk_widget_get_state_flags (widget);
858   gtk_style_context_get_padding (context, state, &padding);
859
860   min_width = (border_width * 2) + padding.left + padding.right;
861   nat_width = min_width;
862
863   child = gtk_bin_get_child (bin);
864
865   if (child != NULL && gtk_widget_get_visible (child))
866     {
867       GtkMenuItemPrivate *priv = menu_item->priv;
868       gint child_min, child_nat;
869
870       gtk_widget_get_preferred_width (child, &child_min, &child_nat);
871
872       if ((menu_item->priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
873         {
874           gint arrow_spacing, arrow_size;
875
876           get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
877
878           min_width += arrow_size;
879           min_width += arrow_spacing;
880
881           min_width = MAX (min_width, get_minimum_width (widget));
882           nat_width = min_width;
883         }
884
885       min_width += child_min;
886       nat_width += child_nat;
887     }
888
889   accel_width = 0;
890   gtk_container_foreach (GTK_CONTAINER (menu_item),
891                          gtk_menu_item_accel_width_foreach,
892                          &accel_width);
893   priv->accelerator_width = accel_width;
894
895   if (minimum_size)
896     *minimum_size = min_width;
897
898   if (natural_size)
899     *natural_size = nat_width;
900 }
901
902 static void
903 gtk_menu_item_real_get_height (GtkWidget *widget,
904                                gint       for_size,
905                                gint      *minimum_size,
906                                gint      *natural_size)
907 {
908   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
909   GtkMenuItemPrivate *priv = menu_item->priv;
910   GtkBin *bin;
911   GtkStyleContext *context;
912   GtkStateFlags state;
913   GtkBorder padding;
914   GtkWidget *child;
915   GtkWidget *parent;
916   guint accel_width;
917   guint border_width;
918   gint min_height, nat_height;
919   gint avail_size = 0;
920
921   min_height = nat_height = 0;
922
923   context = gtk_widget_get_style_context (widget);
924   state = gtk_widget_get_state_flags (widget);
925   gtk_style_context_get_padding (context, state, &padding);
926
927   bin = GTK_BIN (widget);
928   parent = gtk_widget_get_parent (widget);
929
930   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
931   min_height   = (border_width * 2) + padding.top + padding.bottom;
932
933   if (for_size != -1)
934     {
935       avail_size = for_size;
936       avail_size -= (border_width * 2) + padding.left + padding.right;
937     }
938
939   nat_height = min_height;
940
941   child = gtk_bin_get_child (bin);
942
943   if (child != NULL && gtk_widget_get_visible (child))
944     {
945       gint child_min, child_nat;
946       gint arrow_size = 0, arrow_spacing = 0;
947
948       if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
949         get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
950
951       if (for_size != -1)
952         {
953           avail_size -= (arrow_size + arrow_spacing);
954           gtk_widget_get_preferred_height_for_width (child,
955                                                      avail_size,
956                                                      &child_min,
957                                                      &child_nat);
958         }
959       else
960         {
961           gtk_widget_get_preferred_height (child, &child_min, &child_nat);
962         }
963
964       min_height += child_min;
965       nat_height += child_nat;
966
967       min_height = MAX (min_height, arrow_size);
968       nat_height = MAX (nat_height, arrow_size);
969     }
970   else /* separator item */
971     {
972       gboolean wide_separators;
973       gint     separator_height;
974
975       gtk_widget_style_get (widget,
976                             "wide-separators",  &wide_separators,
977                             "separator-height", &separator_height,
978                             NULL);
979
980       if (wide_separators)
981         {
982           min_height += separator_height;
983           nat_height += separator_height;
984         }
985       else
986         {
987           /* force odd, so that we can have the same space above and
988            * below the line.
989            */
990           if (min_height % 2 == 0)
991             min_height += 1;
992           if (nat_height % 2 == 0)
993             nat_height += 1;
994         }
995     }
996
997   accel_width = 0;
998   gtk_container_foreach (GTK_CONTAINER (menu_item),
999                          gtk_menu_item_accel_width_foreach,
1000                          &accel_width);
1001   priv->accelerator_width = accel_width;
1002
1003   if (minimum_size)
1004     *minimum_size = min_height;
1005
1006   if (natural_size)
1007     *natural_size = nat_height;
1008 }
1009
1010 static void
1011 gtk_menu_item_get_preferred_height (GtkWidget *widget,
1012                                     gint      *minimum_size,
1013                                     gint      *natural_size)
1014 {
1015   gtk_menu_item_real_get_height (widget, -1, minimum_size, natural_size);
1016 }
1017
1018 static void
1019 gtk_menu_item_get_preferred_height_for_width (GtkWidget *widget,
1020                                               gint       for_size,
1021                                               gint      *minimum_size,
1022                                               gint      *natural_size)
1023 {
1024   gtk_menu_item_real_get_height (widget, for_size, minimum_size, natural_size);
1025 }
1026
1027 static void
1028 gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface)
1029 {
1030   parent_buildable_iface = g_type_interface_peek_parent (iface);
1031   iface->add_child = gtk_menu_item_buildable_add_child;
1032   iface->custom_finished = gtk_menu_item_buildable_custom_finished;
1033 }
1034
1035 static void
1036 gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
1037                                    GtkBuilder   *builder,
1038                                    GObject      *child,
1039                                    const gchar  *type)
1040 {
1041   if (type && strcmp (type, "submenu") == 0)
1042         gtk_menu_item_set_submenu (GTK_MENU_ITEM (buildable),
1043                                    GTK_WIDGET (child));
1044   else
1045     parent_buildable_iface->add_child (buildable, builder, child, type);
1046 }
1047
1048
1049 static void
1050 gtk_menu_item_buildable_custom_finished (GtkBuildable *buildable,
1051                                          GtkBuilder   *builder,
1052                                          GObject      *child,
1053                                          const gchar  *tagname,
1054                                          gpointer      user_data)
1055 {
1056   GtkWidget *toplevel;
1057
1058   if (strcmp (tagname, "accelerator") == 0)
1059     {
1060       GtkMenuShell *menu_shell;
1061       GtkWidget *attach;
1062
1063       menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (GTK_WIDGET (buildable)));
1064       if (menu_shell)
1065         {
1066           while (GTK_IS_MENU (menu_shell) &&
1067                  (attach = gtk_menu_get_attach_widget (GTK_MENU (menu_shell))) != NULL)
1068             menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (attach));
1069
1070           toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu_shell));
1071         }
1072       else
1073         {
1074           /* Fall back to something ... */
1075           toplevel = gtk_widget_get_toplevel (GTK_WIDGET (buildable));
1076
1077           g_warning ("found a GtkMenuItem '%s' without a parent GtkMenuShell, assigned accelerators wont work.",
1078                      gtk_buildable_get_name (buildable));
1079         }
1080
1081       /* Feed the correct toplevel to the GtkWidget accelerator parsing code */
1082       _gtk_widget_buildable_finish_accelerator (GTK_WIDGET (buildable), toplevel, user_data);
1083     }
1084   else
1085     parent_buildable_iface->custom_finished (buildable, builder, child, tagname, user_data);
1086 }
1087
1088
1089 static void
1090 gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface)
1091 {
1092   iface->update = gtk_menu_item_update;
1093   iface->sync_action_properties = gtk_menu_item_sync_action_properties;
1094 }
1095
1096 static void
1097 activatable_update_label (GtkMenuItem *menu_item, GtkAction *action)
1098 {
1099   GtkWidget *child;
1100
1101   child = gtk_bin_get_child (GTK_BIN (menu_item));
1102
1103   if (GTK_IS_LABEL (child))
1104     {
1105       const gchar *label;
1106
1107       label = gtk_action_get_label (action);
1108       gtk_menu_item_set_label (menu_item, label);
1109     }
1110 }
1111
1112 /*
1113  * gtk_menu_is_empty:
1114  * @menu: (allow-none): a #GtkMenu or %NULL
1115  * 
1116  * Determines whether @menu is empty. A menu is considered empty if it
1117  * the only visible children are tearoff menu items or "filler" menu 
1118  * items which were inserted to mark the menu as empty.
1119  * 
1120  * This function is used by #GtkAction.
1121  *
1122  * Return value: whether @menu is empty.
1123  **/
1124 static gboolean
1125 gtk_menu_is_empty (GtkWidget *menu)
1126 {
1127   GList *children, *cur;
1128   gboolean result = TRUE;
1129
1130   g_return_val_if_fail (menu == NULL || GTK_IS_MENU (menu), TRUE);
1131
1132   if (!menu)
1133     return FALSE;
1134
1135   children = gtk_container_get_children (GTK_CONTAINER (menu));
1136
1137   cur = children;
1138   while (cur) 
1139     {
1140       if (gtk_widget_get_visible (cur->data))
1141         {
1142           if (!GTK_IS_TEAROFF_MENU_ITEM (cur->data) &&
1143               !g_object_get_data (cur->data, "gtk-empty-menu-item"))
1144             {
1145               result = FALSE;
1146               break;
1147             }
1148         }
1149       cur = cur->next;
1150     }
1151   g_list_free (children);
1152
1153   return result;
1154 }
1155
1156
1157 static void
1158 gtk_menu_item_update (GtkActivatable *activatable,
1159                       GtkAction      *action,
1160                       const gchar    *property_name)
1161 {
1162   GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
1163   GtkMenuItemPrivate *priv = menu_item->priv;
1164
1165   if (strcmp (property_name, "visible") == 0)
1166     _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
1167                                    gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
1168   else if (strcmp (property_name, "sensitive") == 0)
1169     gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
1170   else if (priv->use_action_appearance)
1171     {
1172       if (strcmp (property_name, "label") == 0)
1173         activatable_update_label (menu_item, action);
1174     }
1175 }
1176
1177 static void
1178 gtk_menu_item_sync_action_properties (GtkActivatable *activatable,
1179                                       GtkAction      *action)
1180 {
1181   GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
1182   GtkMenuItemPrivate *priv = menu_item->priv;
1183   GtkWidget *label;
1184
1185   if (!priv->use_action_appearance || !action)
1186     {
1187       label = gtk_bin_get_child (GTK_BIN (menu_item));
1188
1189       if (GTK_IS_ACCEL_LABEL (label))
1190         gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), GTK_WIDGET (menu_item));
1191     }
1192
1193   if (!action)
1194     return;
1195
1196   _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
1197                                  gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
1198
1199   gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
1200
1201   if (priv->use_action_appearance)
1202     {
1203       label = gtk_bin_get_child (GTK_BIN (menu_item));
1204
1205       /* make sure label is a label, deleting it otherwise */
1206       if (label && !GTK_IS_LABEL (label))
1207         {
1208           gtk_container_remove (GTK_CONTAINER (menu_item), label);
1209           label = NULL;
1210         }
1211       /* Make sure that menu_item has a label and that any
1212        * accelerators are set */
1213       gtk_menu_item_ensure_label (menu_item);
1214       gtk_menu_item_set_use_underline (menu_item, TRUE);
1215       /* Make label point to the menu_item's label */
1216       label = gtk_bin_get_child (GTK_BIN (menu_item));
1217
1218       if (GTK_IS_ACCEL_LABEL (label) && gtk_action_get_accel_path (action))
1219         {
1220           gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), NULL);
1221           gtk_accel_label_set_accel_closure (GTK_ACCEL_LABEL (label),
1222                                              gtk_action_get_accel_closure (action));
1223         }
1224
1225       activatable_update_label (menu_item, action);
1226     }
1227 }
1228
1229 static void
1230 gtk_menu_item_set_related_action (GtkMenuItem *menu_item,
1231                                   GtkAction   *action)
1232 {
1233     GtkMenuItemPrivate *priv = menu_item->priv;
1234
1235     if (priv->action == action)
1236       return;
1237
1238     if (priv->action)
1239       {
1240         gtk_action_disconnect_accelerator (priv->action);
1241       }
1242
1243     if (action)
1244       {
1245         const gchar *accel_path;
1246
1247         accel_path = gtk_action_get_accel_path (action);
1248         if (accel_path)
1249           {
1250             gtk_action_connect_accelerator (action);
1251             gtk_menu_item_set_accel_path (menu_item, accel_path);
1252           }
1253       }
1254
1255     gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), action);
1256
1257     priv->action = action;
1258 }
1259
1260 static void
1261 gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item,
1262                                          gboolean     use_appearance)
1263 {
1264     GtkMenuItemPrivate *priv = menu_item->priv;
1265
1266     if (priv->use_action_appearance != use_appearance)
1267       {
1268         priv->use_action_appearance = use_appearance;
1269
1270         gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (menu_item), priv->action);
1271       }
1272 }
1273
1274
1275 /**
1276  * gtk_menu_item_set_submenu:
1277  * @menu_item: a #GtkMenuItem
1278  * @submenu: (allow-none): the submenu, or %NULL
1279  *
1280  * Sets or replaces the menu item's submenu, or removes it when a %NULL
1281  * submenu is passed.
1282  */
1283 void
1284 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
1285                            GtkWidget   *submenu)
1286 {
1287   GtkMenuItemPrivate *priv = menu_item->priv;
1288
1289   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1290   g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu));
1291
1292   if (priv->submenu != submenu)
1293     {
1294       if (priv->submenu)
1295         gtk_menu_detach (GTK_MENU (priv->submenu));
1296
1297       if (submenu)
1298         {
1299           priv->submenu = submenu;
1300           gtk_menu_attach_to_widget (GTK_MENU (submenu),
1301                                      GTK_WIDGET (menu_item),
1302                                      gtk_menu_item_detacher);
1303         }
1304
1305       if (gtk_widget_get_parent (GTK_WIDGET (menu_item)))
1306         gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1307
1308       g_object_notify (G_OBJECT (menu_item), "submenu");
1309     }
1310 }
1311
1312 /**
1313  * gtk_menu_item_get_submenu:
1314  * @menu_item: a #GtkMenuItem
1315  *
1316  * Gets the submenu underneath this menu item, if any.
1317  * See gtk_menu_item_set_submenu().
1318  *
1319  * Return value: (transfer none): submenu for this menu item, or %NULL if none
1320  */
1321 GtkWidget *
1322 gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
1323 {
1324   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
1325
1326   return menu_item->priv->submenu;
1327 }
1328
1329 void _gtk_menu_item_set_placement (GtkMenuItem         *menu_item,
1330                                    GtkSubmenuPlacement  placement);
1331
1332 void
1333 _gtk_menu_item_set_placement (GtkMenuItem         *menu_item,
1334                              GtkSubmenuPlacement  placement)
1335 {
1336   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1337
1338   menu_item->priv->submenu_placement = placement;
1339 }
1340
1341 void
1342 gtk_menu_item_select (GtkMenuItem *menu_item)
1343 {
1344   GtkWidget *parent;
1345
1346   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1347
1348   g_signal_emit (menu_item, menu_item_signals[SELECT], 0);
1349
1350   /* Enable themeing of the parent menu item depending on whether
1351    * something is selected in its submenu
1352    */
1353   parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1354   if (GTK_IS_MENU (parent))
1355     {
1356       GtkMenu *menu = GTK_MENU (parent);
1357
1358       if (menu->priv->parent_menu_item)
1359         gtk_widget_queue_draw (GTK_WIDGET (menu->priv->parent_menu_item));
1360     }
1361 }
1362
1363 /**
1364  * gtk_menu_item_deselect:
1365  * @menu_item: the menu item
1366  *
1367  * Emits the #GtkMenuItem::deselect signal on the given item. Behaves
1368  * exactly like #gtk_item_deselect.
1369  */
1370 void
1371 gtk_menu_item_deselect (GtkMenuItem *menu_item)
1372 {
1373   GtkWidget *parent;
1374
1375   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1376
1377   g_signal_emit (menu_item, menu_item_signals[DESELECT], 0);
1378
1379   /* Enable themeing of the parent menu item depending on whether
1380    * something is selected in its submenu
1381    */
1382   parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1383   if (GTK_IS_MENU (parent))
1384     {
1385       GtkMenu *menu = GTK_MENU (parent);
1386
1387       if (menu->priv->parent_menu_item)
1388         gtk_widget_queue_draw (GTK_WIDGET (menu->priv->parent_menu_item));
1389     }
1390 }
1391
1392 /**
1393  * gtk_menu_item_activate:
1394  * @menu_item: the menu item
1395  *
1396  * Emits the #GtkMenuItem::activate signal on the given item
1397  */
1398 void
1399 gtk_menu_item_activate (GtkMenuItem *menu_item)
1400 {
1401   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1402
1403   g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
1404 }
1405
1406 /**
1407  * gtk_menu_item_toggle_size_request:
1408  * @menu_item: the menu item
1409  * @requisition: the requisition to use as signal data.
1410  *
1411  * Emits the #GtkMenuItem::toggle-size-request signal on the given item.
1412  */
1413 void
1414 gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1415                                    gint        *requisition)
1416 {
1417   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1418
1419   g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
1420 }
1421
1422 /**
1423  * gtk_menu_item_toggle_size_allocate:
1424  * @menu_item: the menu item.
1425  * @allocation: the allocation to use as signal data.
1426  *
1427  * Emits the #GtkMenuItem::toggle-size-allocate signal on the given item.
1428  */
1429 void
1430 gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1431                                     gint         allocation)
1432 {
1433   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1434
1435   g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
1436 }
1437
1438 static void
1439 gtk_menu_item_size_allocate (GtkWidget     *widget,
1440                              GtkAllocation *allocation)
1441 {
1442   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1443   GtkMenuItemPrivate *priv = menu_item->priv;
1444   GtkBin *bin;
1445   GtkAllocation child_allocation;
1446   GtkTextDirection direction;
1447   GtkPackDirection child_pack_dir;
1448   GtkWidget *child;
1449   GtkWidget *parent;
1450
1451   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1452   g_return_if_fail (allocation != NULL);
1453
1454   bin = GTK_BIN (widget);
1455
1456   direction = gtk_widget_get_direction (widget);
1457
1458   parent = gtk_widget_get_parent (widget);
1459   if (GTK_IS_MENU_BAR (parent))
1460     {
1461       child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
1462     }
1463   else
1464     {
1465       child_pack_dir = GTK_PACK_DIRECTION_LTR;
1466     }
1467
1468   gtk_widget_set_allocation (widget, allocation);
1469
1470   child = gtk_bin_get_child (bin);
1471   if (child)
1472     {
1473       GtkStyleContext *context;
1474       GtkStateFlags state;
1475       GtkBorder padding;
1476       guint border_width;
1477
1478       context = gtk_widget_get_style_context (widget);
1479       state = gtk_widget_get_state_flags (widget);
1480       gtk_style_context_get_padding (context, state, &padding);
1481
1482       border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1483       child_allocation.x = border_width + padding.left;
1484       child_allocation.y = border_width + padding.top;
1485
1486       child_allocation.width = allocation->width - (border_width * 2) -
1487         padding.left - padding.right;
1488       child_allocation.height = allocation->height - (border_width * 2) -
1489         padding.top - padding.bottom;
1490
1491       if (child_pack_dir == GTK_PACK_DIRECTION_LTR ||
1492           child_pack_dir == GTK_PACK_DIRECTION_RTL)
1493         {
1494           if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL))
1495             child_allocation.x += priv->toggle_size;
1496           child_allocation.width -= priv->toggle_size;
1497         }
1498       else
1499         {
1500           if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT))
1501             child_allocation.y += priv->toggle_size;
1502           child_allocation.height -= priv->toggle_size;
1503         }
1504
1505       child_allocation.x += allocation->x;
1506       child_allocation.y += allocation->y;
1507
1508       if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
1509         {
1510           gint arrow_spacing, arrow_size;
1511
1512           get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
1513
1514           if (direction == GTK_TEXT_DIR_RTL)
1515             child_allocation.x += arrow_size + arrow_spacing;
1516           child_allocation.width -= arrow_size + arrow_spacing;
1517         }
1518       
1519       if (child_allocation.width < 1)
1520         child_allocation.width = 1;
1521
1522       gtk_widget_size_allocate (child, &child_allocation);
1523     }
1524
1525   if (gtk_widget_get_realized (widget))
1526     gdk_window_move_resize (priv->event_window,
1527                             allocation->x, allocation->y,
1528                             allocation->width, allocation->height);
1529
1530   if (priv->submenu)
1531     gtk_menu_reposition (GTK_MENU (priv->submenu));
1532 }
1533
1534 static void
1535 gtk_menu_item_realize (GtkWidget *widget)
1536 {
1537   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1538   GtkMenuItemPrivate *priv = menu_item->priv;
1539   GtkAllocation allocation;
1540   GdkWindow *window;
1541   GdkWindowAttr attributes;
1542   gint attributes_mask;
1543
1544   gtk_widget_set_realized (widget, TRUE);
1545
1546   window = gtk_widget_get_parent_window (widget);
1547   gtk_widget_set_window (widget, window);
1548   g_object_ref (window);
1549
1550   gtk_widget_get_allocation (widget, &allocation);
1551
1552   attributes.x = allocation.x;
1553   attributes.y = allocation.y;
1554   attributes.width = allocation.width;
1555   attributes.height = allocation.height;
1556   attributes.window_type = GDK_WINDOW_CHILD;
1557   attributes.wclass = GDK_INPUT_ONLY;
1558   attributes.event_mask = (gtk_widget_get_events (widget) |
1559                            GDK_BUTTON_PRESS_MASK |
1560                            GDK_BUTTON_RELEASE_MASK |
1561                            GDK_ENTER_NOTIFY_MASK |
1562                            GDK_LEAVE_NOTIFY_MASK |
1563                            GDK_POINTER_MOTION_MASK);
1564
1565   attributes_mask = GDK_WA_X | GDK_WA_Y;
1566
1567   priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1568                                        &attributes, attributes_mask);
1569   gtk_widget_register_window (widget, priv->event_window);
1570 }
1571
1572 static void
1573 gtk_menu_item_unrealize (GtkWidget *widget)
1574 {
1575   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1576   GtkMenuItemPrivate *priv = menu_item->priv;
1577
1578   gtk_widget_unregister_window (widget, priv->event_window);
1579   gdk_window_destroy (priv->event_window);
1580   priv->event_window = NULL;
1581
1582   GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize (widget);
1583 }
1584
1585 static void
1586 gtk_menu_item_map (GtkWidget *widget)
1587 {
1588   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1589   GtkMenuItemPrivate *priv = menu_item->priv;
1590
1591   GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget);
1592
1593   gdk_window_show (priv->event_window);
1594 }
1595
1596 static void
1597 gtk_menu_item_unmap (GtkWidget *widget)
1598 {
1599   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1600   GtkMenuItemPrivate *priv = menu_item->priv;
1601
1602   gdk_window_hide (priv->event_window);
1603
1604   GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget);
1605 }
1606
1607 static gboolean
1608 gtk_menu_item_enter (GtkWidget        *widget,
1609                      GdkEventCrossing *event)
1610 {
1611   g_return_val_if_fail (event != NULL, FALSE);
1612
1613   return gtk_widget_event (gtk_widget_get_parent (widget), (GdkEvent *) event);
1614 }
1615
1616 static gboolean
1617 gtk_menu_item_leave (GtkWidget        *widget,
1618                      GdkEventCrossing *event)
1619 {
1620   g_return_val_if_fail (event != NULL, FALSE);
1621
1622   return gtk_widget_event (gtk_widget_get_parent (widget), (GdkEvent*) event);
1623 }
1624
1625 static gboolean
1626 gtk_menu_item_draw (GtkWidget *widget,
1627                     cairo_t   *cr)
1628 {
1629   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1630   GtkMenuItemPrivate *priv = menu_item->priv;
1631   GtkStateFlags state;
1632   GtkStyleContext *context;
1633   GtkBorder padding;
1634   GtkWidget *child, *parent;
1635   gint x, y, w, h, width, height;
1636   guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1637
1638   state = gtk_widget_get_state_flags (widget);
1639   context = gtk_widget_get_style_context (widget);
1640   width = gtk_widget_get_allocated_width (widget);
1641   height = gtk_widget_get_allocated_height (widget);
1642
1643   x = border_width;
1644   y = border_width;
1645   w = width - border_width * 2;
1646   h = height - border_width * 2;
1647
1648   child = gtk_bin_get_child (GTK_BIN (menu_item));
1649   parent = gtk_widget_get_parent (widget);
1650
1651   gtk_style_context_get_padding (context, state, &padding);
1652
1653   gtk_render_background (context, cr, x, y, w, h);
1654   gtk_render_frame (context, cr, x, y, w, h);
1655
1656   if (priv->submenu && !GTK_IS_MENU_BAR (parent))
1657     {
1658       gint arrow_x, arrow_y;
1659       gint arrow_size;
1660       GtkTextDirection direction;
1661       gdouble angle;
1662
1663       direction = gtk_widget_get_direction (widget);
1664       get_arrow_size (widget, child, &arrow_size, NULL);
1665
1666       if (direction == GTK_TEXT_DIR_LTR)
1667         {
1668           arrow_x = x + w - arrow_size;
1669           angle = G_PI / 2;
1670         }
1671       else
1672         {
1673           arrow_x = x;
1674           angle = (3 * G_PI) / 2;
1675         }
1676
1677       arrow_y = y + (h - arrow_size) / 2;
1678
1679       gtk_render_arrow (context, cr, angle, arrow_x, arrow_y, arrow_size);
1680     }
1681   else if (!child)
1682     {
1683       gboolean wide_separators;
1684       gint     separator_height;
1685
1686       gtk_widget_style_get (widget,
1687                             "wide-separators",    &wide_separators,
1688                             "separator-height",   &separator_height,
1689                             NULL);
1690       if (wide_separators)
1691         gtk_render_frame (context, cr,
1692                           x + padding.left,
1693                           y + padding.top,
1694                           w - padding.left - padding.right,
1695                           separator_height);
1696       else
1697         gtk_render_line (context, cr,
1698                          x + padding.left,
1699                          y + padding.top,
1700                          x + w - padding.right - 1,
1701                          y + padding.top);
1702     }
1703
1704   GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->draw (widget, cr);
1705
1706   return FALSE;
1707 }
1708
1709 /**
1710  * gtk_menu_item_select:
1711  * @menu_item: the menu item
1712  *
1713  * Emits the #GtkMenuItem::select signal on the given item. Behaves
1714  * exactly like #gtk_item_select.
1715  */
1716 static void
1717 gtk_real_menu_item_select (GtkMenuItem *menu_item)
1718 {
1719   GtkMenuItemPrivate *priv = menu_item->priv;
1720   GdkDevice *source_device = NULL;
1721   GdkEvent *current_event;
1722
1723   current_event = gtk_get_current_event ();
1724
1725   if (current_event)
1726     {
1727       source_device = gdk_event_get_source_device (current_event);
1728       gdk_event_free (current_event);
1729     }
1730
1731   if ((!source_device ||
1732        gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN) &&
1733       priv->submenu &&
1734       (!gtk_widget_get_mapped (priv->submenu) ||
1735        GTK_MENU (priv->submenu)->priv->tearoff_active))
1736     {
1737       _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1738     }
1739
1740   gtk_widget_set_state_flags (GTK_WIDGET (menu_item),
1741                               GTK_STATE_FLAG_PRELIGHT, FALSE);
1742   gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1743 }
1744
1745 static void
1746 gtk_real_menu_item_deselect (GtkMenuItem *menu_item)
1747 {
1748   GtkMenuItemPrivate *priv = menu_item->priv;
1749
1750   if (priv->submenu)
1751     _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
1752
1753   gtk_widget_unset_state_flags (GTK_WIDGET (menu_item),
1754                                 GTK_STATE_FLAG_PRELIGHT);
1755   gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1756 }
1757
1758 static gboolean
1759 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
1760                                  gboolean   group_cycling)
1761 {
1762   GtkWidget *parent;
1763
1764   parent = gtk_widget_get_parent (widget);
1765
1766   if (GTK_IS_MENU_SHELL (parent))
1767     _gtk_menu_shell_set_keyboard_mode (GTK_MENU_SHELL (parent), TRUE);
1768
1769   if (group_cycling &&
1770       parent &&
1771       GTK_IS_MENU_SHELL (parent) &&
1772       GTK_MENU_SHELL (parent)->priv->active)
1773     {
1774       gtk_menu_shell_select_item (GTK_MENU_SHELL (parent), widget);
1775     }
1776   else
1777     g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
1778
1779   return TRUE;
1780 }
1781
1782 static void
1783 gtk_real_menu_item_activate (GtkMenuItem *menu_item)
1784 {
1785   GtkMenuItemPrivate *priv = menu_item->priv;
1786
1787   if (priv->action_helper)
1788     gtk_action_helper_activate (priv->action_helper);
1789
1790   if (priv->action)
1791     gtk_action_activate (priv->action);
1792 }
1793
1794
1795 static void
1796 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
1797 {
1798   GtkMenuItemPrivate *priv = menu_item->priv;
1799   GtkWidget *parent;
1800   GtkWidget *widget;
1801
1802   widget = GTK_WIDGET (menu_item);
1803   parent = gtk_widget_get_parent (widget);
1804
1805   if (parent && GTK_IS_MENU_SHELL (parent))
1806     {
1807       GtkMenuShell *menu_shell = GTK_MENU_SHELL (parent);
1808
1809       if (priv->submenu == NULL)
1810         gtk_menu_shell_activate_item (menu_shell, widget, TRUE);
1811       else
1812         {
1813           gtk_menu_shell_select_item (menu_shell, widget);
1814           _gtk_menu_item_popup_submenu (widget, FALSE);
1815
1816           gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->submenu), TRUE);
1817         }
1818     }
1819 }
1820
1821 static void
1822 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1823                                         gint        *requisition)
1824 {
1825   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1826
1827   *requisition = 0;
1828 }
1829
1830 static void
1831 gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1832                                          gint         allocation)
1833 {
1834   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1835
1836   menu_item->priv->toggle_size = allocation;
1837 }
1838
1839 static void
1840 gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
1841                               const gchar *label)
1842 {
1843   GtkWidget *child;
1844
1845   gtk_menu_item_ensure_label (menu_item);
1846
1847   child = gtk_bin_get_child (GTK_BIN (menu_item));
1848   if (GTK_IS_LABEL (child))
1849     {
1850       gtk_label_set_label (GTK_LABEL (child), label ? label : "");
1851
1852       g_object_notify (G_OBJECT (menu_item), "label");
1853     }
1854 }
1855
1856 static const gchar *
1857 gtk_real_menu_item_get_label (GtkMenuItem *menu_item)
1858 {
1859   GtkWidget *child;
1860
1861   gtk_menu_item_ensure_label (menu_item);
1862
1863   child = gtk_bin_get_child (GTK_BIN (menu_item));
1864   if (GTK_IS_LABEL (child))
1865     return gtk_label_get_label (GTK_LABEL (child));
1866
1867   return NULL;
1868 }
1869
1870 static void
1871 free_timeval (GTimeVal *val)
1872 {
1873   g_slice_free (GTimeVal, val);
1874 }
1875
1876 static void
1877 gtk_menu_item_real_popup_submenu (GtkWidget *widget,
1878                                   gboolean   remember_exact_time)
1879 {
1880   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1881   GtkMenuItemPrivate *priv = menu_item->priv;
1882   GtkWidget *parent;
1883
1884   parent = gtk_widget_get_parent (widget);
1885
1886   if (gtk_widget_is_sensitive (priv->submenu) && parent)
1887     {
1888       gboolean take_focus;
1889       GtkMenuPositionFunc menu_position_func;
1890
1891       take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (parent));
1892       gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (priv->submenu), take_focus);
1893
1894       if (remember_exact_time)
1895         {
1896           GTimeVal *popup_time = g_slice_new0 (GTimeVal);
1897
1898           g_get_current_time (popup_time);
1899
1900           g_object_set_data_full (G_OBJECT (priv->submenu),
1901                                   "gtk-menu-exact-popup-time", popup_time,
1902                                   (GDestroyNotify) free_timeval);
1903         }
1904       else
1905         {
1906           g_object_set_data (G_OBJECT (priv->submenu),
1907                              "gtk-menu-exact-popup-time", NULL);
1908         }
1909
1910       /* gtk_menu_item_position_menu positions the submenu from the
1911        * menuitems position. If the menuitem doesn't have a window,
1912        * that doesn't work. In that case we use the default
1913        * positioning function instead which places the submenu at the
1914        * mouse cursor.
1915        */
1916       if (gtk_widget_get_window (widget))
1917         menu_position_func = gtk_menu_item_position_menu;
1918       else
1919         menu_position_func = NULL;
1920
1921       gtk_menu_popup (GTK_MENU (priv->submenu),
1922                       parent,
1923                       widget,
1924                       menu_position_func,
1925                       menu_item,
1926                       GTK_MENU_SHELL (parent)->priv->button,
1927                       0);
1928     }
1929
1930   /* Enable themeing of the parent menu item depending on whether
1931    * its submenu is shown or not.
1932    */
1933   gtk_widget_queue_draw (widget);
1934 }
1935
1936 static gint
1937 gtk_menu_item_popup_timeout (gpointer data)
1938 {
1939   GtkMenuItem *menu_item = GTK_MENU_ITEM (data);
1940   GtkMenuItemPrivate *priv = menu_item->priv;
1941   GtkWidget *parent;
1942
1943   parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1944
1945   if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->priv->active) ||
1946       (GTK_IS_MENU (parent) && GTK_MENU (parent)->priv->torn_off))
1947     {
1948       gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1949       if (priv->timer_from_keypress && priv->submenu)
1950         GTK_MENU_SHELL (priv->submenu)->priv->ignore_enter = TRUE;
1951     }
1952
1953   priv->timer = 0;
1954
1955   return FALSE;
1956 }
1957
1958 static gint
1959 get_popup_delay (GtkWidget *widget)
1960 {
1961   GtkWidget *parent;
1962
1963   parent = gtk_widget_get_parent (widget);
1964   if (GTK_IS_MENU_SHELL (parent))
1965     {
1966       return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (parent));
1967     }
1968   else
1969     {
1970       gint popup_delay;
1971
1972       g_object_get (gtk_widget_get_settings (widget),
1973                     "gtk-menu-popup-delay", &popup_delay,
1974                     NULL);
1975
1976       return popup_delay;
1977     }
1978 }
1979
1980 void
1981 _gtk_menu_item_popup_submenu (GtkWidget *widget,
1982                               gboolean   with_delay)
1983 {
1984   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1985   GtkMenuItemPrivate *priv = menu_item->priv;
1986
1987   if (priv->timer)
1988     {
1989       g_source_remove (priv->timer);
1990       priv->timer = 0;
1991       with_delay = FALSE;
1992     }
1993
1994   if (with_delay)
1995     {
1996       gint popup_delay = get_popup_delay (widget);
1997
1998       if (popup_delay > 0)
1999         {
2000           GdkEvent *event = gtk_get_current_event ();
2001
2002           priv->timer = gdk_threads_add_timeout (popup_delay,
2003                                                  gtk_menu_item_popup_timeout,
2004                                                  menu_item);
2005
2006           if (event &&
2007               event->type != GDK_BUTTON_PRESS &&
2008               event->type != GDK_ENTER_NOTIFY)
2009             priv->timer_from_keypress = TRUE;
2010           else
2011             priv->timer_from_keypress = FALSE;
2012
2013           if (event)
2014             gdk_event_free (event);
2015
2016           return;
2017         }
2018     }
2019
2020   gtk_menu_item_real_popup_submenu (widget, FALSE);
2021 }
2022
2023 void
2024 _gtk_menu_item_popdown_submenu (GtkWidget *widget)
2025 {
2026   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2027   GtkMenuItemPrivate *priv = menu_item->priv;
2028
2029   if (priv->submenu)
2030     {
2031       g_object_set_data (G_OBJECT (priv->submenu),
2032                          "gtk-menu-exact-popup-time", NULL);
2033
2034       if (priv->timer)
2035         {
2036           g_source_remove (priv->timer);
2037           priv->timer = 0;
2038         }
2039       else
2040         gtk_menu_popdown (GTK_MENU (priv->submenu));
2041
2042       gtk_widget_queue_draw (widget);
2043     }
2044 }
2045
2046 static void
2047 get_offsets (GtkMenu *menu,
2048              gint    *horizontal_offset,
2049              gint    *vertical_offset)
2050 {
2051   GtkStyleContext *context;
2052   GtkStateFlags state;
2053   GtkBorder padding;
2054
2055   gtk_widget_style_get (GTK_WIDGET (menu),
2056                         "horizontal-offset", horizontal_offset,
2057                         "vertical-offset", vertical_offset,
2058                         NULL);
2059
2060   context = gtk_widget_get_style_context (GTK_WIDGET (menu));
2061   state = gtk_widget_get_state_flags (GTK_WIDGET (menu));
2062   gtk_style_context_get_padding (context, state, &padding);
2063
2064   *vertical_offset -= padding.top;
2065   *horizontal_offset += padding.left;
2066 }
2067
2068 static void
2069 gtk_menu_item_position_menu (GtkMenu  *menu,
2070                              gint     *x,
2071                              gint     *y,
2072                              gboolean *push_in,
2073                              gpointer  user_data)
2074 {
2075   GtkMenuItem *menu_item = GTK_MENU_ITEM (user_data);
2076   GtkMenuItemPrivate *priv = menu_item->priv;
2077   GtkAllocation allocation;
2078   GtkWidget *widget;
2079   GtkMenuItem *parent_menu_item;
2080   GtkWidget *parent;
2081   GdkScreen *screen;
2082   gint twidth, theight;
2083   gint tx, ty;
2084   GtkTextDirection direction;
2085   GdkRectangle monitor;
2086   gint monitor_num;
2087   gint horizontal_offset;
2088   gint vertical_offset;
2089   gint available_left, available_right;
2090   GtkStyleContext *context;
2091   GtkStateFlags state;
2092   GtkBorder parent_padding;
2093
2094   g_return_if_fail (menu != NULL);
2095   g_return_if_fail (x != NULL);
2096   g_return_if_fail (y != NULL);
2097
2098   widget = GTK_WIDGET (user_data);
2099
2100   if (push_in)
2101     *push_in = FALSE;
2102
2103   direction = gtk_widget_get_direction (widget);
2104
2105   twidth = gtk_widget_get_allocated_width (GTK_WIDGET (menu));
2106   theight = gtk_widget_get_allocated_height (GTK_WIDGET (menu));
2107
2108   screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2109   monitor_num = gdk_screen_get_monitor_at_window (screen, priv->event_window);
2110   if (monitor_num < 0)
2111     monitor_num = 0;
2112   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
2113
2114   if (!gdk_window_get_origin (gtk_widget_get_window (widget), &tx, &ty))
2115     {
2116       g_warning ("Menu not on screen");
2117       return;
2118     }
2119
2120   gtk_widget_get_allocation (widget, &allocation);
2121
2122   tx += allocation.x;
2123   ty += allocation.y;
2124
2125   get_offsets (menu, &horizontal_offset, &vertical_offset);
2126
2127   available_left = tx - monitor.x;
2128   available_right = monitor.x + monitor.width - (tx + allocation.width);
2129
2130   parent = gtk_widget_get_parent (widget);
2131   priv->from_menubar = GTK_IS_MENU_BAR (parent);
2132
2133   switch (priv->submenu_placement)
2134     {
2135     case GTK_TOP_BOTTOM:
2136       if (direction == GTK_TEXT_DIR_LTR)
2137         priv->submenu_direction = GTK_DIRECTION_RIGHT;
2138       else
2139         {
2140           priv->submenu_direction = GTK_DIRECTION_LEFT;
2141           tx += allocation.width - twidth;
2142         }
2143       if ((ty + allocation.height + theight) <= monitor.y + monitor.height)
2144         ty += allocation.height;
2145       else if ((ty - theight) >= monitor.y)
2146         ty -= theight;
2147       else if (monitor.y + monitor.height - (ty + allocation.height) > ty)
2148         ty += allocation.height;
2149       else
2150         ty -= theight;
2151       break;
2152
2153     case GTK_LEFT_RIGHT:
2154       if (GTK_IS_MENU (parent))
2155         parent_menu_item = GTK_MENU_ITEM (GTK_MENU (parent)->priv->parent_menu_item);
2156       else
2157         parent_menu_item = NULL;
2158
2159       context = gtk_widget_get_style_context (parent);
2160       state = gtk_widget_get_state_flags (parent);
2161       gtk_style_context_get_padding (context, state, &parent_padding);
2162
2163       if (parent_menu_item && !GTK_MENU (parent)->priv->torn_off)
2164         {
2165           priv->submenu_direction = parent_menu_item->priv->submenu_direction;
2166         }
2167       else
2168         {
2169           if (direction == GTK_TEXT_DIR_LTR)
2170             priv->submenu_direction = GTK_DIRECTION_RIGHT;
2171           else
2172             priv->submenu_direction = GTK_DIRECTION_LEFT;
2173         }
2174
2175       switch (priv->submenu_direction)
2176         {
2177         case GTK_DIRECTION_LEFT:
2178           if (tx - twidth - parent_padding.left - horizontal_offset >= monitor.x ||
2179               available_left >= available_right)
2180             tx -= twidth + parent_padding.left + horizontal_offset;
2181           else
2182             {
2183               priv->submenu_direction = GTK_DIRECTION_RIGHT;
2184               tx += allocation.width + parent_padding.right + horizontal_offset;
2185             }
2186           break;
2187
2188         case GTK_DIRECTION_RIGHT:
2189           if (tx + allocation.width + parent_padding.right + horizontal_offset + twidth <= monitor.x + monitor.width ||
2190               available_right >= available_left)
2191             tx += allocation.width + parent_padding.right + horizontal_offset;
2192           else
2193             {
2194               priv->submenu_direction = GTK_DIRECTION_LEFT;
2195               tx -= twidth + parent_padding.left + horizontal_offset;
2196             }
2197           break;
2198         }
2199
2200       ty += vertical_offset;
2201
2202       /* If the height of the menu doesn't fit we move it upward. */
2203       ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
2204       break;
2205     }
2206
2207   /* If we have negative, tx, here it is because we can't get
2208    * the menu all the way on screen. Favor the left portion.
2209    */
2210   *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
2211   *y = ty;
2212
2213   gtk_menu_set_monitor (menu, monitor_num);
2214
2215   if (!gtk_widget_get_visible (menu->priv->toplevel))
2216     {
2217       gtk_window_set_type_hint (GTK_WINDOW (menu->priv->toplevel), priv->from_menubar?
2218                                 GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
2219     }
2220 }
2221
2222 /**
2223  * gtk_menu_item_set_right_justified:
2224  * @menu_item: a #GtkMenuItem.
2225  * @right_justified: if %TRUE the menu item will appear at the
2226  *   far right if added to a menu bar
2227  *
2228  * Sets whether the menu item appears justified at the right
2229  * side of a menu bar. This was traditionally done for "Help"
2230  * menu items, but is now considered a bad idea. (If the widget
2231  * layout is reversed for a right-to-left language like Hebrew
2232  * or Arabic, right-justified-menu-items appear at the left.)
2233  *
2234  * Deprecated: 3.2: If you insist on using it, use
2235  *   gtk_widget_set_hexpand() and gtk_widget_set_halign().
2236  **/
2237 void
2238 gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
2239                                    gboolean     right_justified)
2240 {
2241   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2242
2243   gtk_menu_item_do_set_right_justified (menu_item, right_justified);
2244 }
2245
2246 /**
2247  * gtk_menu_item_get_right_justified:
2248  * @menu_item: a #GtkMenuItem
2249  *
2250  * Gets whether the menu item appears justified at the right
2251  * side of the menu bar.
2252  *
2253  * Return value: %TRUE if the menu item will appear at the
2254  *   far right if added to a menu bar.
2255  *
2256  * Deprecated: 3.2: See gtk_menu_item_set_right_justified()
2257  **/
2258 gboolean
2259 gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
2260 {
2261   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2262
2263   return menu_item->priv->right_justify;
2264 }
2265
2266
2267 static void
2268 gtk_menu_item_show_all (GtkWidget *widget)
2269 {
2270   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2271   GtkMenuItemPrivate *priv = menu_item->priv;
2272
2273   /* show children including submenu */
2274   if (priv->submenu)
2275     gtk_widget_show_all (priv->submenu);
2276   gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
2277
2278   gtk_widget_show (widget);
2279 }
2280
2281 static gboolean
2282 gtk_menu_item_can_activate_accel (GtkWidget *widget,
2283                                   guint      signal_id)
2284 {
2285   GtkWidget *parent;
2286
2287   parent = gtk_widget_get_parent (widget);
2288
2289   /* Chain to the parent GtkMenu for further checks */
2290   return (gtk_widget_is_sensitive (widget) && gtk_widget_get_visible (widget) &&
2291           parent && gtk_widget_can_activate_accel (parent, signal_id));
2292 }
2293
2294 static void
2295 gtk_menu_item_accel_name_foreach (GtkWidget *widget,
2296                                   gpointer   data)
2297 {
2298   const gchar **path_p = data;
2299
2300   if (!*path_p)
2301     {
2302       if (GTK_IS_LABEL (widget))
2303         {
2304           *path_p = gtk_label_get_text (GTK_LABEL (widget));
2305           if (*path_p && (*path_p)[0] == 0)
2306             *path_p = NULL;
2307         }
2308       else if (GTK_IS_CONTAINER (widget))
2309         gtk_container_foreach (GTK_CONTAINER (widget),
2310                                gtk_menu_item_accel_name_foreach,
2311                                data);
2312     }
2313 }
2314
2315 static void
2316 gtk_menu_item_parent_set (GtkWidget *widget,
2317                           GtkWidget *previous_parent)
2318 {
2319   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2320   GtkMenu *menu;
2321   GtkWidget *parent;
2322
2323   parent = gtk_widget_get_parent (widget);
2324   menu = GTK_IS_MENU (parent) ? GTK_MENU (parent) : NULL;
2325
2326   if (menu)
2327     _gtk_menu_item_refresh_accel_path (menu_item,
2328                                        menu->priv->accel_path,
2329                                        menu->priv->accel_group,
2330                                        TRUE);
2331
2332   if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set)
2333     GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent);
2334 }
2335
2336 void
2337 _gtk_menu_item_refresh_accel_path (GtkMenuItem   *menu_item,
2338                                    const gchar   *prefix,
2339                                    GtkAccelGroup *accel_group,
2340                                    gboolean       group_changed)
2341 {
2342   GtkMenuItemPrivate *priv = menu_item->priv;
2343   const gchar *path;
2344   GtkWidget *widget;
2345
2346   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2347   g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
2348
2349   widget = GTK_WIDGET (menu_item);
2350
2351   if (!accel_group)
2352     {
2353       gtk_widget_set_accel_path (widget, NULL, NULL);
2354       return;
2355     }
2356
2357   path = _gtk_widget_get_accel_path (widget, NULL);
2358   if (!path)  /* no active accel_path yet */
2359     {
2360       path = priv->accel_path;
2361       if (!path && prefix)
2362         {
2363           const gchar *postfix = NULL;
2364           gchar *new_path;
2365
2366           /* try to construct one from label text */
2367           gtk_container_foreach (GTK_CONTAINER (menu_item),
2368                                  gtk_menu_item_accel_name_foreach,
2369                                  &postfix);
2370           if (postfix)
2371             {
2372               new_path = g_strconcat (prefix, "/", postfix, NULL);
2373               path = priv->accel_path = (char*)g_intern_string (new_path);
2374               g_free (new_path);
2375             }
2376         }
2377       if (path)
2378         gtk_widget_set_accel_path (widget, path, accel_group);
2379     }
2380   else if (group_changed)    /* reinstall accelerators */
2381     gtk_widget_set_accel_path (widget, path, accel_group);
2382 }
2383
2384 /**
2385  * gtk_menu_item_set_accel_path:
2386  * @menu_item:  a valid #GtkMenuItem
2387  * @accel_path: (allow-none): accelerator path, corresponding to this menu
2388  *     item's functionality, or %NULL to unset the current path.
2389  *
2390  * Set the accelerator path on @menu_item, through which runtime
2391  * changes of the menu item's accelerator caused by the user can be
2392  * identified and saved to persistent storage (see gtk_accel_map_save()
2393  * on this). To set up a default accelerator for this menu item, call
2394  * gtk_accel_map_add_entry() with the same @accel_path. See also
2395  * gtk_accel_map_add_entry() on the specifics of accelerator paths,
2396  * and gtk_menu_set_accel_path() for a more convenient variant of
2397  * this function.
2398  *
2399  * This function is basically a convenience wrapper that handles
2400  * calling gtk_widget_set_accel_path() with the appropriate accelerator
2401  * group for the menu item.
2402  *
2403  * Note that you do need to set an accelerator on the parent menu with
2404  * gtk_menu_set_accel_group() for this to work.
2405  *
2406  * Note that @accel_path string will be stored in a #GQuark.
2407  * Therefore, if you pass a static string, you can save some memory
2408  * by interning it first with g_intern_static_string().
2409  */
2410 void
2411 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
2412                               const gchar *accel_path)
2413 {
2414   GtkMenuItemPrivate *priv = menu_item->priv;
2415   GtkWidget *parent;
2416   GtkWidget *widget;
2417
2418   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2419   g_return_if_fail (accel_path == NULL ||
2420                     (accel_path[0] == '<' && strchr (accel_path, '/')));
2421
2422   widget = GTK_WIDGET (menu_item);
2423
2424   /* store new path */
2425   priv->accel_path = (char*)g_intern_string (accel_path);
2426
2427   /* forget accelerators associated with old path */
2428   gtk_widget_set_accel_path (widget, NULL, NULL);
2429
2430   /* install accelerators associated with new path */
2431   parent = gtk_widget_get_parent (widget);
2432   if (GTK_IS_MENU (parent))
2433     {
2434       GtkMenu *menu = GTK_MENU (parent);
2435
2436       if (menu->priv->accel_group)
2437         _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
2438                                            NULL,
2439                                            menu->priv->accel_group,
2440                                            FALSE);
2441     }
2442 }
2443
2444 /**
2445  * gtk_menu_item_get_accel_path:
2446  * @menu_item:  a valid #GtkMenuItem
2447  *
2448  * Retrieve the accelerator path that was previously set on @menu_item.
2449  *
2450  * See gtk_menu_item_set_accel_path() for details.
2451  *
2452  * Returns: the accelerator path corresponding to this menu
2453  *     item's functionality, or %NULL if not set
2454  *
2455  * Since: 2.14
2456  */
2457 const gchar *
2458 gtk_menu_item_get_accel_path (GtkMenuItem *menu_item)
2459 {
2460   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2461
2462   return menu_item->priv->accel_path;
2463 }
2464
2465 static void
2466 gtk_menu_item_forall (GtkContainer *container,
2467                       gboolean      include_internals,
2468                       GtkCallback   callback,
2469                       gpointer      callback_data)
2470 {
2471   GtkWidget *child;
2472
2473   g_return_if_fail (GTK_IS_MENU_ITEM (container));
2474   g_return_if_fail (callback != NULL);
2475
2476   child = gtk_bin_get_child (GTK_BIN (container));
2477   if (child)
2478     callback (child, callback_data);
2479 }
2480
2481 gboolean
2482 _gtk_menu_item_is_selectable (GtkWidget *menu_item)
2483 {
2484   if ((!gtk_bin_get_child (GTK_BIN (menu_item)) &&
2485        G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
2486       GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
2487       !gtk_widget_is_sensitive (menu_item) ||
2488       !gtk_widget_get_visible (menu_item))
2489     return FALSE;
2490
2491   return TRUE;
2492 }
2493
2494 static void
2495 gtk_menu_item_ensure_label (GtkMenuItem *menu_item)
2496 {
2497   GtkWidget *accel_label;
2498
2499   if (!gtk_bin_get_child (GTK_BIN (menu_item)))
2500     {
2501       accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
2502       gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
2503
2504       gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
2505       gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label),
2506                                         GTK_WIDGET (menu_item));
2507       gtk_widget_show (accel_label);
2508     }
2509 }
2510
2511 /**
2512  * gtk_menu_item_set_label:
2513  * @menu_item: a #GtkMenuItem
2514  * @label: the text you want to set
2515  *
2516  * Sets @text on the @menu_item label
2517  *
2518  * Since: 2.16
2519  */
2520 void
2521 gtk_menu_item_set_label (GtkMenuItem *menu_item,
2522                          const gchar *label)
2523 {
2524   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2525
2526   GTK_MENU_ITEM_GET_CLASS (menu_item)->set_label (menu_item, label);
2527 }
2528
2529 /**
2530  * gtk_menu_item_get_label:
2531  * @menu_item: a #GtkMenuItem
2532  *
2533  * Sets @text on the @menu_item label
2534  *
2535  * Returns: The text in the @menu_item label. This is the internal
2536  *   string used by the label, and must not be modified.
2537  *
2538  * Since: 2.16
2539  */
2540 const gchar *
2541 gtk_menu_item_get_label (GtkMenuItem *menu_item)
2542 {
2543   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2544
2545   return GTK_MENU_ITEM_GET_CLASS (menu_item)->get_label (menu_item);
2546 }
2547
2548 /**
2549  * gtk_menu_item_set_use_underline:
2550  * @menu_item: a #GtkMenuItem
2551  * @setting: %TRUE if underlines in the text indicate mnemonics
2552  *
2553  * If true, an underline in the text indicates the next character
2554  * should be used for the mnemonic accelerator key.
2555  *
2556  * Since: 2.16
2557  */
2558 void
2559 gtk_menu_item_set_use_underline (GtkMenuItem *menu_item,
2560                                  gboolean     setting)
2561 {
2562   GtkWidget *child;
2563
2564   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2565
2566   gtk_menu_item_ensure_label (menu_item);
2567
2568   child = gtk_bin_get_child (GTK_BIN (menu_item));
2569   if (GTK_IS_LABEL (child))
2570     {
2571       gtk_label_set_use_underline (GTK_LABEL (child), setting);
2572
2573       g_object_notify (G_OBJECT (menu_item), "use-underline");
2574     }
2575 }
2576
2577 /**
2578  * gtk_menu_item_get_use_underline:
2579  * @menu_item: a #GtkMenuItem
2580  *
2581  * Checks if an underline in the text indicates the next character
2582  * should be used for the mnemonic accelerator key.
2583  *
2584  * Return value: %TRUE if an embedded underline in the label
2585  *     indicates the mnemonic accelerator key.
2586  *
2587  * Since: 2.16
2588  */
2589 gboolean
2590 gtk_menu_item_get_use_underline (GtkMenuItem *menu_item)
2591 {
2592   GtkWidget *child;
2593
2594   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2595
2596   gtk_menu_item_ensure_label (menu_item);
2597
2598   child = gtk_bin_get_child (GTK_BIN (menu_item));
2599   if (GTK_IS_LABEL (child))
2600     return gtk_label_get_use_underline (GTK_LABEL (child));
2601
2602   return FALSE;
2603 }
2604
2605 /**
2606  * gtk_menu_item_set_reserve_indicator:
2607  * @menu_item: a #GtkMenuItem
2608  * @reserve: the new value
2609  *
2610  * Sets whether the @menu_item should reserve space for
2611  * the submenu indicator, regardless if it actually has
2612  * a submenu or not.
2613  *
2614  * There should be little need for applications to call
2615  * this functions.
2616  *
2617  * Since: 3.0
2618  */
2619 void
2620 gtk_menu_item_set_reserve_indicator (GtkMenuItem *menu_item,
2621                                      gboolean     reserve)
2622 {
2623   GtkMenuItemPrivate *priv;
2624
2625   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2626
2627   priv = menu_item->priv;
2628
2629   if (priv->reserve_indicator != reserve)
2630     {
2631       priv->reserve_indicator = reserve;
2632       gtk_widget_queue_resize (GTK_WIDGET (menu_item));
2633     }
2634 }
2635
2636 /**
2637  * gtk_menu_item_get_reserve_indicator:
2638  * @menu_item: a #GtkMenuItem
2639  *
2640  * Returns whether the @menu_item reserves space for
2641  * the submenu indicator, regardless if it has a submenu
2642  * or not.
2643  *
2644  * Returns: %TRUE if @menu_item always reserves space for the
2645  *     submenu indicator
2646  *
2647  * Since: 3.0
2648  */
2649 gboolean
2650 gtk_menu_item_get_reserve_indicator (GtkMenuItem *menu_item)
2651 {
2652   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2653
2654   return menu_item->priv->reserve_indicator;
2655 }