1 /* GTK - The GTK+ 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)
61 static void gtk_menu_item_set_property (GObject *object,
65 static void gtk_menu_item_get_property (GObject *object,
69 static void gtk_menu_item_destroy (GtkObject *object);
70 static void gtk_menu_item_size_request (GtkWidget *widget,
71 GtkRequisition *requisition);
72 static void gtk_menu_item_size_allocate (GtkWidget *widget,
73 GtkAllocation *allocation);
74 static void gtk_menu_item_realize (GtkWidget *widget);
75 static void gtk_menu_item_unrealize (GtkWidget *widget);
76 static void gtk_menu_item_map (GtkWidget *widget);
77 static void gtk_menu_item_unmap (GtkWidget *widget);
78 static void gtk_menu_item_paint (GtkWidget *widget,
80 static gint gtk_menu_item_expose (GtkWidget *widget,
81 GdkEventExpose *event);
82 static void gtk_menu_item_parent_set (GtkWidget *widget,
83 GtkWidget *previous_parent);
86 static void gtk_real_menu_item_select (GtkItem *item);
87 static void gtk_real_menu_item_deselect (GtkItem *item);
88 static void gtk_real_menu_item_activate_item (GtkMenuItem *item);
89 static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
91 static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
93 static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget,
94 gboolean group_cycling);
96 static gint gtk_menu_item_popup_timeout (gpointer data);
97 static void gtk_menu_item_position_menu (GtkMenu *menu,
102 static void gtk_menu_item_show_all (GtkWidget *widget);
103 static void gtk_menu_item_hide_all (GtkWidget *widget);
104 static void gtk_menu_item_forall (GtkContainer *container,
105 gboolean include_internals,
106 GtkCallback callback,
107 gpointer callback_data);
108 static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget,
112 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
114 G_DEFINE_TYPE (GtkMenuItem, gtk_menu_item, GTK_TYPE_ITEM)
117 gtk_menu_item_class_init (GtkMenuItemClass *klass)
119 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
120 GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
121 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
122 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
123 GtkItemClass *item_class = GTK_ITEM_CLASS (klass);
125 gobject_class->set_property = gtk_menu_item_set_property;
126 gobject_class->get_property = gtk_menu_item_get_property;
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:right-justified:
197 * Sets whether the menu item appears justified at the right side of a menu bar.
201 g_object_class_install_property (gobject_class,
202 PROP_RIGHT_JUSTIFIED,
203 g_param_spec_boolean ("right-justified",
204 P_("Right Justified"),
205 P_("Sets whether the menu item appears justified at the right side of a menu bar"),
207 GTK_PARAM_READWRITE));
210 * GtkMenuItem:submenu:
212 * The submenu attached to the menu item, or NULL if it has none.
216 g_object_class_install_property (gobject_class,
218 g_param_spec_object ("submenu",
220 P_("The submenu attached to the menu item, or NULL if it has none"),
222 GTK_PARAM_READWRITE));
225 * GtkMenuItem:accel-path:
227 * Sets the accelerator path of the menu item, through which runtime
228 * changes of the menu item's accelerator caused by the user can be
229 * identified and saved to persistant storage.
233 g_object_class_install_property (gobject_class,
235 g_param_spec_string ("accel-path",
237 P_("Sets the accelerator path of the menu item"),
239 GTK_PARAM_READWRITE));
241 gtk_widget_class_install_style_property_parser (widget_class,
242 g_param_spec_enum ("selected-shadow-type",
243 "Selected Shadow Type",
244 "Shadow type when item is selected",
245 GTK_TYPE_SHADOW_TYPE,
248 gtk_rc_property_parse_enum);
250 gtk_widget_class_install_style_property (widget_class,
251 g_param_spec_int ("horizontal-padding",
252 "Horizontal Padding",
253 "Padding to left and right of the menu item",
257 GTK_PARAM_READABLE));
259 gtk_widget_class_install_style_property (widget_class,
260 g_param_spec_int ("toggle-spacing",
262 "Space between icon and label",
266 GTK_PARAM_READABLE));
268 gtk_widget_class_install_style_property (widget_class,
269 g_param_spec_int ("arrow-spacing",
271 "Space between label and arrow",
275 GTK_PARAM_READABLE));
277 gtk_widget_class_install_style_property (widget_class,
278 g_param_spec_float ("arrow-scaling",
280 P_("Amount of space used up by arrow, relative to the menu item's font size"),
282 GTK_PARAM_READABLE));
286 gtk_menu_item_init (GtkMenuItem *menu_item)
288 GTK_WIDGET_SET_FLAGS (menu_item, GTK_NO_WINDOW);
290 menu_item->submenu = NULL;
291 menu_item->toggle_size = 0;
292 menu_item->accelerator_width = 0;
293 menu_item->show_submenu_indicator = FALSE;
294 if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
295 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
297 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
298 menu_item->submenu_placement = GTK_TOP_BOTTOM;
299 menu_item->right_justify = FALSE;
301 menu_item->timer = 0;
305 gtk_menu_item_new (void)
307 return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
311 gtk_menu_item_new_with_label (const gchar *label)
313 GtkWidget *menu_item;
314 GtkWidget *accel_label;
316 menu_item = gtk_menu_item_new ();
317 accel_label = gtk_accel_label_new (label);
318 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
320 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
321 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
322 gtk_widget_show (accel_label);
329 * gtk_menu_item_new_with_mnemonic:
330 * @label: The text of the button, with an underscore in front of the
332 * @returns: a new #GtkMenuItem
334 * Creates a new #GtkMenuItem containing a label. The label
335 * will be created using gtk_label_new_with_mnemonic(), so underscores
336 * in @label indicate the mnemonic for the menu item.
339 gtk_menu_item_new_with_mnemonic (const gchar *label)
341 GtkWidget *menu_item;
342 GtkWidget *accel_label;
344 menu_item = gtk_menu_item_new ();
345 accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
346 gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
347 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
349 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
350 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
351 gtk_widget_show (accel_label);
357 gtk_menu_item_set_property (GObject *object,
362 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
366 case PROP_RIGHT_JUSTIFIED:
367 gtk_menu_item_set_right_justified (menu_item, g_value_get_boolean (value));
370 gtk_menu_item_set_submenu (menu_item, g_value_get_object (value));
372 case PROP_ACCEL_PATH:
373 gtk_menu_item_set_accel_path (menu_item, g_value_get_string (value));
377 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
383 gtk_menu_item_get_property (GObject *object,
388 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
392 case PROP_RIGHT_JUSTIFIED:
393 g_value_set_boolean (value, gtk_menu_item_get_right_justified (menu_item));
396 g_value_set_object (value, gtk_menu_item_get_submenu (menu_item));
398 case PROP_ACCEL_PATH:
399 g_value_set_string (value, gtk_menu_item_get_accel_path (menu_item));
403 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
409 gtk_menu_item_destroy (GtkObject *object)
411 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
413 if (menu_item->submenu)
414 gtk_widget_destroy (menu_item->submenu);
416 GTK_OBJECT_CLASS (gtk_menu_item_parent_class)->destroy (object);
420 gtk_menu_item_detacher (GtkWidget *widget,
423 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
425 g_return_if_fail (menu_item->submenu == (GtkWidget*) menu);
427 menu_item->submenu = NULL;
431 * gtk_menu_item_set_submenu:
432 * @menu_item: a #GtkMenuItem
433 * @submenu: the submenu, or %NULL
435 * Sets or replaces the menu item's submenu, or removes it when a %NULL
439 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
442 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
443 g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu));
445 if (menu_item->submenu != submenu)
447 if (menu_item->submenu)
448 gtk_menu_detach (GTK_MENU (menu_item->submenu));
452 menu_item->submenu = submenu;
453 gtk_menu_attach_to_widget (GTK_MENU (submenu),
454 GTK_WIDGET (menu_item),
455 gtk_menu_item_detacher);
458 if (GTK_WIDGET (menu_item)->parent)
459 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
461 g_object_notify (G_OBJECT (menu_item), "submenu");
466 * gtk_menu_item_get_submenu:
467 * @menu_item: a #GtkMenuItem
469 * Gets the submenu underneath this menu item, if any. See
470 * gtk_menu_item_set_submenu().
472 * Return value: submenu for this menu item, or %NULL if none.
475 gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
477 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
479 return menu_item->submenu;
483 * gtk_menu_item_remove_submenu:
484 * @menu_item: a #GtkMenuItem
486 * Removes the widget's submenu.
488 * Deprecated: 2.12: gtk_menu_item_remove_submenu() is deprecated and
489 * should not be used in newly written code. Use
490 * gtk_menu_item_set_submenu() instead.
493 gtk_menu_item_remove_submenu (GtkMenuItem *menu_item)
495 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
497 gtk_menu_item_set_submenu (menu_item, NULL);
500 void _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
501 GtkSubmenuPlacement placement);
504 _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
505 GtkSubmenuPlacement placement)
507 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
509 menu_item->submenu_placement = placement;
513 gtk_menu_item_select (GtkMenuItem *menu_item)
515 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
517 gtk_item_select (GTK_ITEM (menu_item));
519 /* Enable themeing of the parent menu item depending on whether
520 * something is selected in its submenu
522 if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
524 GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
526 if (menu->parent_menu_item)
527 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
532 gtk_menu_item_deselect (GtkMenuItem *menu_item)
534 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
536 gtk_item_deselect (GTK_ITEM (menu_item));
538 /* Enable themeing of the parent menu item depending on whether
539 * something is selected in its submenu
541 if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
543 GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
545 if (menu->parent_menu_item)
546 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
551 gtk_menu_item_activate (GtkMenuItem *menu_item)
553 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
555 g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
559 gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
562 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
564 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
568 gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
571 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
573 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
577 gtk_menu_item_accel_width_foreach (GtkWidget *widget,
582 if (GTK_IS_ACCEL_LABEL (widget))
586 w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
587 *width = MAX (*width, w);
589 else if (GTK_IS_CONTAINER (widget))
590 gtk_container_foreach (GTK_CONTAINER (widget),
591 gtk_menu_item_accel_width_foreach,
596 get_minimum_width (GtkWidget *widget)
598 PangoContext *context;
599 PangoFontMetrics *metrics;
602 context = gtk_widget_get_pango_context (widget);
603 metrics = pango_context_get_metrics (context,
604 widget->style->font_desc,
605 pango_context_get_language (context));
607 height = pango_font_metrics_get_ascent (metrics) +
608 pango_font_metrics_get_descent (metrics);
610 pango_font_metrics_unref (metrics);
612 return PANGO_PIXELS (7 * height);
616 gtk_menu_item_size_request (GtkWidget *widget,
617 GtkRequisition *requisition)
619 GtkMenuItem *menu_item;
622 guint horizontal_padding;
623 GtkPackDirection pack_dir;
624 GtkPackDirection child_pack_dir;
626 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
627 g_return_if_fail (requisition != NULL);
629 gtk_widget_style_get (widget,
630 "horizontal-padding", &horizontal_padding,
633 bin = GTK_BIN (widget);
634 menu_item = GTK_MENU_ITEM (widget);
636 if (GTK_IS_MENU_BAR (widget->parent))
638 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
639 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
643 pack_dir = GTK_PACK_DIRECTION_LTR;
644 child_pack_dir = GTK_PACK_DIRECTION_LTR;
647 requisition->width = (GTK_CONTAINER (widget)->border_width +
648 widget->style->xthickness) * 2;
649 requisition->height = (GTK_CONTAINER (widget)->border_width +
650 widget->style->ythickness) * 2;
652 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
653 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
654 requisition->width += 2 * horizontal_padding;
655 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
656 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
657 requisition->height += 2 * horizontal_padding;
659 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
661 GtkRequisition child_requisition;
663 gtk_widget_size_request (bin->child, &child_requisition);
665 requisition->width += child_requisition.width;
666 requisition->height += child_requisition.height;
668 if (menu_item->submenu && menu_item->show_submenu_indicator)
672 gtk_widget_style_get (widget,
673 "arrow-spacing", &arrow_spacing,
676 requisition->width += child_requisition.height;
677 requisition->width += arrow_spacing;
679 requisition->width = MAX (requisition->width, get_minimum_width (widget));
682 else /* separator item */
684 gboolean wide_separators;
685 gint separator_height;
687 gtk_widget_style_get (widget,
688 "wide-separators", &wide_separators,
689 "separator-height", &separator_height,
693 requisition->height += separator_height + widget->style->ythickness;
695 requisition->height += widget->style->ythickness * 2;
699 gtk_container_foreach (GTK_CONTAINER (menu_item),
700 gtk_menu_item_accel_width_foreach,
702 menu_item->accelerator_width = accel_width;
706 gtk_menu_item_size_allocate (GtkWidget *widget,
707 GtkAllocation *allocation)
709 GtkMenuItem *menu_item;
711 GtkAllocation child_allocation;
712 GtkTextDirection direction;
713 GtkPackDirection pack_dir;
714 GtkPackDirection child_pack_dir;
716 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
717 g_return_if_fail (allocation != NULL);
719 menu_item = GTK_MENU_ITEM (widget);
720 bin = GTK_BIN (widget);
722 direction = gtk_widget_get_direction (widget);
724 if (GTK_IS_MENU_BAR (widget->parent))
726 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
727 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
731 pack_dir = GTK_PACK_DIRECTION_LTR;
732 child_pack_dir = GTK_PACK_DIRECTION_LTR;
735 widget->allocation = *allocation;
739 GtkRequisition child_requisition;
740 guint horizontal_padding;
742 gtk_widget_style_get (widget,
743 "horizontal-padding", &horizontal_padding,
746 child_allocation.x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
747 child_allocation.y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness;
749 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
750 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
751 child_allocation.x += horizontal_padding;
752 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
753 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
754 child_allocation.y += horizontal_padding;
756 child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
757 child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
759 if (child_pack_dir == GTK_PACK_DIRECTION_LTR ||
760 child_pack_dir == GTK_PACK_DIRECTION_RTL)
762 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL))
763 child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
764 child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size;
768 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT))
769 child_allocation.y += GTK_MENU_ITEM (widget)->toggle_size;
770 child_allocation.height -= GTK_MENU_ITEM (widget)->toggle_size;
773 child_allocation.x += widget->allocation.x;
774 child_allocation.y += widget->allocation.y;
776 gtk_widget_get_child_requisition (bin->child, &child_requisition);
777 if (menu_item->submenu && menu_item->show_submenu_indicator)
779 if (direction == GTK_TEXT_DIR_RTL)
780 child_allocation.x += child_requisition.height;
781 child_allocation.width -= child_requisition.height;
784 if (child_allocation.width < 1)
785 child_allocation.width = 1;
787 gtk_widget_size_allocate (bin->child, &child_allocation);
790 if (GTK_WIDGET_REALIZED (widget))
791 gdk_window_move_resize (menu_item->event_window,
792 allocation->x, allocation->y,
793 allocation->width, allocation->height);
795 if (menu_item->submenu)
796 gtk_menu_reposition (GTK_MENU (menu_item->submenu));
800 gtk_menu_item_realize (GtkWidget *widget)
802 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
803 GdkWindowAttr attributes;
804 gint attributes_mask;
806 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
808 widget->window = gtk_widget_get_parent_window (widget);
809 g_object_ref (widget->window);
811 attributes.x = widget->allocation.x;
812 attributes.y = widget->allocation.y;
813 attributes.width = widget->allocation.width;
814 attributes.height = widget->allocation.height;
815 attributes.window_type = GDK_WINDOW_CHILD;
816 attributes.wclass = GDK_INPUT_ONLY;
817 attributes.event_mask = (gtk_widget_get_events (widget) |
818 GDK_BUTTON_PRESS_MASK |
819 GDK_BUTTON_RELEASE_MASK |
820 GDK_ENTER_NOTIFY_MASK |
821 GDK_LEAVE_NOTIFY_MASK |
822 GDK_POINTER_MOTION_MASK);
824 attributes_mask = GDK_WA_X | GDK_WA_Y;
825 menu_item->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
826 gdk_window_set_user_data (menu_item->event_window, widget);
828 widget->style = gtk_style_attach (widget->style, widget->window);
832 gtk_menu_item_unrealize (GtkWidget *widget)
834 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
836 gdk_window_set_user_data (menu_item->event_window, NULL);
837 gdk_window_destroy (menu_item->event_window);
838 menu_item->event_window = NULL;
840 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize)
841 (* GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize) (widget);
845 gtk_menu_item_map (GtkWidget *widget)
847 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
849 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget);
851 gdk_window_show (menu_item->event_window);
855 gtk_menu_item_unmap (GtkWidget *widget)
857 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
859 gdk_window_hide (menu_item->event_window);
861 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget);
865 gtk_menu_item_paint (GtkWidget *widget,
868 GtkMenuItem *menu_item;
869 GtkStateType state_type;
870 GtkShadowType shadow_type, selected_shadow_type;
873 gint border_width = GTK_CONTAINER (widget)->border_width;
875 if (GTK_WIDGET_DRAWABLE (widget))
877 menu_item = GTK_MENU_ITEM (widget);
879 state_type = widget->state;
881 x = widget->allocation.x + border_width;
882 y = widget->allocation.y + border_width;
883 width = widget->allocation.width - border_width * 2;
884 height = widget->allocation.height - border_width * 2;
886 if ((state_type == GTK_STATE_PRELIGHT) &&
887 (GTK_BIN (menu_item)->child))
889 gtk_widget_style_get (widget,
890 "selected-shadow-type", &selected_shadow_type,
892 gtk_paint_box (widget->style,
895 selected_shadow_type,
896 area, widget, "menuitem",
897 x, y, width, height);
900 if (menu_item->submenu && menu_item->show_submenu_indicator)
902 gint arrow_x, arrow_y;
905 guint horizontal_padding;
906 gfloat arrow_scaling;
907 GtkTextDirection direction;
908 GtkArrowType arrow_type;
909 PangoContext *context;
910 PangoFontMetrics *metrics;
912 direction = gtk_widget_get_direction (widget);
914 gtk_widget_style_get (widget,
915 "horizontal-padding", &horizontal_padding,
916 "arrow-scaling", &arrow_scaling,
919 context = gtk_widget_get_pango_context (GTK_BIN (menu_item)->child);
920 metrics = pango_context_get_metrics (context,
921 GTK_WIDGET (GTK_BIN (menu_item)->child)->style->font_desc,
922 pango_context_get_language (context));
924 arrow_size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
925 pango_font_metrics_get_descent (metrics)));
927 pango_font_metrics_unref (metrics);
929 arrow_extent = arrow_size * arrow_scaling;
931 shadow_type = GTK_SHADOW_OUT;
932 if (state_type == GTK_STATE_PRELIGHT)
933 shadow_type = GTK_SHADOW_IN;
935 if (direction == GTK_TEXT_DIR_LTR)
937 arrow_x = x + width - horizontal_padding - arrow_extent;
938 arrow_type = GTK_ARROW_RIGHT;
942 arrow_x = x + horizontal_padding;
943 arrow_type = GTK_ARROW_LEFT;
946 arrow_y = y + (height - arrow_extent) / 2;
948 gtk_paint_arrow (widget->style, widget->window,
949 state_type, shadow_type,
950 area, widget, "menuitem",
953 arrow_extent, arrow_extent);
955 else if (!GTK_BIN (menu_item)->child)
957 gboolean wide_separators;
958 gint separator_height;
959 guint horizontal_padding;
961 gtk_widget_style_get (widget,
962 "wide-separators", &wide_separators,
963 "separator-height", &separator_height,
964 "horizontal-padding", &horizontal_padding,
968 gtk_paint_box (widget->style, widget->window,
969 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
970 area, widget, "hseparator",
971 widget->allocation.x + horizontal_padding + widget->style->xthickness,
972 widget->allocation.y + (widget->allocation.height -
974 widget->style->ythickness) / 2,
975 widget->allocation.width -
976 2 * (horizontal_padding + widget->style->xthickness),
979 gtk_paint_hline (widget->style, widget->window,
980 GTK_STATE_NORMAL, area, widget, "menuitem",
981 widget->allocation.x + horizontal_padding + widget->style->xthickness,
982 widget->allocation.x + widget->allocation.width - horizontal_padding - widget->style->xthickness - 1,
983 widget->allocation.y + (widget->allocation.height -
984 widget->style->ythickness) / 2);
990 gtk_menu_item_expose (GtkWidget *widget,
991 GdkEventExpose *event)
993 g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
994 g_return_val_if_fail (event != NULL, FALSE);
996 if (GTK_WIDGET_DRAWABLE (widget))
998 gtk_menu_item_paint (widget, &event->area);
1000 (* GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->expose_event) (widget, event);
1007 gtk_real_menu_item_select (GtkItem *item)
1009 GtkMenuItem *menu_item;
1010 gboolean touchscreen_mode;
1012 g_return_if_fail (GTK_IS_MENU_ITEM (item));
1014 menu_item = GTK_MENU_ITEM (item);
1016 g_object_get (gtk_widget_get_settings (GTK_WIDGET (item)),
1017 "gtk-touchscreen-mode", &touchscreen_mode,
1020 if (!touchscreen_mode &&
1021 menu_item->submenu &&
1022 (!GTK_WIDGET_MAPPED (menu_item->submenu) ||
1023 GTK_MENU (menu_item->submenu)->tearoff_active))
1025 _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1028 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
1029 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1033 gtk_real_menu_item_deselect (GtkItem *item)
1035 GtkMenuItem *menu_item;
1037 g_return_if_fail (GTK_IS_MENU_ITEM (item));
1039 menu_item = GTK_MENU_ITEM (item);
1041 if (menu_item->submenu)
1042 _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
1044 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
1045 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1049 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
1050 gboolean group_cycling)
1052 if (group_cycling &&
1054 GTK_IS_MENU_SHELL (widget->parent) &&
1055 GTK_MENU_SHELL (widget->parent)->active)
1057 gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent),
1061 g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
1067 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
1071 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1073 widget = GTK_WIDGET (menu_item);
1075 if (widget->parent &&
1076 GTK_IS_MENU_SHELL (widget->parent))
1078 if (menu_item->submenu == NULL)
1079 gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget->parent),
1083 GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget->parent);
1085 _gtk_menu_shell_activate (menu_shell);
1087 gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget);
1088 _gtk_menu_item_popup_submenu (widget, FALSE);
1090 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
1096 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1099 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1105 gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1108 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1110 menu_item->toggle_size = allocation;
1114 free_timeval (GTimeVal *val)
1116 g_slice_free (GTimeVal, val);
1120 gtk_menu_item_real_popup_submenu (GtkWidget *widget,
1121 gboolean remember_exact_time)
1123 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1125 if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
1127 gboolean take_focus;
1129 take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent));
1130 gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),
1133 if (remember_exact_time)
1135 GTimeVal *popup_time = g_slice_new0 (GTimeVal);
1137 g_get_current_time (popup_time);
1139 g_object_set_data_full (G_OBJECT (menu_item->submenu),
1140 "gtk-menu-exact-popup-time", popup_time,
1141 (GDestroyNotify) free_timeval);
1145 g_object_set_data (G_OBJECT (menu_item->submenu),
1146 "gtk-menu-exact-popup-time", NULL);
1149 gtk_menu_popup (GTK_MENU (menu_item->submenu),
1152 gtk_menu_item_position_menu,
1154 GTK_MENU_SHELL (widget->parent)->button,
1158 /* Enable themeing of the parent menu item depending on whether
1159 * its submenu is shown or not.
1161 gtk_widget_queue_draw (widget);
1165 gtk_menu_item_popup_timeout (gpointer data)
1167 GtkMenuItem *menu_item;
1170 menu_item = GTK_MENU_ITEM (data);
1172 parent = GTK_WIDGET (menu_item)->parent;
1174 if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active) ||
1175 (GTK_IS_MENU (parent) && GTK_MENU (parent)->torn_off))
1177 gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1178 if (menu_item->timer_from_keypress && menu_item->submenu)
1179 GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
1182 menu_item->timer = 0;
1188 get_popup_delay (GtkWidget *widget)
1190 if (GTK_IS_MENU_SHELL (widget->parent))
1192 return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (widget->parent));
1198 g_object_get (gtk_widget_get_settings (widget),
1199 "gtk-menu-popup-delay", &popup_delay,
1207 _gtk_menu_item_popup_submenu (GtkWidget *widget,
1208 gboolean with_delay)
1210 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1212 if (menu_item->timer)
1214 g_source_remove (menu_item->timer);
1215 menu_item->timer = 0;
1221 gint popup_delay = get_popup_delay (widget);
1223 if (popup_delay > 0)
1225 GdkEvent *event = gtk_get_current_event ();
1227 menu_item->timer = gdk_threads_add_timeout (popup_delay,
1228 gtk_menu_item_popup_timeout,
1232 event->type != GDK_BUTTON_PRESS &&
1233 event->type != GDK_ENTER_NOTIFY)
1234 menu_item->timer_from_keypress = TRUE;
1236 menu_item->timer_from_keypress = FALSE;
1239 gdk_event_free (event);
1245 gtk_menu_item_real_popup_submenu (widget, FALSE);
1249 _gtk_menu_item_popdown_submenu (GtkWidget *widget)
1251 GtkMenuItem *menu_item;
1253 menu_item = GTK_MENU_ITEM (widget);
1255 if (menu_item->submenu)
1257 g_object_set_data (G_OBJECT (menu_item->submenu),
1258 "gtk-menu-exact-popup-time", NULL);
1260 if (menu_item->timer)
1262 g_source_remove (menu_item->timer);
1263 menu_item->timer = 0;
1266 gtk_menu_popdown (GTK_MENU (menu_item->submenu));
1268 gtk_widget_queue_draw (widget);
1273 get_offsets (GtkMenu *menu,
1274 gint *horizontal_offset,
1275 gint *vertical_offset)
1277 gint vertical_padding;
1278 gint horizontal_padding;
1280 gtk_widget_style_get (GTK_WIDGET (menu),
1281 "horizontal-offset", horizontal_offset,
1282 "vertical-offset", vertical_offset,
1283 "horizontal-padding", &horizontal_padding,
1284 "vertical-padding", &vertical_padding,
1287 *vertical_offset -= GTK_WIDGET (menu)->style->ythickness;
1288 *vertical_offset -= vertical_padding;
1289 *horizontal_offset += horizontal_padding;
1293 gtk_menu_item_position_menu (GtkMenu *menu,
1299 GtkMenuItem *menu_item;
1301 GtkMenuItem *parent_menu_item;
1303 gint twidth, theight;
1305 GtkTextDirection direction;
1306 GdkRectangle monitor;
1308 gint horizontal_offset;
1309 gint vertical_offset;
1310 gint parent_xthickness;
1311 gint available_left, available_right;
1313 g_return_if_fail (menu != NULL);
1314 g_return_if_fail (x != NULL);
1315 g_return_if_fail (y != NULL);
1317 menu_item = GTK_MENU_ITEM (user_data);
1318 widget = GTK_WIDGET (user_data);
1323 direction = gtk_widget_get_direction (widget);
1325 twidth = GTK_WIDGET (menu)->requisition.width;
1326 theight = GTK_WIDGET (menu)->requisition.height;
1328 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
1329 monitor_num = gdk_screen_get_monitor_at_window (screen, menu_item->event_window);
1330 if (monitor_num < 0)
1332 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1334 if (!gdk_window_get_origin (widget->window, &tx, &ty))
1336 g_warning ("Menu not on screen");
1340 tx += widget->allocation.x;
1341 ty += widget->allocation.y;
1343 get_offsets (menu, &horizontal_offset, &vertical_offset);
1345 available_left = tx - monitor.x;
1346 available_right = monitor.x + monitor.width - (tx + widget->allocation.width);
1348 if (GTK_IS_MENU_BAR (widget->parent))
1350 menu_item->from_menubar = TRUE;
1352 else if (GTK_IS_MENU (widget->parent))
1354 if (GTK_MENU (widget->parent)->parent_menu_item)
1355 menu_item->from_menubar = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item)->from_menubar;
1357 menu_item->from_menubar = FALSE;
1361 menu_item->from_menubar = FALSE;
1364 switch (menu_item->submenu_placement)
1366 case GTK_TOP_BOTTOM:
1367 if (direction == GTK_TEXT_DIR_LTR)
1368 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1371 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1372 tx += widget->allocation.width - twidth;
1374 if ((ty + widget->allocation.height + theight) <= monitor.y + monitor.height)
1375 ty += widget->allocation.height;
1376 else if ((ty - theight) >= monitor.y)
1378 else if (monitor.y + monitor.height - (ty + widget->allocation.height) > ty)
1379 ty += widget->allocation.height;
1384 case GTK_LEFT_RIGHT:
1385 if (GTK_IS_MENU (widget->parent))
1386 parent_menu_item = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item);
1388 parent_menu_item = NULL;
1390 parent_xthickness = widget->parent->style->xthickness;
1392 if (parent_menu_item && !GTK_MENU (widget->parent)->torn_off)
1394 menu_item->submenu_direction = parent_menu_item->submenu_direction;
1398 if (direction == GTK_TEXT_DIR_LTR)
1399 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1401 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1404 switch (menu_item->submenu_direction)
1406 case GTK_DIRECTION_LEFT:
1407 if (tx - twidth - parent_xthickness - horizontal_offset >= monitor.x ||
1408 available_left >= available_right)
1409 tx -= twidth + parent_xthickness + horizontal_offset;
1412 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1413 tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1417 case GTK_DIRECTION_RIGHT:
1418 if (tx + widget->allocation.width + parent_xthickness + horizontal_offset + twidth <= monitor.x + monitor.width ||
1419 available_right >= available_left)
1420 tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1423 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1424 tx -= twidth + parent_xthickness + horizontal_offset;
1429 ty += vertical_offset;
1431 /* If the height of the menu doesn't fit we move it upward. */
1432 ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
1436 /* If we have negative, tx, here it is because we can't get
1437 * the menu all the way on screen. Favor the left portion.
1439 *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
1442 gtk_menu_set_monitor (menu, monitor_num);
1444 if (!GTK_WIDGET_VISIBLE (menu->toplevel))
1446 gtk_window_set_type_hint (GTK_WINDOW (menu->toplevel), menu_item->from_menubar?
1447 GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
1452 * gtk_menu_item_set_right_justified:
1453 * @menu_item: a #GtkMenuItem.
1454 * @right_justified: if %TRUE the menu item will appear at the
1455 * far right if added to a menu bar.
1457 * Sets whether the menu item appears justified at the right
1458 * side of a menu bar. This was traditionally done for "Help" menu
1459 * items, but is now considered a bad idea. (If the widget
1460 * layout is reversed for a right-to-left language like Hebrew
1461 * or Arabic, right-justified-menu-items appear at the left.)
1464 gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
1465 gboolean right_justified)
1467 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1469 right_justified = right_justified != FALSE;
1471 if (right_justified != menu_item->right_justify)
1473 menu_item->right_justify = right_justified;
1474 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1479 * gtk_menu_item_get_right_justified:
1480 * @menu_item: a #GtkMenuItem
1482 * Gets whether the menu item appears justified at the right
1483 * side of the menu bar.
1485 * Return value: %TRUE if the menu item will appear at the
1486 * far right if added to a menu bar.
1489 gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
1491 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
1493 return menu_item->right_justify;
1498 gtk_menu_item_show_all (GtkWidget *widget)
1500 GtkMenuItem *menu_item;
1502 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1504 menu_item = GTK_MENU_ITEM (widget);
1506 /* show children including submenu */
1507 if (menu_item->submenu)
1508 gtk_widget_show_all (menu_item->submenu);
1509 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1511 gtk_widget_show (widget);
1515 gtk_menu_item_hide_all (GtkWidget *widget)
1517 GtkMenuItem *menu_item;
1519 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1521 gtk_widget_hide (widget);
1523 menu_item = GTK_MENU_ITEM (widget);
1525 /* hide children including submenu */
1526 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);
1527 if (menu_item->submenu)
1528 gtk_widget_hide_all (menu_item->submenu);
1532 gtk_menu_item_can_activate_accel (GtkWidget *widget,
1535 /* Chain to the parent GtkMenu for further checks */
1536 return (GTK_WIDGET_IS_SENSITIVE (widget) && GTK_WIDGET_VISIBLE (widget) &&
1537 widget->parent && gtk_widget_can_activate_accel (widget->parent, signal_id));
1541 gtk_menu_item_accel_name_foreach (GtkWidget *widget,
1544 const gchar **path_p = data;
1548 if (GTK_IS_LABEL (widget))
1550 *path_p = gtk_label_get_text (GTK_LABEL (widget));
1551 if (*path_p && (*path_p)[0] == 0)
1554 else if (GTK_IS_CONTAINER (widget))
1555 gtk_container_foreach (GTK_CONTAINER (widget),
1556 gtk_menu_item_accel_name_foreach,
1562 gtk_menu_item_parent_set (GtkWidget *widget,
1563 GtkWidget *previous_parent)
1565 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1566 GtkMenu *menu = GTK_IS_MENU (widget->parent) ? GTK_MENU (widget->parent) : NULL;
1569 _gtk_menu_item_refresh_accel_path (menu_item,
1574 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set)
1575 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent);
1579 _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item,
1580 const gchar *prefix,
1581 GtkAccelGroup *accel_group,
1582 gboolean group_changed)
1587 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1588 g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
1590 widget = GTK_WIDGET (menu_item);
1594 gtk_widget_set_accel_path (widget, NULL, NULL);
1598 path = _gtk_widget_get_accel_path (widget, NULL);
1599 if (!path) /* no active accel_path yet */
1601 path = menu_item->accel_path;
1602 if (!path && prefix)
1604 const gchar *postfix = NULL;
1607 /* try to construct one from label text */
1608 gtk_container_foreach (GTK_CONTAINER (menu_item),
1609 gtk_menu_item_accel_name_foreach,
1613 new_path = g_strconcat (prefix, "/", postfix, NULL);
1614 path = menu_item->accel_path = (char*)g_intern_string (new_path);
1619 gtk_widget_set_accel_path (widget, path, accel_group);
1621 else if (group_changed) /* reinstall accelerators */
1622 gtk_widget_set_accel_path (widget, path, accel_group);
1626 * gtk_menu_item_set_accel_path
1627 * @menu_item: a valid #GtkMenuItem
1628 * @accel_path: accelerator path, corresponding to this menu item's
1629 * functionality, or %NULL to unset the current path.
1631 * Set the accelerator path on @menu_item, through which runtime changes of the
1632 * menu item's accelerator caused by the user can be identified and saved to
1633 * persistant storage (see gtk_accel_map_save() on this).
1634 * To setup a default accelerator for this menu item, call
1635 * gtk_accel_map_add_entry() with the same @accel_path.
1636 * See also gtk_accel_map_add_entry() on the specifics of accelerator paths,
1637 * and gtk_menu_set_accel_path() for a more convenient variant of this function.
1639 * This function is basically a convenience wrapper that handles calling
1640 * gtk_widget_set_accel_path() with the appropriate accelerator group for
1643 * Note that you do need to set an accelerator on the parent menu with
1644 * gtk_menu_set_accel_group() for this to work.
1646 * Note that @accel_path string will be stored in a #GQuark. Therefore, if you
1647 * pass a static string, you can save some memory by interning it first with
1648 * g_intern_static_string().
1651 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
1652 const gchar *accel_path)
1656 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1657 g_return_if_fail (accel_path == NULL ||
1658 (accel_path[0] == '<' && strchr (accel_path, '/')));
1660 widget = GTK_WIDGET (menu_item);
1662 /* store new path */
1663 menu_item->accel_path = (char*)g_intern_string (accel_path);
1665 /* forget accelerators associated with old path */
1666 gtk_widget_set_accel_path (widget, NULL, NULL);
1668 /* install accelerators associated with new path */
1669 if (GTK_IS_MENU (widget->parent))
1671 GtkMenu *menu = GTK_MENU (widget->parent);
1673 if (menu->accel_group)
1674 _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
1682 * gtk_menu_item_get_accel_path
1683 * @menu_item: a valid #GtkMenuItem
1685 * Retrieve the accelerator path that was previously set on @menu_item.
1687 * See gtk_menu_item_set_accel_path() for details.
1689 * Returns: the accelerator path corresponding to this menu item's
1690 * functionality, or %NULL if not set
1694 G_CONST_RETURN gchar *
1695 gtk_menu_item_get_accel_path (GtkMenuItem *menu_item)
1697 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
1699 return menu_item->accel_path;
1703 gtk_menu_item_forall (GtkContainer *container,
1704 gboolean include_internals,
1705 GtkCallback callback,
1706 gpointer callback_data)
1710 g_return_if_fail (GTK_IS_MENU_ITEM (container));
1711 g_return_if_fail (callback != NULL);
1713 bin = GTK_BIN (container);
1716 callback (bin->child, callback_data);
1720 _gtk_menu_item_is_selectable (GtkWidget *menu_item)
1722 if ((!GTK_BIN (menu_item)->child &&
1723 G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
1724 GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
1725 !GTK_WIDGET_IS_SENSITIVE (menu_item) ||
1726 !GTK_WIDGET_VISIBLE (menu_item))
1732 #define __GTK_MENU_ITEM_C__
1733 #include "gtkaliasdef.c"