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