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/.
27 #define GTK_MENU_INTERNALS
32 #include "gtkaccellabel.h"
34 #include "gtkmarshalers.h"
36 #include "gtkmenubar.h"
37 #include "gtkmenuitem.h"
38 #include "gtkseparatormenuitem.h"
39 #include "gtkprivate.h"
43 #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
59 static void gtk_menu_item_set_property (GObject *object,
63 static void gtk_menu_item_get_property (GObject *object,
67 static void gtk_menu_item_finalize (GObject *object);
68 static void gtk_menu_item_destroy (GtkObject *object);
69 static void gtk_menu_item_size_request (GtkWidget *widget,
70 GtkRequisition *requisition);
71 static void gtk_menu_item_size_allocate (GtkWidget *widget,
72 GtkAllocation *allocation);
73 static void gtk_menu_item_realize (GtkWidget *widget);
74 static void gtk_menu_item_unrealize (GtkWidget *widget);
75 static void gtk_menu_item_map (GtkWidget *widget);
76 static void gtk_menu_item_unmap (GtkWidget *widget);
77 static void gtk_menu_item_paint (GtkWidget *widget,
79 static gint gtk_menu_item_expose (GtkWidget *widget,
80 GdkEventExpose *event);
81 static void gtk_menu_item_parent_set (GtkWidget *widget,
82 GtkWidget *previous_parent);
85 static void gtk_real_menu_item_select (GtkItem *item);
86 static void gtk_real_menu_item_deselect (GtkItem *item);
87 static void gtk_real_menu_item_activate_item (GtkMenuItem *item);
88 static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
90 static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
92 static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget,
93 gboolean group_cycling);
95 static gint gtk_menu_item_popup_timeout (gpointer data);
96 static void gtk_menu_item_position_menu (GtkMenu *menu,
101 static void gtk_menu_item_show_all (GtkWidget *widget);
102 static void gtk_menu_item_hide_all (GtkWidget *widget);
103 static void gtk_menu_item_forall (GtkContainer *container,
104 gboolean include_internals,
105 GtkCallback callback,
106 gpointer callback_data);
107 static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget,
111 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
113 G_DEFINE_TYPE (GtkMenuItem, gtk_menu_item, GTK_TYPE_ITEM)
116 gtk_menu_item_class_init (GtkMenuItemClass *klass)
118 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
119 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
120 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
121 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
122 GtkItemClass *item_class = GTK_ITEM_CLASS (klass);
124 gobject_class->set_property = gtk_menu_item_set_property;
125 gobject_class->get_property = gtk_menu_item_get_property;
126 gobject_class->finalize = gtk_menu_item_finalize;
128 object_class->destroy = gtk_menu_item_destroy;
130 widget_class->size_request = gtk_menu_item_size_request;
131 widget_class->size_allocate = gtk_menu_item_size_allocate;
132 widget_class->expose_event = gtk_menu_item_expose;
133 widget_class->realize = gtk_menu_item_realize;
134 widget_class->unrealize = gtk_menu_item_unrealize;
135 widget_class->map = gtk_menu_item_map;
136 widget_class->unmap = gtk_menu_item_unmap;
137 widget_class->show_all = gtk_menu_item_show_all;
138 widget_class->hide_all = gtk_menu_item_hide_all;
139 widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate;
140 widget_class->parent_set = gtk_menu_item_parent_set;
141 widget_class->can_activate_accel = gtk_menu_item_can_activate_accel;
143 container_class->forall = gtk_menu_item_forall;
145 item_class->select = gtk_real_menu_item_select;
146 item_class->deselect = gtk_real_menu_item_deselect;
148 klass->activate = NULL;
149 klass->activate_item = gtk_real_menu_item_activate_item;
150 klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
151 klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
153 klass->hide_on_activate = TRUE;
155 menu_item_signals[ACTIVATE] =
156 g_signal_new (I_("activate"),
157 G_OBJECT_CLASS_TYPE (gobject_class),
158 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
159 G_STRUCT_OFFSET (GtkMenuItemClass, activate),
161 _gtk_marshal_VOID__VOID,
163 widget_class->activate_signal = menu_item_signals[ACTIVATE];
165 menu_item_signals[ACTIVATE_ITEM] =
166 g_signal_new (I_("activate_item"),
167 G_OBJECT_CLASS_TYPE (gobject_class),
169 G_STRUCT_OFFSET (GtkMenuItemClass, activate_item),
171 _gtk_marshal_VOID__VOID,
174 menu_item_signals[TOGGLE_SIZE_REQUEST] =
175 g_signal_new (I_("toggle_size_request"),
176 G_OBJECT_CLASS_TYPE (gobject_class),
178 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request),
180 _gtk_marshal_VOID__POINTER,
184 menu_item_signals[TOGGLE_SIZE_ALLOCATE] =
185 g_signal_new (I_("toggle_size_allocate"),
186 G_OBJECT_CLASS_TYPE (gobject_class),
188 G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate),
190 _gtk_marshal_NONE__INT,
195 * GtkMenuItem:submenu:
197 * The submenu attached to the menu item, or NULL if it has none.
201 g_object_class_install_property (gobject_class,
203 g_param_spec_object ("submenu",
205 P_("The submenu attached to the menu item, or NULL if it has none"),
207 GTK_PARAM_READWRITE));
209 gtk_widget_class_install_style_property_parser (widget_class,
210 g_param_spec_enum ("selected-shadow-type",
211 "Selected Shadow Type",
212 "Shadow type when item is selected",
213 GTK_TYPE_SHADOW_TYPE,
216 gtk_rc_property_parse_enum);
218 gtk_widget_class_install_style_property (widget_class,
219 g_param_spec_int ("horizontal-padding",
220 "Horizontal Padding",
221 "Padding to left and right of the menu item",
225 GTK_PARAM_READABLE));
227 gtk_widget_class_install_style_property (widget_class,
228 g_param_spec_int ("toggle-spacing",
230 "Space between icon and label",
234 GTK_PARAM_READABLE));
236 gtk_widget_class_install_style_property (widget_class,
237 g_param_spec_int ("arrow-spacing",
239 "Space between label and arrow",
243 GTK_PARAM_READABLE));
247 gtk_menu_item_init (GtkMenuItem *menu_item)
249 GTK_WIDGET_SET_FLAGS (menu_item, GTK_NO_WINDOW);
251 menu_item->submenu = NULL;
252 menu_item->toggle_size = 0;
253 menu_item->accelerator_width = 0;
254 menu_item->show_submenu_indicator = FALSE;
255 if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
256 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
258 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
259 menu_item->submenu_placement = GTK_TOP_BOTTOM;
260 menu_item->right_justify = FALSE;
262 menu_item->timer = 0;
266 gtk_menu_item_new (void)
268 return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
272 gtk_menu_item_new_with_label (const gchar *label)
274 GtkWidget *menu_item;
275 GtkWidget *accel_label;
277 menu_item = gtk_menu_item_new ();
278 accel_label = gtk_accel_label_new (label);
279 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
281 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
282 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
283 gtk_widget_show (accel_label);
290 * gtk_menu_item_new_with_mnemonic:
291 * @label: The text of the button, with an underscore in front of the
293 * @returns: a new #GtkMenuItem
295 * Creates a new #GtkMenuItem containing a label. The label
296 * will be created using gtk_label_new_with_mnemonic(), so underscores
297 * in @label indicate the mnemonic for the menu item.
300 gtk_menu_item_new_with_mnemonic (const gchar *label)
302 GtkWidget *menu_item;
303 GtkWidget *accel_label;
305 menu_item = gtk_menu_item_new ();
306 accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
307 gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
308 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
310 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
311 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
312 gtk_widget_show (accel_label);
318 gtk_menu_item_set_property (GObject *object,
323 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
328 gtk_menu_item_set_submenu (menu_item, g_value_get_object (value));
332 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
338 gtk_menu_item_get_property (GObject *object,
343 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
348 g_value_set_object (value, gtk_menu_item_get_submenu (menu_item));
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
358 gtk_menu_item_finalize (GObject *object)
360 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
362 g_free (menu_item->accel_path);
364 G_OBJECT_CLASS (gtk_menu_item_parent_class)->finalize (object);
368 gtk_menu_item_destroy (GtkObject *object)
370 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
372 if (menu_item->submenu)
373 gtk_widget_destroy (menu_item->submenu);
375 GTK_OBJECT_CLASS (gtk_menu_item_parent_class)->destroy (object);
379 gtk_menu_item_detacher (GtkWidget *widget,
382 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
384 g_return_if_fail (menu_item->submenu == (GtkWidget*) menu);
386 menu_item->submenu = NULL;
390 * gtk_menu_item_set_submenu:
391 * @menu_item: a #GtkMenuItem
392 * @submenu: the submenu, or %NULL
394 * Sets or replaces the menu item's submenu, or removes it when a %NULL
398 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
401 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
402 g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu));
404 if (menu_item->submenu != submenu)
406 if (menu_item->submenu)
407 gtk_menu_detach (GTK_MENU (menu_item->submenu));
411 menu_item->submenu = submenu;
412 gtk_menu_attach_to_widget (GTK_MENU (submenu),
413 GTK_WIDGET (menu_item),
414 gtk_menu_item_detacher);
417 if (GTK_WIDGET (menu_item)->parent)
418 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
420 g_object_notify (G_OBJECT (menu_item), "submenu");
425 * gtk_menu_item_get_submenu:
426 * @menu_item: a #GtkMenuItem
428 * Gets the submenu underneath this menu item, if any. See
429 * gtk_menu_item_set_submenu().
431 * Return value: submenu for this menu item, or %NULL if none.
434 gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
436 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
438 return menu_item->submenu;
442 * gtk_menu_item_remove_submenu:
443 * @menu_item: a #GtkMenuItem
445 * Removes the widget's submenu.
447 * Deprecated: 2.12: gtk_menu_item_remove_submenu() is deprecated and
448 * should not be used in newly written code. Use
449 * gtk_menu_item_set_submenu() instead.
452 gtk_menu_item_remove_submenu (GtkMenuItem *menu_item)
454 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
456 gtk_menu_item_set_submenu (menu_item, NULL);
459 void _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
460 GtkSubmenuPlacement placement);
463 _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
464 GtkSubmenuPlacement placement)
466 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
468 menu_item->submenu_placement = placement;
472 gtk_menu_item_select (GtkMenuItem *menu_item)
474 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
476 gtk_item_select (GTK_ITEM (menu_item));
478 /* Enable themeing of the parent menu item depending on whether
479 * something is selected in its submenu
481 if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
483 GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
485 if (menu->parent_menu_item)
486 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
491 gtk_menu_item_deselect (GtkMenuItem *menu_item)
493 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
495 gtk_item_deselect (GTK_ITEM (menu_item));
497 /* Enable themeing of the parent menu item depending on whether
498 * something is selected in its submenu
500 if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
502 GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
504 if (menu->parent_menu_item)
505 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
510 gtk_menu_item_activate (GtkMenuItem *menu_item)
512 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
514 g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
518 gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
521 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
523 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
527 gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
530 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
532 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
536 gtk_menu_item_accel_width_foreach (GtkWidget *widget,
541 if (GTK_IS_ACCEL_LABEL (widget))
545 w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
546 *width = MAX (*width, w);
548 else if (GTK_IS_CONTAINER (widget))
549 gtk_container_foreach (GTK_CONTAINER (widget),
550 gtk_menu_item_accel_width_foreach,
555 get_minimum_width (GtkWidget *widget)
557 PangoContext *context;
558 PangoFontMetrics *metrics;
561 context = gtk_widget_get_pango_context (widget);
562 metrics = pango_context_get_metrics (context,
563 widget->style->font_desc,
564 pango_context_get_language (context));
566 height = pango_font_metrics_get_ascent (metrics) +
567 pango_font_metrics_get_descent (metrics);
569 pango_font_metrics_unref (metrics);
571 return PANGO_PIXELS (7 * height);
575 gtk_menu_item_size_request (GtkWidget *widget,
576 GtkRequisition *requisition)
578 GtkMenuItem *menu_item;
581 guint horizontal_padding;
582 GtkPackDirection pack_dir;
583 GtkPackDirection child_pack_dir;
585 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
586 g_return_if_fail (requisition != NULL);
588 gtk_widget_style_get (widget,
589 "horizontal-padding", &horizontal_padding,
592 bin = GTK_BIN (widget);
593 menu_item = GTK_MENU_ITEM (widget);
595 if (GTK_IS_MENU_BAR (widget->parent))
597 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
598 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
602 pack_dir = GTK_PACK_DIRECTION_LTR;
603 child_pack_dir = GTK_PACK_DIRECTION_LTR;
606 requisition->width = (GTK_CONTAINER (widget)->border_width +
607 widget->style->xthickness) * 2;
608 requisition->height = (GTK_CONTAINER (widget)->border_width +
609 widget->style->ythickness) * 2;
611 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
612 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
613 requisition->width += 2 * horizontal_padding;
614 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
615 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
616 requisition->height += 2 * horizontal_padding;
618 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
620 GtkRequisition child_requisition;
622 gtk_widget_size_request (bin->child, &child_requisition);
624 requisition->width += child_requisition.width;
625 requisition->height += child_requisition.height;
627 if (menu_item->submenu && menu_item->show_submenu_indicator)
631 gtk_widget_style_get (widget,
632 "arrow-spacing", &arrow_spacing,
635 requisition->width += child_requisition.height;
636 requisition->width += arrow_spacing;
638 requisition->width = MAX (requisition->width, get_minimum_width (widget));
641 else /* separator item */
643 gboolean wide_separators;
644 gint separator_height;
646 gtk_widget_style_get (widget,
647 "wide-separators", &wide_separators,
648 "separator-height", &separator_height,
652 requisition->height += separator_height + widget->style->ythickness;
654 requisition->height += widget->style->ythickness * 2;
658 gtk_container_foreach (GTK_CONTAINER (menu_item),
659 gtk_menu_item_accel_width_foreach,
661 menu_item->accelerator_width = accel_width;
665 gtk_menu_item_size_allocate (GtkWidget *widget,
666 GtkAllocation *allocation)
668 GtkMenuItem *menu_item;
670 GtkAllocation child_allocation;
671 GtkTextDirection direction;
672 GtkPackDirection pack_dir;
673 GtkPackDirection child_pack_dir;
675 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
676 g_return_if_fail (allocation != NULL);
678 menu_item = GTK_MENU_ITEM (widget);
679 bin = GTK_BIN (widget);
681 direction = gtk_widget_get_direction (widget);
683 if (GTK_IS_MENU_BAR (widget->parent))
685 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
686 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
690 pack_dir = GTK_PACK_DIRECTION_LTR;
691 child_pack_dir = GTK_PACK_DIRECTION_LTR;
694 widget->allocation = *allocation;
698 GtkRequisition child_requisition;
699 guint horizontal_padding;
701 gtk_widget_style_get (widget,
702 "horizontal-padding", &horizontal_padding,
705 child_allocation.x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
706 child_allocation.y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness;
708 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
709 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
710 child_allocation.x += horizontal_padding;
711 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
712 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
713 child_allocation.y += horizontal_padding;
715 child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
716 child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
718 if (child_pack_dir == GTK_PACK_DIRECTION_LTR ||
719 child_pack_dir == GTK_PACK_DIRECTION_RTL)
721 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL))
722 child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
723 child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size;
727 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT))
728 child_allocation.y += GTK_MENU_ITEM (widget)->toggle_size;
729 child_allocation.height -= GTK_MENU_ITEM (widget)->toggle_size;
732 child_allocation.x += widget->allocation.x;
733 child_allocation.y += widget->allocation.y;
735 gtk_widget_get_child_requisition (bin->child, &child_requisition);
736 if (menu_item->submenu && menu_item->show_submenu_indicator)
738 if (direction == GTK_TEXT_DIR_RTL)
739 child_allocation.x += child_requisition.height;
740 child_allocation.width -= child_requisition.height;
743 if (child_allocation.width < 1)
744 child_allocation.width = 1;
746 gtk_widget_size_allocate (bin->child, &child_allocation);
749 if (GTK_WIDGET_REALIZED (widget))
750 gdk_window_move_resize (menu_item->event_window,
751 allocation->x, allocation->y,
752 allocation->width, allocation->height);
754 if (menu_item->submenu)
755 gtk_menu_reposition (GTK_MENU (menu_item->submenu));
759 gtk_menu_item_realize (GtkWidget *widget)
761 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
762 GdkWindowAttr attributes;
763 gint attributes_mask;
765 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
767 widget->window = gtk_widget_get_parent_window (widget);
768 g_object_ref (widget->window);
770 attributes.x = widget->allocation.x;
771 attributes.y = widget->allocation.y;
772 attributes.width = widget->allocation.width;
773 attributes.height = widget->allocation.height;
774 attributes.window_type = GDK_WINDOW_CHILD;
775 attributes.wclass = GDK_INPUT_ONLY;
776 attributes.event_mask = (gtk_widget_get_events (widget) |
777 GDK_BUTTON_PRESS_MASK |
778 GDK_BUTTON_RELEASE_MASK |
779 GDK_ENTER_NOTIFY_MASK |
780 GDK_LEAVE_NOTIFY_MASK |
781 GDK_POINTER_MOTION_MASK);
783 attributes_mask = GDK_WA_X | GDK_WA_Y;
784 menu_item->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
785 gdk_window_set_user_data (menu_item->event_window, widget);
787 widget->style = gtk_style_attach (widget->style, widget->window);
791 gtk_menu_item_unrealize (GtkWidget *widget)
793 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
795 gdk_window_set_user_data (menu_item->event_window, NULL);
796 gdk_window_destroy (menu_item->event_window);
797 menu_item->event_window = NULL;
799 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize)
800 (* GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize) (widget);
804 gtk_menu_item_map (GtkWidget *widget)
806 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
808 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget);
810 gdk_window_show (menu_item->event_window);
814 gtk_menu_item_unmap (GtkWidget *widget)
816 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
818 gdk_window_hide (menu_item->event_window);
820 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget);
824 gtk_menu_item_paint (GtkWidget *widget,
827 GtkMenuItem *menu_item;
828 GtkStateType state_type;
829 GtkShadowType shadow_type, selected_shadow_type;
832 gint border_width = GTK_CONTAINER (widget)->border_width;
834 if (GTK_WIDGET_DRAWABLE (widget))
836 menu_item = GTK_MENU_ITEM (widget);
838 state_type = widget->state;
840 x = widget->allocation.x + border_width;
841 y = widget->allocation.y + border_width;
842 width = widget->allocation.width - border_width * 2;
843 height = widget->allocation.height - border_width * 2;
845 if ((state_type == GTK_STATE_PRELIGHT) &&
846 (GTK_BIN (menu_item)->child))
848 gtk_widget_style_get (widget,
849 "selected-shadow-type", &selected_shadow_type,
851 gtk_paint_box (widget->style,
854 selected_shadow_type,
855 area, widget, "menuitem",
856 x, y, width, height);
859 if (menu_item->submenu && menu_item->show_submenu_indicator)
861 gint arrow_x, arrow_y;
864 guint horizontal_padding;
865 GtkTextDirection direction;
866 GtkArrowType arrow_type;
867 PangoContext *context;
868 PangoFontMetrics *metrics;
869 gint ascent, descent;
871 direction = gtk_widget_get_direction (widget);
873 gtk_widget_style_get (widget,
874 "horizontal-padding", &horizontal_padding,
877 context = gtk_widget_get_pango_context (GTK_BIN (menu_item)->child);
878 metrics = pango_context_get_metrics (context,
879 GTK_WIDGET (GTK_BIN (menu_item)->child)->style->font_desc,
880 pango_context_get_language (context));
882 ascent = pango_font_metrics_get_ascent (metrics);
883 descent = pango_font_metrics_get_descent (metrics);
884 pango_font_metrics_unref (metrics);
886 arrow_size = PANGO_PIXELS (ascent + descent) - 2 * widget->style->ythickness;
888 arrow_extent = arrow_size * 0.8;
890 shadow_type = GTK_SHADOW_OUT;
891 if (state_type == GTK_STATE_PRELIGHT)
892 shadow_type = GTK_SHADOW_IN;
894 if (direction == GTK_TEXT_DIR_LTR)
896 arrow_x = x + width - horizontal_padding - arrow_extent;
897 arrow_type = GTK_ARROW_RIGHT;
901 arrow_x = x + horizontal_padding;
902 arrow_type = GTK_ARROW_LEFT;
905 arrow_y = y + (height - arrow_extent) / 2;
907 gtk_paint_arrow (widget->style, widget->window,
908 state_type, shadow_type,
909 area, widget, "menuitem",
912 arrow_extent, arrow_extent);
914 else if (!GTK_BIN (menu_item)->child)
916 gboolean wide_separators;
917 gint separator_height;
918 guint horizontal_padding;
920 gtk_widget_style_get (widget,
921 "wide-separators", &wide_separators,
922 "separator-height", &separator_height,
923 "horizontal-padding", &horizontal_padding,
927 gtk_paint_box (widget->style, widget->window,
928 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
929 area, widget, "hseparator",
930 widget->allocation.x + horizontal_padding + widget->style->xthickness,
931 widget->allocation.y + (widget->allocation.height -
933 widget->style->ythickness) / 2,
934 widget->allocation.width -
935 2 * (horizontal_padding + widget->style->xthickness),
938 gtk_paint_hline (widget->style, widget->window,
939 GTK_STATE_NORMAL, area, widget, "menuitem",
940 widget->allocation.x + horizontal_padding + widget->style->xthickness,
941 widget->allocation.x + widget->allocation.width - horizontal_padding - widget->style->xthickness - 1,
942 widget->allocation.y + (widget->allocation.height -
943 widget->style->ythickness) / 2);
949 gtk_menu_item_expose (GtkWidget *widget,
950 GdkEventExpose *event)
952 g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
953 g_return_val_if_fail (event != NULL, FALSE);
955 if (GTK_WIDGET_DRAWABLE (widget))
957 gtk_menu_item_paint (widget, &event->area);
959 (* GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->expose_event) (widget, event);
966 gtk_real_menu_item_select (GtkItem *item)
968 GtkMenuItem *menu_item;
969 gboolean touchscreen_mode;
971 g_return_if_fail (GTK_IS_MENU_ITEM (item));
973 menu_item = GTK_MENU_ITEM (item);
975 g_object_get (gtk_widget_get_settings (GTK_WIDGET (item)),
976 "gtk-touchscreen-mode", &touchscreen_mode,
979 if (!touchscreen_mode &&
980 menu_item->submenu &&
981 (!GTK_WIDGET_MAPPED (menu_item->submenu) ||
982 GTK_MENU (menu_item->submenu)->tearoff_active))
984 _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
987 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
988 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
992 gtk_real_menu_item_deselect (GtkItem *item)
994 GtkMenuItem *menu_item;
996 g_return_if_fail (GTK_IS_MENU_ITEM (item));
998 menu_item = GTK_MENU_ITEM (item);
1000 if (menu_item->submenu)
1001 _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
1003 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
1004 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1008 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
1009 gboolean group_cycling)
1011 if (group_cycling &&
1013 GTK_IS_MENU_SHELL (widget->parent) &&
1014 GTK_MENU_SHELL (widget->parent)->active)
1016 gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent),
1020 g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
1026 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
1030 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1032 widget = GTK_WIDGET (menu_item);
1034 if (widget->parent &&
1035 GTK_IS_MENU_SHELL (widget->parent))
1037 if (menu_item->submenu == NULL)
1038 gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget->parent),
1042 GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget->parent);
1044 _gtk_menu_shell_activate (menu_shell);
1046 gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget);
1047 _gtk_menu_item_popup_submenu (widget, FALSE);
1049 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
1055 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1058 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1064 gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1067 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1069 menu_item->toggle_size = allocation;
1073 gtk_menu_item_real_popup_submenu (GtkWidget *widget,
1074 gboolean remember_exact_time)
1076 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1078 if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
1080 gboolean take_focus;
1082 take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent));
1083 gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),
1086 if (remember_exact_time)
1088 GTimeVal *popup_time = g_new0 (GTimeVal, 1);
1090 g_get_current_time (popup_time);
1092 g_object_set_data_full (G_OBJECT (menu_item->submenu),
1093 "gtk-menu-exact-popup-time", popup_time,
1094 (GDestroyNotify) g_free);
1098 g_object_set_data (G_OBJECT (menu_item->submenu),
1099 "gtk-menu-exact-popup-time", NULL);
1102 gtk_menu_popup (GTK_MENU (menu_item->submenu),
1105 gtk_menu_item_position_menu,
1107 GTK_MENU_SHELL (widget->parent)->button,
1111 /* Enable themeing of the parent menu item depending on whether
1112 * its submenu is shown or not.
1114 gtk_widget_queue_draw (widget);
1118 gtk_menu_item_popup_timeout (gpointer data)
1120 GtkMenuItem *menu_item;
1123 menu_item = GTK_MENU_ITEM (data);
1125 parent = GTK_WIDGET (menu_item)->parent;
1127 if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active) ||
1128 (GTK_IS_MENU (parent) && GTK_MENU (parent)->torn_off))
1130 gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1131 if (menu_item->timer_from_keypress && menu_item->submenu)
1132 GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
1135 menu_item->timer = 0;
1141 get_popup_delay (GtkWidget *widget)
1143 if (GTK_IS_MENU_SHELL (widget->parent))
1145 return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (widget->parent));
1151 g_object_get (gtk_widget_get_settings (widget),
1152 "gtk-menu-popup-delay", &popup_delay,
1160 _gtk_menu_item_popup_submenu (GtkWidget *widget,
1161 gboolean with_delay)
1163 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1165 if (menu_item->timer)
1167 g_source_remove (menu_item->timer);
1168 menu_item->timer = 0;
1174 gint popup_delay = get_popup_delay (widget);
1176 if (popup_delay > 0)
1178 GdkEvent *event = gtk_get_current_event ();
1180 menu_item->timer = gdk_threads_add_timeout (popup_delay,
1181 gtk_menu_item_popup_timeout,
1185 event->type != GDK_BUTTON_PRESS &&
1186 event->type != GDK_ENTER_NOTIFY)
1187 menu_item->timer_from_keypress = TRUE;
1189 menu_item->timer_from_keypress = FALSE;
1192 gdk_event_free (event);
1198 gtk_menu_item_real_popup_submenu (widget, FALSE);
1202 _gtk_menu_item_popdown_submenu (GtkWidget *widget)
1204 GtkMenuItem *menu_item;
1206 menu_item = GTK_MENU_ITEM (widget);
1208 if (menu_item->submenu)
1210 g_object_set_data (G_OBJECT (menu_item->submenu),
1211 "gtk-menu-exact-popup-time", NULL);
1213 if (menu_item->timer)
1215 g_source_remove (menu_item->timer);
1216 menu_item->timer = 0;
1219 gtk_menu_popdown (GTK_MENU (menu_item->submenu));
1221 gtk_widget_queue_draw (widget);
1226 get_offsets (GtkMenu *menu,
1227 gint *horizontal_offset,
1228 gint *vertical_offset)
1230 gint vertical_padding;
1231 gint horizontal_padding;
1233 gtk_widget_style_get (GTK_WIDGET (menu),
1234 "horizontal-offset", horizontal_offset,
1235 "vertical-offset", vertical_offset,
1236 "horizontal-padding", &horizontal_padding,
1237 "vertical-padding", &vertical_padding,
1240 *vertical_offset -= GTK_WIDGET (menu)->style->ythickness;
1241 *vertical_offset -= vertical_padding;
1242 *horizontal_offset += horizontal_padding;
1246 gtk_menu_item_position_menu (GtkMenu *menu,
1252 GtkMenuItem *menu_item;
1254 GtkMenuItem *parent_menu_item;
1256 gint twidth, theight;
1258 GtkTextDirection direction;
1259 GdkRectangle monitor;
1261 gint horizontal_offset;
1262 gint vertical_offset;
1263 gint parent_xthickness;
1264 gint available_left, available_right;
1266 g_return_if_fail (menu != NULL);
1267 g_return_if_fail (x != NULL);
1268 g_return_if_fail (y != NULL);
1270 menu_item = GTK_MENU_ITEM (user_data);
1271 widget = GTK_WIDGET (user_data);
1276 direction = gtk_widget_get_direction (widget);
1278 twidth = GTK_WIDGET (menu)->requisition.width;
1279 theight = GTK_WIDGET (menu)->requisition.height;
1281 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
1282 monitor_num = gdk_screen_get_monitor_at_window (screen, menu_item->event_window);
1283 if (monitor_num < 0)
1285 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1287 if (!gdk_window_get_origin (widget->window, &tx, &ty))
1289 g_warning ("Menu not on screen");
1293 tx += widget->allocation.x;
1294 ty += widget->allocation.y;
1296 get_offsets (menu, &horizontal_offset, &vertical_offset);
1298 available_left = tx - monitor.x;
1299 available_right = monitor.x + monitor.width - (tx + widget->allocation.width);
1301 if (GTK_IS_MENU_BAR (widget->parent))
1303 menu_item->from_menubar = TRUE;
1305 else if (GTK_IS_MENU (widget->parent))
1307 if (GTK_MENU (widget->parent)->parent_menu_item)
1308 menu_item->from_menubar = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item)->from_menubar;
1310 menu_item->from_menubar = FALSE;
1314 menu_item->from_menubar = FALSE;
1317 switch (menu_item->submenu_placement)
1319 case GTK_TOP_BOTTOM:
1320 if (direction == GTK_TEXT_DIR_LTR)
1321 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1324 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1325 tx += widget->allocation.width - twidth;
1327 if ((ty + widget->allocation.height + theight) <= monitor.y + monitor.height)
1328 ty += widget->allocation.height;
1329 else if ((ty - theight) >= monitor.y)
1331 else if (monitor.y + monitor.height - (ty + widget->allocation.height) > ty)
1332 ty += widget->allocation.height;
1337 case GTK_LEFT_RIGHT:
1338 if (GTK_IS_MENU (widget->parent))
1339 parent_menu_item = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item);
1341 parent_menu_item = NULL;
1343 parent_xthickness = widget->parent->style->xthickness;
1345 if (parent_menu_item && !GTK_MENU (widget->parent)->torn_off)
1347 menu_item->submenu_direction = parent_menu_item->submenu_direction;
1351 if (direction == GTK_TEXT_DIR_LTR)
1352 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1354 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1357 switch (menu_item->submenu_direction)
1359 case GTK_DIRECTION_LEFT:
1360 if (tx - twidth - parent_xthickness - horizontal_offset >= monitor.x ||
1361 available_left >= available_right)
1362 tx -= twidth + parent_xthickness + horizontal_offset;
1365 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1366 tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1370 case GTK_DIRECTION_RIGHT:
1371 if (tx + widget->allocation.width + parent_xthickness + horizontal_offset + twidth <= monitor.x + monitor.width ||
1372 available_right >= available_left)
1373 tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1376 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1377 tx -= twidth + parent_xthickness + horizontal_offset;
1382 ty += vertical_offset;
1384 /* If the height of the menu doesn't fit we move it upward. */
1385 ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
1389 /* If we have negative, tx, here it is because we can't get
1390 * the menu all the way on screen. Favor the left portion.
1392 *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
1395 gtk_menu_set_monitor (menu, monitor_num);
1397 if (!GTK_WIDGET_VISIBLE (menu->toplevel))
1399 gtk_window_set_type_hint (GTK_WINDOW (menu->toplevel), menu_item->from_menubar?
1400 GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
1405 * gtk_menu_item_set_right_justified:
1406 * @menu_item: a #GtkMenuItem.
1407 * @right_justified: if %TRUE the menu item will appear at the
1408 * far right if added to a menu bar.
1410 * Sets whether the menu item appears justified at the right
1411 * side of a menu bar. This was traditionally done for "Help" menu
1412 * items, but is now considered a bad idea. (If the widget
1413 * layout is reversed for a right-to-left language like Hebrew
1414 * or Arabic, right-justified-menu-items appear at the left.)
1417 gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
1418 gboolean right_justified)
1420 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1422 right_justified = right_justified != FALSE;
1424 if (right_justified != menu_item->right_justify)
1426 menu_item->right_justify = right_justified;
1427 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1432 * gtk_menu_item_get_right_justified:
1433 * @menu_item: a #GtkMenuItem
1435 * Gets whether the menu item appears justified at the right
1436 * side of the menu bar.
1438 * Return value: %TRUE if the menu item will appear at the
1439 * far right if added to a menu bar.
1442 gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
1444 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
1446 return menu_item->right_justify;
1451 gtk_menu_item_show_all (GtkWidget *widget)
1453 GtkMenuItem *menu_item;
1455 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1457 menu_item = GTK_MENU_ITEM (widget);
1459 /* show children including submenu */
1460 if (menu_item->submenu)
1461 gtk_widget_show_all (menu_item->submenu);
1462 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1464 gtk_widget_show (widget);
1468 gtk_menu_item_hide_all (GtkWidget *widget)
1470 GtkMenuItem *menu_item;
1472 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1474 gtk_widget_hide (widget);
1476 menu_item = GTK_MENU_ITEM (widget);
1478 /* hide children including submenu */
1479 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);
1480 if (menu_item->submenu)
1481 gtk_widget_hide_all (menu_item->submenu);
1485 gtk_menu_item_can_activate_accel (GtkWidget *widget,
1488 /* Chain to the parent GtkMenu for further checks */
1489 return (GTK_WIDGET_IS_SENSITIVE (widget) && GTK_WIDGET_VISIBLE (widget) &&
1490 widget->parent && gtk_widget_can_activate_accel (widget->parent, signal_id));
1494 gtk_menu_item_accel_name_foreach (GtkWidget *widget,
1497 const gchar **path_p = data;
1501 if (GTK_IS_LABEL (widget))
1503 *path_p = gtk_label_get_text (GTK_LABEL (widget));
1504 if (*path_p && (*path_p)[0] == 0)
1507 else if (GTK_IS_CONTAINER (widget))
1508 gtk_container_foreach (GTK_CONTAINER (widget),
1509 gtk_menu_item_accel_name_foreach,
1515 gtk_menu_item_parent_set (GtkWidget *widget,
1516 GtkWidget *previous_parent)
1518 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1519 GtkMenu *menu = GTK_IS_MENU (widget->parent) ? GTK_MENU (widget->parent) : NULL;
1522 _gtk_menu_item_refresh_accel_path (menu_item,
1527 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set)
1528 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent);
1532 _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item,
1533 const gchar *prefix,
1534 GtkAccelGroup *accel_group,
1535 gboolean group_changed)
1540 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1541 g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
1543 widget = GTK_WIDGET (menu_item);
1547 gtk_widget_set_accel_path (widget, NULL, NULL);
1551 path = _gtk_widget_get_accel_path (widget, NULL);
1552 if (!path) /* no active accel_path yet */
1554 path = menu_item->accel_path;
1555 if (!path && prefix)
1557 gchar *postfix = NULL;
1559 /* try to construct one from label text */
1560 gtk_container_foreach (GTK_CONTAINER (menu_item),
1561 gtk_menu_item_accel_name_foreach,
1563 menu_item->accel_path = postfix ? g_strconcat (prefix, "/", postfix, NULL) : NULL;
1564 path = menu_item->accel_path;
1567 gtk_widget_set_accel_path (widget, path, accel_group);
1569 else if (group_changed) /* reinstall accelerators */
1570 gtk_widget_set_accel_path (widget, path, accel_group);
1574 * gtk_menu_item_set_accel_path
1575 * @menu_item: a valid #GtkMenuItem
1576 * @accel_path: accelerator path, corresponding to this menu item's
1577 * functionality, or %NULL to unset the current path.
1579 * Set the accelerator path on @menu_item, through which runtime changes of the
1580 * menu item's accelerator caused by the user can be identified and saved to
1581 * persistant storage (see gtk_accel_map_save() on this).
1582 * To setup a default accelerator for this menu item, call
1583 * gtk_accel_map_add_entry() with the same @accel_path.
1584 * See also gtk_accel_map_add_entry() on the specifics of accelerator paths,
1585 * and gtk_menu_set_accel_path() for a more convenient variant of this function.
1587 * This function is basically a convenience wrapper that handles calling
1588 * gtk_widget_set_accel_path() with the appropriate accelerator group for
1591 * Note that you do need to set an accelerator on the parent menu with
1592 * gtk_menu_set_accel_group() for this to work.
1595 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
1596 const gchar *accel_path)
1600 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1601 g_return_if_fail (accel_path == NULL ||
1602 (accel_path[0] == '<' && strchr (accel_path, '/')));
1604 widget = GTK_WIDGET (menu_item);
1606 /* store new path */
1607 g_free (menu_item->accel_path);
1608 menu_item->accel_path = g_strdup (accel_path);
1610 /* forget accelerators associated with old path */
1611 gtk_widget_set_accel_path (widget, NULL, NULL);
1613 /* install accelerators associated with new path */
1614 if (widget->parent && GTK_IS_MENU (widget->parent))
1616 GtkMenu *menu = GTK_MENU (widget->parent);
1618 if (menu->accel_group)
1619 _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
1627 gtk_menu_item_forall (GtkContainer *container,
1628 gboolean include_internals,
1629 GtkCallback callback,
1630 gpointer callback_data)
1634 g_return_if_fail (GTK_IS_MENU_ITEM (container));
1635 g_return_if_fail (callback != NULL);
1637 bin = GTK_BIN (container);
1640 callback (bin->child, callback_data);
1644 _gtk_menu_item_is_selectable (GtkWidget *menu_item)
1646 if ((!GTK_BIN (menu_item)->child &&
1647 G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
1648 GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
1649 !GTK_WIDGET_IS_SENSITIVE (menu_item) ||
1650 !GTK_WIDGET_VISIBLE (menu_item))
1656 #define __GTK_MENU_ITEM_C__
1657 #include "gtkaliasdef.c"