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