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