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 "gtkseparatormenuitem.h"
38
#include "gtkprivate.h"
39
#include "gtkbuildable.h"
40
#include "gtkactivatable.h"
47
gboolean use_action_appearance;
66
/* activatable properties */
67
PROP_ACTIVATABLE_RELATED_ACTION,
68
PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
72
static void gtk_menu_item_dispose (GObject *object);
73
static void gtk_menu_item_set_property (GObject *object,
77
static void gtk_menu_item_get_property (GObject *object,
81
static void gtk_menu_item_destroy (GtkObject *object);
82
static void gtk_menu_item_size_request (GtkWidget *widget,
83
GtkRequisition *requisition);
84
static void gtk_menu_item_size_allocate (GtkWidget *widget,
85
GtkAllocation *allocation);
86
static void gtk_menu_item_realize (GtkWidget *widget);
87
static void gtk_menu_item_unrealize (GtkWidget *widget);
88
static void gtk_menu_item_map (GtkWidget *widget);
89
static void gtk_menu_item_unmap (GtkWidget *widget);
90
static void gtk_menu_item_paint (GtkWidget *widget,
92
static gint gtk_menu_item_expose (GtkWidget *widget,
93
GdkEventExpose *event);
94
static void gtk_menu_item_parent_set (GtkWidget *widget,
95
GtkWidget *previous_parent);
98
static void gtk_real_menu_item_select (GtkItem *item);
99
static void gtk_real_menu_item_deselect (GtkItem *item);
100
static void gtk_real_menu_item_activate (GtkMenuItem *item);
101
static void gtk_real_menu_item_activate_item (GtkMenuItem *item);
102
static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
104
static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
106
static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget,
107
gboolean group_cycling);
109
static void gtk_menu_item_ensure_label (GtkMenuItem *menu_item);
110
static gint gtk_menu_item_popup_timeout (gpointer data);
111
static void gtk_menu_item_position_menu (GtkMenu *menu,
116
static void gtk_menu_item_show_all (GtkWidget *widget);
117
static void gtk_menu_item_hide_all (GtkWidget *widget);
118
static void gtk_menu_item_forall (GtkContainer *container,
119
gboolean include_internals,
120
GtkCallback callback,
121
gpointer callback_data);
122
static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget,
125
static void gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
127
static const gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item);
130
static void gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface);
131
static void gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
135
static void gtk_menu_item_buildable_custom_finished(GtkBuildable *buildable,
138
const gchar *tagname,
141
static void gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface);
142
static void gtk_menu_item_update (GtkActivatable *activatable,
144
const gchar *property_name);
145
static void gtk_menu_item_sync_action_properties (GtkActivatable *activatable,
147
static void gtk_menu_item_set_related_action (GtkMenuItem *menu_item,
149
static void gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item,
150
gboolean use_appearance);
153
static guint menu_item_signals[LAST_SIGNAL] = { 0 };
155
static GtkBuildableIface *parent_buildable_iface;
157
G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_ITEM,
158
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
159
gtk_menu_item_buildable_interface_init)
160
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
161
gtk_menu_item_activatable_interface_init))
163
#define GET_PRIVATE(object) \
164
(G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_MENU_ITEM, GtkMenuItemPrivate))
167
gtk_menu_item_class_init (GtkMenuItemClass *klass)
169
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
170
GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
171
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
172
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
173
GtkItemClass *item_class = GTK_ITEM_CLASS (klass);
175
gobject_class->dispose = gtk_menu_item_dispose;
176
gobject_class->set_property = gtk_menu_item_set_property;
177
gobject_class->get_property = gtk_menu_item_get_property;
179
object_class->destroy = gtk_menu_item_destroy;
181
widget_class->size_request = gtk_menu_item_size_request;
182
widget_class->size_allocate = gtk_menu_item_size_allocate;
183
widget_class->expose_event = gtk_menu_item_expose;
184
widget_class->realize = gtk_menu_item_realize;
185
widget_class->unrealize = gtk_menu_item_unrealize;
186
widget_class->map = gtk_menu_item_map;
187
widget_class->unmap = gtk_menu_item_unmap;
188
widget_class->show_all = gtk_menu_item_show_all;
189
widget_class->hide_all = gtk_menu_item_hide_all;
190
widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate;
191
widget_class->parent_set = gtk_menu_item_parent_set;
192
widget_class->can_activate_accel = gtk_menu_item_can_activate_accel;
194
container_class->forall = gtk_menu_item_forall;
196
item_class->select = gtk_real_menu_item_select;
197
item_class->deselect = gtk_real_menu_item_deselect;
199
klass->activate = gtk_real_menu_item_activate;
200
klass->activate_item = gtk_real_menu_item_activate_item;
201
klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
202
klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
203
klass->set_label = gtk_real_menu_item_set_label;
204
klass->get_label = gtk_real_menu_item_get_label;
206
klass->hide_on_activate = TRUE;
208
menu_item_signals[ACTIVATE] =
209
g_signal_new (I_("activate"),
210
G_OBJECT_CLASS_TYPE (gobject_class),
211
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
212
G_STRUCT_OFFSET (GtkMenuItemClass, activate),
214
_gtk_marshal_VOID__VOID,
216
widget_class->activate_signal = menu_item_signals[ACTIVATE];
218
menu_item_signals[ACTIVATE_ITEM] =
219
g_signal_new (I_("activate-item"),
220
G_OBJECT_CLASS_TYPE (gobject_class),
222
G_STRUCT_OFFSET (GtkMenuItemClass, activate_item),
224
_gtk_marshal_VOID__VOID,
227
menu_item_signals[TOGGLE_SIZE_REQUEST] =
228
g_signal_new (I_("toggle-size-request"),
229
G_OBJECT_CLASS_TYPE (gobject_class),
231
G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request),
233
_gtk_marshal_VOID__POINTER,
237
menu_item_signals[TOGGLE_SIZE_ALLOCATE] =
238
g_signal_new (I_("toggle-size-allocate"),
239
G_OBJECT_CLASS_TYPE (gobject_class),
241
G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate),
243
_gtk_marshal_VOID__INT,
248
* GtkMenuItem:right-justified:
250
* Sets whether the menu item appears justified at the right side of a menu bar.
254
g_object_class_install_property (gobject_class,
255
PROP_RIGHT_JUSTIFIED,
256
g_param_spec_boolean ("right-justified",
257
P_("Right Justified"),
258
P_("Sets whether the menu item appears justified at the right side of a menu bar"),
260
GTK_PARAM_READWRITE));
263
* GtkMenuItem:submenu:
265
* The submenu attached to the menu item, or NULL if it has none.
269
g_object_class_install_property (gobject_class,
271
g_param_spec_object ("submenu",
273
P_("The submenu attached to the menu item, or NULL if it has none"),
275
GTK_PARAM_READWRITE));
279
* GtkMenuItem:accel-path:
281
* Sets the accelerator path of the menu item, through which runtime
282
* changes of the menu item's accelerator caused by the user can be
283
* identified and saved to persistant storage.
287
g_object_class_install_property (gobject_class,
289
g_param_spec_string ("accel-path",
291
P_("Sets the accelerator path of the menu item"),
293
GTK_PARAM_READWRITE));
298
* The text for the child label.
302
g_object_class_install_property (gobject_class,
304
g_param_spec_string ("label",
306
P_("The text for the child label"),
308
GTK_PARAM_READWRITE));
311
* GtkMenuItem:use-underline:
313
* %TRUE if underlines in the text indicate mnemonics
317
g_object_class_install_property (gobject_class,
319
g_param_spec_boolean ("use-underline",
321
P_("If set, an underline in the text indicates "
322
"the next character should be used for the "
323
"mnemonic accelerator key"),
325
GTK_PARAM_READWRITE));
327
g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
328
g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
330
gtk_widget_class_install_style_property_parser (widget_class,
331
g_param_spec_enum ("selected-shadow-type",
332
"Selected Shadow Type",
333
"Shadow type when item is selected",
334
GTK_TYPE_SHADOW_TYPE,
337
gtk_rc_property_parse_enum);
339
gtk_widget_class_install_style_property (widget_class,
340
g_param_spec_int ("horizontal-padding",
341
"Horizontal Padding",
342
"Padding to left and right of the menu item",
346
GTK_PARAM_READABLE));
348
gtk_widget_class_install_style_property (widget_class,
349
g_param_spec_int ("toggle-spacing",
351
"Space between icon and label",
355
GTK_PARAM_READABLE));
357
gtk_widget_class_install_style_property (widget_class,
358
g_param_spec_int ("arrow-spacing",
360
"Space between label and arrow",
364
GTK_PARAM_READABLE));
366
gtk_widget_class_install_style_property (widget_class,
367
g_param_spec_float ("arrow-scaling",
369
P_("Amount of space used up by arrow, relative to the menu item's font size"),
371
GTK_PARAM_READABLE));
374
* GtkMenuItem:width-chars:
376
* The minimum desired width of the menu item in characters.
380
gtk_widget_class_install_style_property (widget_class,
381
g_param_spec_int ("width-chars",
382
P_("Width in Characters"),
383
P_("The minimum desired width of the menu item in characters"),
385
GTK_PARAM_READABLE));
387
g_type_class_add_private (object_class, sizeof (GtkMenuItemPrivate));
391
gtk_menu_item_init (GtkMenuItem *menu_item)
393
GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
395
gtk_widget_set_has_window (GTK_WIDGET (menu_item), FALSE);
398
priv->use_action_appearance = TRUE;
400
menu_item->submenu = NULL;
401
menu_item->toggle_size = 0;
402
menu_item->accelerator_width = 0;
403
menu_item->show_submenu_indicator = FALSE;
404
if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL)
405
menu_item->submenu_direction = GTK_DIRECTION_LEFT;
407
menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
408
menu_item->submenu_placement = GTK_TOP_BOTTOM;
409
menu_item->right_justify = FALSE;
411
menu_item->timer = 0;
415
gtk_menu_item_new (void)
417
return g_object_new (GTK_TYPE_MENU_ITEM, NULL);
421
gtk_menu_item_new_with_label (const gchar *label)
423
return g_object_new (GTK_TYPE_MENU_ITEM,
430
* gtk_menu_item_new_with_mnemonic:
431
* @label: The text of the button, with an underscore in front of the
433
* @returns: a new #GtkMenuItem
435
* Creates a new #GtkMenuItem containing a label. The label
436
* will be created using gtk_label_new_with_mnemonic(), so underscores
437
* in @label indicate the mnemonic for the menu item.
440
gtk_menu_item_new_with_mnemonic (const gchar *label)
442
return g_object_new (GTK_TYPE_MENU_ITEM,
443
"use-underline", TRUE,
449
gtk_menu_item_dispose (GObject *object)
451
GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
452
GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
456
gtk_action_disconnect_accelerator (priv->action);
457
gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), NULL);
461
G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object);
465
gtk_menu_item_set_property (GObject *object,
470
GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
474
case PROP_RIGHT_JUSTIFIED:
475
gtk_menu_item_set_right_justified (menu_item, g_value_get_boolean (value));
478
gtk_menu_item_set_submenu (menu_item, g_value_get_object (value));
480
case PROP_ACCEL_PATH:
481
gtk_menu_item_set_accel_path (menu_item, g_value_get_string (value));
484
gtk_menu_item_set_label (menu_item, g_value_get_string (value));
486
case PROP_USE_UNDERLINE:
487
gtk_menu_item_set_use_underline (menu_item, g_value_get_boolean (value));
489
case PROP_ACTIVATABLE_RELATED_ACTION:
490
gtk_menu_item_set_related_action (menu_item, g_value_get_object (value));
492
case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
493
gtk_menu_item_set_use_action_appearance (menu_item, g_value_get_boolean (value));
496
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
502
gtk_menu_item_get_property (GObject *object,
507
GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
508
GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
512
case PROP_RIGHT_JUSTIFIED:
513
g_value_set_boolean (value, gtk_menu_item_get_right_justified (menu_item));
516
g_value_set_object (value, gtk_menu_item_get_submenu (menu_item));
518
case PROP_ACCEL_PATH:
519
g_value_set_string (value, gtk_menu_item_get_accel_path (menu_item));
522
g_value_set_string (value, gtk_menu_item_get_label (menu_item));
524
case PROP_USE_UNDERLINE:
525
g_value_set_boolean (value, gtk_menu_item_get_use_underline (menu_item));
527
case PROP_ACTIVATABLE_RELATED_ACTION:
528
g_value_set_object (value, priv->action);
530
case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
531
g_value_set_boolean (value, priv->use_action_appearance);
534
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
540
gtk_menu_item_destroy (GtkObject *object)
542
GtkMenuItem *menu_item = GTK_MENU_ITEM (object);
544
if (menu_item->submenu)
545
gtk_widget_destroy (menu_item->submenu);
547
GTK_OBJECT_CLASS (gtk_menu_item_parent_class)->destroy (object);
551
gtk_menu_item_detacher (GtkWidget *widget,
554
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
556
g_return_if_fail (menu_item->submenu == (GtkWidget*) menu);
558
menu_item->submenu = NULL;
562
gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface)
564
parent_buildable_iface = g_type_interface_peek_parent (iface);
565
iface->add_child = gtk_menu_item_buildable_add_child;
566
iface->custom_finished = gtk_menu_item_buildable_custom_finished;
570
gtk_menu_item_buildable_add_child (GtkBuildable *buildable,
575
if (type && strcmp (type, "submenu") == 0)
576
gtk_menu_item_set_submenu (GTK_MENU_ITEM (buildable),
579
parent_buildable_iface->add_child (buildable, builder, child, type);
584
gtk_menu_item_buildable_custom_finished (GtkBuildable *buildable,
587
const gchar *tagname,
592
if (strcmp (tagname, "accelerator") == 0)
594
GtkMenuShell *menu_shell = (GtkMenuShell *) GTK_WIDGET (buildable)->parent;
599
while (GTK_IS_MENU (menu_shell) &&
600
(attach = gtk_menu_get_attach_widget (GTK_MENU (menu_shell))) != NULL)
601
menu_shell = (GtkMenuShell *)attach->parent;
603
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu_shell));
607
/* Fall back to something ... */
608
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (buildable));
610
g_warning ("found a GtkMenuItem '%s' without a parent GtkMenuShell, assigned accelerators wont work.",
611
gtk_buildable_get_name (buildable));
614
/* Feed the correct toplevel to the GtkWidget accelerator parsing code */
615
_gtk_widget_buildable_finish_accelerator (GTK_WIDGET (buildable), toplevel, user_data);
618
parent_buildable_iface->custom_finished (buildable, builder, child, tagname, user_data);
623
gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface)
625
iface->update = gtk_menu_item_update;
626
iface->sync_action_properties = gtk_menu_item_sync_action_properties;
630
activatable_update_label (GtkMenuItem *menu_item, GtkAction *action)
632
GtkWidget *child = GTK_BIN (menu_item)->child;
634
if (GTK_IS_LABEL (child))
638
label = gtk_action_get_label (action);
639
gtk_menu_item_set_label (menu_item, label);
643
gboolean _gtk_menu_is_empty (GtkWidget *menu);
646
gtk_menu_item_update (GtkActivatable *activatable,
648
const gchar *property_name)
650
GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
651
GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
653
if (strcmp (property_name, "visible") == 0)
654
_gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
655
_gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
656
else if (strcmp (property_name, "sensitive") == 0)
657
gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
658
else if (priv->use_action_appearance)
660
if (strcmp (property_name, "label") == 0)
661
activatable_update_label (menu_item, action);
666
gtk_menu_item_sync_action_properties (GtkActivatable *activatable,
669
GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable);
670
GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
672
if (!priv->use_action_appearance || !action)
674
GtkWidget *label = GTK_BIN (menu_item)->child;
676
label = GTK_BIN (menu_item)->child;
678
if (GTK_IS_ACCEL_LABEL (label))
679
gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), GTK_WIDGET (menu_item));
685
_gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item),
686
_gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item)));
688
gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action));
690
if (priv->use_action_appearance)
692
GtkWidget *label = GTK_BIN (menu_item)->child;
694
/* make sure label is a label */
695
if (label && !GTK_IS_LABEL (label))
697
gtk_container_remove (GTK_CONTAINER (menu_item), label);
701
gtk_menu_item_ensure_label (menu_item);
702
gtk_menu_item_set_use_underline (menu_item, TRUE);
704
label = GTK_BIN (menu_item)->child;
706
if (GTK_IS_ACCEL_LABEL (label) && gtk_action_get_accel_path (action))
708
gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), NULL);
709
gtk_accel_label_set_accel_closure (GTK_ACCEL_LABEL (label),
710
gtk_action_get_accel_closure (action));
713
activatable_update_label (menu_item, action);
718
gtk_menu_item_set_related_action (GtkMenuItem *menu_item,
721
GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
723
if (priv->action == action)
728
gtk_action_disconnect_accelerator (priv->action);
733
const gchar *accel_path;
735
accel_path = gtk_action_get_accel_path (action);
738
gtk_action_connect_accelerator (action);
739
gtk_menu_item_set_accel_path (menu_item, accel_path);
743
gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), action);
745
priv->action = action;
749
gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item,
750
gboolean use_appearance)
752
GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item);
754
if (priv->use_action_appearance != use_appearance)
756
priv->use_action_appearance = use_appearance;
758
gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (menu_item), priv->action);
764
* gtk_menu_item_set_submenu:
765
* @menu_item: a #GtkMenuItem
766
* @submenu: (allow-none): the submenu, or %NULL
768
* Sets or replaces the menu item's submenu, or removes it when a %NULL
772
gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
775
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
776
g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu));
778
if (menu_item->submenu != submenu)
780
if (menu_item->submenu)
781
gtk_menu_detach (GTK_MENU (menu_item->submenu));
785
menu_item->submenu = submenu;
786
gtk_menu_attach_to_widget (GTK_MENU (submenu),
787
GTK_WIDGET (menu_item),
788
gtk_menu_item_detacher);
791
if (GTK_WIDGET (menu_item)->parent)
792
gtk_widget_queue_resize (GTK_WIDGET (menu_item));
794
g_object_notify (G_OBJECT (menu_item), "submenu");
799
* gtk_menu_item_get_submenu:
800
* @menu_item: a #GtkMenuItem
802
* Gets the submenu underneath this menu item, if any.
803
* See gtk_menu_item_set_submenu().
805
* Return value: (transfer none): submenu for this menu item, or %NULL if none.
808
gtk_menu_item_get_submenu (GtkMenuItem *menu_item)
810
g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
812
return menu_item->submenu;
816
* gtk_menu_item_remove_submenu:
817
* @menu_item: a #GtkMenuItem
819
* Removes the widget's submenu.
821
* Deprecated: 2.12: gtk_menu_item_remove_submenu() is deprecated and
822
* should not be used in newly written code. Use
823
* gtk_menu_item_set_submenu() instead.
826
gtk_menu_item_remove_submenu (GtkMenuItem *menu_item)
828
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
830
gtk_menu_item_set_submenu (menu_item, NULL);
833
void _gtk_menu_item_set_placement (GtkMenuItem *menu_item,
834
GtkSubmenuPlacement placement);
837
_gtk_menu_item_set_placement (GtkMenuItem *menu_item,
838
GtkSubmenuPlacement placement)
840
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
842
menu_item->submenu_placement = placement;
846
gtk_menu_item_select (GtkMenuItem *menu_item)
848
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
850
gtk_item_select (GTK_ITEM (menu_item));
852
/* Enable themeing of the parent menu item depending on whether
853
* something is selected in its submenu
855
if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
857
GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
859
if (menu->parent_menu_item)
860
gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
865
gtk_menu_item_deselect (GtkMenuItem *menu_item)
867
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
869
gtk_item_deselect (GTK_ITEM (menu_item));
871
/* Enable themeing of the parent menu item depending on whether
872
* something is selected in its submenu
874
if (GTK_IS_MENU (GTK_WIDGET (menu_item)->parent))
876
GtkMenu *menu = GTK_MENU (GTK_WIDGET (menu_item)->parent);
878
if (menu->parent_menu_item)
879
gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item));
884
gtk_menu_item_activate (GtkMenuItem *menu_item)
886
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
888
g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0);
892
gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item,
895
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
897
g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition);
901
gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
904
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
906
g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_ALLOCATE], 0, allocation);
910
gtk_menu_item_accel_width_foreach (GtkWidget *widget,
915
if (GTK_IS_ACCEL_LABEL (widget))
919
w = gtk_accel_label_get_accel_width (GTK_ACCEL_LABEL (widget));
920
*width = MAX (*width, w);
922
else if (GTK_IS_CONTAINER (widget))
923
gtk_container_foreach (GTK_CONTAINER (widget),
924
gtk_menu_item_accel_width_foreach,
929
get_minimum_width (GtkWidget *widget)
931
PangoContext *context;
932
PangoFontMetrics *metrics;
936
context = gtk_widget_get_pango_context (widget);
937
metrics = pango_context_get_metrics (context,
938
widget->style->font_desc,
939
pango_context_get_language (context));
941
width = pango_font_metrics_get_approximate_char_width (metrics);
943
pango_font_metrics_unref (metrics);
945
gtk_widget_style_get (widget, "width-chars", &width_chars, NULL);
947
return PANGO_PIXELS (width_chars * width);
951
gtk_menu_item_size_request (GtkWidget *widget,
952
GtkRequisition *requisition)
954
GtkMenuItem *menu_item;
957
guint horizontal_padding;
958
GtkPackDirection pack_dir;
959
GtkPackDirection child_pack_dir;
961
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
962
g_return_if_fail (requisition != NULL);
964
gtk_widget_style_get (widget,
965
"horizontal-padding", &horizontal_padding,
968
bin = GTK_BIN (widget);
969
menu_item = GTK_MENU_ITEM (widget);
971
if (GTK_IS_MENU_BAR (widget->parent))
973
pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
974
child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
978
pack_dir = GTK_PACK_DIRECTION_LTR;
979
child_pack_dir = GTK_PACK_DIRECTION_LTR;
982
requisition->width = (GTK_CONTAINER (widget)->border_width +
983
widget->style->xthickness) * 2;
984
requisition->height = (GTK_CONTAINER (widget)->border_width +
985
widget->style->ythickness) * 2;
987
if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
988
(child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
989
requisition->width += 2 * horizontal_padding;
990
else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
991
(child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
992
requisition->height += 2 * horizontal_padding;
994
if (bin->child && gtk_widget_get_visible (bin->child))
996
GtkRequisition child_requisition;
998
gtk_widget_size_request (bin->child, &child_requisition);
1000
requisition->width += child_requisition.width;
1001
requisition->height += child_requisition.height;
1003
if (menu_item->submenu && menu_item->show_submenu_indicator)
1005
guint arrow_spacing;
1007
gtk_widget_style_get (widget,
1008
"arrow-spacing", &arrow_spacing,
1011
requisition->width += child_requisition.height;
1012
requisition->width += arrow_spacing;
1014
requisition->width = MAX (requisition->width, get_minimum_width (widget));
1017
else /* separator item */
1019
gboolean wide_separators;
1020
gint separator_height;
1022
gtk_widget_style_get (widget,
1023
"wide-separators", &wide_separators,
1024
"separator-height", &separator_height,
1027
if (wide_separators)
1028
requisition->height += separator_height + widget->style->ythickness;
1030
requisition->height += widget->style->ythickness * 2;
1034
gtk_container_foreach (GTK_CONTAINER (menu_item),
1035
gtk_menu_item_accel_width_foreach,
1037
menu_item->accelerator_width = accel_width;
1041
gtk_menu_item_size_allocate (GtkWidget *widget,
1042
GtkAllocation *allocation)
1044
GtkMenuItem *menu_item;
1046
GtkAllocation child_allocation;
1047
GtkTextDirection direction;
1048
GtkPackDirection pack_dir;
1049
GtkPackDirection child_pack_dir;
1051
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1052
g_return_if_fail (allocation != NULL);
1054
menu_item = GTK_MENU_ITEM (widget);
1055
bin = GTK_BIN (widget);
1057
direction = gtk_widget_get_direction (widget);
1059
if (GTK_IS_MENU_BAR (widget->parent))
1061
pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget->parent));
1062
child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget->parent));
1066
pack_dir = GTK_PACK_DIRECTION_LTR;
1067
child_pack_dir = GTK_PACK_DIRECTION_LTR;
1070
widget->allocation = *allocation;
1074
GtkRequisition child_requisition;
1075
guint horizontal_padding;
1077
gtk_widget_style_get (widget,
1078
"horizontal-padding", &horizontal_padding,
1081
child_allocation.x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
1082
child_allocation.y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness;
1084
if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) &&
1085
(child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL))
1086
child_allocation.x += horizontal_padding;
1087
else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
1088
(child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT))
1089
child_allocation.y += horizontal_padding;
1091
child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
1092
child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
1094
if (child_pack_dir == GTK_PACK_DIRECTION_LTR ||
1095
child_pack_dir == GTK_PACK_DIRECTION_RTL)
1097
if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL))
1098
child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
1099
child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size;
1103
if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT))
1104
child_allocation.y += GTK_MENU_ITEM (widget)->toggle_size;
1105
child_allocation.height -= GTK_MENU_ITEM (widget)->toggle_size;
1108
child_allocation.x += widget->allocation.x;
1109
child_allocation.y += widget->allocation.y;
1111
gtk_widget_get_child_requisition (bin->child, &child_requisition);
1112
if (menu_item->submenu && menu_item->show_submenu_indicator)
1114
if (direction == GTK_TEXT_DIR_RTL)
1115
child_allocation.x += child_requisition.height;
1116
child_allocation.width -= child_requisition.height;
1119
if (child_allocation.width < 1)
1120
child_allocation.width = 1;
1122
gtk_widget_size_allocate (bin->child, &child_allocation);
1125
if (gtk_widget_get_realized (widget))
1126
gdk_window_move_resize (menu_item->event_window,
1127
allocation->x, allocation->y,
1128
allocation->width, allocation->height);
1130
if (menu_item->submenu)
1131
gtk_menu_reposition (GTK_MENU (menu_item->submenu));
1135
gtk_menu_item_realize (GtkWidget *widget)
1137
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1138
GdkWindowAttr attributes;
1139
gint attributes_mask;
1141
gtk_widget_set_realized (widget, TRUE);
1143
widget->window = gtk_widget_get_parent_window (widget);
1144
g_object_ref (widget->window);
1146
attributes.x = widget->allocation.x;
1147
attributes.y = widget->allocation.y;
1148
attributes.width = widget->allocation.width;
1149
attributes.height = widget->allocation.height;
1150
attributes.window_type = GDK_WINDOW_CHILD;
1151
attributes.wclass = GDK_INPUT_ONLY;
1152
attributes.event_mask = (gtk_widget_get_events (widget) |
1153
GDK_BUTTON_PRESS_MASK |
1154
GDK_BUTTON_RELEASE_MASK |
1155
GDK_ENTER_NOTIFY_MASK |
1156
GDK_LEAVE_NOTIFY_MASK |
1157
GDK_POINTER_MOTION_MASK);
1159
attributes_mask = GDK_WA_X | GDK_WA_Y;
1160
menu_item->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
1161
gdk_window_set_user_data (menu_item->event_window, widget);
1163
widget->style = gtk_style_attach (widget->style, widget->window);
1167
gtk_menu_item_unrealize (GtkWidget *widget)
1169
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1171
gdk_window_set_user_data (menu_item->event_window, NULL);
1172
gdk_window_destroy (menu_item->event_window);
1173
menu_item->event_window = NULL;
1175
GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize (widget);
1179
gtk_menu_item_map (GtkWidget *widget)
1181
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1183
GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget);
1185
gdk_window_show (menu_item->event_window);
1189
gtk_menu_item_unmap (GtkWidget *widget)
1191
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1193
gdk_window_hide (menu_item->event_window);
1195
GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget);
1199
gtk_menu_item_paint (GtkWidget *widget,
1202
GtkMenuItem *menu_item;
1203
GtkStateType state_type;
1204
GtkShadowType shadow_type, selected_shadow_type;
1207
gint border_width = GTK_CONTAINER (widget)->border_width;
1209
if (gtk_widget_is_drawable (widget))
1211
menu_item = GTK_MENU_ITEM (widget);
1213
state_type = widget->state;
1215
x = widget->allocation.x + border_width;
1216
y = widget->allocation.y + border_width;
1217
width = widget->allocation.width - border_width * 2;
1218
height = widget->allocation.height - border_width * 2;
1220
if ((state_type == GTK_STATE_PRELIGHT) &&
1221
(GTK_BIN (menu_item)->child))
1223
gtk_widget_style_get (widget,
1224
"selected-shadow-type", &selected_shadow_type,
1226
gtk_paint_box (widget->style,
1229
selected_shadow_type,
1230
area, widget, "menuitem",
1231
x, y, width, height);
1234
if (menu_item->submenu && menu_item->show_submenu_indicator)
1236
gint arrow_x, arrow_y;
1239
guint horizontal_padding;
1240
gfloat arrow_scaling;
1241
GtkTextDirection direction;
1242
GtkArrowType arrow_type;
1243
PangoContext *context;
1244
PangoFontMetrics *metrics;
1246
direction = gtk_widget_get_direction (widget);
1248
gtk_widget_style_get (widget,
1249
"horizontal-padding", &horizontal_padding,
1250
"arrow-scaling", &arrow_scaling,
1253
context = gtk_widget_get_pango_context (GTK_BIN (menu_item)->child);
1254
metrics = pango_context_get_metrics (context,
1255
GTK_WIDGET (GTK_BIN (menu_item)->child)->style->font_desc,
1256
pango_context_get_language (context));
1258
arrow_size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
1259
pango_font_metrics_get_descent (metrics)));
1261
pango_font_metrics_unref (metrics);
1263
arrow_extent = arrow_size * arrow_scaling;
1265
shadow_type = GTK_SHADOW_OUT;
1266
if (state_type == GTK_STATE_PRELIGHT)
1267
shadow_type = GTK_SHADOW_IN;
1269
if (direction == GTK_TEXT_DIR_LTR)
1271
arrow_x = x + width - horizontal_padding - arrow_extent;
1272
arrow_type = GTK_ARROW_RIGHT;
1276
arrow_x = x + horizontal_padding;
1277
arrow_type = GTK_ARROW_LEFT;
1280
arrow_y = y + (height - arrow_extent) / 2;
1282
gtk_paint_arrow (widget->style, widget->window,
1283
state_type, shadow_type,
1284
area, widget, "menuitem",
1287
arrow_extent, arrow_extent);
1289
else if (!GTK_BIN (menu_item)->child)
1291
gboolean wide_separators;
1292
gint separator_height;
1293
guint horizontal_padding;
1295
gtk_widget_style_get (widget,
1296
"wide-separators", &wide_separators,
1297
"separator-height", &separator_height,
1298
"horizontal-padding", &horizontal_padding,
1301
if (wide_separators)
1302
gtk_paint_box (widget->style, widget->window,
1303
GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
1304
area, widget, "hseparator",
1305
widget->allocation.x + horizontal_padding + widget->style->xthickness,
1306
widget->allocation.y + (widget->allocation.height -
1308
widget->style->ythickness) / 2,
1309
widget->allocation.width -
1310
2 * (horizontal_padding + widget->style->xthickness),
1313
gtk_paint_hline (widget->style, widget->window,
1314
GTK_STATE_NORMAL, area, widget, "menuitem",
1315
widget->allocation.x + horizontal_padding + widget->style->xthickness,
1316
widget->allocation.x + widget->allocation.width - horizontal_padding - widget->style->xthickness - 1,
1317
widget->allocation.y + (widget->allocation.height -
1318
widget->style->ythickness) / 2);
1324
gtk_menu_item_expose (GtkWidget *widget,
1325
GdkEventExpose *event)
1327
g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
1328
g_return_val_if_fail (event != NULL, FALSE);
1330
if (gtk_widget_is_drawable (widget))
1332
gtk_menu_item_paint (widget, &event->area);
1334
GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->expose_event (widget, event);
1341
gtk_real_menu_item_select (GtkItem *item)
1343
GtkMenuItem *menu_item;
1344
gboolean touchscreen_mode;
1346
g_return_if_fail (GTK_IS_MENU_ITEM (item));
1348
menu_item = GTK_MENU_ITEM (item);
1350
g_object_get (gtk_widget_get_settings (GTK_WIDGET (item)),
1351
"gtk-touchscreen-mode", &touchscreen_mode,
1354
if (!touchscreen_mode &&
1355
menu_item->submenu &&
1356
(!gtk_widget_get_mapped (menu_item->submenu) ||
1357
GTK_MENU (menu_item->submenu)->tearoff_active))
1359
_gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1362
gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
1363
gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1367
gtk_real_menu_item_deselect (GtkItem *item)
1369
GtkMenuItem *menu_item;
1371
g_return_if_fail (GTK_IS_MENU_ITEM (item));
1373
menu_item = GTK_MENU_ITEM (item);
1375
if (menu_item->submenu)
1376
_gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item));
1378
gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
1379
gtk_widget_queue_draw (GTK_WIDGET (menu_item));
1383
gtk_menu_item_mnemonic_activate (GtkWidget *widget,
1384
gboolean group_cycling)
1386
if (GTK_IS_MENU_SHELL (widget->parent))
1387
_gtk_menu_shell_set_keyboard_mode (GTK_MENU_SHELL (widget->parent), TRUE);
1389
if (group_cycling &&
1391
GTK_IS_MENU_SHELL (widget->parent) &&
1392
GTK_MENU_SHELL (widget->parent)->active)
1394
gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent),
1398
g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0);
1404
gtk_real_menu_item_activate (GtkMenuItem *menu_item)
1406
GtkMenuItemPrivate *priv;
1408
priv = GET_PRIVATE (menu_item);
1411
gtk_action_activate (priv->action);
1416
gtk_real_menu_item_activate_item (GtkMenuItem *menu_item)
1418
GtkMenuItemPrivate *priv;
1421
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1423
priv = GET_PRIVATE (menu_item);
1424
widget = GTK_WIDGET (menu_item);
1426
if (widget->parent &&
1427
GTK_IS_MENU_SHELL (widget->parent))
1429
if (menu_item->submenu == NULL)
1430
gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget->parent),
1434
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget->parent);
1436
_gtk_menu_shell_activate (menu_shell);
1438
gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget);
1439
_gtk_menu_item_popup_submenu (widget, FALSE);
1441
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
1447
gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item,
1450
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1456
gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item,
1459
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1461
menu_item->toggle_size = allocation;
1465
gtk_real_menu_item_set_label (GtkMenuItem *menu_item,
1468
gtk_menu_item_ensure_label (menu_item);
1470
if (GTK_IS_LABEL (GTK_BIN (menu_item)->child))
1472
gtk_label_set_label (GTK_LABEL (GTK_BIN (menu_item)->child), label ? label : "");
1474
g_object_notify (G_OBJECT (menu_item), "label");
1478
static const gchar *
1479
gtk_real_menu_item_get_label (GtkMenuItem *menu_item)
1481
gtk_menu_item_ensure_label (menu_item);
1483
if (GTK_IS_LABEL (GTK_BIN (menu_item)->child))
1484
return gtk_label_get_label (GTK_LABEL (GTK_BIN (menu_item)->child));
1490
free_timeval (GTimeVal *val)
1492
g_slice_free (GTimeVal, val);
1496
gtk_menu_item_real_popup_submenu (GtkWidget *widget,
1497
gboolean remember_exact_time)
1499
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1501
if (gtk_widget_is_sensitive (menu_item->submenu) && widget->parent)
1503
gboolean take_focus;
1504
GtkMenuPositionFunc menu_position_func;
1506
take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent));
1507
gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),
1510
if (remember_exact_time)
1512
GTimeVal *popup_time = g_slice_new0 (GTimeVal);
1514
g_get_current_time (popup_time);
1516
g_object_set_data_full (G_OBJECT (menu_item->submenu),
1517
"gtk-menu-exact-popup-time", popup_time,
1518
(GDestroyNotify) free_timeval);
1522
g_object_set_data (G_OBJECT (menu_item->submenu),
1523
"gtk-menu-exact-popup-time", NULL);
1526
/* gtk_menu_item_position_menu positions the submenu from the
1527
* menuitems position. If the menuitem doesn't have a window,
1528
* that doesn't work. In that case we use the default
1529
* positioning function instead which places the submenu at the
1533
menu_position_func = gtk_menu_item_position_menu;
1535
menu_position_func = NULL;
1537
gtk_menu_popup (GTK_MENU (menu_item->submenu),
1542
GTK_MENU_SHELL (widget->parent)->button,
1546
/* Enable themeing of the parent menu item depending on whether
1547
* its submenu is shown or not.
1549
gtk_widget_queue_draw (widget);
1553
gtk_menu_item_popup_timeout (gpointer data)
1555
GtkMenuItem *menu_item;
1558
menu_item = GTK_MENU_ITEM (data);
1560
parent = GTK_WIDGET (menu_item)->parent;
1562
if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active) ||
1563
(GTK_IS_MENU (parent) && GTK_MENU (parent)->torn_off))
1565
gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE);
1566
if (menu_item->timer_from_keypress && menu_item->submenu)
1567
GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
1570
menu_item->timer = 0;
1576
get_popup_delay (GtkWidget *widget)
1578
if (GTK_IS_MENU_SHELL (widget->parent))
1580
return _gtk_menu_shell_get_popup_delay (GTK_MENU_SHELL (widget->parent));
1586
g_object_get (gtk_widget_get_settings (widget),
1587
"gtk-menu-popup-delay", &popup_delay,
1595
_gtk_menu_item_popup_submenu (GtkWidget *widget,
1596
gboolean with_delay)
1598
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1600
if (menu_item->timer)
1602
g_source_remove (menu_item->timer);
1603
menu_item->timer = 0;
1609
gint popup_delay = get_popup_delay (widget);
1611
if (popup_delay > 0)
1613
GdkEvent *event = gtk_get_current_event ();
1615
menu_item->timer = gdk_threads_add_timeout (popup_delay,
1616
gtk_menu_item_popup_timeout,
1620
event->type != GDK_BUTTON_PRESS &&
1621
event->type != GDK_ENTER_NOTIFY)
1622
menu_item->timer_from_keypress = TRUE;
1624
menu_item->timer_from_keypress = FALSE;
1627
gdk_event_free (event);
1633
gtk_menu_item_real_popup_submenu (widget, FALSE);
1637
_gtk_menu_item_popdown_submenu (GtkWidget *widget)
1639
GtkMenuItem *menu_item;
1641
menu_item = GTK_MENU_ITEM (widget);
1643
if (menu_item->submenu)
1645
g_object_set_data (G_OBJECT (menu_item->submenu),
1646
"gtk-menu-exact-popup-time", NULL);
1648
if (menu_item->timer)
1650
g_source_remove (menu_item->timer);
1651
menu_item->timer = 0;
1654
gtk_menu_popdown (GTK_MENU (menu_item->submenu));
1656
gtk_widget_queue_draw (widget);
1661
get_offsets (GtkMenu *menu,
1662
gint *horizontal_offset,
1663
gint *vertical_offset)
1665
gint vertical_padding;
1666
gint horizontal_padding;
1668
gtk_widget_style_get (GTK_WIDGET (menu),
1669
"horizontal-offset", horizontal_offset,
1670
"vertical-offset", vertical_offset,
1671
"horizontal-padding", &horizontal_padding,
1672
"vertical-padding", &vertical_padding,
1675
*vertical_offset -= GTK_WIDGET (menu)->style->ythickness;
1676
*vertical_offset -= vertical_padding;
1677
*horizontal_offset += horizontal_padding;
1681
gtk_menu_item_position_menu (GtkMenu *menu,
1687
GtkMenuItem *menu_item;
1689
GtkMenuItem *parent_menu_item;
1691
gint twidth, theight;
1693
GtkTextDirection direction;
1694
GdkRectangle monitor;
1696
gint horizontal_offset;
1697
gint vertical_offset;
1698
gint parent_xthickness;
1699
gint available_left, available_right;
1701
g_return_if_fail (menu != NULL);
1702
g_return_if_fail (x != NULL);
1703
g_return_if_fail (y != NULL);
1705
menu_item = GTK_MENU_ITEM (user_data);
1706
widget = GTK_WIDGET (user_data);
1711
direction = gtk_widget_get_direction (widget);
1713
twidth = GTK_WIDGET (menu)->requisition.width;
1714
theight = GTK_WIDGET (menu)->requisition.height;
1716
screen = gtk_widget_get_screen (GTK_WIDGET (menu));
1717
monitor_num = gdk_screen_get_monitor_at_window (screen, menu_item->event_window);
1718
if (monitor_num < 0)
1720
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1722
if (!gdk_window_get_origin (widget->window, &tx, &ty))
1724
g_warning ("Menu not on screen");
1728
tx += widget->allocation.x;
1729
ty += widget->allocation.y;
1731
get_offsets (menu, &horizontal_offset, &vertical_offset);
1733
available_left = tx - monitor.x;
1734
available_right = monitor.x + monitor.width - (tx + widget->allocation.width);
1736
if (GTK_IS_MENU_BAR (widget->parent))
1738
menu_item->from_menubar = TRUE;
1740
else if (GTK_IS_MENU (widget->parent))
1742
if (GTK_MENU (widget->parent)->parent_menu_item)
1743
menu_item->from_menubar = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item)->from_menubar;
1745
menu_item->from_menubar = FALSE;
1749
menu_item->from_menubar = FALSE;
1752
switch (menu_item->submenu_placement)
1754
case GTK_TOP_BOTTOM:
1755
if (direction == GTK_TEXT_DIR_LTR)
1756
menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1759
menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1760
tx += widget->allocation.width - twidth;
1762
if ((ty + widget->allocation.height + theight) <= monitor.y + monitor.height)
1763
ty += widget->allocation.height;
1764
else if ((ty - theight) >= monitor.y)
1766
else if (monitor.y + monitor.height - (ty + widget->allocation.height) > ty)
1767
ty += widget->allocation.height;
1772
case GTK_LEFT_RIGHT:
1773
if (GTK_IS_MENU (widget->parent))
1774
parent_menu_item = GTK_MENU_ITEM (GTK_MENU (widget->parent)->parent_menu_item);
1776
parent_menu_item = NULL;
1778
parent_xthickness = widget->parent->style->xthickness;
1780
if (parent_menu_item && !GTK_MENU (widget->parent)->torn_off)
1782
menu_item->submenu_direction = parent_menu_item->submenu_direction;
1786
if (direction == GTK_TEXT_DIR_LTR)
1787
menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1789
menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1792
switch (menu_item->submenu_direction)
1794
case GTK_DIRECTION_LEFT:
1795
if (tx - twidth - parent_xthickness - horizontal_offset >= monitor.x ||
1796
available_left >= available_right)
1797
tx -= twidth + parent_xthickness + horizontal_offset;
1800
menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
1801
tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1805
case GTK_DIRECTION_RIGHT:
1806
if (tx + widget->allocation.width + parent_xthickness + horizontal_offset + twidth <= monitor.x + monitor.width ||
1807
available_right >= available_left)
1808
tx += widget->allocation.width + parent_xthickness + horizontal_offset;
1811
menu_item->submenu_direction = GTK_DIRECTION_LEFT;
1812
tx -= twidth + parent_xthickness + horizontal_offset;
1817
ty += vertical_offset;
1819
/* If the height of the menu doesn't fit we move it upward. */
1820
ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight));
1824
/* If we have negative, tx, here it is because we can't get
1825
* the menu all the way on screen. Favor the left portion.
1827
*x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
1830
gtk_menu_set_monitor (menu, monitor_num);
1832
if (!gtk_widget_get_visible (menu->toplevel))
1834
gtk_window_set_type_hint (GTK_WINDOW (menu->toplevel), menu_item->from_menubar?
1835
GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU);
1840
* gtk_menu_item_set_right_justified:
1841
* @menu_item: a #GtkMenuItem.
1842
* @right_justified: if %TRUE the menu item will appear at the
1843
* far right if added to a menu bar.
1845
* Sets whether the menu item appears justified at the right
1846
* side of a menu bar. This was traditionally done for "Help" menu
1847
* items, but is now considered a bad idea. (If the widget
1848
* layout is reversed for a right-to-left language like Hebrew
1849
* or Arabic, right-justified-menu-items appear at the left.)
1852
gtk_menu_item_set_right_justified (GtkMenuItem *menu_item,
1853
gboolean right_justified)
1855
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1857
right_justified = right_justified != FALSE;
1859
if (right_justified != menu_item->right_justify)
1861
menu_item->right_justify = right_justified;
1862
gtk_widget_queue_resize (GTK_WIDGET (menu_item));
1867
* gtk_menu_item_get_right_justified:
1868
* @menu_item: a #GtkMenuItem
1870
* Gets whether the menu item appears justified at the right
1871
* side of the menu bar.
1873
* Return value: %TRUE if the menu item will appear at the
1874
* far right if added to a menu bar.
1877
gtk_menu_item_get_right_justified (GtkMenuItem *menu_item)
1879
g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
1881
return menu_item->right_justify;
1886
gtk_menu_item_show_all (GtkWidget *widget)
1888
GtkMenuItem *menu_item;
1890
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1892
menu_item = GTK_MENU_ITEM (widget);
1894
/* show children including submenu */
1895
if (menu_item->submenu)
1896
gtk_widget_show_all (menu_item->submenu);
1897
gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1899
gtk_widget_show (widget);
1903
gtk_menu_item_hide_all (GtkWidget *widget)
1905
GtkMenuItem *menu_item;
1907
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
1909
gtk_widget_hide (widget);
1911
menu_item = GTK_MENU_ITEM (widget);
1913
/* hide children including submenu */
1914
gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);
1915
if (menu_item->submenu)
1916
gtk_widget_hide_all (menu_item->submenu);
1920
gtk_menu_item_can_activate_accel (GtkWidget *widget,
1923
/* Chain to the parent GtkMenu for further checks */
1924
return (gtk_widget_is_sensitive (widget) && gtk_widget_get_visible (widget) &&
1925
widget->parent && gtk_widget_can_activate_accel (widget->parent, signal_id));
1929
gtk_menu_item_accel_name_foreach (GtkWidget *widget,
1932
const gchar **path_p = data;
1936
if (GTK_IS_LABEL (widget))
1938
*path_p = gtk_label_get_text (GTK_LABEL (widget));
1939
if (*path_p && (*path_p)[0] == 0)
1942
else if (GTK_IS_CONTAINER (widget))
1943
gtk_container_foreach (GTK_CONTAINER (widget),
1944
gtk_menu_item_accel_name_foreach,
1950
gtk_menu_item_parent_set (GtkWidget *widget,
1951
GtkWidget *previous_parent)
1953
GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
1954
GtkMenu *menu = GTK_IS_MENU (widget->parent) ? GTK_MENU (widget->parent) : NULL;
1957
_gtk_menu_item_refresh_accel_path (menu_item,
1962
if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set)
1963
GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent);
1967
_gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item,
1968
const gchar *prefix,
1969
GtkAccelGroup *accel_group,
1970
gboolean group_changed)
1975
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1976
g_return_if_fail (!accel_group || GTK_IS_ACCEL_GROUP (accel_group));
1978
widget = GTK_WIDGET (menu_item);
1982
gtk_widget_set_accel_path (widget, NULL, NULL);
1986
path = _gtk_widget_get_accel_path (widget, NULL);
1987
if (!path) /* no active accel_path yet */
1989
path = menu_item->accel_path;
1990
if (!path && prefix)
1992
const gchar *postfix = NULL;
1995
/* try to construct one from label text */
1996
gtk_container_foreach (GTK_CONTAINER (menu_item),
1997
gtk_menu_item_accel_name_foreach,
2001
new_path = g_strconcat (prefix, "/", postfix, NULL);
2002
path = menu_item->accel_path = (char*)g_intern_string (new_path);
2007
gtk_widget_set_accel_path (widget, path, accel_group);
2009
else if (group_changed) /* reinstall accelerators */
2010
gtk_widget_set_accel_path (widget, path, accel_group);
2014
* gtk_menu_item_set_accel_path
2015
* @menu_item: a valid #GtkMenuItem
2016
* @accel_path: (allow-none): accelerator path, corresponding to this menu item's
2017
* functionality, or %NULL to unset the current path.
2019
* Set the accelerator path on @menu_item, through which runtime changes of the
2020
* menu item's accelerator caused by the user can be identified and saved to
2021
* persistant storage (see gtk_accel_map_save() on this).
2022
* To setup a default accelerator for this menu item, call
2023
* gtk_accel_map_add_entry() with the same @accel_path.
2024
* See also gtk_accel_map_add_entry() on the specifics of accelerator paths,
2025
* and gtk_menu_set_accel_path() for a more convenient variant of this function.
2027
* This function is basically a convenience wrapper that handles calling
2028
* gtk_widget_set_accel_path() with the appropriate accelerator group for
2031
* Note that you do need to set an accelerator on the parent menu with
2032
* gtk_menu_set_accel_group() for this to work.
2034
* Note that @accel_path string will be stored in a #GQuark. Therefore, if you
2035
* pass a static string, you can save some memory by interning it first with
2036
* g_intern_static_string().
2039
gtk_menu_item_set_accel_path (GtkMenuItem *menu_item,
2040
const gchar *accel_path)
2044
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2045
g_return_if_fail (accel_path == NULL ||
2046
(accel_path[0] == '<' && strchr (accel_path, '/')));
2048
widget = GTK_WIDGET (menu_item);
2050
/* store new path */
2051
menu_item->accel_path = (char*)g_intern_string (accel_path);
2053
/* forget accelerators associated with old path */
2054
gtk_widget_set_accel_path (widget, NULL, NULL);
2056
/* install accelerators associated with new path */
2057
if (GTK_IS_MENU (widget->parent))
2059
GtkMenu *menu = GTK_MENU (widget->parent);
2061
if (menu->accel_group)
2062
_gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget),
2070
* gtk_menu_item_get_accel_path
2071
* @menu_item: a valid #GtkMenuItem
2073
* Retrieve the accelerator path that was previously set on @menu_item.
2075
* See gtk_menu_item_set_accel_path() for details.
2077
* Returns: the accelerator path corresponding to this menu item's
2078
* functionality, or %NULL if not set
2083
gtk_menu_item_get_accel_path (GtkMenuItem *menu_item)
2085
g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2087
return menu_item->accel_path;
2091
gtk_menu_item_forall (GtkContainer *container,
2092
gboolean include_internals,
2093
GtkCallback callback,
2094
gpointer callback_data)
2098
g_return_if_fail (GTK_IS_MENU_ITEM (container));
2099
g_return_if_fail (callback != NULL);
2101
bin = GTK_BIN (container);
2104
callback (bin->child, callback_data);
2108
_gtk_menu_item_is_selectable (GtkWidget *menu_item)
2110
if ((!GTK_BIN (menu_item)->child &&
2111
G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
2112
GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
2113
!gtk_widget_is_sensitive (menu_item) ||
2114
!gtk_widget_get_visible (menu_item))
2121
gtk_menu_item_ensure_label (GtkMenuItem *menu_item)
2123
GtkWidget *accel_label;
2125
if (!GTK_BIN (menu_item)->child)
2127
accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
2128
gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
2130
gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
2131
gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label),
2132
GTK_WIDGET (menu_item));
2133
gtk_widget_show (accel_label);
2138
* gtk_menu_item_set_label:
2139
* @menu_item: a #GtkMenuItem
2140
* @label: the text you want to set
2142
* Sets @text on the @menu_item label
2147
gtk_menu_item_set_label (GtkMenuItem *menu_item,
2150
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2152
GTK_MENU_ITEM_GET_CLASS (menu_item)->set_label (menu_item, label);
2156
* gtk_menu_item_get_label:
2157
* @menu_item: a #GtkMenuItem
2159
* Sets @text on the @menu_item label
2161
* Returns: The text in the @menu_item label. This is the internal
2162
* string used by the label, and must not be modified.
2167
gtk_menu_item_get_label (GtkMenuItem *menu_item)
2169
g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL);
2171
return GTK_MENU_ITEM_GET_CLASS (menu_item)->get_label (menu_item);
2175
* gtk_menu_item_set_use_underline:
2176
* @menu_item: a #GtkMenuItem
2177
* @setting: %TRUE if underlines in the text indicate mnemonics
2179
* If true, an underline in the text indicates the next character should be
2180
* used for the mnemonic accelerator key.
2185
gtk_menu_item_set_use_underline (GtkMenuItem *menu_item,
2188
g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
2190
gtk_menu_item_ensure_label (menu_item);
2192
if (GTK_IS_LABEL (GTK_BIN (menu_item)->child))
2194
gtk_label_set_use_underline (GTK_LABEL (GTK_BIN (menu_item)->child), setting);
2196
g_object_notify (G_OBJECT (menu_item), "use-underline");
2201
* gtk_menu_item_get_use_underline:
2202
* @menu_item: a #GtkMenuItem
2204
* Checks if an underline in the text indicates the next character should be
2205
* used for the mnemonic accelerator key.
2207
* Return value: %TRUE if an embedded underline in the label indicates
2208
* the mnemonic accelerator key.
2213
gtk_menu_item_get_use_underline (GtkMenuItem *menu_item)
2215
g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE);
2217
gtk_menu_item_ensure_label (menu_item);
2219
if (GTK_IS_LABEL (GTK_BIN (menu_item)->child))
2220
return gtk_label_get_use_underline (GTK_LABEL (GTK_BIN (menu_item)->child));
2227
#define __GTK_MENU_ITEM_C__
2228
#include "gtkaliasdef.c"