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