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));
245 gtk_widget_class_install_style_property (widget_class,
246 g_param_spec_float ("arrow-scaling",
248 P_("Amount of space used up by arrow, relative to the menu item's font size"),
250 GTK_PARAM_READABLE));
254 gtk_menu_item_init (GtkMenuItem *menu_item)
256 GTK_WIDGET_SET_FLAGS (menu_item, GTK_NO_WINDOW);
258 menu_item->submenu = NULL;
259 menu_item->toggle_size = 0;
260 menu_item->accelerator_width = 0;
261 menu_item->show_submenu_indicator = FALSE;
262 if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
263 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
265 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
266 menu_item->submenu_placement = GTK_TOP_BOTTOM;
267 menu_item->right_justify = FALSE;
269 menu_item->timer = 0;
273 gtk_menu_item_new (void)
275 return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
279 gtk_menu_item_new_with_label (const gchar *label)
281 GtkWidget *menu_item;
282 GtkWidget *accel_label;
284 menu_item = gtk_menu_item_new ();
285 accel_label = gtk_accel_label_new (label);
286 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
288 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
289 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
290 gtk_widget_show (accel_label);
297 * gtk_menu_item_new_with_mnemonic:
298 * @label: The text of the button, with an underscore in front of the
300 * @returns: a new #GtkMenuItem
302 * Creates a new #GtkMenuItem containing a label. The label
303 * will be created using gtk_label_new_with_mnemonic(), so underscores
304 * in @label indicate the mnemonic for the menu item.
307 gtk_menu_item_new_with_mnemonic (const gchar *label)
309 GtkWidget *menu_item;
310 GtkWidget *accel_label;
312 menu_item = gtk_menu_item_new ();
313 accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
314 gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
315 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
317 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
318 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menu_item);
319 gtk_widget_show (accel_label);
325 gtk_menu_item_set_property (GObject *object,
330 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
335 gtk_menu_item_set_submenu (menu_item, g_value_get_object (value));
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
345 gtk_menu_item_get_property (GObject *object,
350 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
355 g_value_set_object (value, gtk_menu_item_get_submenu (menu_item));
359 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
365 gtk_menu_item_finalize (GObject *object)
367 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
369 g_free (menu_item->accel_path);
371 G_OBJECT_CLASS (gtk_menu_item_parent_class)->finalize (object);
375 gtk_menu_item_destroy (GtkObject *object)
377 GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
379 if (menu_item->submenu)
380 gtk_widget_destroy (menu_item->submenu);
382 GTK_OBJECT_CLASS (gtk_menu_item_parent_class)->destroy (object);
386 gtk_menu_item_detacher (GtkWidget *widget,
389 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
391 g_return_if_fail (menu_item->submenu == (GtkWidget*) menu);
393 menu_item->submenu = NULL;
397 * gtk_menu_item_set_submenu:
398 * @menu_item: a #GtkMenuItem
399 * @submenu: the submenu, or %NULL
401 * Sets or replaces the menu item's submenu, or removes it when a %NULL
405 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
408 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
409 g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu));
411 if (menu_item->submenu != submenu)
413 if (menu_item->submenu)
414 gtk_menu_detach (GTK_MENU (menu_item->submenu));
418 menu_item->submenu = submenu;
419 gtk_menu_attach_to_widget (GTK_MENU (submenu),
420 GTK_WIDGET (menu_item),
421 gtk_menu_item_detacher);
424 if (GTK_WIDGET (menu_item)->parent)
425 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
427 g_object_notify (G_OBJECT (menu_item), "submenu");
432 * gtk_menu_item_get_submenu:
433 * @menu_item: a #GtkMenuItem
435 * Gets the submenu underneath this menu item, if any. See
436 * gtk_menu_item_set_submenu().
438 * Return value: submenu for this menu item, or %NULL if none.
441 gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
443 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
445 return menu_item->submenu;
449 * gtk_menu_item_remove_submenu:
450 * @menu_item: a #GtkMenuItem
452 * Removes the widget's submenu.
454 * Deprecated: 2.12: gtk_menu_item_remove_submenu() is deprecated and
455 * should not be used in newly written code. Use
456 * gtk_menu_item_set_submenu() instead.
459 gtk_menu_item_remove_submenu (GtkMenuItem *menu_item)
461 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
463 gtk_menu_item_set_submenu (menu_item, NULL);
466 void _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
467 GtkSubmenuPlacement placement);
470 _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
471 GtkSubmenuPlacement placement)
473 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
475 menu_item->submenu_placement = placement;
479 gtk_menu_item_select (GtkMenuItem *menu_item)
481 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
483 gtk_item_select (GTK_ITEM (menu_item));
485 /* Enable themeing of the parent menu item depending on whether
486 * something is selected in its submenu
488 if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
490 GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
492 if (menu->parent_menu_item)
493 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
498 gtk_menu_item_deselect (GtkMenuItem *menu_item)
500 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
502 gtk_item_deselect (GTK_ITEM (menu_item));
504 /* Enable themeing of the parent menu item depending on whether
505 * something is selected in its submenu
507 if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
509 GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
511 if (menu->parent_menu_item)
512 gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
517 gtk_menu_item_activate (GtkMenuItem *menu_item)
519 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
521 g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
525 gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
528 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
530 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
534 gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
537 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
539 g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
543 gtk_menu_item_accel_width_foreach (GtkWidget *widget,
548 if (GTK_IS_ACCEL_LABEL (widget))
552 w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
553 *width = MAX (*width, w);
555 else if (GTK_IS_CONTAINER (widget))
556 gtk_container_foreach (GTK_CONTAINER (widget),
557 gtk_menu_item_accel_width_foreach,
562 get_minimum_width (GtkWidget *widget)
564 PangoContext *context;
565 PangoFontMetrics *metrics;
568 context = gtk_widget_get_pango_context (widget);
569 metrics = pango_context_get_metrics (context,
570 widget->style->font_desc,
571 pango_context_get_language (context));
573 height = pango_font_metrics_get_ascent (metrics) +
574 pango_font_metrics_get_descent (metrics);
576 pango_font_metrics_unref (metrics);
578 return PANGO_PIXELS (7 * height);
582 gtk_menu_item_size_request (GtkWidget *widget,
583 GtkRequisition *requisition)
585 GtkMenuItem *menu_item;
588 guint horizontal_padding;
589 GtkPackDirection pack_dir;
590 GtkPackDirection child_pack_dir;
592 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
593 g_return_if_fail (requisition != NULL);
595 gtk_widget_style_get (widget,
596 "horizontal-padding", &horizontal_padding,
599 bin = GTK_BIN (widget);
600 menu_item = GTK_MENU_ITEM (widget);
602 if (GTK_IS_MENU_BAR (widget->parent))
604 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
605 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
609 pack_dir = GTK_PACK_DIRECTION_LTR;
610 child_pack_dir = GTK_PACK_DIRECTION_LTR;
613 requisition->width = (GTK_CONTAINER (widget)->border_width +
614 widget->style->xthickness) * 2;
615 requisition->height = (GTK_CONTAINER (widget)->border_width +
616 widget->style->ythickness) * 2;
618 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
619 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
620 requisition->width += 2 * horizontal_padding;
621 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
622 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
623 requisition->height += 2 * horizontal_padding;
625 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
627 GtkRequisition child_requisition;
629 gtk_widget_size_request (bin->child, &child_requisition);
631 requisition->width += child_requisition.width;
632 requisition->height += child_requisition.height;
634 if (menu_item->submenu && menu_item->show_submenu_indicator)
638 gtk_widget_style_get (widget,
639 "arrow-spacing", &arrow_spacing,
642 requisition->width += child_requisition.height;
643 requisition->width += arrow_spacing;
645 requisition->width = MAX (requisition->width, get_minimum_width (widget));
648 else /* separator item */
650 gboolean wide_separators;
651 gint separator_height;
653 gtk_widget_style_get (widget,
654 "wide-separators", &wide_separators,
655 "separator-height", &separator_height,
659 requisition->height += separator_height + widget->style->ythickness;
661 requisition->height += widget->style->ythickness * 2;
665 gtk_container_foreach (GTK_CONTAINER (menu_item),
666 gtk_menu_item_accel_width_foreach,
668 menu_item->accelerator_width = accel_width;
672 gtk_menu_item_size_allocate (GtkWidget *widget,
673 GtkAllocation *allocation)
675 GtkMenuItem *menu_item;
677 GtkAllocation child_allocation;
678 GtkTextDirection direction;
679 GtkPackDirection pack_dir;
680 GtkPackDirection child_pack_dir;
682 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
683 g_return_if_fail (allocation != NULL);
685 menu_item = GTK_MENU_ITEM (widget);
686 bin = GTK_BIN (widget);
688 direction = gtk_widget_get_direction (widget);
690 if (GTK_IS_MENU_BAR (widget->parent))
692 pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
693 child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
697 pack_dir = GTK_PACK_DIRECTION_LTR;
698 child_pack_dir = GTK_PACK_DIRECTION_LTR;
701 widget->allocation = *allocation;
705 GtkRequisition child_requisition;
706 guint horizontal_padding;
708 gtk_widget_style_get (widget,
709 "horizontal-padding", &horizontal_padding,
712 child_allocation.x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
713 child_allocation.y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness;
715 if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
716 (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
717 child_allocation.x += horizontal_padding;
718 else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
719 (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
720 child_allocation.y += horizontal_padding;
722 child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
723 child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
725 if (child_pack_dir == GTK_PACK_DIRECTION_LTR ||
726 child_pack_dir == GTK_PACK_DIRECTION_RTL)
728 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL))
729 child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
730 child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size;
734 if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT))
735 child_allocation.y += GTK_MENU_ITEM (widget)->toggle_size;
736 child_allocation.height -= GTK_MENU_ITEM (widget)->toggle_size;
739 child_allocation.x += widget->allocation.x;
740 child_allocation.y += widget->allocation.y;
742 gtk_widget_get_child_requisition (bin->child, &child_requisition);
743 if (menu_item->submenu && menu_item->show_submenu_indicator)
745 if (direction == GTK_TEXT_DIR_RTL)
746 child_allocation.x += child_requisition.height;
747 child_allocation.width -= child_requisition.height;
750 if (child_allocation.width < 1)
751 child_allocation.width = 1;
753 gtk_widget_size_allocate (bin->child, &child_allocation);
756 if (GTK_WIDGET_REALIZED (widget))
757 gdk_window_move_resize (menu_item->event_window,
758 allocation->x, allocation->y,
759 allocation->width, allocation->height);
761 if (menu_item->submenu)
762 gtk_menu_reposition (GTK_MENU (menu_item->submenu));
766 gtk_menu_item_realize (GtkWidget *widget)
768 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
769 GdkWindowAttr attributes;
770 gint attributes_mask;
772 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
774 widget->window = gtk_widget_get_parent_window (widget);
775 g_object_ref (widget->window);
777 attributes.x = widget->allocation.x;
778 attributes.y = widget->allocation.y;
779 attributes.width = widget->allocation.width;
780 attributes.height = widget->allocation.height;
781 attributes.window_type = GDK_WINDOW_CHILD;
782 attributes.wclass = GDK_INPUT_ONLY;
783 attributes.event_mask = (gtk_widget_get_events (widget) |
784 GDK_BUTTON_PRESS_MASK |
785 GDK_BUTTON_RELEASE_MASK |
786 GDK_ENTER_NOTIFY_MASK |
787 GDK_LEAVE_NOTIFY_MASK |
788 GDK_POINTER_MOTION_MASK);
790 attributes_mask = GDK_WA_X | GDK_WA_Y;
791 menu_item->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
792 gdk_window_set_user_data (menu_item->event_window, widget);
794 widget->style = gtk_style_attach (widget->style, widget->window);
798 gtk_menu_item_unrealize (GtkWidget *widget)
800 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
802 gdk_window_set_user_data (menu_item->event_window, NULL);
803 gdk_window_destroy (menu_item->event_window);
804 menu_item->event_window = NULL;
806 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize)
807 (* GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize) (widget);
811 gtk_menu_item_map (GtkWidget *widget)
813 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
815 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget);
817 gdk_window_show (menu_item->event_window);
821 gtk_menu_item_unmap (GtkWidget *widget)
823 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
825 gdk_window_hide (menu_item->event_window);
827 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget);
831 gtk_menu_item_paint (GtkWidget *widget,
834 GtkMenuItem *menu_item;
835 GtkStateType state_type;
836 GtkShadowType shadow_type, selected_shadow_type;
839 gint border_width = GTK_CONTAINER (widget)->border_width;
841 if (GTK_WIDGET_DRAWABLE (widget))
843 menu_item = GTK_MENU_ITEM (widget);
845 state_type = widget->state;
847 x = widget->allocation.x + border_width;
848 y = widget->allocation.y + border_width;
849 width = widget->allocation.width - border_width * 2;
850 height = widget->allocation.height - border_width * 2;
852 if ((state_type == GTK_STATE_PRELIGHT) &&
853 (GTK_BIN (menu_item)->child))
855 gtk_widget_style_get (widget,
856 "selected-shadow-type", &selected_shadow_type,
858 gtk_paint_box (widget->style,
861 selected_shadow_type,
862 area, widget, "menuitem",
863 x, y, width, height);
866 if (menu_item->submenu && menu_item->show_submenu_indicator)
868 gint arrow_x, arrow_y;
871 guint horizontal_padding;
872 gfloat arrow_scaling;
873 GtkTextDirection direction;
874 GtkArrowType arrow_type;
875 PangoContext *context;
876 PangoFontMetrics *metrics;
878 direction = gtk_widget_get_direction (widget);
880 gtk_widget_style_get (widget,
881 "horizontal-padding", &horizontal_padding,
882 "arrow-scaling", &arrow_scaling,
885 context = gtk_widget_get_pango_context (GTK_BIN (menu_item)->child);
886 metrics = pango_context_get_metrics (context,
887 GTK_WIDGET (GTK_BIN (menu_item)->child)->style->font_desc,
888 pango_context_get_language (context));
890 arrow_size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
891 pango_font_metrics_get_descent (metrics)));
893 pango_font_metrics_unref (metrics);
895 arrow_extent = arrow_size * arrow_scaling;
897 g_printerr ("%s: scaling = %f size = %d extent = %d\n",
898 G_STRFUNC, arrow_scaling, arrow_size, arrow_extent);
900 shadow_type = GTK_SHADOW_OUT;
901 if (state_type == GTK_STATE_PRELIGHT)
902 shadow_type = GTK_SHADOW_IN;
904 if (direction == GTK_TEXT_DIR_LTR)
906 arrow_x = x + width - horizontal_padding - arrow_extent;
907 arrow_type = GTK_ARROW_RIGHT;
911 arrow_x = x + horizontal_padding;
912 arrow_type = GTK_ARROW_LEFT;
915 arrow_y = y + (height - arrow_extent) / 2;
917 gtk_paint_arrow (widget->style, widget->window,
918 state_type, shadow_type,
919 area, widget, "menuitem",
922 arrow_extent, arrow_extent);
924 else if (!GTK_BIN (menu_item)->child)
926 gboolean wide_separators;
927 gint separator_height;
928 guint horizontal_padding;
930 gtk_widget_style_get (widget,
931 "wide-separators", &wide_separators,
932 "separator-height", &separator_height,
933 "horizontal-padding", &horizontal_padding,
937 gtk_paint_box (widget->style, widget->window,
938 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
939 area, widget, "hseparator",
940 widget->allocation.x + horizontal_padding + widget->style->xthickness,
941 widget->allocation.y + (widget->allocation.height -
943 widget->style->ythickness) / 2,
944 widget->allocation.width -
945 2 * (horizontal_padding + widget->style->xthickness),
948 gtk_paint_hline (widget->style, widget->window,
949 GTK_STATE_NORMAL, area, widget, "menuitem",
950 widget->allocation.x + horizontal_padding + widget->style->xthickness,
951 widget->allocation.x + widget->allocation.width - horizontal_padding - widget->style->xthickness - 1,
952 widget->allocation.y + (widget->allocation.height -
953 widget->style->ythickness) / 2);
959 gtk_menu_item_expose (GtkWidget *widget,
960 GdkEventExpose *event)
962 g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
963 g_return_val_if_fail (event != NULL, FALSE);
965 if (GTK_WIDGET_DRAWABLE (widget))
967 gtk_menu_item_paint (widget, &event->area);
969 (* GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->expose_event) (widget, event);
976 gtk_real_menu_item_select (GtkItem *item)
978 GtkMenuItem *menu_item;
979 gboolean touchscreen_mode;
981 g_return_if_fail (GTK_IS_MENU_ITEM (item));
983 menu_item = GTK_MENU_ITEM (item);
985 g_object_get (gtk_widget_get_settings (GTK_WIDGET (item)),
986 "gtk-touchscreen-mode", &touchscreen_mode,
989 if (!touchscreen_mode &&
990 menu_item->submenu &&
991 (!GTK_WIDGET_MAPPED (menu_item->submenu) ||
992 GTK_MENU (menu_item->submenu)->tearoff_active))
994 _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
997 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
998 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1002 gtk_real_menu_item_deselect (GtkItem *item)
1004 GtkMenuItem *menu_item;
1006 g_return_if_fail (GTK_IS_MENU_ITEM (item));
1008 menu_item = GTK_MENU_ITEM (item);
1010 if (menu_item->submenu)
1011 _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
1013 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
1014 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1018 gtk_menu_item_mnemonic_activate (GtkWidget *widget,
1019 gboolean group_cycling)
1021 if (group_cycling &&
1023 GTK_IS_MENU_SHELL (widget->parent) &&
1024 GTK_MENU_SHELL (widget->parent)->active)
1026 gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent),
1030 g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
1036 gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
1040 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1042 widget = GTK_WIDGET (menu_item);
1044 if (widget->parent &&
1045 GTK_IS_MENU_SHELL (widget->parent))
1047 if (menu_item->submenu == NULL)
1048 gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget->parent),
1052 GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget->parent);
1054 _gtk_menu_shell_activate (menu_shell);
1056 gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget);
1057 _gtk_menu_item_popup_submenu (widget, FALSE);
1059 gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
1065 gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1068 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1074 gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1077 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1079 menu_item->toggle_size = allocation;
1083 gtk_menu_item_real_popup_submenu (GtkWidget *widget,
1084 gboolean remember_exact_time)
1086 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1088 if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
1090 gboolean take_focus;
1092 take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent));
1093 gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),
1096 if (remember_exact_time)
1098 GTimeVal *popup_time = g_new0 (GTimeVal, 1);
1100 g_get_current_time (popup_time);
1102 g_object_set_data_full (G_OBJECT (menu_item->submenu),
1103 "gtk-menu-exact-popup-time", popup_time,
1104 (GDestroyNotify) g_free);
1108 g_object_set_data (G_OBJECT (menu_item->submenu),
1109 "gtk-menu-exact-popup-time", NULL);
1112 gtk_menu_popup (GTK_MENU (menu_item->submenu),
1115 gtk_menu_item_position_menu,
1117 GTK_MENU_SHELL (widget->parent)->button,
1121 /* Enable themeing of the parent menu item depending on whether
1122 * its submenu is shown or not.
1124 gtk_widget_queue_draw (widget);
1128 gtk_menu_item_popup_timeout (gpointer data)
1130 GtkMenuItem *menu_item;
1133 menu_item = GTK_MENU_ITEM (data);
1135 parent = GTK_WIDGET (menu_item)->parent;
1137 if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active) ||
1138 (GTK_IS_MENU (parent) && GTK_MENU (parent)->torn_off))
1140 gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1141 if (menu_item->timer_from_keypress && menu_item->submenu)
1142 GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
1145 menu_item->timer = 0;
1151 get_popup_delay (GtkWidget *widget)
1153 if (GTK_IS_MENU_SHELL (widget->parent))
1155 return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (widget->parent));
1161 g_object_get (gtk_widget_get_settings (widget),
1162 "gtk-menu-popup-delay", &popup_delay,
1170 _gtk_menu_item_popup_submenu (GtkWidget *widget,
1171 gboolean with_delay)
1173 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1175 if (menu_item->timer)
1177 g_source_remove (menu_item->timer);
1178 menu_item->timer = 0;
1184 gint popup_delay = get_popup_delay (widget);
1186 if (popup_delay > 0)
1188 GdkEvent *event = gtk_get_current_event ();
1190 menu_item->timer = gdk_threads_add_timeout (popup_delay,
1191 gtk_menu_item_popup_timeout,
1195 event->type != GDK_BUTTON_PRESS &&
1196 event->type != GDK_ENTER_NOTIFY)
1197 menu_item->timer_from_keypress = TRUE;
1199 menu_item->timer_from_keypress = FALSE;
1202 gdk_event_free (event);
1208 gtk_menu_item_real_popup_submenu (widget, FALSE);
1212 _gtk_menu_item_popdown_submenu (GtkWidget *widget)
1214 GtkMenuItem *menu_item;
1216 menu_item = GTK_MENU_ITEM (widget);
1218 if (menu_item->submenu)
1220 g_object_set_data (G_OBJECT (menu_item->submenu),
1221 "gtk-menu-exact-popup-time", NULL);
1223 if (menu_item->timer)
1225 g_source_remove (menu_item->timer);
1226 menu_item->timer = 0;
1229 gtk_menu_popdown (GTK_MENU (menu_item->submenu));
1231 gtk_widget_queue_draw (widget);
1236 get_offsets (GtkMenu *menu,
1237 gint *horizontal_offset,
1238 gint *vertical_offset)
1240 gint vertical_padding;
1241 gint horizontal_padding;
1243 gtk_widget_style_get (GTK_WIDGET (menu),
1244 "horizontal-offset", horizontal_offset,
1245 "vertical-offset", vertical_offset,
1246 "horizontal-padding", &horizontal_padding,
1247 "vertical-padding", &vertical_padding,
1250 *vertical_offset -= GTK_WIDGET (menu)->style->ythickness;
1251 *vertical_offset -= vertical_padding;
1252 *horizontal_offset += horizontal_padding;
1256 gtk_menu_item_position_menu (GtkMenu *menu,
1262 GtkMenuItem *menu_item;
1264 GtkMenuItem *parent_menu_item;
1266 gint twidth, theight;
1268 GtkTextDirection direction;
1269 GdkRectangle monitor;
1271 gint horizontal_offset;
1272 gint vertical_offset;
1273 gint parent_xthickness;
1274 gint available_left, available_right;
1276 g_return_if_fail (menu != NULL);
1277 g_return_if_fail (x != NULL);
1278 g_return_if_fail (y != NULL);
1280 menu_item = GTK_MENU_ITEM (user_data);
1281 widget = GTK_WIDGET (user_data);
1286 direction = gtk_widget_get_direction (widget);
1288 twidth = GTK_WIDGET (menu)->requisition.width;
1289 theight = GTK_WIDGET (menu)->requisition.height;
1291 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
1292 monitor_num = gdk_screen_get_monitor_at_window (screen, menu_item->event_window);
1293 if (monitor_num < 0)
1295 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1297 if (!gdk_window_get_origin (widget->window, &tx, &ty))
1299 g_warning ("Menu not on screen");
1303 tx += widget->allocation.x;
1304 ty += widget->allocation.y;
1306 get_offsets (menu, &horizontal_offset, &vertical_offset);
1308 available_left = tx - monitor.x;
1309 available_right = monitor.x + monitor.width - (tx + widget->allocation.width);
1311 if (GTK_IS_MENU_BAR (widget->parent))
1313 menu_item->from_menubar = TRUE;
1315 else if (GTK_IS_MENU (widget->parent))
1317 if (GTK_MENU (widget->parent)->parent_menu_item)
1318 menu_item->from_menubar = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item)->from_menubar;
1320 menu_item->from_menubar = FALSE;
1324 menu_item->from_menubar = FALSE;
1327 switch (menu_item->submenu_placement)
1329 case GTK_TOP_BOTTOM:
1330 if (direction == GTK_TEXT_DIR_LTR)
1331 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1334 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1335 tx += widget->allocation.width - twidth;
1337 if ((ty + widget->allocation.height + theight) <= monitor.y + monitor.height)
1338 ty += widget->allocation.height;
1339 else if ((ty - theight) >= monitor.y)
1341 else if (monitor.y + monitor.height - (ty + widget->allocation.height) > ty)
1342 ty += widget->allocation.height;
1347 case GTK_LEFT_RIGHT:
1348 if (GTK_IS_MENU (widget->parent))
1349 parent_menu_item = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item);
1351 parent_menu_item = NULL;
1353 parent_xthickness = widget->parent->style->xthickness;
1355 if (parent_menu_item && !GTK_MENU (widget->parent)->torn_off)
1357 menu_item->submenu_direction = parent_menu_item->submenu_direction;
1361 if (direction == GTK_TEXT_DIR_LTR)
1362 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1364 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1367 switch (menu_item->submenu_direction)
1369 case GTK_DIRECTION_LEFT:
1370 if (tx - twidth - parent_xthickness - horizontal_offset >= monitor.x ||
1371 available_left >= available_right)
1372 tx -= twidth + parent_xthickness + horizontal_offset;
1375 menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1376 tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1380 case GTK_DIRECTION_RIGHT:
1381 if (tx + widget->allocation.width + parent_xthickness + horizontal_offset + twidth <= monitor.x + monitor.width ||
1382 available_right >= available_left)
1383 tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1386 menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1387 tx -= twidth + parent_xthickness + horizontal_offset;
1392 ty += vertical_offset;
1394 /* If the height of the menu doesn't fit we move it upward. */
1395 ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
1399 /* If we have negative, tx, here it is because we can't get
1400 * the menu all the way on screen. Favor the left portion.
1402 *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
1405 gtk_menu_set_monitor (menu, monitor_num);
1407 if (!GTK_WIDGET_VISIBLE (menu->toplevel))
1409 gtk_window_set_type_hint (GTK_WINDOW (menu->toplevel), menu_item->from_menubar?
1410 GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
1415 * gtk_menu_item_set_right_justified:
1416 * @menu_item: a #GtkMenuItem.
1417 * @right_justified: if %TRUE the menu item will appear at the
1418 * far right if added to a menu bar.
1420 * Sets whether the menu item appears justified at the right
1421 * side of a menu bar. This was traditionally done for "Help" menu
1422 * items, but is now considered a bad idea. (If the widget
1423 * layout is reversed for a right-to-left language like Hebrew
1424 * or Arabic, right-justified-menu-items appear at the left.)
1427 gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
1428 gboolean right_justified)
1430 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1432 right_justified = right_justified != FALSE;
1434 if (right_justified != menu_item->right_justify)
1436 menu_item->right_justify = right_justified;
1437 gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1442 * gtk_menu_item_get_right_justified:
1443 * @menu_item: a #GtkMenuItem
1445 * Gets whether the menu item appears justified at the right
1446 * side of the menu bar.
1448 * Return value: %TRUE if the menu item will appear at the
1449 * far right if added to a menu bar.
1452 gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
1454 g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
1456 return menu_item->right_justify;
1461 gtk_menu_item_show_all (GtkWidget *widget)
1463 GtkMenuItem *menu_item;
1465 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1467 menu_item = GTK_MENU_ITEM (widget);
1469 /* show children including submenu */
1470 if (menu_item->submenu)
1471 gtk_widget_show_all (menu_item->submenu);
1472 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1474 gtk_widget_show (widget);
1478 gtk_menu_item_hide_all (GtkWidget *widget)
1480 GtkMenuItem *menu_item;
1482 g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1484 gtk_widget_hide (widget);
1486 menu_item = GTK_MENU_ITEM (widget);
1488 /* hide children including submenu */
1489 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);
1490 if (menu_item->submenu)
1491 gtk_widget_hide_all (menu_item->submenu);
1495 gtk_menu_item_can_activate_accel (GtkWidget *widget,
1498 /* Chain to the parent GtkMenu for further checks */
1499 return (GTK_WIDGET_IS_SENSITIVE (widget) && GTK_WIDGET_VISIBLE (widget) &&
1500 widget->parent && gtk_widget_can_activate_accel (widget->parent, signal_id));
1504 gtk_menu_item_accel_name_foreach (GtkWidget *widget,
1507 const gchar **path_p = data;
1511 if (GTK_IS_LABEL (widget))
1513 *path_p = gtk_label_get_text (GTK_LABEL (widget));
1514 if (*path_p && (*path_p)[0] == 0)
1517 else if (GTK_IS_CONTAINER (widget))
1518 gtk_container_foreach (GTK_CONTAINER (widget),
1519 gtk_menu_item_accel_name_foreach,
1525 gtk_menu_item_parent_set (GtkWidget *widget,
1526 GtkWidget *previous_parent)
1528 GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1529 GtkMenu *menu = GTK_IS_MENU (widget->parent) ? GTK_MENU (widget->parent) : NULL;
1532 _gtk_menu_item_refresh_accel_path (menu_item,
1537 if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set)
1538 GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent);
1542 _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item,
1543 const gchar *prefix,
1544 GtkAccelGroup *accel_group,
1545 gboolean group_changed)
1550 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1551 g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
1553 widget = GTK_WIDGET (menu_item);
1557 gtk_widget_set_accel_path (widget, NULL, NULL);
1561 path = _gtk_widget_get_accel_path (widget, NULL);
1562 if (!path) /* no active accel_path yet */
1564 path = menu_item->accel_path;
1565 if (!path && prefix)
1567 gchar *postfix = NULL;
1569 /* try to construct one from label text */
1570 gtk_container_foreach (GTK_CONTAINER (menu_item),
1571 gtk_menu_item_accel_name_foreach,
1573 menu_item->accel_path = postfix ? g_strconcat (prefix, "/", postfix, NULL) : NULL;
1574 path = menu_item->accel_path;
1577 gtk_widget_set_accel_path (widget, path, accel_group);
1579 else if (group_changed) /* reinstall accelerators */
1580 gtk_widget_set_accel_path (widget, path, accel_group);
1584 * gtk_menu_item_set_accel_path
1585 * @menu_item: a valid #GtkMenuItem
1586 * @accel_path: accelerator path, corresponding to this menu item's
1587 * functionality, or %NULL to unset the current path.
1589 * Set the accelerator path on @menu_item, through which runtime changes of the
1590 * menu item's accelerator caused by the user can be identified and saved to
1591 * persistant storage (see gtk_accel_map_save() on this).
1592 * To setup a default accelerator for this menu item, call
1593 * gtk_accel_map_add_entry() with the same @accel_path.
1594 * See also gtk_accel_map_add_entry() on the specifics of accelerator paths,
1595 * and gtk_menu_set_accel_path() for a more convenient variant of this function.
1597 * This function is basically a convenience wrapper that handles calling
1598 * gtk_widget_set_accel_path() with the appropriate accelerator group for
1601 * Note that you do need to set an accelerator on the parent menu with
1602 * gtk_menu_set_accel_group() for this to work.
1605 gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
1606 const gchar *accel_path)
1610 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1611 g_return_if_fail (accel_path == NULL ||
1612 (accel_path[0] == '<' && strchr (accel_path, '/')));
1614 widget = GTK_WIDGET (menu_item);
1616 /* store new path */
1617 g_free (menu_item->accel_path);
1618 menu_item->accel_path = g_strdup (accel_path);
1620 /* forget accelerators associated with old path */
1621 gtk_widget_set_accel_path (widget, NULL, NULL);
1623 /* install accelerators associated with new path */
1624 if (widget->parent && GTK_IS_MENU (widget->parent))
1626 GtkMenu *menu = GTK_MENU (widget->parent);
1628 if (menu->accel_group)
1629 _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
1637 gtk_menu_item_forall (GtkContainer *container,
1638 gboolean include_internals,
1639 GtkCallback callback,
1640 gpointer callback_data)
1644 g_return_if_fail (GTK_IS_MENU_ITEM (container));
1645 g_return_if_fail (callback != NULL);
1647 bin = GTK_BIN (container);
1650 callback (bin->child, callback_data);
1654 _gtk_menu_item_is_selectable (GtkWidget *menu_item)
1656 if ((!GTK_BIN (menu_item)->child &&
1657 G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
1658 GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
1659 !GTK_WIDGET_IS_SENSITIVE (menu_item) ||
1660 !GTK_WIDGET_VISIBLE (menu_item))
1666 #define __GTK_MENU_ITEM_C__
1667 #include "gtkaliasdef.c"