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