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/.
31 #include "gtkaccellabel.h"
33 #include "gtkmarshalers.h"
34 #include "gtkmenuprivate.h"
35 #include "gtkmenushellprivate.h"
36 #include "gtkmenuitemprivate.h"
37 #include "gtkmenubar.h"
38 #include "gtkmenuprivate.h"
39 #include "gtkseparatormenuitem.h"
40 #include "gtkprivate.h"
41 #include "gtkbuildable.h"
42 #include "gtkactivatable.h"
44 #include "gtktypebuiltins.h"
49 * @Short_description: The widget used for item in menus
51 * @See_also: #GtkBin, #GtkItem, #GtkMenuShell
53 * The #GtkMenuItem widget and the derived widgets are the only valid
54 * childs for menus. Their function is to correctly handle highlighting,
55 * alignment, events and submenus.
57 * As it derives from #GtkBin it can hold any valid child widget, altough
58 * only a few are really useful.
60 * <refsect2 id="GtkMenuItem-BUILDER-UI">
61 * <title>GtkMenuItem as GtkBuildable</title>
62 * The GtkMenuItem implementation of the GtkBuildable interface
63 * supports adding a submenu by specifying "submenu" as the "type"
64 * attribute of a <child> element.
66 * <title>A UI definition fragment with submenus</title>
67 * <programlisting><![CDATA[
68 * <object class="GtkMenuItem">
69 * <child type="submenu">
70 * <object class="GtkMenu"/>
73 * ]]></programlisting>
97 /* activatable properties */
98 PROP_ACTIVATABLE_RELATED_ACTION,
99 PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
103 static void gtk_menu_item_dispose (GObject *object);
104 static void gtk_menu_item_set_property (GObject *object,
108 static void gtk_menu_item_get_property (GObject *object,
112 static void gtk_menu_item_destroy (GtkWidget *widget);
113 static void gtk_menu_item_size_allocate (GtkWidget *widget,
114 GtkAllocation *allocation);
115 static void gtk_menu_item_realize (GtkWidget *widget);
116 static void gtk_menu_item_unrealize (GtkWidget *widget);
117 static void gtk_menu_item_map (GtkWidget *widget);
118 static void gtk_menu_item_unmap (GtkWidget *widget);
119 static gboolean gtk_menu_item_enter (GtkWidget *widget,
120 GdkEventCrossing *event);
121 static gboolean gtk_menu_item_leave (GtkWidget *widget,
122 GdkEventCrossing *event);
123 static gboolean gtk_menu_item_draw (GtkWidget *widget,
125 static void gtk_menu_item_parent_set (GtkWidget *widget,
126 GtkWidget *previous_parent);
129 static void gtk_real_menu_item_select (GtkMenuItem *item);
130 static void gtk_real_menu_item_deselect (GtkMenuItem *item);
131 static void gtk_real_menu_item_activate (GtkMenuItem *item);
132 static void gtk_real_menu_item_activate_item (GtkMenuItem *item);
133 static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
135 static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
137 static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget,
138 gboolean group_cycling);
140 static void gtk_menu_item_ensure_label (GtkMenuItem *menu_item);
141 static gint gtk_menu_item_popup_timeout (gpointer data);
142 static void gtk_menu_item_position_menu (GtkMenu *menu,
147 static void gtk_menu_item_show_all (GtkWidget *widget);
148 static void gtk_menu_item_forall (GtkContainer *container,
149 gboolean include_internals,
150 GtkCallback callback,
151 gpointer callback_data);
152 static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget,
155 static void gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
157 static G_CONST_RETURN gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item);
159 static void gtk_menu_item_get_preferred_width (GtkWidget *widget,
162 static void gtk_menu_item_get_preferred_height (GtkWidget *widget,
165 static void gtk_menu_item_get_preferred_height_for_width (GtkWidget *widget,
170 static void gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface);
171 static void gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
175 static void gtk_menu_item_buildable_custom_finished(GtkBuildable *buildable,
178 const gchar *tagname,
181 static void gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface);
182 static void gtk_menu_item_update (GtkActivatable *activatable,
184 const gchar *property_name);
185 static void gtk_menu_item_sync_action_properties (GtkActivatable *activatable,
187 static void gtk_menu_item_set_related_action (GtkMenuItem *menu_item,
189 static void gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item,
190 gboolean use_appearance);
192 /* Declare deprecated function that need a declaration */
193 #ifdef GTK_DISABLE_DEPRECATED
194 void gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
195 gboolean right_justified);
196 gboolean gtk_menu_item_get_right_justified (GtkMenuItem *menu_item);
197 #endif /* GTK_DISABLE_DEPRECATED */
199 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
201 static GtkBuildableIface *parent_buildable_iface;
203 G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_BIN,
204 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
205 gtk_menu_item_buildable_interface_init)
206 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
207 gtk_menu_item_activatable_interface_init))
211 gtk_menu_item_class_init (GtkMenuItemClass *klass)
213 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
214 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
215 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
217 gobject_class->dispose = gtk_menu_item_dispose;
218 gobject_class->set_property = gtk_menu_item_set_property;
219 gobject_class->get_property = gtk_menu_item_get_property;
221 widget_class->destroy = gtk_menu_item_destroy;
222 widget_class->size_allocate = gtk_menu_item_size_allocate;
223 widget_class->draw = gtk_menu_item_draw;
224 widget_class->realize = gtk_menu_item_realize;
225 widget_class->unrealize = gtk_menu_item_unrealize;
226 widget_class->map = gtk_menu_item_map;
227 widget_class->unmap = gtk_menu_item_unmap;
228 widget_class->enter_notify_event = gtk_menu_item_enter;
229 widget_class->leave_notify_event = gtk_menu_item_leave;
230 widget_class->show_all = gtk_menu_item_show_all;
231 widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate;
232 widget_class->parent_set = gtk_menu_item_parent_set;
233 widget_class->can_activate_accel = gtk_menu_item_can_activate_accel;
234 widget_class->get_preferred_width = gtk_menu_item_get_preferred_width;
235 widget_class->get_preferred_height = gtk_menu_item_get_preferred_height;
236 widget_class->get_preferred_height_for_width = gtk_menu_item_get_preferred_height_for_width;
238 container_class->forall = gtk_menu_item_forall;
240 klass->activate = gtk_real_menu_item_activate;
241 klass->activate_item = gtk_real_menu_item_activate_item;
242 klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
243 klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
244 klass->set_label = gtk_real_menu_item_set_label;
245 klass->get_label = gtk_real_menu_item_get_label;
246 klass->select = gtk_real_menu_item_select;
247 klass->deselect = gtk_real_menu_item_deselect;
249 klass->hide_on_activate = TRUE;
252 * GtkMenuItem::activate:
253 * @menuitem: the object which received the signal.
255 * Emitted when the item is activated.
257 menu_item_signals[ACTIVATE] =
258 g_signal_new (I_("activate"),
259 G_OBJECT_CLASS_TYPE (gobject_class),
260 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
261 G_STRUCT_OFFSET (GtkMenuItemClass, activate),
263 _gtk_marshal_VOID__VOID,
265 widget_class->activate_signal = menu_item_signals[ACTIVATE];
268 * GtkMenuItem::activate-item:
269 * @menuitem: the object which received the signal.
271 * Emitted when the item is activated, but also if the menu item has a
272 * submenu. For normal applications, the relevant signal is
273 * #GtkMenuItem::activate.
275 menu_item_signals[ACTIVATE_ITEM] =
276 g_signal_new (I_("activate-item"),
277 G_OBJECT_CLASS_TYPE (gobject_class),
279 G_STRUCT_OFFSET (GtkMenuItemClass, activate_item),
281 _gtk_marshal_VOID__VOID,
284 menu_item_signals[TOGGLE_SIZE_REQUEST] =
285 g_signal_new (I_("toggle-size-request"),
286 G_OBJECT_CLASS_TYPE (gobject_class),
288 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request),
290 _gtk_marshal_VOID__POINTER,
294 menu_item_signals[TOGGLE_SIZE_ALLOCATE] =
295 g_signal_new (I_("toggle-size-allocate"),
296 G_OBJECT_CLASS_TYPE (gobject_class),
298 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate),
300 _gtk_marshal_VOID__INT,
304 menu_item_signals[SELECT] =
305 g_signal_new (I_("select"),
306 G_OBJECT_CLASS_TYPE (gobject_class),
308 G_STRUCT_OFFSET (GtkMenuItemClass, select),
310 _gtk_marshal_VOID__VOID,
313 menu_item_signals[DESELECT] =
314 g_signal_new (I_("deselect"),
315 G_OBJECT_CLASS_TYPE (gobject_class),
317 G_STRUCT_OFFSET (GtkMenuItemClass, deselect),
319 _gtk_marshal_VOID__VOID,
323 * GtkMenuItem:right-justified:
325 * Sets whether the menu item appears justified
326 * at the right side of a menu bar.
330 g_object_class_install_property (gobject_class,
331 PROP_RIGHT_JUSTIFIED,
332 g_param_spec_boolean ("right-justified",
333 P_("Right Justified"),
334 P_("Sets whether the menu item appears justified at the right side of a menu bar"),
336 GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
339 * GtkMenuItem:submenu:
341 * The submenu attached to the menu item, or %NULL if it has none.
345 g_object_class_install_property (gobject_class,
347 g_param_spec_object ("submenu",
349 P_("The submenu attached to the menu item, or NULL if it has none"),
351 GTK_PARAM_READWRITE));
354 * GtkMenuItem:accel-path:
356 * Sets the accelerator path of the menu item, through which runtime
357 * changes of the menu item's accelerator caused by the user can be
358 * identified and saved to persistant storage.
362 g_object_class_install_property (gobject_class,
364 g_param_spec_string ("accel-path",
366 P_("Sets the accelerator path of the menu item"),
368 GTK_PARAM_READWRITE));
373 * The text for the child label.
377 g_object_class_install_property (gobject_class,
379 g_param_spec_string ("label",
381 P_("The text for the child label"),
383 GTK_PARAM_READWRITE));
386 * GtkMenuItem:use-underline:
388 * %TRUE if underlines in the text indicate mnemonics.
392 g_object_class_install_property (gobject_class,
394 g_param_spec_boolean ("use-underline",
396 P_("If set, an underline in the text indicates "
397 "the next character should be used for the "
398 "mnemonic accelerator key"),
400 GTK_PARAM_READWRITE));
402 g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
403 g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
405 gtk_widget_class_install_style_property_parser (widget_class,
406 g_param_spec_enum ("selected-shadow-type",
407 "Selected Shadow Type",
408 "Shadow type when item is selected",
409 GTK_TYPE_SHADOW_TYPE,
412 gtk_rc_property_parse_enum);
414 gtk_widget_class_install_style_property (widget_class,
415 g_param_spec_int ("horizontal-padding",
416 "Horizontal Padding",
417 "Padding to left and right of the menu item",
421 GTK_PARAM_READABLE));
423 gtk_widget_class_install_style_property (widget_class,
424 g_param_spec_int ("toggle-spacing",
426 "Space between icon and label",
430 GTK_PARAM_READABLE));
432 gtk_widget_class_install_style_property (widget_class,
433 g_param_spec_int ("arrow-spacing",
435 "Space between label and arrow",
439 GTK_PARAM_READABLE));
441 gtk_widget_class_install_style_property (widget_class,
442 g_param_spec_float ("arrow-scaling",
444 P_("Amount of space used up by arrow, relative to the menu item's font size"),
446 GTK_PARAM_READABLE));
449 * GtkMenuItem:width-chars:
451 * The minimum desired width of the menu item in characters.
455 gtk_widget_class_install_style_property (widget_class,
456 g_param_spec_int ("width-chars",
457 P_("Width in Characters"),
458 P_("The minimum desired width of the menu item in characters"),
460 GTK_PARAM_READABLE));
462 g_type_class_add_private (klass, sizeof (GtkMenuItemPrivate));
466 gtk_menu_item_init (GtkMenuItem *menu_item)
468 GtkStyleContext *context;
469 GtkMenuItemPrivate *priv;
471 priv = G_TYPE_INSTANCE_GET_PRIVATE (menu_item,
474 menu_item->priv = priv;
476 gtk_widget_set_has_window (GTK_WIDGET (menu_item), FALSE);
479 priv->use_action_appearance = TRUE;
481 menu_item->priv->submenu = NULL;
482 menu_item->priv->toggle_size = 0;
483 menu_item->priv->accelerator_width = 0;
484 if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
485 priv->submenu_direction = GTK_DIRECTION_LEFT;
487 priv->submenu_direction = GTK_DIRECTION_RIGHT;
488 priv->submenu_placement = GTK_TOP_BOTTOM;
489 priv->right_justify = FALSE;
490 priv->use_action_appearance = TRUE;
494 context = gtk_widget_get_style_context (GTK_WIDGET (menu_item));
495 gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUITEM);
501 * Creates a new #GtkMenuItem.
503 * Returns: the newly created #GtkMenuItem
506 gtk_menu_item_new (void)
508 return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
512 * gtk_menu_item_new_with_label:
513 * @label: the text for the label
515 * Creates a new #GtkMenuItem whose child is a #GtkLabel.
517 * Returns: the newly created #GtkMenuItem
520 gtk_menu_item_new_with_label (const gchar *label)
522 return g_object_new (GTK_TYPE_MENU_ITEM,
529 * gtk_menu_item_new_with_mnemonic:
530 * @label: The text of the button, with an underscore in front of the
533 * Creates a new #GtkMenuItem containing a label.
535 * The label will be created using gtk_label_new_with_mnemonic(),
536 * so underscores in @label indicate the mnemonic for the menu item.
538 * Returns: a new #GtkMenuItem
541 gtk_menu_item_new_with_mnemonic (const gchar *label)
543 return g_object_new (GTK_TYPE_MENU_ITEM,
544 "use-underline", TRUE,
550 gtk_menu_item_dispose (GObject *object)
552 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
553 GtkMenuItemPrivate *priv = menu_item->priv;
557 gtk_action_disconnect_accelerator (priv->action);
558 gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), NULL);
561 G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object);
565 gtk_menu_item_set_property (GObject *object,
570 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
574 case PROP_RIGHT_JUSTIFIED:
575 gtk_menu_item_set_right_justified (menu_item, g_value_get_boolean (value));
578 gtk_menu_item_set_submenu (menu_item, g_value_get_object (value));
580 case PROP_ACCEL_PATH:
581 gtk_menu_item_set_accel_path (menu_item, g_value_get_string (value));
584 gtk_menu_item_set_label (menu_item, g_value_get_string (value));
586 case PROP_USE_UNDERLINE:
587 gtk_menu_item_set_use_underline (menu_item, g_value_get_boolean (value));
589 case PROP_ACTIVATABLE_RELATED_ACTION:
590 gtk_menu_item_set_related_action (menu_item, g_value_get_object (value));
592 case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
593 gtk_menu_item_set_use_action_appearance (menu_item, g_value_get_boolean (value));
596 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
602 gtk_menu_item_get_property (GObject *object,
607 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
608 GtkMenuItemPrivate *priv = menu_item->priv;
612 case PROP_RIGHT_JUSTIFIED:
613 g_value_set_boolean (value, gtk_menu_item_get_right_justified (menu_item));
616 g_value_set_object (value, gtk_menu_item_get_submenu (menu_item));
618 case PROP_ACCEL_PATH:
619 g_value_set_string (value, gtk_menu_item_get_accel_path (menu_item));
622 g_value_set_string (value, gtk_menu_item_get_label (menu_item));
624 case PROP_USE_UNDERLINE:
625 g_value_set_boolean (value, gtk_menu_item_get_use_underline (menu_item));
627 case PROP_ACTIVATABLE_RELATED_ACTION:
628 g_value_set_object (value, priv->action);
630 case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
631 g_value_set_boolean (value, priv->use_action_appearance);
634 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
640 gtk_menu_item_destroy (GtkWidget *widget)
642 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
643 GtkMenuItemPrivate *priv = menu_item->priv;
646 gtk_widget_destroy (priv->submenu);
648 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->destroy (widget);
652 gtk_menu_item_detacher (GtkWidget *widget,
655 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
656 GtkMenuItemPrivate *priv = menu_item->priv;
658 g_return_if_fail (priv->submenu == (GtkWidget*) menu);
660 priv->submenu = NULL;
664 get_arrow_size (GtkWidget *widget,
668 GtkStyleContext *style_context;
670 PangoContext *context;
671 PangoFontMetrics *metrics;
672 gfloat arrow_scaling;
676 gtk_widget_style_get (widget,
677 "arrow-scaling", &arrow_scaling,
680 context = gtk_widget_get_pango_context (child);
681 style_context = gtk_widget_get_style_context (child);
682 state = gtk_widget_get_state_flags (child);
684 metrics = pango_context_get_metrics (context,
685 gtk_style_context_get_font (style_context, state),
686 pango_context_get_language (context));
688 *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
689 pango_font_metrics_get_descent (metrics)));
691 pango_font_metrics_unref (metrics);
693 *size = *size * arrow_scaling;
698 gtk_menu_item_accel_width_foreach (GtkWidget *widget,
703 if (GTK_IS_ACCEL_LABEL (widget))
707 w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
708 *width = MAX (*width, w);
710 else if (GTK_IS_CONTAINER (widget))
711 gtk_container_foreach (GTK_CONTAINER (widget),
712 gtk_menu_item_accel_width_foreach,
717 get_minimum_width (GtkWidget *widget)
719 GtkStyleContext *style_context;
721 PangoContext *context;
722 PangoFontMetrics *metrics;
726 context = gtk_widget_get_pango_context (widget);
727 style_context = gtk_widget_get_style_context (widget);
728 state = gtk_widget_get_state_flags (widget);
730 metrics = pango_context_get_metrics (context,
731 gtk_style_context_get_font (style_context, state),
732 pango_context_get_language (context));
734 width = pango_font_metrics_get_approximate_char_width (metrics);
736 pango_font_metrics_unref (metrics);
738 gtk_widget_style_get (widget, "width-chars", &width_chars, NULL);
740 return PANGO_PIXELS (width_chars * width);
744 gtk_menu_item_get_preferred_width (GtkWidget *widget,
748 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
749 GtkMenuItemPrivate *priv = menu_item->priv;
754 guint horizontal_padding;
756 GtkPackDirection pack_dir;
757 GtkPackDirection child_pack_dir;
758 gint min_width, nat_width;
759 GtkStyleContext *context;
763 min_width = nat_width = 0;
765 gtk_widget_style_get (widget,
766 "horizontal-padding", &horizontal_padding,
769 bin = GTK_BIN (widget);
770 parent = gtk_widget_get_parent (widget);
772 if (GTK_IS_MENU_BAR (parent))
774 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
775 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
779 pack_dir = GTK_PACK_DIRECTION_LTR;
780 child_pack_dir = GTK_PACK_DIRECTION_LTR;
783 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
785 context = gtk_widget_get_style_context (widget);
786 state = gtk_widget_get_state_flags (widget);
787 gtk_style_context_get_padding (context, state, &padding);
789 min_width = (border_width * 2) + padding.left + padding.right;
791 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
792 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
793 min_width += 2 * horizontal_padding;
795 nat_width = min_width;
797 child = gtk_bin_get_child (bin);
799 if (child != NULL && gtk_widget_get_visible (child))
801 GtkMenuItemPrivate *priv = menu_item->priv;
802 gint child_min, child_nat;
804 gtk_widget_get_preferred_width (child, &child_min, &child_nat);
806 if ((menu_item->priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
811 gtk_widget_style_get (widget,
812 "arrow-spacing", &arrow_spacing,
815 get_arrow_size (widget, child, &arrow_size);
817 gtk_widget_style_get (widget,
818 "arrow-spacing", &arrow_spacing,
821 get_arrow_size (widget, child, &arrow_size);
823 min_width += arrow_size;
824 min_width += arrow_spacing;
826 min_width = MAX (min_width, get_minimum_width (widget));
827 nat_width = min_width;
830 min_width += child_min;
831 nat_width += child_nat;
835 gtk_container_foreach (GTK_CONTAINER (menu_item),
836 gtk_menu_item_accel_width_foreach,
838 priv->accelerator_width = accel_width;
841 *minimum_size = min_width;
844 *natural_size = nat_width;
848 gtk_menu_item_get_preferred_height (GtkWidget *widget,
852 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
853 GtkMenuItemPrivate *priv = menu_item->priv;
855 GtkStyleContext *context;
861 guint horizontal_padding;
863 GtkPackDirection pack_dir;
864 GtkPackDirection child_pack_dir;
865 gint min_height, nat_height;
867 min_height = nat_height = 0;
869 context = gtk_widget_get_style_context (widget);
870 state = gtk_widget_get_state_flags (widget);
871 gtk_style_context_get_padding (context, state, &padding);
873 gtk_widget_style_get (widget,
874 "horizontal-padding", &horizontal_padding,
877 bin = GTK_BIN (widget);
878 parent = gtk_widget_get_parent (widget);
880 if (GTK_IS_MENU_BAR (parent))
882 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
883 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
887 pack_dir = GTK_PACK_DIRECTION_LTR;
888 child_pack_dir = GTK_PACK_DIRECTION_LTR;
891 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
892 min_height = (border_width * 2) + padding.top + padding.bottom;
894 if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
895 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
896 min_height += 2 * horizontal_padding;
898 nat_height = min_height;
900 child = gtk_bin_get_child (bin);
902 if (child != NULL && gtk_widget_get_visible (child))
904 GtkMenuItemPrivate *priv = menu_item->priv;
905 gint child_min, child_nat;
907 gtk_widget_get_preferred_height (child, &child_min, &child_nat);
909 min_height += child_min;
910 nat_height += child_nat;
912 if ((menu_item->priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
916 get_arrow_size (widget, child, &arrow_size);
918 min_height = MAX (min_height, arrow_size);
919 nat_height = MAX (nat_height, arrow_size);
922 else /* separator item */
924 gboolean wide_separators;
925 gint separator_height;
927 gtk_widget_style_get (widget,
928 "wide-separators", &wide_separators,
929 "separator-height", &separator_height,
933 min_height += separator_height + padding.top;
935 min_height += padding.top + padding.bottom;
937 nat_height = min_height;
941 gtk_container_foreach (GTK_CONTAINER (menu_item),
942 gtk_menu_item_accel_width_foreach,
944 priv->accelerator_width = accel_width;
947 *minimum_size = min_height;
950 *natural_size = nat_height;
954 gtk_menu_item_get_preferred_height_for_width (GtkWidget *widget,
959 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
960 GtkMenuItemPrivate *priv = menu_item->priv;
962 GtkStyleContext *context;
967 guint horizontal_padding;
969 GtkPackDirection pack_dir;
970 GtkPackDirection child_pack_dir;
971 gint min_height, nat_height;
974 min_height = nat_height = 0;
976 context = gtk_widget_get_style_context (widget);
977 state = gtk_widget_get_state_flags (widget);
978 gtk_style_context_get_padding (context, state, &padding);
980 gtk_widget_style_get (widget,
981 "horizontal-padding", &horizontal_padding,
984 bin = GTK_BIN (widget);
985 parent = gtk_widget_get_parent (widget);
987 if (GTK_IS_MENU_BAR (parent))
989 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
990 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
994 pack_dir = GTK_PACK_DIRECTION_LTR;
995 child_pack_dir = GTK_PACK_DIRECTION_LTR;
998 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
999 min_height = (border_width * 2) + padding.top + padding.bottom;
1001 avail_size = for_size;
1002 avail_size -= (border_width * 2) + padding.left + padding.right;
1004 if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
1005 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
1006 min_height += 2 * horizontal_padding;
1008 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
1009 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
1010 avail_size -= 2 * horizontal_padding;
1012 nat_height = min_height;
1014 child = gtk_bin_get_child (bin);
1016 if (child != NULL && gtk_widget_get_visible (child))
1018 gint child_min, child_nat;
1019 gint arrow_size = 0;
1021 if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
1023 guint arrow_spacing;
1025 gtk_widget_style_get (widget,
1026 "arrow-spacing", &arrow_spacing,
1029 get_arrow_size (widget, child, &arrow_size);
1031 avail_size -= arrow_size;
1032 avail_size -= arrow_spacing;
1035 gtk_widget_get_preferred_height_for_width (child,
1040 min_height += child_min;
1041 nat_height += child_nat;
1043 if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
1045 min_height = MAX (min_height, arrow_size);
1046 nat_height = MAX (nat_height, arrow_size);
1049 else /* separator item */
1051 gboolean wide_separators;
1052 gint separator_height;
1054 gtk_widget_style_get (widget,
1055 "wide-separators", &wide_separators,
1056 "separator-height", &separator_height,
1059 if (wide_separators)
1060 min_height += separator_height + padding.top;
1062 min_height += padding.top + padding.bottom;
1064 nat_height = min_height;
1068 *minimum_size = min_height;
1071 *natural_size = nat_height;
1075 gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface)
1077 parent_buildable_iface = g_type_interface_peek_parent (iface);
1078 iface->add_child = gtk_menu_item_buildable_add_child;
1079 iface->custom_finished = gtk_menu_item_buildable_custom_finished;
1083 gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
1084 GtkBuilder *builder,
1088 if (type && strcmp (type, "submenu") == 0)
1089 gtk_menu_item_set_submenu (GTK_MENU_ITEM (buildable),
1090 GTK_WIDGET (child));
1092 parent_buildable_iface->add_child (buildable, builder, child, type);
1097 gtk_menu_item_buildable_custom_finished (GtkBuildable *buildable,
1098 GtkBuilder *builder,
1100 const gchar *tagname,
1103 GtkWidget *toplevel;
1105 if (strcmp (tagname, "accelerator") == 0)
1107 GtkMenuShell *menu_shell;
1110 menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (GTK_WIDGET (buildable)));
1113 while (GTK_IS_MENU (menu_shell) &&
1114 (attach = gtk_menu_get_attach_widget (GTK_MENU (menu_shell))) != NULL)
1115 menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (attach));
1117 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu_shell));
1121 /* Fall back to something ... */
1122 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (buildable));
1124 g_warning ("found a GtkMenuItem '%s' without a parent GtkMenuShell, assigned accelerators wont work.",
1125 gtk_buildable_get_name (buildable));
1128 /* Feed the correct toplevel to the GtkWidget accelerator parsing code */
1129 _gtk_widget_buildable_finish_accelerator (GTK_WIDGET (buildable), toplevel, user_data);
1132 parent_buildable_iface->custom_finished (buildable, builder, child, tagname, user_data);
1137 gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface)
1139 iface->update = gtk_menu_item_update;
1140 iface->sync_action_properties = gtk_menu_item_sync_action_properties;
1144 activatable_update_label (GtkMenuItem *menu_item, GtkAction *action)
1148 child = gtk_bin_get_child (GTK_BIN (menu_item));
1150 if (GTK_IS_LABEL (child))
1154 label = gtk_action_get_label (action);
1155 gtk_menu_item_set_label (menu_item, label);
1159 gboolean _gtk_menu_is_empty (GtkWidget *menu);
1162 gtk_menu_item_update (GtkActivatable *activatable,
1164 const gchar *property_name)
1166 GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
1167 GtkMenuItemPrivate *priv = menu_item->priv;
1169 if (strcmp (property_name, "visible") == 0)
1170 _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
1171 _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
1172 else if (strcmp (property_name, "sensitive") == 0)
1173 gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
1174 else if (priv->use_action_appearance)
1176 if (strcmp (property_name, "label") == 0)
1177 activatable_update_label (menu_item, action);
1182 gtk_menu_item_sync_action_properties (GtkActivatable *activatable,
1185 GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
1186 GtkMenuItemPrivate *priv = menu_item->priv;
1189 if (!priv->use_action_appearance || !action)
1191 label = gtk_bin_get_child (GTK_BIN (menu_item));
1193 if (GTK_IS_ACCEL_LABEL (label))
1194 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), GTK_WIDGET (menu_item));
1200 _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
1201 _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
1203 gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
1205 if (priv->use_action_appearance)
1207 label = gtk_bin_get_child (GTK_BIN (menu_item));
1209 /* make sure label is a label, deleting it otherwise */
1210 if (label && !GTK_IS_LABEL (label))
1212 gtk_container_remove (GTK_CONTAINER (menu_item), label);
1215 /* Make sure that menu_item has a label and that any
1216 * accelerators are set */
1217 gtk_menu_item_ensure_label (menu_item);
1218 gtk_menu_item_set_use_underline (menu_item, TRUE);
1219 /* Make label point to the menu_item's label */
1220 label = gtk_bin_get_child (GTK_BIN (menu_item));
1222 if (GTK_IS_ACCEL_LABEL (label) && gtk_action_get_accel_path (action))
1224 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), NULL);
1225 gtk_accel_label_set_accel_closure (GTK_ACCEL_LABEL (label),
1226 gtk_action_get_accel_closure (action));
1229 activatable_update_label (menu_item, action);
1234 gtk_menu_item_set_related_action (GtkMenuItem *menu_item,
1237 GtkMenuItemPrivate *priv = menu_item->priv;
1239 if (priv->action == action)
1244 gtk_action_disconnect_accelerator (priv->action);
1249 const gchar *accel_path;
1251 accel_path = gtk_action_get_accel_path (action);
1254 gtk_action_connect_accelerator (action);
1255 gtk_menu_item_set_accel_path (menu_item, accel_path);
1259 gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), action);
1261 priv->action = action;
1265 gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item,
1266 gboolean use_appearance)
1268 GtkMenuItemPrivate *priv = menu_item->priv;
1270 if (priv->use_action_appearance != use_appearance)
1272 priv->use_action_appearance = use_appearance;
1274 gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (menu_item), priv->action);
1280 * gtk_menu_item_set_submenu:
1281 * @menu_item: a #GtkMenuItem
1282 * @submenu: (allow-none): the submenu, or %NULL
1284 * Sets or replaces the menu item's submenu, or removes it when a %NULL
1285 * submenu is passed.
1288 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
1291 GtkMenuItemPrivate *priv = menu_item->priv;
1293 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1294 g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu));
1296 if (priv->submenu != submenu)
1299 gtk_menu_detach (GTK_MENU (priv->submenu));
1303 priv->submenu = submenu;
1304 gtk_menu_attach_to_widget (GTK_MENU (submenu),
1305 GTK_WIDGET (menu_item),
1306 gtk_menu_item_detacher);
1309 if (gtk_widget_get_parent (GTK_WIDGET (menu_item)))
1310 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1312 g_object_notify (G_OBJECT (menu_item), "submenu");
1317 * gtk_menu_item_get_submenu:
1318 * @menu_item: a #GtkMenuItem
1320 * Gets the submenu underneath this menu item, if any.
1321 * See gtk_menu_item_set_submenu().
1323 * Return value: (transfer none): submenu for this menu item, or %NULL if none
1326 gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
1328 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
1330 return menu_item->priv->submenu;
1333 void _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
1334 GtkSubmenuPlacement placement);
1337 _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
1338 GtkSubmenuPlacement placement)
1340 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1342 menu_item->priv->submenu_placement = placement;
1346 gtk_menu_item_select (GtkMenuItem *menu_item)
1350 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1352 g_signal_emit (menu_item, menu_item_signals[SELECT], 0);
1354 /* Enable themeing of the parent menu item depending on whether
1355 * something is selected in its submenu
1357 parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1358 if (GTK_IS_MENU (parent))
1360 GtkMenu *menu = GTK_MENU (parent);
1362 if (menu->priv->parent_menu_item)
1363 gtk_widget_queue_draw (GTK_WIDGET (menu->priv->parent_menu_item));
1368 * gtk_menu_item_deselect:
1369 * @menu_item: the menu item
1371 * Emits the #GtkMenuItem::deselect signal on the given item. Behaves
1372 * exactly like #gtk_item_deselect.
1375 gtk_menu_item_deselect (GtkMenuItem *menu_item)
1379 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1381 g_signal_emit (menu_item, menu_item_signals[DESELECT], 0);
1383 /* Enable themeing of the parent menu item depending on whether
1384 * something is selected in its submenu
1386 parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1387 if (GTK_IS_MENU (parent))
1389 GtkMenu *menu = GTK_MENU (parent);
1391 if (menu->priv->parent_menu_item)
1392 gtk_widget_queue_draw (GTK_WIDGET (menu->priv->parent_menu_item));
1397 * gtk_menu_item_activate:
1398 * @menu_item: the menu item
1400 * Emits the #GtkMenuItem::activate signal on the given item
1403 gtk_menu_item_activate (GtkMenuItem *menu_item)
1405 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1407 g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
1411 * gtk_menu_item_toggle_size_request:
1412 * @menu_item: the menu item
1413 * @requisition: the requisition to use as signal data.
1415 * Emits the #GtkMenuItem::toggle-size-request signal on the given item.
1418 gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1421 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1423 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
1427 * gtk_menu_item_toggle_size_allocate:
1428 * @menu_item: the menu item.
1429 * @allocation: the allocation to use as signal data.
1431 * Emits the #GtkMenuItem::toggle-size-allocate signal on the given item.
1434 gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1437 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1439 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
1443 gtk_menu_item_size_allocate (GtkWidget *widget,
1444 GtkAllocation *allocation)
1446 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1447 GtkMenuItemPrivate *priv = menu_item->priv;
1449 GtkAllocation child_allocation;
1450 GtkTextDirection direction;
1451 GtkPackDirection pack_dir;
1452 GtkPackDirection child_pack_dir;
1456 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1457 g_return_if_fail (allocation != NULL);
1459 bin = GTK_BIN (widget);
1461 direction = gtk_widget_get_direction (widget);
1463 parent = gtk_widget_get_parent (widget);
1464 if (GTK_IS_MENU_BAR (parent))
1466 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent));
1467 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
1471 pack_dir = GTK_PACK_DIRECTION_LTR;
1472 child_pack_dir = GTK_PACK_DIRECTION_LTR;
1475 gtk_widget_set_allocation (widget, allocation);
1477 child = gtk_bin_get_child (bin);
1480 GtkStyleContext *context;
1481 GtkStateFlags state;
1483 guint horizontal_padding;
1486 context = gtk_widget_get_style_context (widget);
1487 state = gtk_widget_get_state_flags (widget);
1488 gtk_style_context_get_padding (context, state, &padding);
1490 gtk_widget_style_get (widget,
1491 "horizontal-padding", &horizontal_padding,
1494 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1495 child_allocation.x = border_width + padding.left;
1496 child_allocation.y = border_width + padding.top;
1498 child_allocation.width = allocation->width - (border_width * 2) -
1499 padding.left - padding.right;
1500 child_allocation.height = allocation->height - (border_width * 2) -
1501 padding.top - padding.bottom;
1503 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
1504 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
1506 child_allocation.x += horizontal_padding;
1507 child_allocation.width -= 2 * horizontal_padding;
1509 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
1510 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
1512 child_allocation.y += horizontal_padding;
1513 child_allocation.height -= 2 * horizontal_padding;
1516 if (child_pack_dir == GTK_PACK_DIRECTION_LTR ||
1517 child_pack_dir == GTK_PACK_DIRECTION_RTL)
1519 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL))
1520 child_allocation.x += priv->toggle_size;
1521 child_allocation.width -= priv->toggle_size;
1525 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT))
1526 child_allocation.y += priv->toggle_size;
1527 child_allocation.height -= priv->toggle_size;
1530 child_allocation.x += allocation->x;
1531 child_allocation.y += allocation->y;
1533 if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
1535 guint arrow_spacing;
1538 gtk_widget_style_get (widget,
1539 "arrow-spacing", &arrow_spacing,
1542 get_arrow_size (widget, child, &arrow_size);
1544 if (direction == GTK_TEXT_DIR_RTL)
1545 child_allocation.x += arrow_size + arrow_spacing;
1546 child_allocation.width -= arrow_size + arrow_spacing;
1549 if (child_allocation.width < 1)
1550 child_allocation.width = 1;
1552 gtk_widget_size_allocate (child, &child_allocation);
1555 if (gtk_widget_get_realized (widget))
1556 gdk_window_move_resize (priv->event_window,
1557 allocation->x, allocation->y,
1558 allocation->width, allocation->height);
1561 gtk_menu_reposition (GTK_MENU (priv->submenu));
1565 gtk_menu_item_realize (GtkWidget *widget)
1567 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1568 GtkMenuItemPrivate *priv = menu_item->priv;
1569 GtkAllocation allocation;
1571 GdkWindowAttr attributes;
1572 gint attributes_mask;
1574 gtk_widget_set_realized (widget, TRUE);
1576 window = gtk_widget_get_parent_window (widget);
1577 gtk_widget_set_window (widget, window);
1578 g_object_ref (window);
1580 gtk_widget_get_allocation (widget, &allocation);
1582 attributes.x = allocation.x;
1583 attributes.y = allocation.y;
1584 attributes.width = allocation.width;
1585 attributes.height = allocation.height;
1586 attributes.window_type = GDK_WINDOW_CHILD;
1587 attributes.wclass = GDK_INPUT_ONLY;
1588 attributes.event_mask = (gtk_widget_get_events (widget) |
1589 GDK_BUTTON_PRESS_MASK |
1590 GDK_BUTTON_RELEASE_MASK |
1591 GDK_ENTER_NOTIFY_MASK |
1592 GDK_LEAVE_NOTIFY_MASK |
1593 GDK_POINTER_MOTION_MASK);
1595 attributes_mask = GDK_WA_X | GDK_WA_Y;
1597 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1598 &attributes, attributes_mask);
1599 gdk_window_set_user_data (priv->event_window, widget);
1603 gtk_menu_item_unrealize (GtkWidget *widget)
1605 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1606 GtkMenuItemPrivate *priv = menu_item->priv;
1608 gdk_window_set_user_data (priv->event_window, NULL);
1609 gdk_window_destroy (priv->event_window);
1610 priv->event_window = NULL;
1612 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize (widget);
1616 gtk_menu_item_map (GtkWidget *widget)
1618 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1619 GtkMenuItemPrivate *priv = menu_item->priv;
1621 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget);
1623 gdk_window_show (priv->event_window);
1627 gtk_menu_item_unmap (GtkWidget *widget)
1629 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1630 GtkMenuItemPrivate *priv = menu_item->priv;
1632 gdk_window_hide (priv->event_window);
1634 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget);
1638 gtk_menu_item_enter (GtkWidget *widget,
1639 GdkEventCrossing *event)
1641 g_return_val_if_fail (event != NULL, FALSE);
1643 return gtk_widget_event (gtk_widget_get_parent (widget), (GdkEvent *) event);
1647 gtk_menu_item_leave (GtkWidget *widget,
1648 GdkEventCrossing *event)
1650 g_return_val_if_fail (event != NULL, FALSE);
1652 return gtk_widget_event (gtk_widget_get_parent (widget), (GdkEvent*) event);
1656 gtk_menu_item_draw (GtkWidget *widget,
1659 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1660 GtkMenuItemPrivate *priv = menu_item->priv;
1661 GtkStateFlags state;
1662 GtkStyleContext *context;
1664 GtkWidget *child, *parent;
1665 gint x, y, w, h, width, height;
1666 guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1668 state = gtk_widget_get_state_flags (widget);
1669 context = gtk_widget_get_style_context (widget);
1670 width = gtk_widget_get_allocated_width (widget);
1671 height = gtk_widget_get_allocated_height (widget);
1675 w = width - border_width * 2;
1676 h = height - border_width * 2;
1678 child = gtk_bin_get_child (GTK_BIN (menu_item));
1679 parent = gtk_widget_get_parent (widget);
1681 gtk_style_context_save (context);
1682 gtk_style_context_set_state (context, state);
1684 gtk_style_context_get_padding (context, state, &padding);
1686 if (GTK_IS_MENU_BAR (parent))
1687 gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUBAR);
1689 if (child && (state & GTK_STATE_FLAG_PRELIGHT))
1691 gtk_render_background (context, cr, x, y, w, h);
1692 gtk_render_frame (context, cr, x, y, w, h);
1695 if (priv->submenu && !GTK_IS_MENU_BAR (parent))
1697 gint arrow_x, arrow_y;
1699 guint horizontal_padding;
1700 GtkTextDirection direction;
1703 direction = gtk_widget_get_direction (widget);
1705 gtk_widget_style_get (widget,
1706 "horizontal-padding", &horizontal_padding,
1709 get_arrow_size (widget, child, &arrow_size);
1711 if (direction == GTK_TEXT_DIR_LTR)
1713 arrow_x = x + w - horizontal_padding - arrow_size;
1718 arrow_x = x + horizontal_padding;
1719 angle = (3 * G_PI) / 2;
1722 arrow_y = y + (h - arrow_size) / 2;
1724 gtk_render_arrow (context, cr, angle, arrow_x, arrow_y, arrow_size);
1728 gboolean wide_separators;
1729 gint separator_height;
1730 guint horizontal_padding;
1732 gtk_widget_style_get (widget,
1733 "wide-separators", &wide_separators,
1734 "separator-height", &separator_height,
1735 "horizontal-padding", &horizontal_padding,
1737 if (wide_separators)
1738 gtk_render_frame (context, cr,
1739 horizontal_padding + padding.left,
1740 (height - separator_height - padding.top) / 2,
1741 width - (2 * horizontal_padding) - padding.left - padding.right,
1744 gtk_render_line (context, cr,
1745 horizontal_padding + padding.left,
1746 (height - padding.top) / 2,
1747 width - horizontal_padding - padding.right - 1,
1748 (height - padding.top) / 2);
1751 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->draw (widget, cr);
1753 gtk_style_context_restore (context);
1759 * gtk_menu_item_select:
1760 * @menu_item: the menu item
1762 * Emits the #GtkMenuItem::select signal on the given item. Behaves
1763 * exactly like #gtk_item_select.
1766 gtk_real_menu_item_select (GtkMenuItem *menu_item)
1768 GtkMenuItemPrivate *priv = menu_item->priv;
1769 gboolean touchscreen_mode;
1771 g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)),
1772 "gtk-touchscreen-mode", &touchscreen_mode,
1775 if (!touchscreen_mode && priv->submenu &&
1776 (!gtk_widget_get_mapped (priv->submenu) ||
1777 GTK_MENU (priv->submenu)->priv->tearoff_active))
1779 _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1782 gtk_widget_set_state_flags (GTK_WIDGET (menu_item),
1783 GTK_STATE_FLAG_PRELIGHT, FALSE);
1784 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1788 gtk_real_menu_item_deselect (GtkMenuItem *menu_item)
1790 GtkMenuItemPrivate *priv = menu_item->priv;
1793 _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
1795 gtk_widget_unset_state_flags (GTK_WIDGET (menu_item),
1796 GTK_STATE_FLAG_PRELIGHT);
1797 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1801 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
1802 gboolean group_cycling)
1806 parent = gtk_widget_get_parent (widget);
1808 if (GTK_IS_MENU_SHELL (parent))
1809 _gtk_menu_shell_set_keyboard_mode (GTK_MENU_SHELL (parent), TRUE);
1811 if (group_cycling &&
1813 GTK_IS_MENU_SHELL (parent) &&
1814 GTK_MENU_SHELL (parent)->priv->active)
1816 gtk_menu_shell_select_item (GTK_MENU_SHELL (parent), widget);
1819 g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
1825 gtk_real_menu_item_activate (GtkMenuItem *menu_item)
1827 GtkMenuItemPrivate *priv = menu_item->priv;
1830 gtk_action_activate (priv->action);
1835 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
1837 GtkMenuItemPrivate *priv = menu_item->priv;
1841 widget = GTK_WIDGET (menu_item);
1842 parent = gtk_widget_get_parent (widget);
1844 if (parent && GTK_IS_MENU_SHELL (parent))
1846 GtkMenuShell *menu_shell = GTK_MENU_SHELL (parent);
1848 if (priv->submenu == NULL)
1849 gtk_menu_shell_activate_item (menu_shell, widget, TRUE);
1852 gtk_menu_shell_select_item (menu_shell, widget);
1853 _gtk_menu_item_popup_submenu (widget, FALSE);
1855 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->submenu), TRUE);
1861 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1864 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1870 gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1873 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1875 menu_item->priv->toggle_size = allocation;
1879 gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
1884 gtk_menu_item_ensure_label (menu_item);
1886 child = gtk_bin_get_child (GTK_BIN (menu_item));
1887 if (GTK_IS_LABEL (child))
1889 gtk_label_set_label (GTK_LABEL (child), label ? label : "");
1891 g_object_notify (G_OBJECT (menu_item), "label");
1895 static G_CONST_RETURN gchar *
1896 gtk_real_menu_item_get_label (GtkMenuItem *menu_item)
1900 gtk_menu_item_ensure_label (menu_item);
1902 child = gtk_bin_get_child (GTK_BIN (menu_item));
1903 if (GTK_IS_LABEL (child))
1904 return gtk_label_get_label (GTK_LABEL (child));
1910 free_timeval (GTimeVal *val)
1912 g_slice_free (GTimeVal, val);
1916 gtk_menu_item_real_popup_submenu (GtkWidget *widget,
1917 gboolean remember_exact_time)
1919 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1920 GtkMenuItemPrivate *priv = menu_item->priv;
1923 parent = gtk_widget_get_parent (widget);
1925 if (gtk_widget_is_sensitive (priv->submenu) && parent)
1927 gboolean take_focus;
1928 GtkMenuPositionFunc menu_position_func;
1930 take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (parent));
1931 gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (priv->submenu), take_focus);
1933 if (remember_exact_time)
1935 GTimeVal *popup_time = g_slice_new0 (GTimeVal);
1937 g_get_current_time (popup_time);
1939 g_object_set_data_full (G_OBJECT (priv->submenu),
1940 "gtk-menu-exact-popup-time", popup_time,
1941 (GDestroyNotify) free_timeval);
1945 g_object_set_data (G_OBJECT (priv->submenu),
1946 "gtk-menu-exact-popup-time", NULL);
1949 /* gtk_menu_item_position_menu positions the submenu from the
1950 * menuitems position. If the menuitem doesn't have a window,
1951 * that doesn't work. In that case we use the default
1952 * positioning function instead which places the submenu at the
1955 if (gtk_widget_get_window (widget))
1956 menu_position_func = gtk_menu_item_position_menu;
1958 menu_position_func = NULL;
1960 gtk_menu_popup (GTK_MENU (priv->submenu),
1965 GTK_MENU_SHELL (parent)->priv->button,
1969 /* Enable themeing of the parent menu item depending on whether
1970 * its submenu is shown or not.
1972 gtk_widget_queue_draw (widget);
1976 gtk_menu_item_popup_timeout (gpointer data)
1978 GtkMenuItem *menu_item = GTK_MENU_ITEM (data);
1979 GtkMenuItemPrivate *priv = menu_item->priv;
1982 parent = gtk_widget_get_parent (GTK_WIDGET (menu_item));
1984 if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->priv->active) ||
1985 (GTK_IS_MENU (parent) && GTK_MENU (parent)->priv->torn_off))
1987 gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1988 if (priv->timer_from_keypress && priv->submenu)
1989 GTK_MENU_SHELL (priv->submenu)->priv->ignore_enter = TRUE;
1998 get_popup_delay (GtkWidget *widget)
2002 parent = gtk_widget_get_parent (widget);
2003 if (GTK_IS_MENU_SHELL (parent))
2005 return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (parent));
2011 g_object_get (gtk_widget_get_settings (widget),
2012 "gtk-menu-popup-delay", &popup_delay,
2020 _gtk_menu_item_popup_submenu (GtkWidget *widget,
2021 gboolean with_delay)
2023 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2024 GtkMenuItemPrivate *priv = menu_item->priv;
2028 g_source_remove (priv->timer);
2035 gint popup_delay = get_popup_delay (widget);
2037 if (popup_delay > 0)
2039 GdkEvent *event = gtk_get_current_event ();
2041 priv->timer = gdk_threads_add_timeout (popup_delay,
2042 gtk_menu_item_popup_timeout,
2046 event->type != GDK_BUTTON_PRESS &&
2047 event->type != GDK_ENTER_NOTIFY)
2048 priv->timer_from_keypress = TRUE;
2050 priv->timer_from_keypress = FALSE;
2053 gdk_event_free (event);
2059 gtk_menu_item_real_popup_submenu (widget, FALSE);
2063 _gtk_menu_item_popdown_submenu (GtkWidget *widget)
2065 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2066 GtkMenuItemPrivate *priv = menu_item->priv;
2070 g_object_set_data (G_OBJECT (priv->submenu),
2071 "gtk-menu-exact-popup-time", NULL);
2075 g_source_remove (priv->timer);
2079 gtk_menu_popdown (GTK_MENU (priv->submenu));
2081 gtk_widget_queue_draw (widget);
2086 get_offsets (GtkMenu *menu,
2087 gint *horizontal_offset,
2088 gint *vertical_offset)
2090 gint vertical_padding;
2091 gint horizontal_padding;
2092 GtkStyleContext *context;
2093 GtkStateFlags state;
2096 gtk_widget_style_get (GTK_WIDGET (menu),
2097 "horizontal-offset", horizontal_offset,
2098 "vertical-offset", vertical_offset,
2099 "horizontal-padding", &horizontal_padding,
2100 "vertical-padding", &vertical_padding,
2103 context = gtk_widget_get_style_context (GTK_WIDGET (menu));
2104 state = gtk_widget_get_state_flags (GTK_WIDGET (menu));
2105 gtk_style_context_get_padding (context, state, &padding);
2107 *vertical_offset -= padding.top;
2108 *vertical_offset -= vertical_padding;
2109 *horizontal_offset += horizontal_padding;
2113 gtk_menu_item_position_menu (GtkMenu *menu,
2119 GtkMenuItem *menu_item = GTK_MENU_ITEM (user_data);
2120 GtkMenuItemPrivate *priv = menu_item->priv;
2121 GtkAllocation allocation;
2123 GtkMenuItem *parent_menu_item;
2124 GtkRequisition requisition;
2127 gint twidth, theight;
2129 GtkTextDirection direction;
2130 GdkRectangle monitor;
2132 gint horizontal_offset;
2133 gint vertical_offset;
2134 gint available_left, available_right;
2135 GtkStyleContext *context;
2136 GtkStateFlags state;
2137 GtkBorder parent_padding;
2139 g_return_if_fail (menu != NULL);
2140 g_return_if_fail (x != NULL);
2141 g_return_if_fail (y != NULL);
2143 widget = GTK_WIDGET (user_data);
2148 direction = gtk_widget_get_direction (widget);
2150 twidth = gtk_widget_get_allocated_width (GTK_WIDGET (menu));
2151 theight = gtk_widget_get_allocated_width (GTK_WIDGET (menu));
2153 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2154 monitor_num = gdk_screen_get_monitor_at_window (screen, priv->event_window);
2155 if (monitor_num < 0)
2157 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2159 if (!gdk_window_get_origin (gtk_widget_get_window (widget), &tx, &ty))
2161 g_warning ("Menu not on screen");
2165 gtk_widget_get_allocation (widget, &allocation);
2170 get_offsets (menu, &horizontal_offset, &vertical_offset);
2172 available_left = tx - monitor.x;
2173 available_right = monitor.x + monitor.width - (tx + allocation.width);
2175 parent = gtk_widget_get_parent (widget);
2176 if (GTK_IS_MENU_BAR (parent))
2178 priv->from_menubar = TRUE;
2180 else if (GTK_IS_MENU (parent))
2182 if (GTK_MENU (parent)->priv->parent_menu_item)
2183 priv->from_menubar = GTK_MENU_ITEM (GTK_MENU (parent)->priv->parent_menu_item)->priv->from_menubar;
2185 priv->from_menubar = FALSE;
2189 priv->from_menubar = FALSE;
2192 switch (priv->submenu_placement)
2194 case GTK_TOP_BOTTOM:
2195 if (direction == GTK_TEXT_DIR_LTR)
2196 priv->submenu_direction = GTK_DIRECTION_RIGHT;
2199 priv->submenu_direction = GTK_DIRECTION_LEFT;
2200 tx += allocation.width - twidth;
2202 if ((ty + allocation.height + theight) <= monitor.y + monitor.height)
2203 ty += allocation.height;
2204 else if ((ty - theight) >= monitor.y)
2206 else if (monitor.y + monitor.height - (ty + allocation.height) > ty)
2207 ty += allocation.height;
2212 case GTK_LEFT_RIGHT:
2213 if (GTK_IS_MENU (parent))
2214 parent_menu_item = GTK_MENU_ITEM (GTK_MENU (parent)->priv->parent_menu_item);
2216 parent_menu_item = NULL;
2218 context = gtk_widget_get_style_context (parent);
2219 state = gtk_widget_get_state_flags (parent);
2220 gtk_style_context_get_padding (context, state, &parent_padding);
2222 if (parent_menu_item && !GTK_MENU (parent)->priv->torn_off)
2224 priv->submenu_direction = parent_menu_item->priv->submenu_direction;
2228 if (direction == GTK_TEXT_DIR_LTR)
2229 priv->submenu_direction = GTK_DIRECTION_RIGHT;
2231 priv->submenu_direction = GTK_DIRECTION_LEFT;
2234 switch (priv->submenu_direction)
2236 case GTK_DIRECTION_LEFT:
2237 if (tx - twidth - parent_padding.left - horizontal_offset >= monitor.x ||
2238 available_left >= available_right)
2239 tx -= twidth + parent_padding.left + horizontal_offset;
2242 priv->submenu_direction = GTK_DIRECTION_RIGHT;
2243 tx += allocation.width + parent_padding.right + horizontal_offset;
2247 case GTK_DIRECTION_RIGHT:
2248 if (tx + allocation.width + parent_padding.right + horizontal_offset + twidth <= monitor.x + monitor.width ||
2249 available_right >= available_left)
2250 tx += allocation.width + parent_padding.right + horizontal_offset;
2253 priv->submenu_direction = GTK_DIRECTION_LEFT;
2254 tx -= twidth + parent_padding.left + horizontal_offset;
2259 ty += vertical_offset;
2261 /* If the height of the menu doesn't fit we move it upward. */
2262 ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
2266 /* If we have negative, tx, here it is because we can't get
2267 * the menu all the way on screen. Favor the left portion.
2269 *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
2272 gtk_menu_set_monitor (menu, monitor_num);
2274 if (!gtk_widget_get_visible (menu->priv->toplevel))
2276 gtk_window_set_type_hint (GTK_WINDOW (menu->priv->toplevel), priv->from_menubar?
2277 GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
2282 * gtk_menu_item_set_right_justified:
2283 * @menu_item: a #GtkMenuItem.
2284 * @right_justified: if %TRUE the menu item will appear at the
2285 * far right if added to a menu bar
2287 * Sets whether the menu item appears justified at the right
2288 * side of a menu bar. This was traditionally done for "Help"
2289 * menu items, but is now considered a bad idea. (If the widget
2290 * layout is reversed for a right-to-left language like Hebrew
2291 * or Arabic, right-justified-menu-items appear at the left.)
2293 * Deprecated: 3.2: If you insist on using it, use
2294 * gtk_widget_set_hexpand() and gtk_widget_set_halign().
2297 gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
2298 gboolean right_justified)
2300 GtkMenuItemPrivate *priv = menu_item->priv;
2302 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2304 right_justified = right_justified != FALSE;
2306 if (priv->right_justify != right_justified)
2308 priv->right_justify = right_justified;
2309 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
2314 * gtk_menu_item_get_right_justified:
2315 * @menu_item: a #GtkMenuItem
2317 * Gets whether the menu item appears justified at the right
2318 * side of the menu bar.
2320 * Return value: %TRUE if the menu item will appear at the
2321 * far right if added to a menu bar.
2323 * Deprecated: 3.2: See gtk_menu_item_set_right_justified()
2326 gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
2328 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2330 return menu_item->priv->right_justify;
2335 gtk_menu_item_show_all (GtkWidget *widget)
2337 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2338 GtkMenuItemPrivate *priv = menu_item->priv;
2340 /* show children including submenu */
2342 gtk_widget_show_all (priv->submenu);
2343 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
2345 gtk_widget_show (widget);
2349 gtk_menu_item_can_activate_accel (GtkWidget *widget,
2354 parent = gtk_widget_get_parent (widget);
2356 /* Chain to the parent GtkMenu for further checks */
2357 return (gtk_widget_is_sensitive (widget) && gtk_widget_get_visible (widget) &&
2358 parent && gtk_widget_can_activate_accel (parent, signal_id));
2362 gtk_menu_item_accel_name_foreach (GtkWidget *widget,
2365 const gchar **path_p = data;
2369 if (GTK_IS_LABEL (widget))
2371 *path_p = gtk_label_get_text (GTK_LABEL (widget));
2372 if (*path_p && (*path_p)[0] == 0)
2375 else if (GTK_IS_CONTAINER (widget))
2376 gtk_container_foreach (GTK_CONTAINER (widget),
2377 gtk_menu_item_accel_name_foreach,
2383 gtk_menu_item_parent_set (GtkWidget *widget,
2384 GtkWidget *previous_parent)
2386 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
2390 parent = gtk_widget_get_parent (widget);
2391 menu = GTK_IS_MENU (parent) ? GTK_MENU (parent) : NULL;
2394 _gtk_menu_item_refresh_accel_path (menu_item,
2395 menu->priv->accel_path,
2396 menu->priv->accel_group,
2399 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set)
2400 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent);
2404 _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item,
2405 const gchar *prefix,
2406 GtkAccelGroup *accel_group,
2407 gboolean group_changed)
2409 GtkMenuItemPrivate *priv = menu_item->priv;
2413 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2414 g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
2416 widget = GTK_WIDGET (menu_item);
2420 gtk_widget_set_accel_path (widget, NULL, NULL);
2424 path = _gtk_widget_get_accel_path (widget, NULL);
2425 if (!path) /* no active accel_path yet */
2427 path = priv->accel_path;
2428 if (!path && prefix)
2430 const gchar *postfix = NULL;
2433 /* try to construct one from label text */
2434 gtk_container_foreach (GTK_CONTAINER (menu_item),
2435 gtk_menu_item_accel_name_foreach,
2439 new_path = g_strconcat (prefix, "/", postfix, NULL);
2440 path = priv->accel_path = (char*)g_intern_string (new_path);
2445 gtk_widget_set_accel_path (widget, path, accel_group);
2447 else if (group_changed) /* reinstall accelerators */
2448 gtk_widget_set_accel_path (widget, path, accel_group);
2452 * gtk_menu_item_set_accel_path
2453 * @menu_item: a valid #GtkMenuItem
2454 * @accel_path: (allow-none): accelerator path, corresponding to this menu
2455 * item's functionality, or %NULL to unset the current path.
2457 * Set the accelerator path on @menu_item, through which runtime
2458 * changes of the menu item's accelerator caused by the user can be
2459 * identified and saved to persistent storage (see gtk_accel_map_save()
2460 * on this). To set up a default accelerator for this menu item, call
2461 * gtk_accel_map_add_entry() with the same @accel_path. See also
2462 * gtk_accel_map_add_entry() on the specifics of accelerator paths,
2463 * and gtk_menu_set_accel_path() for a more convenient variant of
2466 * This function is basically a convenience wrapper that handles
2467 * calling gtk_widget_set_accel_path() with the appropriate accelerator
2468 * group for the menu item.
2470 * Note that you do need to set an accelerator on the parent menu with
2471 * gtk_menu_set_accel_group() for this to work.
2473 * Note that @accel_path string will be stored in a #GQuark.
2474 * Therefore, if you pass a static string, you can save some memory
2475 * by interning it first with g_intern_static_string().
2478 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
2479 const gchar *accel_path)
2481 GtkMenuItemPrivate *priv = menu_item->priv;
2485 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2486 g_return_if_fail (accel_path == NULL ||
2487 (accel_path[0] == '<' && strchr (accel_path, '/')));
2489 widget = GTK_WIDGET (menu_item);
2491 /* store new path */
2492 priv->accel_path = (char*)g_intern_string (accel_path);
2494 /* forget accelerators associated with old path */
2495 gtk_widget_set_accel_path (widget, NULL, NULL);
2497 /* install accelerators associated with new path */
2498 parent = gtk_widget_get_parent (widget);
2499 if (GTK_IS_MENU (parent))
2501 GtkMenu *menu = GTK_MENU (parent);
2503 if (menu->priv->accel_group)
2504 _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
2506 menu->priv->accel_group,
2512 * gtk_menu_item_get_accel_path
2513 * @menu_item: a valid #GtkMenuItem
2515 * Retrieve the accelerator path that was previously set on @menu_item.
2517 * See gtk_menu_item_set_accel_path() for details.
2519 * Returns: the accelerator path corresponding to this menu
2520 * item's functionality, or %NULL if not set
2524 G_CONST_RETURN gchar *
2525 gtk_menu_item_get_accel_path (GtkMenuItem *menu_item)
2527 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2529 return menu_item->priv->accel_path;
2533 gtk_menu_item_forall (GtkContainer *container,
2534 gboolean include_internals,
2535 GtkCallback callback,
2536 gpointer callback_data)
2540 g_return_if_fail (GTK_IS_MENU_ITEM (container));
2541 g_return_if_fail (callback != NULL);
2543 child = gtk_bin_get_child (GTK_BIN (container));
2545 callback (child, callback_data);
2549 _gtk_menu_item_is_selectable (GtkWidget *menu_item)
2551 if ((!gtk_bin_get_child (GTK_BIN (menu_item)) &&
2552 G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
2553 GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
2554 !gtk_widget_is_sensitive (menu_item) ||
2555 !gtk_widget_get_visible (menu_item))
2562 gtk_menu_item_ensure_label (GtkMenuItem *menu_item)
2564 GtkWidget *accel_label;
2566 if (!gtk_bin_get_child (GTK_BIN (menu_item)))
2568 accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
2569 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
2571 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
2572 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label),
2573 GTK_WIDGET (menu_item));
2574 gtk_widget_show (accel_label);
2579 * gtk_menu_item_set_label:
2580 * @menu_item: a #GtkMenuItem
2581 * @label: the text you want to set
2583 * Sets @text on the @menu_item label
2588 gtk_menu_item_set_label (GtkMenuItem *menu_item,
2591 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2593 GTK_MENU_ITEM_GET_CLASS (menu_item)->set_label (menu_item, label);
2597 * gtk_menu_item_get_label:
2598 * @menu_item: a #GtkMenuItem
2600 * Sets @text on the @menu_item label
2602 * Returns: The text in the @menu_item label. This is the internal
2603 * string used by the label, and must not be modified.
2607 G_CONST_RETURN gchar *
2608 gtk_menu_item_get_label (GtkMenuItem *menu_item)
2610 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2612 return GTK_MENU_ITEM_GET_CLASS (menu_item)->get_label (menu_item);
2616 * gtk_menu_item_set_use_underline:
2617 * @menu_item: a #GtkMenuItem
2618 * @setting: %TRUE if underlines in the text indicate mnemonics
2620 * If true, an underline in the text indicates the next character
2621 * should be used for the mnemonic accelerator key.
2626 gtk_menu_item_set_use_underline (GtkMenuItem *menu_item,
2631 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2633 gtk_menu_item_ensure_label (menu_item);
2635 child = gtk_bin_get_child (GTK_BIN (menu_item));
2636 if (GTK_IS_LABEL (child))
2638 gtk_label_set_use_underline (GTK_LABEL (child), setting);
2640 g_object_notify (G_OBJECT (menu_item), "use-underline");
2645 * gtk_menu_item_get_use_underline:
2646 * @menu_item: a #GtkMenuItem
2648 * Checks if an underline in the text indicates the next character
2649 * should be used for the mnemonic accelerator key.
2651 * Return value: %TRUE if an embedded underline in the label
2652 * indicates the mnemonic accelerator key.
2657 gtk_menu_item_get_use_underline (GtkMenuItem *menu_item)
2661 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2663 gtk_menu_item_ensure_label (menu_item);
2665 child = gtk_bin_get_child (GTK_BIN (menu_item));
2666 if (GTK_IS_LABEL (child))
2667 return gtk_label_get_use_underline (GTK_LABEL (child));
2673 * gtk_menu_item_set_reserve_indicator:
2674 * @menu_item: a #GtkMenuItem
2675 * @reserve: the new value
2677 * Sets whether the @menu_item should reserve space for
2678 * the submenu indicator, regardless if it actually has
2681 * There should be little need for applications to call
2687 gtk_menu_item_set_reserve_indicator (GtkMenuItem *menu_item,
2690 GtkMenuItemPrivate *priv;
2692 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2694 priv = menu_item->priv;
2696 if (priv->reserve_indicator != reserve)
2698 priv->reserve_indicator = reserve;
2699 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
2704 * gtk_menu_item_get_reserve_indicator:
2705 * @menu_item: a #GtkMenuItem
2707 * Returns whether the @menu_item reserves space for
2708 * the submenu indicator, regardless if it has a submenu
2711 * Returns: %TRUE if @menu_item always reserves space for the
2717 gtk_menu_item_get_reserve_indicator (GtkMenuItem *menu_item)
2719 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2721 return menu_item->priv->reserve_indicator;