1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
30 #include "gtkaccellabel.h"
32 #include "gtkmarshalers.h"
34 #include "gtkmenubar.h"
35 #include "gtkmenuprivate.h"
36 #include "gtkseparatormenuitem.h"
37 #include "gtkprivate.h"
38 #include "gtkbuildable.h"
39 #include "gtkactivatable.h"
40 #include "gtksizerequest.h"
46 gboolean use_action_appearance;
67 /* activatable properties */
68 PROP_ACTIVATABLE_RELATED_ACTION,
69 PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
73 static void gtk_menu_item_dispose (GObject *object);
74 static void gtk_menu_item_set_property (GObject *object,
78 static void gtk_menu_item_get_property (GObject *object,
82 static void gtk_menu_item_destroy (GtkObject *object);
83 static void gtk_menu_item_size_allocate (GtkWidget *widget,
84 GtkAllocation *allocation);
85 static void gtk_menu_item_realize (GtkWidget *widget);
86 static void gtk_menu_item_unrealize (GtkWidget *widget);
87 static void gtk_menu_item_map (GtkWidget *widget);
88 static void gtk_menu_item_unmap (GtkWidget *widget);
89 static gboolean gtk_menu_item_enter (GtkWidget *widget,
90 GdkEventCrossing *event);
91 static gboolean gtk_menu_item_leave (GtkWidget *widget,
92 GdkEventCrossing *event);
93 static void gtk_menu_item_paint (GtkWidget *widget,
95 static gint gtk_menu_item_expose (GtkWidget *widget,
96 GdkEventExpose *event);
97 static void gtk_menu_item_parent_set (GtkWidget *widget,
98 GtkWidget *previous_parent);
101 static void gtk_real_menu_item_select (GtkMenuItem *item);
102 static void gtk_real_menu_item_deselect (GtkMenuItem *item);
103 static void gtk_real_menu_item_activate (GtkMenuItem *item);
104 static void gtk_real_menu_item_activate_item (GtkMenuItem *item);
105 static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
107 static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
109 static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget,
110 gboolean group_cycling);
112 static void gtk_menu_item_ensure_label (GtkMenuItem *menu_item);
113 static gint gtk_menu_item_popup_timeout (gpointer data);
114 static void gtk_menu_item_position_menu (GtkMenu *menu,
119 static void gtk_menu_item_show_all (GtkWidget *widget);
120 static void gtk_menu_item_hide_all (GtkWidget *widget);
121 static void gtk_menu_item_forall (GtkContainer *container,
122 gboolean include_internals,
123 GtkCallback callback,
124 gpointer callback_data);
125 static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget,
128 static void gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
130 static G_CONST_RETURN gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item);
132 static void gtk_menu_item_size_request_init (GtkSizeRequestIface *iface);
133 static void gtk_menu_item_get_width (GtkSizeRequest *widget,
136 static void gtk_menu_item_get_height (GtkSizeRequest *widget,
139 static void gtk_menu_item_get_height_for_width (GtkSizeRequest *widget,
144 static void gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface);
145 static void gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
149 static void gtk_menu_item_buildable_custom_finished(GtkBuildable *buildable,
152 const gchar *tagname,
155 static void gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface);
156 static void gtk_menu_item_update (GtkActivatable *activatable,
158 const gchar *property_name);
159 static void gtk_menu_item_sync_action_properties (GtkActivatable *activatable,
161 static void gtk_menu_item_set_related_action (GtkMenuItem *menu_item,
163 static void gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item,
164 gboolean use_appearance);
167 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
169 static GtkBuildableIface *parent_buildable_iface;
171 G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_BIN,
172 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
173 gtk_menu_item_buildable_interface_init)
174 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
175 gtk_menu_item_activatable_interface_init)
176 G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST,
177 gtk_menu_item_size_request_init))
179 #define GET_PRIVATE(object) \
180 (G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_MENU_ITEM, GtkMenuItemPrivate))
183 gtk_menu_item_class_init (GtkMenuItemClass *klass)
185 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
186 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
187 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
188 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
190 gobject_class->dispose = gtk_menu_item_dispose;
191 gobject_class->set_property = gtk_menu_item_set_property;
192 gobject_class->get_property = gtk_menu_item_get_property;
194 object_class->destroy = gtk_menu_item_destroy;
196 widget_class->size_allocate = gtk_menu_item_size_allocate;
197 widget_class->expose_event = gtk_menu_item_expose;
198 widget_class->realize = gtk_menu_item_realize;
199 widget_class->unrealize = gtk_menu_item_unrealize;
200 widget_class->map = gtk_menu_item_map;
201 widget_class->unmap = gtk_menu_item_unmap;
202 widget_class->enter_notify_event = gtk_menu_item_enter;
203 widget_class->leave_notify_event = gtk_menu_item_leave;
204 widget_class->show_all = gtk_menu_item_show_all;
205 widget_class->hide_all = gtk_menu_item_hide_all;
206 widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate;
207 widget_class->parent_set = gtk_menu_item_parent_set;
208 widget_class->can_activate_accel = gtk_menu_item_can_activate_accel;
210 container_class->forall = gtk_menu_item_forall;
212 klass->activate = gtk_real_menu_item_activate;
213 klass->activate_item = gtk_real_menu_item_activate_item;
214 klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
215 klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
216 klass->set_label = gtk_real_menu_item_set_label;
217 klass->get_label = gtk_real_menu_item_get_label;
218 klass->select = gtk_real_menu_item_select;
219 klass->deselect = gtk_real_menu_item_deselect;
221 klass->hide_on_activate = TRUE;
223 menu_item_signals[ACTIVATE] =
224 g_signal_new (I_("activate"),
225 G_OBJECT_CLASS_TYPE (gobject_class),
226 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
227 G_STRUCT_OFFSET (GtkMenuItemClass, activate),
229 _gtk_marshal_VOID__VOID,
231 widget_class->activate_signal = menu_item_signals[ACTIVATE];
233 menu_item_signals[ACTIVATE_ITEM] =
234 g_signal_new (I_("activate-item"),
235 G_OBJECT_CLASS_TYPE (gobject_class),
237 G_STRUCT_OFFSET (GtkMenuItemClass, activate_item),
239 _gtk_marshal_VOID__VOID,
242 menu_item_signals[TOGGLE_SIZE_REQUEST] =
243 g_signal_new (I_("toggle-size-request"),
244 G_OBJECT_CLASS_TYPE (gobject_class),
246 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request),
248 _gtk_marshal_VOID__POINTER,
252 menu_item_signals[TOGGLE_SIZE_ALLOCATE] =
253 g_signal_new (I_("toggle-size-allocate"),
254 G_OBJECT_CLASS_TYPE (gobject_class),
256 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate),
258 _gtk_marshal_VOID__INT,
262 menu_item_signals[SELECT] =
263 g_signal_new (I_("select"),
264 G_OBJECT_CLASS_TYPE (gobject_class),
266 G_STRUCT_OFFSET (GtkMenuItemClass, select),
268 _gtk_marshal_VOID__VOID,
271 menu_item_signals[DESELECT] =
272 g_signal_new (I_("deselect"),
273 G_OBJECT_CLASS_TYPE (gobject_class),
275 G_STRUCT_OFFSET (GtkMenuItemClass, deselect),
277 _gtk_marshal_VOID__VOID,
281 * GtkMenuItem:right-justified:
283 * Sets whether the menu item appears justified at the right side of a menu bar.
287 g_object_class_install_property (gobject_class,
288 PROP_RIGHT_JUSTIFIED,
289 g_param_spec_boolean ("right-justified",
290 P_("Right Justified"),
291 P_("Sets whether the menu item appears justified at the right side of a menu bar"),
293 GTK_PARAM_READWRITE));
296 * GtkMenuItem:submenu:
298 * The submenu attached to the menu item, or NULL if it has none.
302 g_object_class_install_property (gobject_class,
304 g_param_spec_object ("submenu",
306 P_("The submenu attached to the menu item, or NULL if it has none"),
308 GTK_PARAM_READWRITE));
312 * GtkMenuItem:accel-path:
314 * Sets the accelerator path of the menu item, through which runtime
315 * changes of the menu item's accelerator caused by the user can be
316 * identified and saved to persistant storage.
320 g_object_class_install_property (gobject_class,
322 g_param_spec_string ("accel-path",
324 P_("Sets the accelerator path of the menu item"),
326 GTK_PARAM_READWRITE));
331 * The text for the child label.
335 g_object_class_install_property (gobject_class,
337 g_param_spec_string ("label",
339 P_("The text for the child label"),
341 GTK_PARAM_READWRITE));
344 * GtkMenuItem:use-underline:
346 * %TRUE if underlines in the text indicate mnemonics
350 g_object_class_install_property (gobject_class,
352 g_param_spec_boolean ("use-underline",
354 P_("If set, an underline in the text indicates "
355 "the next character should be used for the "
356 "mnemonic accelerator key"),
358 GTK_PARAM_READWRITE));
360 g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
361 g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
363 gtk_widget_class_install_style_property_parser (widget_class,
364 g_param_spec_enum ("selected-shadow-type",
365 "Selected Shadow Type",
366 "Shadow type when item is selected",
367 GTK_TYPE_SHADOW_TYPE,
370 gtk_rc_property_parse_enum);
372 gtk_widget_class_install_style_property (widget_class,
373 g_param_spec_int ("horizontal-padding",
374 "Horizontal Padding",
375 "Padding to left and right of the menu item",
379 GTK_PARAM_READABLE));
381 gtk_widget_class_install_style_property (widget_class,
382 g_param_spec_int ("toggle-spacing",
384 "Space between icon and label",
388 GTK_PARAM_READABLE));
390 gtk_widget_class_install_style_property (widget_class,
391 g_param_spec_int ("arrow-spacing",
393 "Space between label and arrow",
397 GTK_PARAM_READABLE));
399 gtk_widget_class_install_style_property (widget_class,
400 g_param_spec_float ("arrow-scaling",
402 P_("Amount of space used up by arrow, relative to the menu item's font size"),
404 GTK_PARAM_READABLE));
407 * GtkMenuItem:width-chars:
409 * The minimum desired width of the menu item in characters.
413 gtk_widget_class_install_style_property (widget_class,
414 g_param_spec_int ("width-chars",
415 P_("Width in Characters"),
416 P_("The minimum desired width of the menu item in characters"),
418 GTK_PARAM_READABLE));
420 g_type_class_add_private (object_class, sizeof (GtkMenuItemPrivate));
424 gtk_menu_item_init (GtkMenuItem *menu_item)
426 GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
428 gtk_widget_set_has_window (GTK_WIDGET (menu_item), FALSE);
431 priv->use_action_appearance = TRUE;
433 menu_item->submenu = NULL;
434 menu_item->toggle_size = 0;
435 menu_item->accelerator_width = 0;
436 menu_item->show_submenu_indicator = FALSE;
437 if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
438 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
440 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
441 menu_item->submenu_placement = GTK_TOP_BOTTOM;
442 menu_item->right_justify = FALSE;
444 menu_item->timer = 0;
448 gtk_menu_item_new (void)
450 return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
454 gtk_menu_item_new_with_label (const gchar *label)
456 return g_object_new (GTK_TYPE_MENU_ITEM,
463 * gtk_menu_item_new_with_mnemonic:
464 * @label: The text of the button, with an underscore in front of the
466 * @returns: a new #GtkMenuItem
468 * Creates a new #GtkMenuItem containing a label. The label
469 * will be created using gtk_label_new_with_mnemonic(), so underscores
470 * in @label indicate the mnemonic for the menu item.
473 gtk_menu_item_new_with_mnemonic (const gchar *label)
475 return g_object_new (GTK_TYPE_MENU_ITEM,
476 "use-underline", TRUE,
482 gtk_menu_item_dispose (GObject *object)
484 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
485 GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
489 gtk_action_disconnect_accelerator (priv->action);
490 gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), NULL);
494 G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object);
498 gtk_menu_item_set_property (GObject *object,
503 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
507 case PROP_RIGHT_JUSTIFIED:
508 gtk_menu_item_set_right_justified (menu_item, g_value_get_boolean (value));
511 gtk_menu_item_set_submenu (menu_item, g_value_get_object (value));
513 case PROP_ACCEL_PATH:
514 gtk_menu_item_set_accel_path (menu_item, g_value_get_string (value));
517 gtk_menu_item_set_label (menu_item, g_value_get_string (value));
519 case PROP_USE_UNDERLINE:
520 gtk_menu_item_set_use_underline (menu_item, g_value_get_boolean (value));
522 case PROP_ACTIVATABLE_RELATED_ACTION:
523 gtk_menu_item_set_related_action (menu_item, g_value_get_object (value));
525 case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
526 gtk_menu_item_set_use_action_appearance (menu_item, g_value_get_boolean (value));
529 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
535 gtk_menu_item_get_property (GObject *object,
540 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
541 GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
545 case PROP_RIGHT_JUSTIFIED:
546 g_value_set_boolean (value, gtk_menu_item_get_right_justified (menu_item));
549 g_value_set_object (value, gtk_menu_item_get_submenu (menu_item));
551 case PROP_ACCEL_PATH:
552 g_value_set_string (value, gtk_menu_item_get_accel_path (menu_item));
555 g_value_set_string (value, gtk_menu_item_get_label (menu_item));
557 case PROP_USE_UNDERLINE:
558 g_value_set_boolean (value, gtk_menu_item_get_use_underline (menu_item));
560 case PROP_ACTIVATABLE_RELATED_ACTION:
561 g_value_set_object (value, priv->action);
563 case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
564 g_value_set_boolean (value, priv->use_action_appearance);
567 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
573 gtk_menu_item_destroy (GtkObject *object)
575 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
577 if (menu_item->submenu)
578 gtk_widget_destroy (menu_item->submenu);
580 GTK_OBJECT_CLASS (gtk_menu_item_parent_class)->destroy (object);
584 gtk_menu_item_detacher (GtkWidget *widget,
587 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
589 g_return_if_fail (menu_item->submenu == (GtkWidget*) menu);
591 menu_item->submenu = NULL;
595 get_arrow_size (GtkWidget *widget,
599 PangoContext *context;
600 PangoFontMetrics *metrics;
601 gfloat arrow_scaling;
605 gtk_widget_style_get (widget,
606 "arrow-scaling", &arrow_scaling,
609 context = gtk_widget_get_pango_context (child);
610 metrics = pango_context_get_metrics (context,
611 gtk_widget_get_style (child)->font_desc,
612 pango_context_get_language (context));
614 *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
615 pango_font_metrics_get_descent (metrics)));
617 pango_font_metrics_unref (metrics);
619 *size = *size * arrow_scaling;
624 gtk_menu_item_accel_width_foreach (GtkWidget *widget,
629 if (GTK_IS_ACCEL_LABEL (widget))
633 w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
634 *width = MAX (*width, w);
636 else if (GTK_IS_CONTAINER (widget))
637 gtk_container_foreach (GTK_CONTAINER (widget),
638 gtk_menu_item_accel_width_foreach,
643 get_minimum_width (GtkWidget *widget)
645 PangoContext *context;
646 PangoFontMetrics *metrics;
650 context = gtk_widget_get_pango_context (widget);
651 metrics = pango_context_get_metrics (context,
652 gtk_widget_get_style (widget)->font_desc,
653 pango_context_get_language (context));
655 width = pango_font_metrics_get_approximate_char_width (metrics);
657 pango_font_metrics_unref (metrics);
659 gtk_widget_style_get (widget, "width-chars", &width_chars, NULL);
661 return PANGO_PIXELS (width_chars * width);
665 gtk_menu_item_size_request_init (GtkSizeRequestIface *iface)
667 iface->get_width = gtk_menu_item_get_width;
668 iface->get_height = gtk_menu_item_get_height;
669 iface->get_height_for_width = gtk_menu_item_get_height_for_width;
673 gtk_menu_item_get_width (GtkSizeRequest *request,
677 GtkMenuItem *menu_item;
679 GtkWidget *child, *widget = GTK_WIDGET (request);
682 guint horizontal_padding;
684 GtkPackDirection pack_dir;
685 GtkPackDirection child_pack_dir;
686 gint min_width, nat_width;
688 min_width = nat_width = 0;
690 gtk_widget_style_get (widget,
691 "horizontal-padding", &horizontal_padding,
694 bin = GTK_BIN (widget);
695 menu_item = GTK_MENU_ITEM (widget);
696 parent = gtk_widget_get_parent (widget);
698 if (GTK_IS_MENU_BAR (parent))
700 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
701 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
705 pack_dir = GTK_PACK_DIRECTION_LTR;
706 child_pack_dir = GTK_PACK_DIRECTION_LTR;
709 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
711 min_width = (border_width + gtk_widget_get_style (widget)->xthickness) * 2;
713 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
714 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
715 min_width += 2 * horizontal_padding;
717 nat_width = min_width;
719 child = gtk_bin_get_child (bin);
721 if (child != NULL && gtk_widget_get_visible (child))
723 gint child_min, child_nat;
725 gtk_size_request_get_width (GTK_SIZE_REQUEST (child), &child_min, &child_nat);
727 if (menu_item->submenu && menu_item->show_submenu_indicator)
732 gtk_widget_style_get (widget,
733 "arrow-spacing", &arrow_spacing,
736 get_arrow_size (widget, child, &arrow_size);
738 min_width += arrow_size;
739 min_width += arrow_spacing;
741 min_width = MAX (min_width, get_minimum_width (widget));
743 nat_width = min_width;
747 min_width += child_min;
748 nat_width += child_nat;
754 gtk_container_foreach (GTK_CONTAINER (menu_item),
755 gtk_menu_item_accel_width_foreach,
757 menu_item->accelerator_width = accel_width;
760 *minimum_size = min_width;
763 *natural_size = nat_width;
767 gtk_menu_item_get_height (GtkSizeRequest *request,
771 GtkMenuItem *menu_item;
774 GtkWidget *child, *widget = GTK_WIDGET (request);
777 guint horizontal_padding;
779 GtkPackDirection pack_dir;
780 GtkPackDirection child_pack_dir;
781 gint min_height, nat_height;
783 min_height = nat_height = 0;
785 style = gtk_widget_get_style (widget);
787 gtk_widget_style_get (widget,
788 "horizontal-padding", &horizontal_padding,
791 bin = GTK_BIN (widget);
792 menu_item = GTK_MENU_ITEM (widget);
793 parent = gtk_widget_get_parent (widget);
795 if (GTK_IS_MENU_BAR (parent))
797 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
798 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
802 pack_dir = GTK_PACK_DIRECTION_LTR;
803 child_pack_dir = GTK_PACK_DIRECTION_LTR;
806 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
807 min_height = (border_width + style->ythickness) * 2;
809 if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
810 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
811 min_height += 2 * horizontal_padding;
813 nat_height = min_height;
815 child = gtk_bin_get_child (bin);
817 if (child != NULL && gtk_widget_get_visible (child))
819 gint child_min, child_nat;
821 gtk_size_request_get_height (GTK_SIZE_REQUEST (child), &child_min, &child_nat);
823 min_height += child_min;
824 nat_height += child_nat;
826 if (menu_item->submenu && menu_item->show_submenu_indicator)
830 get_arrow_size (widget, child, &arrow_size);
832 min_height = MAX (min_height, arrow_size);
833 nat_height = MAX (nat_height, arrow_size);
836 else /* separator item */
838 gboolean wide_separators;
839 gint separator_height;
841 gtk_widget_style_get (widget,
842 "wide-separators", &wide_separators,
843 "separator-height", &separator_height,
847 min_height += separator_height + style->ythickness;
849 min_height += style->ythickness * 2;
851 nat_height = min_height;
855 gtk_container_foreach (GTK_CONTAINER (menu_item),
856 gtk_menu_item_accel_width_foreach,
858 menu_item->accelerator_width = accel_width;
861 *minimum_size = min_height;
864 *natural_size = nat_height;
868 gtk_menu_item_get_height_for_width (GtkSizeRequest *request,
873 GtkMenuItem *menu_item;
876 GtkWidget *child, *widget = GTK_WIDGET (request);
878 guint horizontal_padding;
880 GtkPackDirection pack_dir;
881 GtkPackDirection child_pack_dir;
882 gint min_height, nat_height;
885 min_height = nat_height = 0;
887 style = gtk_widget_get_style (widget);
889 gtk_widget_style_get (widget,
890 "horizontal-padding", &horizontal_padding,
893 bin = GTK_BIN (widget);
894 menu_item = GTK_MENU_ITEM (widget);
895 parent = gtk_widget_get_parent (widget);
897 if (GTK_IS_MENU_BAR (parent))
899 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
900 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
904 pack_dir = GTK_PACK_DIRECTION_LTR;
905 child_pack_dir = GTK_PACK_DIRECTION_LTR;
908 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
909 min_height = (border_width + style->ythickness) * 2;
911 avail_size = for_size;
912 avail_size -= (border_width + style->xthickness) * 2;
914 if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
915 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
916 min_height += 2 * horizontal_padding;
918 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
919 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
920 avail_size -= 2 * horizontal_padding;
922 nat_height = min_height;
924 child = gtk_bin_get_child (bin);
926 if (child != NULL && gtk_widget_get_visible (child))
928 gint child_min, child_nat;
931 if (menu_item->submenu && menu_item->show_submenu_indicator)
936 gtk_widget_style_get (widget,
937 "arrow-spacing", &arrow_spacing,
940 get_arrow_size (widget, child, &arrow_size);
942 avail_size -= arrow_size;
943 avail_size -= arrow_spacing;
946 gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (child), avail_size, &child_min, &child_nat);
948 min_height += child_min;
949 nat_height += child_nat;
951 if (menu_item->submenu && menu_item->show_submenu_indicator)
953 min_height = MAX (min_height, arrow_size);
954 nat_height = MAX (nat_height, arrow_size);
957 else /* separator item */
959 gboolean wide_separators;
960 gint separator_height;
962 gtk_widget_style_get (widget,
963 "wide-separators", &wide_separators,
964 "separator-height", &separator_height,
968 min_height += separator_height + style->ythickness;
970 min_height += style->ythickness * 2;
972 nat_height = min_height;
976 *minimum_size = min_height;
979 *natural_size = nat_height;
983 gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface)
985 parent_buildable_iface = g_type_interface_peek_parent (iface);
986 iface->add_child = gtk_menu_item_buildable_add_child;
987 iface->custom_finished = gtk_menu_item_buildable_custom_finished;
991 gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
996 if (type && strcmp (type, "submenu") == 0)
997 gtk_menu_item_set_submenu (GTK_MENU_ITEM (buildable),
1000 parent_buildable_iface->add_child (buildable, builder, child, type);
1005 gtk_menu_item_buildable_custom_finished (GtkBuildable *buildable,
1006 GtkBuilder *builder,
1008 const gchar *tagname,
1011 GtkWidget *toplevel;
1013 if (strcmp (tagname, "accelerator") == 0)
1015 GtkMenuShell *menu_shell;
1018 menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (GTK_WIDGET (buildable)));
1021 while (GTK_IS_MENU (menu_shell) &&
1022 (attach = gtk_menu_get_attach_widget (GTK_MENU (menu_shell))) != NULL)
1023 menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (attach));
1025 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu_shell));
1029 /* Fall back to something ... */
1030 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (buildable));
1032 g_warning ("found a GtkMenuItem '%s' without a parent GtkMenuShell, assigned accelerators wont work.",
1033 gtk_buildable_get_name (buildable));
1036 /* Feed the correct toplevel to the GtkWidget accelerator parsing code */
1037 _gtk_widget_buildable_finish_accelerator (GTK_WIDGET (buildable), toplevel, user_data);
1040 parent_buildable_iface->custom_finished (buildable, builder, child, tagname, user_data);
1045 gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface)
1047 iface->update = gtk_menu_item_update;
1048 iface->sync_action_properties = gtk_menu_item_sync_action_properties;
1052 activatable_update_label (GtkMenuItem *menu_item, GtkAction *action)
1056 child = gtk_bin_get_child (GTK_BIN (menu_item));
1058 if (GTK_IS_LABEL (child))
1062 label = gtk_action_get_label (action);
1063 gtk_menu_item_set_label (menu_item, label);
1067 gboolean _gtk_menu_is_empty (GtkWidget *menu);
1070 gtk_menu_item_update (GtkActivatable *activatable,
1072 const gchar *property_name)
1074 GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
1075 GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
1077 if (strcmp (property_name, "visible") == 0)
1078 _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
1079 _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
1080 else if (strcmp (property_name, "sensitive") == 0)
1081 gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
1082 else if (priv->use_action_appearance)
1084 if (strcmp (property_name, "label") == 0)
1085 activatable_update_label (menu_item, action);
1090 gtk_menu_item_sync_action_properties (GtkActivatable *activatable,
1093 GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
1094 GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
1097 if (!priv->use_action_appearance || !action)
1099 label = gtk_bin_get_child (GTK_BIN (menu_item));
1101 if (GTK_IS_ACCEL_LABEL (label))
1102 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), GTK_WIDGET (menu_item));
1108 _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
1109 _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
1111 gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
1113 if (priv->use_action_appearance)
1115 label = gtk_bin_get_child (GTK_BIN (menu_item));
1117 /* make sure label is a label */
1118 if (label && !GTK_IS_LABEL (label))
1120 gtk_container_remove (GTK_CONTAINER (menu_item), label);
1124 gtk_menu_item_ensure_label (menu_item);
1125 gtk_menu_item_set_use_underline (menu_item, TRUE);
1127 if (GTK_IS_ACCEL_LABEL (label) && gtk_action_get_accel_path (action))
1129 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), NULL);
1130 gtk_accel_label_set_accel_closure (GTK_ACCEL_LABEL (label),
1131 gtk_action_get_accel_closure (action));
1134 activatable_update_label (menu_item, action);
1139 gtk_menu_item_set_related_action (GtkMenuItem *menu_item,
1142 GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
1144 if (priv->action == action)
1149 gtk_action_disconnect_accelerator (priv->action);
1154 const gchar *accel_path;
1156 accel_path = gtk_action_get_accel_path (action);
1159 gtk_action_connect_accelerator (action);
1160 gtk_menu_item_set_accel_path (menu_item, accel_path);
1164 gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), action);
1166 priv->action = action;
1170 gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item,
1171 gboolean use_appearance)
1173 GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
1175 if (priv->use_action_appearance != use_appearance)
1177 priv->use_action_appearance = use_appearance;
1179 gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (menu_item), priv->action);
1185 * gtk_menu_item_set_submenu:
1186 * @menu_item: a #GtkMenuItem
1187 * @submenu: (allow-none): the submenu, or %NULL
1189 * Sets or replaces the menu item's submenu, or removes it when a %NULL
1190 * submenu is passed.
1193 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
1196 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1197 g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu));
1199 if (menu_item->submenu != submenu)
1201 if (menu_item->submenu)
1202 gtk_menu_detach (GTK_MENU (menu_item->submenu));
1206 menu_item->submenu = submenu;
1207 gtk_menu_attach_to_widget (GTK_MENU (submenu),
1208 GTK_WIDGET (menu_item),
1209 gtk_menu_item_detacher);
1212 if (gtk_widget_get_parent (GTK_WIDGET (menu_item)))
1213 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1215 g_object_notify (G_OBJECT (menu_item), "submenu");
1220 * gtk_menu_item_get_submenu:
1221 * @menu_item: a #GtkMenuItem
1223 * Gets the submenu underneath this menu item, if any. See
1224 * gtk_menu_item_set_submenu().
1226 * Return value: submenu for this menu item, or %NULL if none.
1229 gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
1231 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
1233 return menu_item->submenu;
1236 void _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
1237 GtkSubmenuPlacement placement);
1240 _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
1241 GtkSubmenuPlacement placement)
1243 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1245 menu_item->submenu_placement = placement;
1249 gtk_menu_item_select (GtkMenuItem *menu_item)
1253 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1255 g_signal_emit (menu_item, menu_item_signals[SELECT], 0);
1257 /* Enable themeing of the parent menu item depending on whether
1258 * something is selected in its submenu
1260 parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1261 if (GTK_IS_MENU (parent))
1263 GtkMenu *menu = GTK_MENU (parent);
1265 if (menu->parent_menu_item)
1266 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
1271 gtk_menu_item_deselect (GtkMenuItem *menu_item)
1275 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1277 g_signal_emit (menu_item, menu_item_signals[DESELECT], 0);
1279 /* Enable themeing of the parent menu item depending on whether
1280 * something is selected in its submenu
1282 parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1283 if (GTK_IS_MENU (parent))
1285 GtkMenu *menu = GTK_MENU (parent);
1287 if (menu->parent_menu_item)
1288 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
1293 gtk_menu_item_activate (GtkMenuItem *menu_item)
1295 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1297 g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
1301 gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1304 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1306 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
1310 gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1313 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1315 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
1319 gtk_menu_item_size_allocate (GtkWidget *widget,
1320 GtkAllocation *allocation)
1322 GtkMenuItem *menu_item;
1324 GtkAllocation child_allocation;
1325 GtkTextDirection direction;
1326 GtkPackDirection pack_dir;
1327 GtkPackDirection child_pack_dir;
1331 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1332 g_return_if_fail (allocation != NULL);
1334 menu_item = GTK_MENU_ITEM (widget);
1335 bin = GTK_BIN (widget);
1337 direction = gtk_widget_get_direction (widget);
1339 parent = gtk_widget_get_parent (widget);
1340 if (GTK_IS_MENU_BAR (parent))
1342 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
1343 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
1347 pack_dir = GTK_PACK_DIRECTION_LTR;
1348 child_pack_dir = GTK_PACK_DIRECTION_LTR;
1351 gtk_widget_set_allocation (widget, allocation);
1353 child = gtk_bin_get_child (bin);
1356 GtkRequisition child_requisition;
1358 guint horizontal_padding;
1361 style = gtk_widget_get_style (widget);
1362 gtk_widget_style_get (widget,
1363 "horizontal-padding", &horizontal_padding,
1366 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1367 child_allocation.x = border_width + style->xthickness;
1368 child_allocation.y = border_width + style->ythickness;
1370 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
1371 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
1372 child_allocation.x += horizontal_padding;
1373 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
1374 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
1375 child_allocation.y += horizontal_padding;
1377 child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
1378 child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
1380 if (child_pack_dir == GTK_PACK_DIRECTION_LTR ||
1381 child_pack_dir == GTK_PACK_DIRECTION_RTL)
1383 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL))
1384 child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
1385 child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size;
1389 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT))
1390 child_allocation.y += GTK_MENU_ITEM (widget)->toggle_size;
1391 child_allocation.height -= GTK_MENU_ITEM (widget)->toggle_size;
1394 child_allocation.x += allocation->x;
1395 child_allocation.y += allocation->y;
1397 gtk_widget_get_child_requisition (child, &child_requisition);
1398 if (menu_item->submenu && menu_item->show_submenu_indicator)
1400 if (direction == GTK_TEXT_DIR_RTL)
1401 child_allocation.x += child_requisition.height;
1402 child_allocation.width -= child_requisition.height;
1405 if (child_allocation.width < 1)
1406 child_allocation.width = 1;
1408 gtk_widget_size_allocate (child, &child_allocation);
1411 if (gtk_widget_get_realized (widget))
1412 gdk_window_move_resize (menu_item->event_window,
1413 allocation->x, allocation->y,
1414 allocation->width, allocation->height);
1416 if (menu_item->submenu)
1417 gtk_menu_reposition (GTK_MENU (menu_item->submenu));
1421 gtk_menu_item_realize (GtkWidget *widget)
1423 GtkAllocation allocation;
1424 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1426 GdkWindowAttr attributes;
1427 gint attributes_mask;
1429 gtk_widget_set_realized (widget, TRUE);
1431 window = gtk_widget_get_parent_window (widget);
1432 gtk_widget_set_window (widget, window);
1433 g_object_ref (window);
1435 gtk_widget_get_allocation (widget, &allocation);
1437 attributes.x = allocation.x;
1438 attributes.y = allocation.y;
1439 attributes.width = allocation.width;
1440 attributes.height = allocation.height;
1441 attributes.window_type = GDK_WINDOW_CHILD;
1442 attributes.wclass = GDK_INPUT_ONLY;
1443 attributes.event_mask = (gtk_widget_get_events (widget) |
1444 GDK_BUTTON_PRESS_MASK |
1445 GDK_BUTTON_RELEASE_MASK |
1446 GDK_ENTER_NOTIFY_MASK |
1447 GDK_LEAVE_NOTIFY_MASK |
1448 GDK_POINTER_MOTION_MASK);
1450 attributes_mask = GDK_WA_X | GDK_WA_Y;
1452 menu_item->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1453 &attributes, attributes_mask);
1454 gdk_window_set_user_data (menu_item->event_window, widget);
1456 gtk_widget_style_attach (widget);
1460 gtk_menu_item_unrealize (GtkWidget *widget)
1462 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1464 gdk_window_set_user_data (menu_item->event_window, NULL);
1465 gdk_window_destroy (menu_item->event_window);
1466 menu_item->event_window = NULL;
1468 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize (widget);
1472 gtk_menu_item_map (GtkWidget *widget)
1474 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1476 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget);
1478 gdk_window_show (menu_item->event_window);
1482 gtk_menu_item_unmap (GtkWidget *widget)
1484 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1486 gdk_window_hide (menu_item->event_window);
1488 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget);
1492 gtk_menu_item_enter (GtkWidget *widget,
1493 GdkEventCrossing *event)
1495 g_return_val_if_fail (event != NULL, FALSE);
1497 return gtk_widget_event (gtk_widget_get_parent (widget), (GdkEvent *) event);
1501 gtk_menu_item_leave (GtkWidget *widget,
1502 GdkEventCrossing *event)
1504 g_return_val_if_fail (event != NULL, FALSE);
1506 return gtk_widget_event (gtk_widget_get_parent (widget), (GdkEvent*) event);
1510 gtk_menu_item_paint (GtkWidget *widget,
1513 GtkAllocation allocation;
1514 GtkMenuItem *menu_item;
1515 GtkStateType state_type;
1516 GtkShadowType shadow_type, selected_shadow_type;
1522 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1524 if (gtk_widget_is_drawable (widget))
1526 menu_item = GTK_MENU_ITEM (widget);
1528 gtk_widget_get_allocation (widget, &allocation);
1529 state_type = gtk_widget_get_state (widget);
1530 style = gtk_widget_get_style (widget);
1531 window = gtk_widget_get_window (widget);
1533 x = allocation.x + border_width;
1534 y = allocation.y + border_width;
1535 width = allocation.width - border_width * 2;
1536 height = allocation.height - border_width * 2;
1538 child = gtk_bin_get_child (GTK_BIN (menu_item));
1540 if (child && state_type == GTK_STATE_PRELIGHT)
1542 gtk_widget_style_get (widget,
1543 "selected-shadow-type", &selected_shadow_type,
1545 gtk_paint_box (style,
1548 selected_shadow_type,
1549 area, widget, "menuitem",
1550 x, y, width, height);
1553 if (menu_item->submenu && menu_item->show_submenu_indicator)
1555 gint arrow_x, arrow_y;
1557 guint horizontal_padding;
1558 GtkTextDirection direction;
1559 GtkArrowType arrow_type;
1561 direction = gtk_widget_get_direction (widget);
1563 gtk_widget_style_get (widget,
1564 "horizontal-padding", &horizontal_padding,
1567 get_arrow_size (widget, child, &arrow_size);
1569 shadow_type = GTK_SHADOW_OUT;
1570 if (state_type == GTK_STATE_PRELIGHT)
1571 shadow_type = GTK_SHADOW_IN;
1573 if (direction == GTK_TEXT_DIR_LTR)
1575 arrow_x = x + width - horizontal_padding - arrow_size;
1576 arrow_type = GTK_ARROW_RIGHT;
1580 arrow_x = x + horizontal_padding;
1581 arrow_type = GTK_ARROW_LEFT;
1584 arrow_y = y + (height - arrow_size) / 2;
1586 gtk_paint_arrow (style, window,
1587 state_type, shadow_type,
1588 area, widget, "menuitem",
1591 arrow_size, arrow_size);
1595 gboolean wide_separators;
1596 gint separator_height;
1597 guint horizontal_padding;
1599 gtk_widget_style_get (widget,
1600 "wide-separators", &wide_separators,
1601 "separator-height", &separator_height,
1602 "horizontal-padding", &horizontal_padding,
1605 if (wide_separators)
1606 gtk_paint_box (style, window,
1607 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
1608 area, widget, "hseparator",
1609 allocation.x + horizontal_padding + style->xthickness,
1610 allocation.y + (allocation.height - separator_height - style->ythickness) / 2,
1611 allocation.width - 2 * (horizontal_padding + style->xthickness),
1614 gtk_paint_hline (style, window,
1615 GTK_STATE_NORMAL, area, widget, "menuitem",
1616 allocation.x + horizontal_padding + style->xthickness,
1617 allocation.x + allocation.width - horizontal_padding - style->xthickness - 1,
1618 allocation.y + (allocation.height - style->ythickness) / 2);
1624 gtk_menu_item_expose (GtkWidget *widget,
1625 GdkEventExpose *event)
1627 g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
1628 g_return_val_if_fail (event != NULL, FALSE);
1630 if (gtk_widget_is_drawable (widget))
1632 gtk_menu_item_paint (widget, &event->area);
1634 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->expose_event (widget, event);
1641 gtk_real_menu_item_select (GtkMenuItem *menu_item)
1643 gboolean touchscreen_mode;
1645 g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)),
1646 "gtk-touchscreen-mode", &touchscreen_mode,
1649 if (!touchscreen_mode &&
1650 menu_item->submenu &&
1651 (!gtk_widget_get_mapped (menu_item->submenu) ||
1652 GTK_MENU (menu_item->submenu)->tearoff_active))
1654 _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1657 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
1658 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1662 gtk_real_menu_item_deselect (GtkMenuItem *menu_item)
1664 if (menu_item->submenu)
1665 _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
1667 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
1668 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1672 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
1673 gboolean group_cycling)
1677 parent = gtk_widget_get_parent (widget);
1679 if (GTK_IS_MENU_SHELL (parent))
1680 _gtk_menu_shell_set_keyboard_mode (GTK_MENU_SHELL (parent), TRUE);
1682 if (group_cycling &&
1684 GTK_IS_MENU_SHELL (parent) &&
1685 GTK_MENU_SHELL (parent)->active)
1687 gtk_menu_shell_select_item (GTK_MENU_SHELL (parent),
1691 g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
1697 gtk_real_menu_item_activate (GtkMenuItem *menu_item)
1699 GtkMenuItemPrivate *priv;
1701 priv = GET_PRIVATE (menu_item);
1704 gtk_action_activate (priv->action);
1709 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
1711 GtkMenuItemPrivate *priv;
1715 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1717 priv = GET_PRIVATE (menu_item);
1718 widget = GTK_WIDGET (menu_item);
1719 parent = gtk_widget_get_parent (widget);
1721 if (parent && GTK_IS_MENU_SHELL (parent))
1723 GtkMenuShell *menu_shell = GTK_MENU_SHELL (parent);
1725 if (menu_item->submenu == NULL)
1726 gtk_menu_shell_activate_item (menu_shell,
1730 _gtk_menu_shell_activate (menu_shell);
1732 gtk_menu_shell_select_item (menu_shell, widget);
1733 _gtk_menu_item_popup_submenu (widget, FALSE);
1735 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
1741 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1744 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1750 gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1753 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1755 menu_item->toggle_size = allocation;
1759 gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
1764 gtk_menu_item_ensure_label (menu_item);
1766 child = gtk_bin_get_child (GTK_BIN (menu_item));
1767 if (GTK_IS_LABEL (child))
1769 gtk_label_set_label (GTK_LABEL (child), label ? label : "");
1771 g_object_notify (G_OBJECT (menu_item), "label");
1775 static G_CONST_RETURN gchar *
1776 gtk_real_menu_item_get_label (GtkMenuItem *menu_item)
1780 gtk_menu_item_ensure_label (menu_item);
1782 child = gtk_bin_get_child (GTK_BIN (menu_item));
1783 if (GTK_IS_LABEL (child))
1784 return gtk_label_get_label (GTK_LABEL (child));
1790 free_timeval (GTimeVal *val)
1792 g_slice_free (GTimeVal, val);
1796 gtk_menu_item_real_popup_submenu (GtkWidget *widget,
1797 gboolean remember_exact_time)
1799 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1802 parent = gtk_widget_get_parent (widget);
1804 if (gtk_widget_is_sensitive (menu_item->submenu) && parent)
1806 gboolean take_focus;
1807 GtkMenuPositionFunc menu_position_func;
1809 take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (parent));
1810 gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),
1813 if (remember_exact_time)
1815 GTimeVal *popup_time = g_slice_new0 (GTimeVal);
1817 g_get_current_time (popup_time);
1819 g_object_set_data_full (G_OBJECT (menu_item->submenu),
1820 "gtk-menu-exact-popup-time", popup_time,
1821 (GDestroyNotify) free_timeval);
1825 g_object_set_data (G_OBJECT (menu_item->submenu),
1826 "gtk-menu-exact-popup-time", NULL);
1829 /* gtk_menu_item_position_menu positions the submenu from the
1830 * menuitems position. If the menuitem doesn't have a window,
1831 * that doesn't work. In that case we use the default
1832 * positioning function instead which places the submenu at the
1835 if (gtk_widget_get_window (widget))
1836 menu_position_func = gtk_menu_item_position_menu;
1838 menu_position_func = NULL;
1840 gtk_menu_popup (GTK_MENU (menu_item->submenu),
1845 GTK_MENU_SHELL (parent)->button,
1849 /* Enable themeing of the parent menu item depending on whether
1850 * its submenu is shown or not.
1852 gtk_widget_queue_draw (widget);
1856 gtk_menu_item_popup_timeout (gpointer data)
1858 GtkMenuItem *menu_item;
1861 menu_item = GTK_MENU_ITEM (data);
1863 parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1865 if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active) ||
1866 (GTK_IS_MENU (parent) && GTK_MENU (parent)->torn_off))
1868 gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1869 if (menu_item->timer_from_keypress && menu_item->submenu)
1870 GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
1873 menu_item->timer = 0;
1879 get_popup_delay (GtkWidget *widget)
1883 parent = gtk_widget_get_parent (widget);
1884 if (GTK_IS_MENU_SHELL (parent))
1886 return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (parent));
1892 g_object_get (gtk_widget_get_settings (widget),
1893 "gtk-menu-popup-delay", &popup_delay,
1901 _gtk_menu_item_popup_submenu (GtkWidget *widget,
1902 gboolean with_delay)
1904 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1906 if (menu_item->timer)
1908 g_source_remove (menu_item->timer);
1909 menu_item->timer = 0;
1915 gint popup_delay = get_popup_delay (widget);
1917 if (popup_delay > 0)
1919 GdkEvent *event = gtk_get_current_event ();
1921 menu_item->timer = gdk_threads_add_timeout (popup_delay,
1922 gtk_menu_item_popup_timeout,
1926 event->type != GDK_BUTTON_PRESS &&
1927 event->type != GDK_ENTER_NOTIFY)
1928 menu_item->timer_from_keypress = TRUE;
1930 menu_item->timer_from_keypress = FALSE;
1933 gdk_event_free (event);
1939 gtk_menu_item_real_popup_submenu (widget, FALSE);
1943 _gtk_menu_item_popdown_submenu (GtkWidget *widget)
1945 GtkMenuItem *menu_item;
1947 menu_item = GTK_MENU_ITEM (widget);
1949 if (menu_item->submenu)
1951 g_object_set_data (G_OBJECT (menu_item->submenu),
1952 "gtk-menu-exact-popup-time", NULL);
1954 if (menu_item->timer)
1956 g_source_remove (menu_item->timer);
1957 menu_item->timer = 0;
1960 gtk_menu_popdown (GTK_MENU (menu_item->submenu));
1962 gtk_widget_queue_draw (widget);
1967 get_offsets (GtkMenu *menu,
1968 gint *horizontal_offset,
1969 gint *vertical_offset)
1971 gint vertical_padding;
1972 gint horizontal_padding;
1974 gtk_widget_style_get (GTK_WIDGET (menu),
1975 "horizontal-offset", horizontal_offset,
1976 "vertical-offset", vertical_offset,
1977 "horizontal-padding", &horizontal_padding,
1978 "vertical-padding", &vertical_padding,
1981 *vertical_offset -= gtk_widget_get_style (GTK_WIDGET (menu))->ythickness;
1982 *vertical_offset -= vertical_padding;
1983 *horizontal_offset += horizontal_padding;
1987 gtk_menu_item_position_menu (GtkMenu *menu,
1993 GtkAllocation allocation;
1994 GtkMenuItem *menu_item;
1996 GtkMenuItem *parent_menu_item;
1997 GtkRequisition requisition;
2000 gint twidth, theight;
2002 GtkTextDirection direction;
2003 GdkRectangle monitor;
2005 gint horizontal_offset;
2006 gint vertical_offset;
2007 gint parent_xthickness;
2008 gint available_left, available_right;
2010 g_return_if_fail (menu != NULL);
2011 g_return_if_fail (x != NULL);
2012 g_return_if_fail (y != NULL);
2014 menu_item = GTK_MENU_ITEM (user_data);
2015 widget = GTK_WIDGET (user_data);
2020 direction = gtk_widget_get_direction (widget);
2022 gtk_size_request_get_size (GTK_SIZE_REQUEST (menu), &requisition, NULL);
2023 twidth = requisition.width;
2024 theight = requisition.height;
2026 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2027 monitor_num = gdk_screen_get_monitor_at_window (screen, menu_item->event_window);
2028 if (monitor_num < 0)
2030 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2032 if (!gdk_window_get_origin (gtk_widget_get_window (widget),
2035 g_warning ("Menu not on screen");
2039 gtk_widget_get_allocation (widget, &allocation);
2044 get_offsets (menu, &horizontal_offset, &vertical_offset);
2046 available_left = tx - monitor.x;
2047 available_right = monitor.x + monitor.width - (tx + allocation.width);
2049 parent = gtk_widget_get_parent (widget);
2050 if (GTK_IS_MENU_BAR (parent))
2052 menu_item->from_menubar = TRUE;
2054 else if (GTK_IS_MENU (parent))
2056 if (GTK_MENU (parent)->parent_menu_item)
2057 menu_item->from_menubar = GTK_MENU_ITEM (GTK_MENU (parent)->parent_menu_item)->from_menubar;
2059 menu_item->from_menubar = FALSE;
2063 menu_item->from_menubar = FALSE;
2066 switch (menu_item->submenu_placement)
2068 case GTK_TOP_BOTTOM:
2069 if (direction == GTK_TEXT_DIR_LTR)
2070 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
2073 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
2074 tx += allocation.width - twidth;
2076 if ((ty + allocation.height + theight) <= monitor.y + monitor.height)
2077 ty += allocation.height;
2078 else if ((ty - theight) >= monitor.y)
2080 else if (monitor.y + monitor.height - (ty + allocation.height) > ty)
2081 ty += allocation.height;
2086 case GTK_LEFT_RIGHT:
2087 if (GTK_IS_MENU (parent))
2088 parent_menu_item = GTK_MENU_ITEM (GTK_MENU (parent)->parent_menu_item);
2090 parent_menu_item = NULL;
2092 parent_xthickness = gtk_widget_get_style (parent)->xthickness;
2094 if (parent_menu_item && !GTK_MENU (parent)->torn_off)
2096 menu_item->submenu_direction = parent_menu_item->submenu_direction;
2100 if (direction == GTK_TEXT_DIR_LTR)
2101 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
2103 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
2106 switch (menu_item->submenu_direction)
2108 case GTK_DIRECTION_LEFT:
2109 if (tx - twidth - parent_xthickness - horizontal_offset >= monitor.x ||
2110 available_left >= available_right)
2111 tx -= twidth + parent_xthickness + horizontal_offset;
2114 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
2115 tx += allocation.width + parent_xthickness + horizontal_offset;
2119 case GTK_DIRECTION_RIGHT:
2120 if (tx + allocation.width + parent_xthickness + horizontal_offset + twidth <= monitor.x + monitor.width ||
2121 available_right >= available_left)
2122 tx += allocation.width + parent_xthickness + horizontal_offset;
2125 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
2126 tx -= twidth + parent_xthickness + horizontal_offset;
2131 ty += vertical_offset;
2133 /* If the height of the menu doesn't fit we move it upward. */
2134 ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
2138 /* If we have negative, tx, here it is because we can't get
2139 * the menu all the way on screen. Favor the left portion.
2141 *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
2144 gtk_menu_set_monitor (menu, monitor_num);
2146 if (!gtk_widget_get_visible (menu->toplevel))
2148 gtk_window_set_type_hint (GTK_WINDOW (menu->toplevel), menu_item->from_menubar?
2149 GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
2154 * gtk_menu_item_set_right_justified:
2155 * @menu_item: a #GtkMenuItem.
2156 * @right_justified: if %TRUE the menu item will appear at the
2157 * far right if added to a menu bar.
2159 * Sets whether the menu item appears justified at the right
2160 * side of a menu bar. This was traditionally done for "Help" menu
2161 * items, but is now considered a bad idea. (If the widget
2162 * layout is reversed for a right-to-left language like Hebrew
2163 * or Arabic, right-justified-menu-items appear at the left.)
2166 gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
2167 gboolean right_justified)
2169 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2171 right_justified = right_justified != FALSE;
2173 if (right_justified != menu_item->right_justify)
2175 menu_item->right_justify = right_justified;
2176 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
2181 * gtk_menu_item_get_right_justified:
2182 * @menu_item: a #GtkMenuItem
2184 * Gets whether the menu item appears justified at the right
2185 * side of the menu bar.
2187 * Return value: %TRUE if the menu item will appear at the
2188 * far right if added to a menu bar.
2191 gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
2193 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2195 return menu_item->right_justify;
2200 gtk_menu_item_show_all (GtkWidget *widget)
2202 GtkMenuItem *menu_item;
2204 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
2206 menu_item = GTK_MENU_ITEM (widget);
2208 /* show children including submenu */
2209 if (menu_item->submenu)
2210 gtk_widget_show_all (menu_item->submenu);
2211 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
2213 gtk_widget_show (widget);
2217 gtk_menu_item_hide_all (GtkWidget *widget)
2219 GtkMenuItem *menu_item;
2221 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
2223 gtk_widget_hide (widget);
2225 menu_item = GTK_MENU_ITEM (widget);
2227 /* hide children including submenu */
2228 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);
2229 if (menu_item->submenu)
2230 gtk_widget_hide_all (menu_item->submenu);
2234 gtk_menu_item_can_activate_accel (GtkWidget *widget,
2239 parent = gtk_widget_get_parent (widget);
2240 /* Chain to the parent GtkMenu for further checks */
2241 return (gtk_widget_is_sensitive (widget) && gtk_widget_get_visible (widget) &&
2242 parent && gtk_widget_can_activate_accel (parent, signal_id));
2246 gtk_menu_item_accel_name_foreach (GtkWidget *widget,
2249 const gchar **path_p = data;
2253 if (GTK_IS_LABEL (widget))
2255 *path_p = gtk_label_get_text (GTK_LABEL (widget));
2256 if (*path_p && (*path_p)[0] == 0)
2259 else if (GTK_IS_CONTAINER (widget))
2260 gtk_container_foreach (GTK_CONTAINER (widget),
2261 gtk_menu_item_accel_name_foreach,
2267 gtk_menu_item_parent_set (GtkWidget *widget,
2268 GtkWidget *previous_parent)
2270 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2274 parent = gtk_widget_get_parent (widget);
2275 menu = GTK_IS_MENU (parent) ? GTK_MENU (parent) : NULL;
2278 _gtk_menu_item_refresh_accel_path (menu_item,
2283 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set)
2284 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent);
2288 _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item,
2289 const gchar *prefix,
2290 GtkAccelGroup *accel_group,
2291 gboolean group_changed)
2296 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2297 g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
2299 widget = GTK_WIDGET (menu_item);
2303 gtk_widget_set_accel_path (widget, NULL, NULL);
2307 path = _gtk_widget_get_accel_path (widget, NULL);
2308 if (!path) /* no active accel_path yet */
2310 path = menu_item->accel_path;
2311 if (!path && prefix)
2313 const gchar *postfix = NULL;
2316 /* try to construct one from label text */
2317 gtk_container_foreach (GTK_CONTAINER (menu_item),
2318 gtk_menu_item_accel_name_foreach,
2322 new_path = g_strconcat (prefix, "/", postfix, NULL);
2323 path = menu_item->accel_path = (char*)g_intern_string (new_path);
2328 gtk_widget_set_accel_path (widget, path, accel_group);
2330 else if (group_changed) /* reinstall accelerators */
2331 gtk_widget_set_accel_path (widget, path, accel_group);
2335 * gtk_menu_item_set_accel_path
2336 * @menu_item: a valid #GtkMenuItem
2337 * @accel_path: (allow-none): accelerator path, corresponding to this menu item's
2338 * functionality, or %NULL to unset the current path.
2340 * Set the accelerator path on @menu_item, through which runtime changes of the
2341 * menu item's accelerator caused by the user can be identified and saved to
2342 * persistant storage (see gtk_accel_map_save() on this).
2343 * To setup a default accelerator for this menu item, call
2344 * gtk_accel_map_add_entry() with the same @accel_path.
2345 * See also gtk_accel_map_add_entry() on the specifics of accelerator paths,
2346 * and gtk_menu_set_accel_path() for a more convenient variant of this function.
2348 * This function is basically a convenience wrapper that handles calling
2349 * gtk_widget_set_accel_path() with the appropriate accelerator group for
2352 * Note that you do need to set an accelerator on the parent menu with
2353 * gtk_menu_set_accel_group() for this to work.
2355 * Note that @accel_path string will be stored in a #GQuark. Therefore, if you
2356 * pass a static string, you can save some memory by interning it first with
2357 * g_intern_static_string().
2360 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
2361 const gchar *accel_path)
2366 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2367 g_return_if_fail (accel_path == NULL ||
2368 (accel_path[0] == '<' && strchr (accel_path, '/')));
2370 widget = GTK_WIDGET (menu_item);
2372 /* store new path */
2373 menu_item->accel_path = (char*)g_intern_string (accel_path);
2375 /* forget accelerators associated with old path */
2376 gtk_widget_set_accel_path (widget, NULL, NULL);
2378 /* install accelerators associated with new path */
2379 parent = gtk_widget_get_parent (widget);
2380 if (GTK_IS_MENU (parent))
2382 GtkMenu *menu = GTK_MENU (parent);
2384 if (menu->accel_group)
2385 _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
2393 * gtk_menu_item_get_accel_path
2394 * @menu_item: a valid #GtkMenuItem
2396 * Retrieve the accelerator path that was previously set on @menu_item.
2398 * See gtk_menu_item_set_accel_path() for details.
2400 * Returns: the accelerator path corresponding to this menu item's
2401 * functionality, or %NULL if not set
2405 G_CONST_RETURN gchar *
2406 gtk_menu_item_get_accel_path (GtkMenuItem *menu_item)
2408 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2410 return menu_item->accel_path;
2414 gtk_menu_item_forall (GtkContainer *container,
2415 gboolean include_internals,
2416 GtkCallback callback,
2417 gpointer callback_data)
2421 g_return_if_fail (GTK_IS_MENU_ITEM (container));
2422 g_return_if_fail (callback != NULL);
2424 child = gtk_bin_get_child (GTK_BIN (container));
2426 callback (child, callback_data);
2430 _gtk_menu_item_is_selectable (GtkWidget *menu_item)
2432 if ((!gtk_bin_get_child (GTK_BIN (menu_item)) &&
2433 G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
2434 GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
2435 !gtk_widget_is_sensitive (menu_item) ||
2436 !gtk_widget_get_visible (menu_item))
2443 gtk_menu_item_ensure_label (GtkMenuItem *menu_item)
2445 GtkWidget *accel_label;
2447 if (!gtk_bin_get_child (GTK_BIN (menu_item)))
2449 accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
2450 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
2452 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
2453 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label),
2454 GTK_WIDGET (menu_item));
2455 gtk_widget_show (accel_label);
2460 * gtk_menu_item_set_label:
2461 * @menu_item: a #GtkMenuItem
2462 * @label: the text you want to set
2464 * Sets @text on the @menu_item label
2469 gtk_menu_item_set_label (GtkMenuItem *menu_item,
2472 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2474 GTK_MENU_ITEM_GET_CLASS (menu_item)->set_label (menu_item, label);
2478 * gtk_menu_item_get_label:
2479 * @menu_item: a #GtkMenuItem
2481 * Sets @text on the @menu_item label
2483 * Returns: The text in the @menu_item label. This is the internal
2484 * string used by the label, and must not be modified.
2488 G_CONST_RETURN gchar *
2489 gtk_menu_item_get_label (GtkMenuItem *menu_item)
2491 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2493 return GTK_MENU_ITEM_GET_CLASS (menu_item)->get_label (menu_item);
2497 * gtk_menu_item_set_use_underline:
2498 * @menu_item: a #GtkMenuItem
2499 * @setting: %TRUE if underlines in the text indicate mnemonics
2501 * If true, an underline in the text indicates the next character should be
2502 * used for the mnemonic accelerator key.
2507 gtk_menu_item_set_use_underline (GtkMenuItem *menu_item,
2512 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2514 gtk_menu_item_ensure_label (menu_item);
2516 child = gtk_bin_get_child (GTK_BIN (menu_item));
2517 if (GTK_IS_LABEL (child))
2519 gtk_label_set_use_underline (GTK_LABEL (child), setting);
2521 g_object_notify (G_OBJECT (menu_item), "use-underline");
2526 * gtk_menu_item_get_use_underline:
2527 * @menu_item: a #GtkMenuItem
2529 * Checks if an underline in the text indicates the next character should be
2530 * used for the mnemonic accelerator key.
2532 * Return value: %TRUE if an embedded underline in the label indicates
2533 * the mnemonic accelerator key.
2538 gtk_menu_item_get_use_underline (GtkMenuItem *menu_item)
2542 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2544 gtk_menu_item_ensure_label (menu_item);
2546 child = gtk_bin_get_child (GTK_BIN (menu_item));
2547 if (GTK_IS_LABEL (child))
2548 return gtk_label_get_use_underline (GTK_LABEL (child));