]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenuitem.c
Revert accidentally committed changes.
[~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 <string.h>
30 #include "gtkaccellabel.h"
31 #include "gtkmain.h"
32 #include "gtkmarshalers.h"
33 #include "gtkmenu.h"
34 #include "gtkmenubar.h"
35 #include "gtkmenuitem.h"
36 #include "gtkseparatormenuitem.h"
37
38 #define MENU_ITEM_CLASS(w)  GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
39
40 enum {
41   ACTIVATE,
42   ACTIVATE_ITEM,
43   TOGGLE_SIZE_REQUEST,
44   TOGGLE_SIZE_ALLOCATE,
45   LAST_SIGNAL
46 };
47
48
49 static void gtk_menu_item_class_init     (GtkMenuItemClass *klass);
50 static void gtk_menu_item_init           (GtkMenuItem      *menu_item);
51 static void gtk_menu_item_destroy        (GtkObject        *object);
52 static void gtk_menu_item_finalize       (GObject          *object);
53 static void gtk_menu_item_size_request   (GtkWidget        *widget,
54                                           GtkRequisition   *requisition);
55 static void gtk_menu_item_size_allocate  (GtkWidget        *widget,
56                                           GtkAllocation    *allocation);
57 static void gtk_menu_item_realize        (GtkWidget        *widget);
58 static void gtk_menu_item_unrealize      (GtkWidget        *widget);
59 static void gtk_menu_item_map            (GtkWidget        *widget);
60 static void gtk_menu_item_unmap          (GtkWidget        *widget);
61 static void gtk_menu_item_paint          (GtkWidget        *widget,
62                                           GdkRectangle     *area);
63 static gint gtk_menu_item_expose         (GtkWidget        *widget,
64                                           GdkEventExpose   *event);
65 static void gtk_menu_item_parent_set     (GtkWidget        *widget,
66                                           GtkWidget        *previous_parent);
67
68
69 static void gtk_real_menu_item_select               (GtkItem     *item);
70 static void gtk_real_menu_item_deselect             (GtkItem     *item);
71 static void gtk_real_menu_item_activate_item        (GtkMenuItem *item);
72 static void gtk_real_menu_item_toggle_size_request  (GtkMenuItem *menu_item,
73                                                      gint        *requisition);
74 static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
75                                                      gint         allocation);
76 static gboolean gtk_menu_item_mnemonic_activate     (GtkWidget   *widget,
77                                                      gboolean     group_cycling);
78
79 static gint gtk_menu_item_select_timeout (gpointer          data);
80 static void gtk_menu_item_popup_submenu  (gpointer     data);
81 static void gtk_menu_item_position_menu  (GtkMenu          *menu,
82                                           gint             *x,
83                                           gint             *y,
84                                           gboolean         *push_in,
85                                           gpointer          user_data);
86 static void gtk_menu_item_show_all       (GtkWidget        *widget);
87 static void gtk_menu_item_hide_all       (GtkWidget        *widget);
88 static void gtk_menu_item_forall         (GtkContainer    *container,
89                                           gboolean         include_internals,
90                                           GtkCallback      callback,
91                                           gpointer         callback_data);
92
93
94 static GtkItemClass *parent_class;
95 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
96
97 GType
98 gtk_menu_item_get_type (void)
99 {
100   static GType menu_item_type = 0;
101
102   if (!menu_item_type)
103     {
104       static const GTypeInfo menu_item_info =
105       {
106         sizeof (GtkMenuItemClass),
107         NULL,           /* base_init */
108         NULL,           /* base_finalize */
109         (GClassInitFunc) gtk_menu_item_class_init,
110         NULL,           /* class_finalize */
111         NULL,           /* class_data */
112         sizeof (GtkMenuItem),
113         16,             /* n_preallocs */
114         (GInstanceInitFunc) gtk_menu_item_init,
115       };
116
117       menu_item_type = g_type_register_static (GTK_TYPE_ITEM, "GtkMenuItem",
118                                                &menu_item_info, 0);
119     }
120
121   return menu_item_type;
122 }
123
124 static void
125 gtk_menu_item_class_init (GtkMenuItemClass *klass)
126 {
127   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
128   GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
129   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
130   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
131   GtkItemClass *item_class = GTK_ITEM_CLASS (klass);
132
133   parent_class = g_type_class_peek_parent (klass);
134
135   gobject_class->finalize = gtk_menu_item_finalize;
136
137   object_class->destroy = gtk_menu_item_destroy;
138
139   widget_class->size_request = gtk_menu_item_size_request;
140   widget_class->size_allocate = gtk_menu_item_size_allocate;
141   widget_class->expose_event = gtk_menu_item_expose;
142   widget_class->realize = gtk_menu_item_realize;
143   widget_class->unrealize = gtk_menu_item_unrealize;
144   widget_class->map = gtk_menu_item_map;
145   widget_class->unmap = gtk_menu_item_unmap;
146   widget_class->show_all = gtk_menu_item_show_all;
147   widget_class->hide_all = gtk_menu_item_hide_all;
148   widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate;
149   widget_class->parent_set = gtk_menu_item_parent_set;
150   
151   container_class->forall = gtk_menu_item_forall;
152
153   item_class->select = gtk_real_menu_item_select;
154   item_class->deselect = gtk_real_menu_item_deselect;
155
156   klass->activate = NULL;
157   klass->activate_item = gtk_real_menu_item_activate_item;
158   klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
159   klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
160
161   klass->hide_on_activate = TRUE;
162
163   menu_item_signals[ACTIVATE] =
164     g_signal_new ("activate",
165                   G_OBJECT_CLASS_TYPE (gobject_class),
166                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
167                   G_STRUCT_OFFSET (GtkMenuItemClass, activate),
168                   NULL, NULL,
169                   _gtk_marshal_VOID__VOID,
170                   G_TYPE_NONE, 0);
171   widget_class->activate_signal = menu_item_signals[ACTIVATE];
172
173   menu_item_signals[ACTIVATE_ITEM] =
174     g_signal_new ("activate_item",
175                   G_OBJECT_CLASS_TYPE (gobject_class),
176                   G_SIGNAL_RUN_FIRST,
177                   G_STRUCT_OFFSET (GtkMenuItemClass, activate_item),
178                   NULL, NULL,
179                   _gtk_marshal_VOID__VOID,
180                   G_TYPE_NONE, 0);
181
182   menu_item_signals[TOGGLE_SIZE_REQUEST] =
183     g_signal_new ("toggle_size_request",
184                   G_OBJECT_CLASS_TYPE (gobject_class),
185                   G_SIGNAL_RUN_FIRST,
186                   G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request),
187                   NULL, NULL,
188                   _gtk_marshal_VOID__POINTER,
189                   G_TYPE_NONE, 1,
190                   G_TYPE_POINTER);
191
192   menu_item_signals[TOGGLE_SIZE_ALLOCATE] =
193     g_signal_new ("toggle_size_allocate",
194                   G_OBJECT_CLASS_TYPE (gobject_class),
195                   G_SIGNAL_RUN_FIRST,
196                   G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate),
197                   NULL, NULL,
198                   _gtk_marshal_NONE__INT,
199                   G_TYPE_NONE, 1,
200                   G_TYPE_INT);
201
202   gtk_widget_class_install_style_property_parser (widget_class,
203                                                   g_param_spec_enum ("selected_shadow_type",
204                                                                      "Selected Shadow Type",
205                                                                      "Shadow type when item is selected",
206                                                                      GTK_TYPE_SHADOW_TYPE,
207                                                                      GTK_SHADOW_NONE,
208                                                                      G_PARAM_READABLE),
209                                                   gtk_rc_property_parse_enum);
210
211   gtk_widget_class_install_style_property (widget_class,
212                                            g_param_spec_int ("horizontal_padding",
213                                                              "Horizontal Padding",
214                                                              "Padding to left and right of the menu item",
215                                                              0,
216                                                              G_MAXINT,
217                                                              3,
218                                                              G_PARAM_READABLE));
219
220   gtk_widget_class_install_style_property (widget_class,
221                                            g_param_spec_int ("toggle_spacing",
222                                                              "Icon Spacing",
223                                                              "Space between icon and label",
224                                                              0,
225                                                              G_MAXINT,
226                                                              5,
227                                                              G_PARAM_READABLE));
228
229   gtk_widget_class_install_style_property (widget_class,
230                                            g_param_spec_int ("arrow_spacing",
231                                                              "Arrow Spacing",
232                                                              "Space between label and arrow",
233                                                              0,
234                                                              G_MAXINT,
235                                                              10,
236                                                              G_PARAM_READABLE));
237 }
238
239 static void
240 gtk_menu_item_init (GtkMenuItem *menu_item)
241 {
242   GTK_WIDGET_SET_FLAGS (menu_item, GTK_NO_WINDOW);
243   
244   menu_item->submenu = NULL;
245   menu_item->toggle_size = 0;
246   menu_item->accelerator_width = 0;
247   menu_item->show_submenu_indicator = FALSE;
248   if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
249     menu_item->submenu_direction = GTK_DIRECTION_LEFT;
250   else
251     menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
252   menu_item->submenu_placement = GTK_TOP_BOTTOM;
253   menu_item->right_justify = FALSE;
254
255   menu_item->timer = 0;
256 }
257
258 GtkWidget*
259 gtk_menu_item_new (void)
260 {
261   return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
262 }
263
264 GtkWidget*
265 gtk_menu_item_new_with_label (const gchar *label)
266 {
267   GtkWidget *menu_item;
268   GtkWidget *accel_label;
269
270   menu_item = gtk_menu_item_new ();
271   accel_label = gtk_accel_label_new (label);
272   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
273
274   gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
275   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
276   gtk_widget_show (accel_label);
277
278   return menu_item;
279 }
280
281
282 /**
283  * gtk_menu_item_new_with_mnemonic:
284  * @label: The text of the button, with an underscore in front of the
285  *         mnemonic character
286  * @returns: a new #GtkMenuItem
287  *
288  * Creates a new #GtkMenuItem containing a label. The label
289  * will be created using gtk_label_new_with_mnemonic(), so underscores
290  * in @label indicate the mnemonic for the menu item.
291  **/
292 GtkWidget*
293 gtk_menu_item_new_with_mnemonic (const gchar *label)
294 {
295   GtkWidget *menu_item;
296   GtkWidget *accel_label;
297
298   menu_item = gtk_menu_item_new ();
299   accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
300   gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
301   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
302
303   gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
304   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
305   gtk_widget_show (accel_label);
306
307   return menu_item;
308 }
309
310 static void
311 gtk_menu_item_destroy (GtkObject *object)
312 {
313   GtkMenuItem *menu_item;
314
315   g_return_if_fail (GTK_IS_MENU_ITEM (object));
316
317   menu_item = GTK_MENU_ITEM (object);
318
319   if (menu_item->submenu)
320     gtk_widget_destroy (menu_item->submenu);
321
322   GTK_OBJECT_CLASS (parent_class)->destroy (object);
323 }
324
325 static void
326 gtk_menu_item_finalize (GObject *object)
327 {
328   GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
329
330   g_free (menu_item->accel_path);
331
332   G_OBJECT_CLASS (parent_class)->finalize (object);
333 }
334
335 static void
336 gtk_menu_item_detacher (GtkWidget     *widget,
337                         GtkMenu       *menu)
338 {
339   GtkMenuItem *menu_item;
340
341   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
342
343   menu_item = GTK_MENU_ITEM (widget);
344   g_return_if_fail (menu_item->submenu == (GtkWidget*) menu);
345
346   menu_item->submenu = NULL;
347 }
348
349 void
350 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
351                            GtkWidget   *submenu)
352 {
353   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
354   
355   if (menu_item->submenu != submenu)
356     {
357       gtk_menu_item_remove_submenu (menu_item);
358       
359       menu_item->submenu = submenu;
360       gtk_menu_attach_to_widget (GTK_MENU (submenu),
361                                  GTK_WIDGET (menu_item),
362                                  gtk_menu_item_detacher);
363       
364       if (GTK_WIDGET (menu_item)->parent)
365         gtk_widget_queue_resize (GTK_WIDGET (menu_item));
366     }
367 }
368
369 /**
370  * gtk_menu_item_get_submenu:
371  * @menu_item: a #GtkMenuItem
372  *
373  * Gets the submenu underneath this menu item, if any. See
374  * gtk_menu_item_set_submenu().
375  *
376  * Return value: submenu for this menu item, or %NULL if none.
377  **/
378 GtkWidget *
379 gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
380 {
381   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
382
383   return menu_item->submenu;
384 }
385
386 void
387 gtk_menu_item_remove_submenu (GtkMenuItem         *menu_item)
388 {
389   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
390       
391   if (menu_item->submenu)
392     gtk_menu_detach (GTK_MENU (menu_item->submenu));
393 }
394
395 void _gtk_menu_item_set_placement (GtkMenuItem         *menu_item,
396                                    GtkSubmenuPlacement  placement);
397
398 void
399 _gtk_menu_item_set_placement (GtkMenuItem         *menu_item,
400                              GtkSubmenuPlacement  placement)
401 {
402   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
403
404   menu_item->submenu_placement = placement;
405 }
406
407 void
408 gtk_menu_item_select (GtkMenuItem *menu_item)
409 {
410   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
411   
412   gtk_item_select (GTK_ITEM (menu_item));
413 }
414
415 void
416 gtk_menu_item_deselect (GtkMenuItem *menu_item)
417 {
418   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
419   
420   gtk_item_deselect (GTK_ITEM (menu_item));
421 }
422
423 void
424 gtk_menu_item_activate (GtkMenuItem *menu_item)
425 {
426   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
427   
428   g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
429 }
430
431 void
432 gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
433                                    gint        *requisition)
434 {
435   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
436
437   g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
438 }
439
440 void
441 gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
442                                     gint         allocation)
443 {
444   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
445
446   g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
447 }
448
449 static void
450 gtk_menu_item_accel_width_foreach (GtkWidget *widget,
451                                    gpointer data)
452 {
453   guint *width = data;
454
455   if (GTK_IS_ACCEL_LABEL (widget))
456     {
457       guint w;
458
459       w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
460       *width = MAX (*width, w);
461     }
462   else if (GTK_IS_CONTAINER (widget))
463     gtk_container_foreach (GTK_CONTAINER (widget),
464                            gtk_menu_item_accel_width_foreach,
465                            data);
466 }
467
468 static void
469 gtk_menu_item_size_request (GtkWidget      *widget,
470                             GtkRequisition *requisition)
471 {
472   GtkMenuItem *menu_item;
473   GtkBin *bin;
474   guint accel_width;
475   guint horizontal_padding;
476
477   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
478   g_return_if_fail (requisition != NULL);
479
480   gtk_widget_style_get (widget,
481                         "horizontal padding", &horizontal_padding,
482                         NULL);
483   
484   bin = GTK_BIN (widget);
485   menu_item = GTK_MENU_ITEM (widget);
486
487   requisition->width = (GTK_CONTAINER (widget)->border_width +
488                         widget->style->xthickness + horizontal_padding) * 2;
489   requisition->height = (GTK_CONTAINER (widget)->border_width +
490                          widget->style->ythickness) * 2;
491
492   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
493     {
494       GtkRequisition child_requisition;
495       
496       gtk_widget_size_request (bin->child, &child_requisition);
497
498       requisition->width += child_requisition.width;
499       requisition->height += child_requisition.height;
500
501       if (menu_item->submenu && menu_item->show_submenu_indicator)
502         {
503           guint arrow_spacing;
504           
505           gtk_widget_style_get (widget,
506                                 "arrow_spacing", &arrow_spacing,
507                                 NULL);
508
509           requisition->width += child_requisition.height;
510           requisition->width += arrow_spacing;
511         }
512     }
513   else
514     {
515       /* separator item */
516       requisition->height += 4;
517     }
518
519   accel_width = 0;
520   gtk_container_foreach (GTK_CONTAINER (menu_item),
521                          gtk_menu_item_accel_width_foreach,
522                          &accel_width);
523   menu_item->accelerator_width = accel_width;
524 }
525
526 static void
527 gtk_menu_item_size_allocate (GtkWidget     *widget,
528                              GtkAllocation *allocation)
529 {
530   GtkMenuItem *menu_item;
531   GtkBin *bin;
532   GtkAllocation child_allocation;
533   GtkTextDirection direction;
534
535   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
536   g_return_if_fail (allocation != NULL);
537
538   menu_item = GTK_MENU_ITEM (widget);
539   bin = GTK_BIN (widget);
540   
541   direction = gtk_widget_get_direction (widget);
542
543   widget->allocation = *allocation;
544
545   if (bin->child)
546     {
547       GtkRequisition child_requisition;
548       guint horizontal_padding;
549
550       gtk_widget_style_get (widget,
551                             "horizontal_padding", &horizontal_padding,
552                             NULL);
553       
554       child_allocation.x = (GTK_CONTAINER (widget)->border_width +
555                             widget->style->xthickness +
556                             horizontal_padding);
557       child_allocation.y = (GTK_CONTAINER (widget)->border_width +
558                             widget->style->ythickness);
559       child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
560       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
561       if (direction == GTK_TEXT_DIR_LTR)
562         child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
563       child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size;
564       child_allocation.x += widget->allocation.x;
565       child_allocation.y += widget->allocation.y;
566
567       gtk_widget_get_child_requisition (bin->child, &child_requisition);
568       if (menu_item->submenu && menu_item->show_submenu_indicator) 
569         {
570           if (direction == GTK_TEXT_DIR_RTL)
571             child_allocation.x += child_requisition.height;
572           child_allocation.width -= child_requisition.height;
573         }
574       
575       if (child_allocation.width < 1)
576         child_allocation.width = 1;
577
578       gtk_widget_size_allocate (bin->child, &child_allocation);
579     }
580
581   if (GTK_WIDGET_REALIZED (widget))
582     gdk_window_move_resize (menu_item->event_window,
583                             allocation->x, allocation->y,
584                             allocation->width, allocation->height);
585
586   if (menu_item->submenu)
587     gtk_menu_reposition (GTK_MENU (menu_item->submenu));
588 }
589
590 static void
591 gtk_menu_item_realize (GtkWidget *widget)
592 {
593   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
594   GdkWindowAttr attributes;
595   gint attributes_mask;
596
597   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
598
599   widget->window = gtk_widget_get_parent_window (widget);
600   g_object_ref (widget->window);
601   
602   attributes.x = widget->allocation.x;
603   attributes.y = widget->allocation.y;
604   attributes.width = widget->allocation.width;
605   attributes.height = widget->allocation.height;
606   attributes.window_type = GDK_WINDOW_CHILD;
607   attributes.wclass = GDK_INPUT_ONLY;
608   attributes.event_mask = (gtk_widget_get_events (widget) |
609                            GDK_BUTTON_PRESS_MASK |
610                            GDK_BUTTON_RELEASE_MASK |
611                            GDK_ENTER_NOTIFY_MASK |
612                            GDK_LEAVE_NOTIFY_MASK |
613                            GDK_POINTER_MOTION_MASK);
614
615   attributes_mask = GDK_WA_X | GDK_WA_Y;
616   menu_item->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
617   gdk_window_set_user_data (menu_item->event_window, widget);
618
619   widget->style = gtk_style_attach (widget->style, widget->window);
620 }
621
622 static void
623 gtk_menu_item_unrealize (GtkWidget *widget)
624 {
625   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
626
627   gdk_window_set_user_data (menu_item->event_window, NULL);
628   gdk_window_destroy (menu_item->event_window);
629   menu_item->event_window = NULL;
630   
631   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
632     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
633 }
634
635 static void
636 gtk_menu_item_map (GtkWidget *widget)
637 {
638   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
639   
640   GTK_WIDGET_CLASS (parent_class)->map (widget);
641
642   gdk_window_show (menu_item->event_window);
643 }
644
645 static void
646 gtk_menu_item_unmap (GtkWidget *widget)
647 {
648   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
649     
650   gdk_window_hide (menu_item->event_window);
651
652   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
653 }
654
655 static void
656 gtk_menu_item_paint (GtkWidget    *widget,
657                      GdkRectangle *area)
658 {
659   GtkMenuItem *menu_item;
660   GtkStateType state_type;
661   GtkShadowType shadow_type, selected_shadow_type;
662   gint width, height;
663   gint x, y;
664   gint border_width = GTK_CONTAINER (widget)->border_width;
665
666   if (GTK_WIDGET_DRAWABLE (widget))
667     {
668       menu_item = GTK_MENU_ITEM (widget);
669
670       state_type = widget->state;
671       
672       x = widget->allocation.x + border_width;
673       y = widget->allocation.y + border_width;
674       width = widget->allocation.width - border_width * 2;
675       height = widget->allocation.height - border_width * 2;
676       
677       if ((state_type == GTK_STATE_PRELIGHT) &&
678           (GTK_BIN (menu_item)->child))
679         {
680           gtk_widget_style_get (widget,
681                                 "selected_shadow_type", &selected_shadow_type,
682                                 NULL);
683           gtk_paint_box (widget->style,
684                          widget->window,
685                          GTK_STATE_PRELIGHT,
686                          selected_shadow_type,
687                          area, widget, "menuitem",
688                          x, y, width, height);
689         }
690   
691       if (menu_item->submenu && menu_item->show_submenu_indicator)
692         {
693           GtkRequisition child_requisition;
694           gint arrow_x, arrow_y;
695           gint arrow_size;
696           gint arrow_extent;
697           guint horizontal_padding;
698           GtkTextDirection direction;
699           GtkArrowType arrow_type;
700
701           direction = gtk_widget_get_direction (widget);
702       
703           gtk_widget_style_get (widget,
704                                 "horizontal_padding", &horizontal_padding,
705                                 NULL);
706           
707           gtk_widget_get_child_requisition (GTK_BIN (menu_item)->child,
708                                             &child_requisition);
709
710           arrow_size = child_requisition.height - 2 * widget->style->ythickness;
711           arrow_extent = arrow_size * 0.8;
712           
713           shadow_type = GTK_SHADOW_OUT;
714           if (state_type == GTK_STATE_PRELIGHT)
715             shadow_type = GTK_SHADOW_IN;
716
717           if (direction == GTK_TEXT_DIR_LTR)
718             {
719               arrow_x = x + width - horizontal_padding - arrow_extent;
720               arrow_type = GTK_ARROW_RIGHT;
721             }
722           else
723             {
724               arrow_x = x + horizontal_padding;
725               arrow_type = GTK_ARROW_LEFT;
726             }
727
728           arrow_y = y + (height - arrow_extent) / 2;
729
730           gtk_paint_arrow (widget->style, widget->window,
731                            state_type, shadow_type, 
732                            area, widget, "menuitem", 
733                            arrow_type, TRUE,
734                            arrow_x, arrow_y,
735                            arrow_extent, arrow_extent);
736         }
737       else if (!GTK_BIN (menu_item)->child)
738         {
739           guint horizontal_padding;
740
741           gtk_widget_style_get (widget,
742                                 "horizontal_padding", &horizontal_padding,
743                                 NULL);
744           
745           gtk_paint_hline (widget->style, widget->window, GTK_STATE_NORMAL,
746                            area, widget, "menuitem",
747                            widget->allocation.x + horizontal_padding + widget->style->xthickness,
748                            widget->allocation.x + widget->allocation.width - horizontal_padding - widget->style->xthickness - 1,
749                            widget->allocation.y + (widget->allocation.height -
750                                                    widget->style->ythickness) / 2);
751         }
752     }
753 }
754
755 static gint
756 gtk_menu_item_expose (GtkWidget      *widget,
757                       GdkEventExpose *event)
758 {
759   g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
760   g_return_val_if_fail (event != NULL, FALSE);
761
762   if (GTK_WIDGET_DRAWABLE (widget))
763     {
764       gtk_menu_item_paint (widget, &event->area);
765
766       (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
767     }
768
769   return FALSE;
770 }
771
772 static gint
773 get_popup_delay (GtkMenuItem *menu_item)
774 {
775   GtkWidget *parent = GTK_WIDGET (menu_item)->parent;
776
777   if (GTK_IS_MENU_SHELL (parent))
778     {
779       return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (parent));
780     }
781   else
782     {
783       gint popup_delay;
784       
785       g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)),
786                     "gtk-menu-popup-delay", &popup_delay,
787                     NULL);
788
789       return popup_delay;
790     }
791 }
792
793 static void
794 gtk_real_menu_item_select (GtkItem *item)
795 {
796   GtkMenuItem *menu_item;
797
798   g_return_if_fail (GTK_IS_MENU_ITEM (item));
799
800   menu_item = GTK_MENU_ITEM (item);
801
802   if (menu_item->submenu)
803     {
804       gint popup_delay;
805
806       if (menu_item->timer)
807         g_source_remove (menu_item->timer);
808
809       popup_delay = get_popup_delay (menu_item);
810       
811       if (popup_delay > 0)
812         {
813           GdkEvent *event = gtk_get_current_event ();
814           
815           menu_item->timer = g_timeout_add (popup_delay,
816                                             gtk_menu_item_select_timeout,
817                                             menu_item);
818           if (event &&
819               event->type != GDK_BUTTON_PRESS &&
820               event->type != GDK_ENTER_NOTIFY)
821             menu_item->timer_from_keypress = TRUE;
822           else
823             menu_item->timer_from_keypress = FALSE;
824
825           if (event)
826             gdk_event_free (event);
827         }
828       else
829         gtk_menu_item_popup_submenu (menu_item);
830     }
831   
832   gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
833   gtk_widget_queue_draw (GTK_WIDGET (menu_item));
834 }
835
836 static void
837 gtk_real_menu_item_deselect (GtkItem *item)
838 {
839   GtkMenuItem *menu_item;
840
841   g_return_if_fail (GTK_IS_MENU_ITEM (item));
842
843   menu_item = GTK_MENU_ITEM (item);
844
845   if (menu_item->submenu)
846     {
847       if (menu_item->timer)
848         {
849           g_source_remove (menu_item->timer);
850           menu_item->timer = 0;
851         }
852       else
853         gtk_menu_popdown (GTK_MENU (menu_item->submenu));
854     }
855
856   gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
857   gtk_widget_queue_draw (GTK_WIDGET (menu_item));
858 }
859
860 static gboolean
861 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
862                                  gboolean   group_cycling)
863 {
864   if (group_cycling &&
865       widget->parent &&
866       GTK_IS_MENU_SHELL (widget->parent) &&
867       GTK_MENU_SHELL (widget->parent)->active)
868     {
869       gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent),
870                                   widget);
871     }
872   else
873     g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
874   
875   return TRUE;
876 }
877
878
879 static void
880 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
881 {
882   GtkWidget *widget;
883   GtkMenuShell *submenu; 
884
885   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
886
887   widget = GTK_WIDGET (menu_item);
888   
889   if (widget->parent &&
890       GTK_IS_MENU_SHELL (widget->parent))
891     {
892       if (menu_item->submenu == NULL)
893         gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget->parent),
894                                       widget, TRUE);
895       else
896         {
897           GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget->parent);
898
899           _gtk_menu_shell_activate (menu_shell);
900
901           gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget); 
902           gtk_menu_item_popup_submenu (widget); 
903
904           gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
905           submenu = GTK_MENU_SHELL (menu_item->submenu);
906         }
907     }
908 }
909 static void
910 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
911                                         gint        *requisition)
912 {
913   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
914
915   *requisition = 0;
916 }
917
918 static void
919 gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
920                                          gint         allocation)
921 {
922   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
923
924   menu_item->toggle_size = allocation;
925 }
926
927 static gint
928 gtk_menu_item_select_timeout (gpointer data)
929 {
930   GtkMenuItem *menu_item;
931   GtkWidget *parent;
932   
933   GDK_THREADS_ENTER ();
934
935   menu_item = GTK_MENU_ITEM (data);
936
937   parent = GTK_WIDGET (menu_item)->parent;
938
939   if (parent && GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active)
940     {
941       gtk_menu_item_popup_submenu (data);
942       if (menu_item->timer_from_keypress && menu_item->submenu)
943         GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
944     }
945
946   GDK_THREADS_LEAVE ();
947
948   return FALSE;  
949 }
950
951 static void
952 gtk_menu_item_popup_submenu (gpointer data)
953 {
954   GtkWidget *widget;
955   GtkMenuItem *menu_item;
956
957   widget = GTK_WIDGET (data);
958   menu_item = GTK_MENU_ITEM (widget);
959
960   if (menu_item->timer)
961     g_source_remove (menu_item->timer);
962   menu_item->timer = 0;
963
964   if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
965     gtk_menu_popup (GTK_MENU (menu_item->submenu),
966                     widget->parent,
967                     widget,
968                     gtk_menu_item_position_menu,
969                     menu_item,
970                     GTK_MENU_SHELL (widget->parent)->button,
971                     0);
972 }
973
974 static void
975 get_offsets (GtkMenu *menu,
976              gint    *horizontal_offset,
977              gint    *vertical_offset)
978 {
979   gint vertical_padding;
980   
981   gtk_widget_style_get (GTK_WIDGET (menu),
982                         "horizontal_offset", horizontal_offset,
983                         "vertical_offset", vertical_offset,
984                         "vertical_padding", &vertical_padding,
985                         NULL);
986
987   *vertical_offset -= GTK_WIDGET (menu)->style->ythickness;
988   *vertical_offset -= vertical_padding;
989 }
990
991 static void
992 gtk_menu_item_position_menu (GtkMenu  *menu,
993                              gint     *x,
994                              gint     *y,
995                              gboolean *push_in,
996                              gpointer  user_data)
997 {
998   GtkMenuItem *menu_item;
999   GtkWidget *widget;
1000   GtkWidget *parent_menu_item;
1001   GdkScreen *screen;
1002   gint twidth, theight;
1003   gint tx, ty;
1004   GtkTextDirection direction;
1005   GdkRectangle monitor;
1006   gint monitor_num;
1007   gint horizontal_offset;
1008   gint vertical_offset;
1009   gint parent_xthickness;
1010
1011   g_return_if_fail (menu != NULL);
1012   g_return_if_fail (x != NULL);
1013   g_return_if_fail (y != NULL);
1014
1015   menu_item = GTK_MENU_ITEM (user_data);
1016   widget = GTK_WIDGET (user_data);
1017
1018   if (push_in)
1019     *push_in = FALSE;
1020
1021   direction = gtk_widget_get_direction (widget);
1022
1023   twidth = GTK_WIDGET (menu)->requisition.width;
1024   theight = GTK_WIDGET (menu)->requisition.height;
1025
1026   screen = gtk_widget_get_screen (widget);
1027   monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
1028   if (monitor_num < 0)
1029     monitor_num = 0;
1030   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1031
1032   if (!gdk_window_get_origin (widget->window, &tx, &ty))
1033     {
1034       g_warning ("Menu not on screen");
1035       return;
1036     }
1037
1038   tx += widget->allocation.x;
1039   ty += widget->allocation.y;
1040
1041   get_offsets (menu, &horizontal_offset, &vertical_offset);
1042   
1043   switch (menu_item->submenu_placement)
1044     {
1045     case GTK_TOP_BOTTOM:
1046       if (direction == GTK_TEXT_DIR_LTR)
1047         menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1048       else 
1049         {
1050           menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1051           tx += widget->allocation.width - twidth;
1052         }
1053
1054       if ((ty + widget->allocation.height + theight) <= monitor.y + monitor.height)
1055         ty += widget->allocation.height;
1056       else if ((ty - theight) >= monitor.y)
1057         ty -= theight;
1058       else if (monitor.y + monitor.height - (ty + widget->allocation.height) > ty)
1059         ty += widget->allocation.height;
1060       else
1061         ty -= theight;
1062       break;
1063
1064     case GTK_LEFT_RIGHT:
1065       parent_menu_item = GTK_MENU (widget->parent)->parent_menu_item;
1066       parent_xthickness = widget->parent->style->xthickness;
1067       if (parent_menu_item && 
1068           !GTK_MENU (widget->parent)->torn_off && 
1069           !GTK_MENU_SHELL (menu)->active)
1070         menu_item->submenu_direction = GTK_MENU_ITEM (parent_menu_item)->submenu_direction;
1071       else if (direction == GTK_TEXT_DIR_LTR)
1072         menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1073       else
1074         menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1075
1076       switch (menu_item->submenu_direction)
1077         {
1078         case GTK_DIRECTION_LEFT:
1079           if ((tx - twidth - parent_xthickness - horizontal_offset) >= monitor.x)
1080             tx -= twidth + parent_xthickness + horizontal_offset;
1081           else
1082             {
1083               menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1084               tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1085             }
1086           break;
1087
1088         case GTK_DIRECTION_RIGHT:
1089           if ((tx + widget->allocation.width + parent_xthickness + horizontal_offset + twidth) <= monitor.x + monitor.width)
1090             tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1091           else
1092             {
1093               menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1094               tx -= twidth + parent_xthickness + horizontal_offset;
1095             }
1096           break;
1097         }
1098
1099       ty += vertical_offset;
1100       
1101       /* If the height of the menu doesn't fit we move it upward. */
1102       ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
1103       break;
1104     }
1105
1106   /* If we have negative, tx, here it is because we can't get
1107    * the menu all the way on screen. Favor the left portion.
1108    */
1109   *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
1110   *y = ty;
1111 }
1112
1113 /**
1114  * gtk_menu_item_set_right_justified:
1115  * @menu_item: a #GtkMenuItem.
1116  * @right_justified: if %TRUE the menu item will appear at the 
1117  *   far right if added to a menu bar.
1118  * 
1119  * Sets whether the menu item appears justified at the right
1120  * side of a menu bar. This was traditionally done for "Help" menu
1121  * items, but is now considered a bad idea. (If the widget
1122  * layout is reversed for a right-to-left language like Hebrew
1123  * or Arabic, right-justified-menu-items appear at the left.)
1124  **/
1125 void
1126 gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
1127                                    gboolean     right_justified)
1128 {
1129   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1130
1131   right_justified = right_justified != FALSE;
1132
1133   if (right_justified != menu_item->right_justify)
1134     {
1135       menu_item->right_justify = right_justified;
1136       gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1137     }
1138 }
1139
1140 /**
1141  * gtk_menu_item_get_right_justified:
1142  * @menu_item: a #GtkMenuItem
1143  * 
1144  * Gets whether the menu item appears justified at the right
1145  * side of the menu bar.
1146  * 
1147  * Return value: %TRUE if the menu item will appear at the
1148  *   far right if added to a menu bar.
1149  **/
1150 gboolean
1151 gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
1152 {
1153   g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
1154   
1155   return menu_item->right_justify;
1156 }
1157
1158
1159 static void
1160 gtk_menu_item_show_all (GtkWidget *widget)
1161 {
1162   GtkMenuItem *menu_item;
1163
1164   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1165
1166   menu_item = GTK_MENU_ITEM (widget);
1167
1168   /* show children including submenu */
1169   if (menu_item->submenu)
1170     gtk_widget_show_all (menu_item->submenu);
1171   gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1172
1173   gtk_widget_show (widget);
1174 }
1175
1176 static void
1177 gtk_menu_item_hide_all (GtkWidget *widget)
1178 {
1179   GtkMenuItem *menu_item;
1180
1181   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1182
1183   gtk_widget_hide (widget);
1184
1185   menu_item = GTK_MENU_ITEM (widget);
1186
1187   /* hide children including submenu */
1188   gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);
1189   if (menu_item->submenu)
1190     gtk_widget_hide_all (menu_item->submenu);
1191 }
1192
1193 static void
1194 gtk_menu_item_accel_name_foreach (GtkWidget *widget,
1195                                   gpointer data)
1196 {
1197   const gchar **path_p = data;
1198
1199   if (!*path_p)
1200     {
1201       if (GTK_IS_LABEL (widget))
1202         {
1203           *path_p = gtk_label_get_text (GTK_LABEL (widget));
1204           if (*path_p && (*path_p)[0] == 0)
1205             *path_p = NULL;
1206         }
1207       else if (GTK_IS_CONTAINER (widget))
1208         gtk_container_foreach (GTK_CONTAINER (widget),
1209                                gtk_menu_item_accel_name_foreach,
1210                                data);
1211     }
1212 }
1213
1214 static void
1215 gtk_menu_item_parent_set (GtkWidget *widget,
1216                           GtkWidget *previous_parent)
1217 {
1218   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1219   GtkMenu *menu = GTK_IS_MENU (widget->parent) ? GTK_MENU (widget->parent) : NULL;
1220
1221   if (menu)
1222     _gtk_menu_item_refresh_accel_path (menu_item,
1223                                        menu->accel_path,
1224                                        menu->accel_group,
1225                                        TRUE);
1226
1227   if (GTK_WIDGET_CLASS (parent_class)->parent_set)
1228     GTK_WIDGET_CLASS (parent_class)->parent_set (widget, previous_parent);
1229 }
1230
1231 void
1232 _gtk_menu_item_refresh_accel_path (GtkMenuItem   *menu_item,
1233                                    const gchar   *prefix,
1234                                    GtkAccelGroup *accel_group,
1235                                    gboolean       group_changed)
1236 {
1237   const gchar *path;
1238   GtkWidget *widget;
1239
1240   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1241   g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
1242
1243   widget = GTK_WIDGET (menu_item);
1244
1245   if (!accel_group)
1246     {
1247       gtk_widget_set_accel_path (widget, NULL, NULL);
1248       return;
1249     }
1250
1251   path = _gtk_widget_get_accel_path (widget, NULL);
1252   if (!path)                                    /* no active accel_path yet */
1253     {
1254       path = menu_item->accel_path;
1255       if (!path && prefix)
1256         {
1257           gchar *postfix = NULL;
1258
1259           /* try to construct one from label text */
1260           gtk_container_foreach (GTK_CONTAINER (menu_item),
1261                                  gtk_menu_item_accel_name_foreach,
1262                                  &postfix);
1263           menu_item->accel_path = postfix ? g_strconcat (prefix, "/", postfix, NULL) : NULL;
1264           path = menu_item->accel_path;
1265         }
1266       if (path)
1267         gtk_widget_set_accel_path (widget, path, accel_group);
1268     }
1269   else if (group_changed)                       /* reinstall accelerators */
1270     gtk_widget_set_accel_path (widget, path, accel_group);
1271 }
1272
1273 /**
1274  * gtk_menu_item_set_accel_path
1275  * @menu_item:  a valid #GtkMenuItem
1276  * @accel_path: accelerator path, corresponding to this menu item's
1277  *              functionality, or %NULL to unset the current path.
1278  *
1279  * Set the accelerator path on @menu_item, through which runtime changes of the
1280  * menu item's accelerator caused by the user can be identified and saved to
1281  * persistant storage (see gtk_accel_map_save() on this).
1282  * To setup a default accelerator for this menu item, call
1283  * gtk_accel_map_add_entry() with the same @accel_path.
1284  * See also gtk_accel_map_add_entry() on the specifics of accelerator paths,
1285  * and gtk_menu_set_accel_path() for a more convenient variant of this function.
1286  *
1287  * This function is basically a convenience wrapper that handles calling
1288  * gtk_widget_set_accel_path() with the appropriate accelerator group for
1289  * the menu item.
1290  *
1291  * Note that you do need to set an accelerator on the parent menu with
1292  * gtk_menu_set_accel_group() for this to work.
1293  */
1294 void
1295 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
1296                               const gchar *accel_path)
1297 {
1298   GtkWidget *widget;
1299
1300   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1301   g_return_if_fail (accel_path == NULL ||
1302                     (accel_path[0] == '<' && strchr (accel_path, '/')));
1303
1304   widget = GTK_WIDGET (menu_item);
1305
1306   /* store new path */
1307   g_free (menu_item->accel_path);
1308   menu_item->accel_path = g_strdup (accel_path);
1309
1310   /* forget accelerators associated with old path */
1311   gtk_widget_set_accel_path (widget, NULL, NULL);
1312
1313   /* install accelerators associated with new path */
1314   if (widget->parent && GTK_IS_MENU (widget->parent))
1315     {
1316       GtkMenu *menu = GTK_MENU (widget->parent);
1317
1318       if (menu->accel_group)
1319         _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
1320                                            NULL,
1321                                            menu->accel_group,
1322                                            FALSE);
1323     }
1324 }
1325
1326 static void
1327 gtk_menu_item_forall (GtkContainer *container,
1328                       gboolean      include_internals,
1329                       GtkCallback   callback,
1330                       gpointer      callback_data)
1331 {
1332   GtkBin *bin;
1333   GtkMenuItem *menu_item;
1334
1335   g_return_if_fail (GTK_IS_MENU_ITEM (container));
1336   g_return_if_fail (callback != NULL);
1337
1338   bin = GTK_BIN (container);
1339   menu_item = GTK_MENU_ITEM (container);
1340
1341   if (bin->child)
1342     callback (bin->child, callback_data);
1343 }
1344
1345 gboolean
1346 _gtk_menu_item_is_selectable (GtkWidget *menu_item)
1347 {
1348   if ((!GTK_BIN (menu_item)->child &&
1349        G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
1350       GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
1351       !GTK_WIDGET_IS_SENSITIVE (menu_item) ||
1352       !GTK_WIDGET_VISIBLE (menu_item))
1353     return FALSE;
1354
1355   return TRUE;
1356 }