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