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