]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenushell.c
Merge branch 'master' into broadway2
[~andy/gtk] / gtk / gtkmenushell.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 /**
28  * SECTION:gtkmenushell
29  * @Title: GtkMenuShell
30  * @Short_description: A base class for menu objects
31  *
32  * A #GtkMenuShell is the abstract base class used to derive the
33  * #GtkMenu and #GtkMenuBar subclasses.
34  *
35  * A #GtkMenuShell is a container of #GtkMenuItem objects arranged
36  * in a list which can be navigated, selected, and activated by the
37  * user to perform application functions. A #GtkMenuItem can have a
38  * submenu associated with it, allowing for nested hierarchical menus.
39  */
40 #include "config.h"
41
42 #include "gtkbindings.h"
43 #include "gtkkeyhash.h"
44 #include "gtklabel.h"
45 #include "gtkmainprivate.h"
46 #include "gtkmarshalers.h"
47 #include "gtkmenubar.h"
48 #include "gtkmenuitemprivate.h"
49 #include "gtkmenushellprivate.h"
50 #include "gtkmenuprivate.h"
51 #include "gtkmnemonichash.h"
52 #include "gtktearoffmenuitem.h"
53 #include "gtkwindow.h"
54 #include "gtkprivate.h"
55 #include "gtkintl.h"
56 #include "gtktypebuiltins.h"
57
58 #define MENU_SHELL_TIMEOUT   500
59
60 #define PACK_DIRECTION(m)                                 \
61    (GTK_IS_MENU_BAR (m)                                   \
62      ? gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (m)) \
63      : GTK_PACK_DIRECTION_LTR)
64
65 enum {
66   DEACTIVATE,
67   SELECTION_DONE,
68   MOVE_CURRENT,
69   ACTIVATE_CURRENT,
70   CANCEL,
71   CYCLE_FOCUS,
72   MOVE_SELECTED,
73   LAST_SIGNAL
74 };
75
76 enum {
77   PROP_0,
78   PROP_TAKE_FOCUS
79 };
80
81 /* Terminology:
82  * 
83  * A menu item can be "selected", this means that it is displayed
84  * in the prelight state, and if it has a submenu, that submenu
85  * will be popped up. 
86  * 
87  * A menu is "active" when it is visible onscreen and the user
88  * is selecting from it. A menubar is not active until the user
89  * clicks on one of its menuitems. When a menu is active,
90  * passing the mouse over a submenu will pop it up.
91  *
92  * menu_shell->active_menu_item, is however, not an "active"
93  * menu item (there is no such thing) but rather, the selected
94  * menu item in that MenuShell, if there is one.
95  *
96  * There is also is a concept of the current menu and a current
97  * menu item. The current menu item is the selected menu item
98  * that is furthest down in the hierarchy. (Every active menu_shell
99  * does not necessarily contain a selected menu item, but if
100  * it does, then menu_shell->parent_menu_shell must also contain
101  * a selected menu item. The current menu is the menu that 
102  * contains the current menu_item. It will always have a GTK
103  * grab and receive all key presses.
104  *
105  *
106  * Action signals:
107  *
108  *  ::move_current (GtkMenuDirection *dir)
109  *     Moves the current menu item in direction 'dir':
110  *
111  *       GTK_MENU_DIR_PARENT: To the parent menu shell
112  *       GTK_MENU_DIR_CHILD: To the child menu shell (if this item has
113  *          a submenu.
114  *       GTK_MENU_DIR_NEXT/PREV: To the next or previous item
115  *          in this menu.
116  * 
117  *     As a a bit of a hack to get movement between menus and
118  *     menubars working, if submenu_placement is different for
119  *     the menu and its MenuShell then the following apply:
120  * 
121  *       - For 'parent' the current menu is not just moved to
122  *         the parent, but moved to the previous entry in the parent
123  *       - For 'child', if there is no child, then current is
124  *         moved to the next item in the parent.
125  *
126  *    Note that the above explanation of ::move_current was written
127  *    before menus and menubars had support for RTL flipping and
128  *    different packing directions, and therefore only applies for
129  *    when text direction and packing direction are both left-to-right.
130  * 
131  *  ::activate_current (GBoolean *force_hide)
132  *     Activate the current item. If 'force_hide' is true, hide
133  *     the current menu item always. Otherwise, only hide
134  *     it if menu_item->klass->hide_on_activate is true.
135  *
136  *  ::cancel ()
137  *     Cancels the current selection
138  */
139
140
141 static void gtk_menu_shell_set_property      (GObject           *object,
142                                               guint              prop_id,
143                                               const GValue      *value,
144                                               GParamSpec        *pspec);
145 static void gtk_menu_shell_get_property      (GObject           *object,
146                                               guint              prop_id,
147                                               GValue            *value,
148                                               GParamSpec        *pspec);
149 static void gtk_menu_shell_realize           (GtkWidget         *widget);
150 static void gtk_menu_shell_finalize          (GObject           *object);
151 static void gtk_menu_shell_dispose           (GObject           *object);
152 static gint gtk_menu_shell_button_press      (GtkWidget         *widget,
153                                               GdkEventButton    *event);
154 static gint gtk_menu_shell_button_release    (GtkWidget         *widget,
155                                               GdkEventButton    *event);
156 static gint gtk_menu_shell_key_press         (GtkWidget         *widget,
157                                               GdkEventKey       *event);
158 static gint gtk_menu_shell_enter_notify      (GtkWidget         *widget,
159                                               GdkEventCrossing  *event);
160 static gint gtk_menu_shell_leave_notify      (GtkWidget         *widget,
161                                               GdkEventCrossing  *event);
162 static void gtk_menu_shell_screen_changed    (GtkWidget         *widget,
163                                               GdkScreen         *previous_screen);
164 static gboolean gtk_menu_shell_grab_broken       (GtkWidget         *widget,
165                                               GdkEventGrabBroken *event);
166 static void gtk_menu_shell_add               (GtkContainer      *container,
167                                               GtkWidget         *widget);
168 static void gtk_menu_shell_remove            (GtkContainer      *container,
169                                               GtkWidget         *widget);
170 static void gtk_menu_shell_forall            (GtkContainer      *container,
171                                               gboolean           include_internals,
172                                               GtkCallback        callback,
173                                               gpointer           callback_data);
174 static void gtk_menu_shell_real_insert       (GtkMenuShell *menu_shell,
175                                               GtkWidget    *child,
176                                               gint          position);
177 static void gtk_real_menu_shell_deactivate   (GtkMenuShell      *menu_shell);
178 static gint gtk_menu_shell_is_item           (GtkMenuShell      *menu_shell,
179                                               GtkWidget         *child);
180 static GtkWidget *gtk_menu_shell_get_item    (GtkMenuShell      *menu_shell,
181                                               GdkEvent          *event);
182 static GType    gtk_menu_shell_child_type  (GtkContainer      *container);
183 static void gtk_menu_shell_real_select_item  (GtkMenuShell      *menu_shell,
184                                               GtkWidget         *menu_item);
185 static gboolean gtk_menu_shell_select_submenu_first (GtkMenuShell   *menu_shell); 
186
187 static void gtk_real_menu_shell_move_current (GtkMenuShell      *menu_shell,
188                                               GtkMenuDirectionType direction);
189 static void gtk_real_menu_shell_activate_current (GtkMenuShell      *menu_shell,
190                                                   gboolean           force_hide);
191 static void gtk_real_menu_shell_cancel           (GtkMenuShell      *menu_shell);
192 static void gtk_real_menu_shell_cycle_focus      (GtkMenuShell      *menu_shell,
193                                                   GtkDirectionType   dir);
194
195 static void     gtk_menu_shell_reset_key_hash    (GtkMenuShell *menu_shell);
196 static gboolean gtk_menu_shell_activate_mnemonic (GtkMenuShell *menu_shell,
197                                                   GdkEventKey  *event);
198 static gboolean gtk_menu_shell_real_move_selected (GtkMenuShell  *menu_shell, 
199                                                    gint           distance);
200
201 static guint menu_shell_signals[LAST_SIGNAL] = { 0 };
202
203 G_DEFINE_ABSTRACT_TYPE (GtkMenuShell, gtk_menu_shell, GTK_TYPE_CONTAINER)
204
205 static void
206 gtk_menu_shell_class_init (GtkMenuShellClass *klass)
207 {
208   GObjectClass *object_class;
209   GtkWidgetClass *widget_class;
210   GtkContainerClass *container_class;
211
212   GtkBindingSet *binding_set;
213
214   object_class = (GObjectClass*) klass;
215   widget_class = (GtkWidgetClass*) klass;
216   container_class = (GtkContainerClass*) klass;
217
218   object_class->set_property = gtk_menu_shell_set_property;
219   object_class->get_property = gtk_menu_shell_get_property;
220   object_class->finalize = gtk_menu_shell_finalize;
221   object_class->dispose = gtk_menu_shell_dispose;
222
223   widget_class->realize = gtk_menu_shell_realize;
224   widget_class->button_press_event = gtk_menu_shell_button_press;
225   widget_class->button_release_event = gtk_menu_shell_button_release;
226   widget_class->grab_broken_event = gtk_menu_shell_grab_broken;
227   widget_class->key_press_event = gtk_menu_shell_key_press;
228   widget_class->enter_notify_event = gtk_menu_shell_enter_notify;
229   widget_class->leave_notify_event = gtk_menu_shell_leave_notify;
230   widget_class->screen_changed = gtk_menu_shell_screen_changed;
231
232   container_class->add = gtk_menu_shell_add;
233   container_class->remove = gtk_menu_shell_remove;
234   container_class->forall = gtk_menu_shell_forall;
235   container_class->child_type = gtk_menu_shell_child_type;
236
237   klass->submenu_placement = GTK_TOP_BOTTOM;
238   klass->deactivate = gtk_real_menu_shell_deactivate;
239   klass->selection_done = NULL;
240   klass->move_current = gtk_real_menu_shell_move_current;
241   klass->activate_current = gtk_real_menu_shell_activate_current;
242   klass->cancel = gtk_real_menu_shell_cancel;
243   klass->select_item = gtk_menu_shell_real_select_item;
244   klass->insert = gtk_menu_shell_real_insert;
245   klass->move_selected = gtk_menu_shell_real_move_selected;
246
247   /**
248    * GtkMenuShell::deactivate:
249    * @menushell: the object which received the signal
250    *
251    * This signal is emitted when a menu shell is deactivated.
252    */
253   menu_shell_signals[DEACTIVATE] =
254     g_signal_new (I_("deactivate"),
255                   G_OBJECT_CLASS_TYPE (object_class),
256                   G_SIGNAL_RUN_FIRST,
257                   G_STRUCT_OFFSET (GtkMenuShellClass, deactivate),
258                   NULL, NULL,
259                   _gtk_marshal_VOID__VOID,
260                   G_TYPE_NONE, 0);
261
262   /**
263    * GtkMenuShell::selection-done:
264    * @menushell: the object which received the signal
265    *
266    * This signal is emitted when a selection has been
267    * completed within a menu shell.
268    */
269   menu_shell_signals[SELECTION_DONE] =
270     g_signal_new (I_("selection-done"),
271                   G_OBJECT_CLASS_TYPE (object_class),
272                   G_SIGNAL_RUN_FIRST,
273                   G_STRUCT_OFFSET (GtkMenuShellClass, selection_done),
274                   NULL, NULL,
275                   _gtk_marshal_VOID__VOID,
276                   G_TYPE_NONE, 0);
277
278   /**
279    * GtkMenuShell::move-current:
280    * @menushell: the object which received the signal
281    * @direction: the direction to move
282    *
283    * An keybinding signal which moves the current menu item
284    * in the direction specified by @direction.
285    */
286   menu_shell_signals[MOVE_CURRENT] =
287     g_signal_new (I_("move-current"),
288                   G_OBJECT_CLASS_TYPE (object_class),
289                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
290                   G_STRUCT_OFFSET (GtkMenuShellClass, move_current),
291                   NULL, NULL,
292                   _gtk_marshal_VOID__ENUM,
293                   G_TYPE_NONE, 1,
294                   GTK_TYPE_MENU_DIRECTION_TYPE);
295
296   /**
297    * GtkMenuShell::activate-current:
298    * @menushell: the object which received the signal
299    * @force_hide: if %TRUE, hide the menu after activating the menu item
300    *
301    * An action signal that activates the current menu item within
302    * the menu shell.
303    */
304   menu_shell_signals[ACTIVATE_CURRENT] =
305     g_signal_new (I_("activate-current"),
306                   G_OBJECT_CLASS_TYPE (object_class),
307                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
308                   G_STRUCT_OFFSET (GtkMenuShellClass, activate_current),
309                   NULL, NULL,
310                   _gtk_marshal_VOID__BOOLEAN,
311                   G_TYPE_NONE, 1,
312                   G_TYPE_BOOLEAN);
313
314   /**
315    * GtkMenuShell::cancel:
316    * @menushell: the object which received the signal
317    *
318    * An action signal which cancels the selection within the menu shell.
319    * Causes the #GtkMenuShell::selection-done signal to be emitted.
320    */
321   menu_shell_signals[CANCEL] =
322     g_signal_new (I_("cancel"),
323                   G_OBJECT_CLASS_TYPE (object_class),
324                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
325                   G_STRUCT_OFFSET (GtkMenuShellClass, cancel),
326                   NULL, NULL,
327                   _gtk_marshal_VOID__VOID,
328                   G_TYPE_NONE, 0);
329
330   /**
331    * GtkMenuShell::cycle-focus:
332    * @menushell: the object which received the signal
333    * @direction: the direction to cycle in
334    *
335    * A keybinding signal which moves the focus in the
336    * given @direction.
337    */
338   menu_shell_signals[CYCLE_FOCUS] =
339     g_signal_new_class_handler (I_("cycle-focus"),
340                                 G_OBJECT_CLASS_TYPE (object_class),
341                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
342                                 G_CALLBACK (gtk_real_menu_shell_cycle_focus),
343                                 NULL, NULL,
344                                 _gtk_marshal_VOID__ENUM,
345                                 G_TYPE_NONE, 1,
346                                 GTK_TYPE_DIRECTION_TYPE);
347
348   /**
349    * GtkMenuShell::move-selected:
350    * @menu_shell: the object on which the signal is emitted
351    * @distance: +1 to move to the next item, -1 to move to the previous
352    *
353    * The ::move-selected signal is emitted to move the selection to
354    * another item.
355    *
356    * Returns: %TRUE to stop the signal emission, %FALSE to continue
357    *
358    * Since: 2.12
359    */
360   menu_shell_signals[MOVE_SELECTED] =
361     g_signal_new (I_("move-selected"),
362                   G_OBJECT_CLASS_TYPE (object_class),
363                   G_SIGNAL_RUN_LAST,
364                   G_STRUCT_OFFSET (GtkMenuShellClass, move_selected),
365                   _gtk_boolean_handled_accumulator, NULL,
366                   _gtk_marshal_BOOLEAN__INT,
367                   G_TYPE_BOOLEAN, 1,
368                   G_TYPE_INT);
369
370   binding_set = gtk_binding_set_by_class (klass);
371   gtk_binding_entry_add_signal (binding_set,
372                                 GDK_KEY_Escape, 0,
373                                 "cancel", 0);
374   gtk_binding_entry_add_signal (binding_set,
375                                 GDK_KEY_Return, 0,
376                                 "activate-current", 1,
377                                 G_TYPE_BOOLEAN,
378                                 TRUE);
379   gtk_binding_entry_add_signal (binding_set,
380                                 GDK_KEY_ISO_Enter, 0,
381                                 "activate-current", 1,
382                                 G_TYPE_BOOLEAN,
383                                 TRUE);
384   gtk_binding_entry_add_signal (binding_set,
385                                 GDK_KEY_KP_Enter, 0,
386                                 "activate-current", 1,
387                                 G_TYPE_BOOLEAN,
388                                 TRUE);
389   gtk_binding_entry_add_signal (binding_set,
390                                 GDK_KEY_space, 0,
391                                 "activate-current", 1,
392                                 G_TYPE_BOOLEAN,
393                                 FALSE);
394   gtk_binding_entry_add_signal (binding_set,
395                                 GDK_KEY_KP_Space, 0,
396                                 "activate-current", 1,
397                                 G_TYPE_BOOLEAN,
398                                 FALSE);
399   gtk_binding_entry_add_signal (binding_set,
400                                 GDK_KEY_F10, 0,
401                                 "cycle-focus", 1,
402                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_FORWARD);
403   gtk_binding_entry_add_signal (binding_set,
404                                 GDK_KEY_F10, GDK_SHIFT_MASK,
405                                 "cycle-focus", 1,
406                                 GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD);
407
408   /**
409    * GtkMenuShell:take-focus:
410    *
411    * A boolean that determines whether the menu and its submenus grab the
412    * keyboard focus. See gtk_menu_shell_set_take_focus() and
413    * gtk_menu_shell_get_take_focus().
414    *
415    * Since: 2.8
416    **/
417   g_object_class_install_property (object_class,
418                                    PROP_TAKE_FOCUS,
419                                    g_param_spec_boolean ("take-focus",
420                                                          P_("Take Focus"),
421                                                          P_("A boolean that determines whether the menu grabs the keyboard focus"),
422                                                          TRUE,
423                                                          GTK_PARAM_READWRITE));
424
425   g_type_class_add_private (object_class, sizeof (GtkMenuShellPrivate));
426 }
427
428 static GType
429 gtk_menu_shell_child_type (GtkContainer *container)
430 {
431   return GTK_TYPE_MENU_ITEM;
432 }
433
434 static void
435 gtk_menu_shell_init (GtkMenuShell *menu_shell)
436 {
437   GtkMenuShellPrivate *priv;
438
439   priv = G_TYPE_INSTANCE_GET_PRIVATE (menu_shell,
440                                       GTK_TYPE_MENU_SHELL,
441                                       GtkMenuShellPrivate);
442   menu_shell->priv = priv;
443   priv->take_focus = TRUE;
444 }
445
446 static void
447 gtk_menu_shell_set_property (GObject      *object,
448                              guint         prop_id,
449                              const GValue *value,
450                              GParamSpec   *pspec)
451 {
452   GtkMenuShell *menu_shell = GTK_MENU_SHELL (object);
453
454   switch (prop_id)
455     {
456     case PROP_TAKE_FOCUS:
457       gtk_menu_shell_set_take_focus (menu_shell, g_value_get_boolean (value));
458       break;
459     default:
460       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
461       break;
462     }
463 }
464
465 static void
466 gtk_menu_shell_get_property (GObject    *object,
467                              guint       prop_id,
468                              GValue     *value,
469                              GParamSpec *pspec)
470 {
471   GtkMenuShell *menu_shell = GTK_MENU_SHELL (object);
472
473   switch (prop_id)
474     {
475     case PROP_TAKE_FOCUS:
476       g_value_set_boolean (value, gtk_menu_shell_get_take_focus (menu_shell));
477       break;
478     default:
479       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
480       break;
481     }
482 }
483
484 static void
485 gtk_menu_shell_finalize (GObject *object)
486 {
487   GtkMenuShell *menu_shell = GTK_MENU_SHELL (object);
488   GtkMenuShellPrivate *priv = menu_shell->priv;
489
490   if (priv->mnemonic_hash)
491     _gtk_mnemonic_hash_free (priv->mnemonic_hash);
492   if (priv->key_hash)
493     _gtk_key_hash_free (priv->key_hash);
494
495   G_OBJECT_CLASS (gtk_menu_shell_parent_class)->finalize (object);
496 }
497
498
499 static void
500 gtk_menu_shell_dispose (GObject *object)
501 {
502   gtk_menu_shell_deactivate (GTK_MENU_SHELL (object));
503
504   G_OBJECT_CLASS (gtk_menu_shell_parent_class)->dispose (object);
505 }
506
507 /**
508  * gtk_menu_shell_append:
509  * @menu_shell: a #GtkMenuShell
510  * @child: The #GtkMenuItem to add
511  *
512  * Adds a new #GtkMenuItem to the end of the menu shell's
513  * item list.
514  */
515 void
516 gtk_menu_shell_append (GtkMenuShell *menu_shell,
517                        GtkWidget    *child)
518 {
519   gtk_menu_shell_insert (menu_shell, child, -1);
520 }
521
522 /**
523  * gtk_menu_shell_prepend:
524  * @menu_shell: a #GtkMenuShell
525  * @child: The #GtkMenuItem to add
526  *
527  * Adds a new #GtkMenuItem to the beginning of the menu shell's
528  * item list.
529  */
530 void
531 gtk_menu_shell_prepend (GtkMenuShell *menu_shell,
532                         GtkWidget    *child)
533 {
534   gtk_menu_shell_insert (menu_shell, child, 0);
535 }
536
537 /**
538  * gtk_menu_shell_insert:
539  * @menu_shell: a #GtkMenuShell
540  * @child: The #GtkMenuItem to add
541  * @position: The position in the item list where @child
542  *     is added. Positions are numbered from 0 to n-1
543  *
544  * Adds a new #GtkMenuItem to the menu shell's item list
545  * at the position indicated by @position.
546  */
547 void
548 gtk_menu_shell_insert (GtkMenuShell *menu_shell,
549                        GtkWidget    *child,
550                        gint          position)
551 {
552   GtkMenuShellClass *class;
553
554   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
555   g_return_if_fail (GTK_IS_MENU_ITEM (child));
556
557   class = GTK_MENU_SHELL_GET_CLASS (menu_shell);
558
559   if (class->insert)
560     class->insert (menu_shell, child, position);
561 }
562
563 static void
564 gtk_menu_shell_real_insert (GtkMenuShell *menu_shell,
565                             GtkWidget    *child,
566                             gint          position)
567 {
568   GtkMenuShellPrivate *priv = menu_shell->priv;
569
570   priv->children = g_list_insert (priv->children, child, position);
571
572   gtk_widget_set_parent (child, GTK_WIDGET (menu_shell));
573 }
574
575 /**
576  * gtk_menu_shell_deactivate:
577  * @menu_shell: a #GtkMenuShell
578  *
579  * Deactivates the menu shell.
580  *
581  * Typically this results in the menu shell being erased
582  * from the screen.
583  */
584 void
585 gtk_menu_shell_deactivate (GtkMenuShell *menu_shell)
586 {
587   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
588
589   g_signal_emit (menu_shell, menu_shell_signals[DEACTIVATE], 0);
590 }
591
592 static void
593 gtk_menu_shell_realize (GtkWidget *widget)
594 {
595   GtkAllocation allocation;
596   GdkWindow *window;
597   GdkWindowAttr attributes;
598   gint attributes_mask;
599   GtkStyleContext *context;
600
601   gtk_widget_set_realized (widget, TRUE);
602
603   gtk_widget_get_allocation (widget, &allocation);
604
605   attributes.x = allocation.x;
606   attributes.y = allocation.y;
607   attributes.width = allocation.width;
608   attributes.height = allocation.height;
609   attributes.window_type = GDK_WINDOW_CHILD;
610   attributes.wclass = GDK_INPUT_OUTPUT;
611   attributes.visual = gtk_widget_get_visual (widget);
612   attributes.event_mask = gtk_widget_get_events (widget);
613   attributes.event_mask |= (GDK_EXPOSURE_MASK |
614                             GDK_BUTTON_PRESS_MASK |
615                             GDK_BUTTON_RELEASE_MASK |
616                             GDK_KEY_PRESS_MASK |
617                             GDK_ENTER_NOTIFY_MASK |
618                             GDK_LEAVE_NOTIFY_MASK);
619
620   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
621
622   window = gdk_window_new (gtk_widget_get_parent_window (widget),
623                            &attributes, attributes_mask);
624   gtk_widget_set_window (widget, window);
625   gdk_window_set_user_data (window, widget);
626
627   context = gtk_widget_get_style_context (widget);
628   gtk_style_context_set_background (context, window);
629 }
630
631 void
632 _gtk_menu_shell_activate (GtkMenuShell *menu_shell)
633 {
634   GtkMenuShellPrivate *priv = menu_shell->priv;
635
636   if (!priv->active)
637     {
638       GdkDevice *device;
639
640       device = gtk_get_current_event_device ();
641
642       _gtk_menu_shell_set_grab_device (menu_shell, device);
643       gtk_device_grab_add (GTK_WIDGET (menu_shell), device, TRUE);
644
645       priv->have_grab = TRUE;
646       priv->active = TRUE;
647     }
648 }
649
650 static gint
651 gtk_menu_shell_button_press (GtkWidget      *widget,
652                              GdkEventButton *event)
653 {
654   GtkMenuShell *menu_shell;
655   GtkMenuShellPrivate *priv;
656   GtkWidget *menu_item;
657   GtkWidget *parent;
658
659   if (event->type != GDK_BUTTON_PRESS)
660     return FALSE;
661
662   menu_shell = GTK_MENU_SHELL (widget);
663   priv = menu_shell->priv;
664
665   if (priv->parent_menu_shell)
666     return gtk_widget_event (priv->parent_menu_shell, (GdkEvent*) event);
667
668   menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent *)event);
669
670   if (menu_item && _gtk_menu_item_is_selectable (menu_item))
671     {
672       parent = gtk_widget_get_parent (menu_item);
673
674       if (menu_item != GTK_MENU_SHELL (parent)->priv->active_menu_item)
675         {
676           /*  select the menu item *before* activating the shell, so submenus
677            *  which might be open are closed the friendly way. If we activate
678            *  (and thus grab) this menu shell first, we might get grab_broken
679            *  events which will close the entire menu hierarchy. Selecting the
680            *  menu item also fixes up the state as if enter_notify() would
681            *  have run before (which normally selects the item).
682            */
683           if (GTK_MENU_SHELL_GET_CLASS (parent)->submenu_placement != GTK_TOP_BOTTOM)
684             gtk_menu_shell_select_item (GTK_MENU_SHELL (parent), menu_item);
685         }
686     }
687
688   if (!priv->active || !priv->button)
689     {
690       gboolean initially_active = priv->active;
691
692       priv->button = event->button;
693
694       if (menu_item)
695         {
696           if (_gtk_menu_item_is_selectable (menu_item) &&
697               gtk_widget_get_parent (menu_item) == widget &&
698               menu_item != priv->active_menu_item)
699             {
700               _gtk_menu_shell_activate (menu_shell);
701               priv->button = event->button;
702
703               if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
704                 {
705                   priv->activate_time = event->time;
706                   gtk_menu_shell_select_item (menu_shell, menu_item);
707                 }
708             }
709         }
710       else
711         {
712           if (!initially_active)
713             {
714               gboolean window_drag = FALSE;
715
716               gtk_widget_style_get (widget,
717                                     "window-dragging", &window_drag,
718                                     NULL);
719
720               if (window_drag)
721                 {
722                   gtk_menu_shell_deactivate (menu_shell);
723                   gtk_window_begin_move_drag (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
724                                               event->button,
725                                               event->x_root,
726                                               event->y_root,
727                                               event->time);
728                 }
729             }
730         }
731     }
732   else
733     {
734       widget = gtk_get_event_widget ((GdkEvent*) event);
735       if (widget == GTK_WIDGET (menu_shell))
736         {
737           gtk_menu_shell_deactivate (menu_shell);
738           g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
739         }
740     }
741
742   if (menu_item &&
743       _gtk_menu_item_is_selectable (menu_item) &&
744       GTK_MENU_ITEM (menu_item)->priv->submenu != NULL &&
745       !gtk_widget_get_visible (GTK_MENU_ITEM (menu_item)->priv->submenu))
746     {
747       _gtk_menu_item_popup_submenu (menu_item, FALSE);
748       priv->activated_submenu = TRUE;
749     }
750
751   return TRUE;
752 }
753
754 static gboolean
755 gtk_menu_shell_grab_broken (GtkWidget          *widget,
756                             GdkEventGrabBroken *event)
757 {
758   GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
759   GtkMenuShellPrivate *priv = menu_shell->priv;
760
761   if (priv->have_xgrab && event->grab_window == NULL)
762     {
763       /* Unset the active menu item so gtk_menu_popdown() doesn't see it. */
764       gtk_menu_shell_deselect (menu_shell);
765       gtk_menu_shell_deactivate (menu_shell);
766       g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
767     }
768
769   return TRUE;
770 }
771
772 static gint
773 gtk_menu_shell_button_release (GtkWidget      *widget,
774                                GdkEventButton *event)
775 {
776   GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
777   GtkMenuShellPrivate *priv = menu_shell->priv;
778
779   if (priv->active)
780     {
781       GtkWidget *menu_item;
782       gboolean   deactivate = TRUE;
783
784       if (priv->button && (event->button != priv->button))
785         {
786           priv->button = 0;
787           if (priv->parent_menu_shell)
788             return gtk_widget_event (priv->parent_menu_shell, (GdkEvent*) event);
789         }
790
791       priv->button = 0;
792       menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent*) event);
793
794       if ((event->time - priv->activate_time) > MENU_SHELL_TIMEOUT)
795         {
796           if (menu_item && (priv->active_menu_item == menu_item) &&
797               _gtk_menu_item_is_selectable (menu_item))
798             {
799               GtkWidget *submenu = GTK_MENU_ITEM (menu_item)->priv->submenu;
800
801               if (submenu == NULL)
802                 {
803                   gtk_menu_shell_activate_item (menu_shell, menu_item, TRUE);
804                   deactivate = FALSE;
805                 }
806               else if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM ||
807                        priv->activated_submenu)
808                 {
809                   gint popdown_delay;
810                   GTimeVal *popup_time;
811                   gint64 usec_since_popup = 0;
812
813                   g_object_get (gtk_widget_get_settings (widget),
814                                 "gtk-menu-popdown-delay", &popdown_delay,
815                                 NULL);
816
817                   popup_time = g_object_get_data (G_OBJECT (submenu),
818                                                   "gtk-menu-exact-popup-time");
819
820                   if (popup_time)
821                     {
822                       GTimeVal current_time;
823
824                       g_get_current_time (&current_time);
825
826                       usec_since_popup = ((gint64) current_time.tv_sec * 1000 * 1000 +
827                                           (gint64) current_time.tv_usec -
828                                           (gint64) popup_time->tv_sec * 1000 * 1000 -
829                                           (gint64) popup_time->tv_usec);
830
831                       g_object_set_data (G_OBJECT (submenu),
832                                          "gtk-menu-exact-popup-time", NULL);
833                     }
834
835                   /* Only close the submenu on click if we opened the
836                    * menu explicitely (usec_since_popup == 0) or
837                    * enough time has passed since it was opened by
838                    * GtkMenuItem's timeout (usec_since_popup > delay).
839                    */
840                   if (!priv->activated_submenu &&
841                       (usec_since_popup == 0 ||
842                        usec_since_popup > popdown_delay * 1000))
843                     {
844                       _gtk_menu_item_popdown_submenu (menu_item);
845                     }
846                   else
847                     {
848                       gtk_menu_item_select (GTK_MENU_ITEM (menu_item));
849                     }
850
851                   deactivate = FALSE;
852                 }
853             }
854           else if (menu_item &&
855                    !_gtk_menu_item_is_selectable (menu_item) &&
856                    GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
857             {
858               deactivate = FALSE;
859             }
860           else if (priv->parent_menu_shell)
861             {
862               priv->active = TRUE;
863               gtk_widget_event (priv->parent_menu_shell, (GdkEvent*) event);
864               deactivate = FALSE;
865             }
866
867           /* If we ended up on an item with a submenu, leave the menu up. */
868           if (menu_item &&
869               (priv->active_menu_item == menu_item) &&
870               GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
871             {
872               deactivate = FALSE;
873             }
874         }
875       else /* a very fast press-release */
876         {
877           /* We only ever want to prevent deactivation on the first
878            * press/release. Setting the time to zero is a bit of a
879            * hack, since we could be being triggered in the first
880            * few fractions of a second after a server time wraparound.
881            * the chances of that happening are ~1/10^6, without
882            * serious harm if we lose.
883            */
884           priv->activate_time = 0;
885           deactivate = FALSE;
886         }
887
888       if (deactivate)
889         {
890           gtk_menu_shell_deactivate (menu_shell);
891           g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
892         }
893
894       priv->activated_submenu = FALSE;
895     }
896
897   return TRUE;
898 }
899
900 void
901 _gtk_menu_shell_set_keyboard_mode (GtkMenuShell *menu_shell,
902                                    gboolean      keyboard_mode)
903 {
904   menu_shell->priv->keyboard_mode = keyboard_mode;
905 }
906
907 gboolean
908 _gtk_menu_shell_get_keyboard_mode (GtkMenuShell *menu_shell)
909 {
910   return menu_shell->priv->keyboard_mode;
911 }
912
913 void
914 _gtk_menu_shell_update_mnemonics (GtkMenuShell *menu_shell)
915 {
916   GtkMenuShell *target;
917   gboolean auto_mnemonics;
918   gboolean found;
919   gboolean mnemonics_visible;
920
921   g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
922                 "gtk-auto-mnemonics", &auto_mnemonics,
923                 NULL);
924
925   if (!auto_mnemonics)
926     return;
927
928   target = menu_shell;
929   found = FALSE;
930   while (target)
931     {
932       GtkMenuShellPrivate *priv = target->priv;
933       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (target));
934
935       /* The idea with keyboard mode is that once you start using
936        * the keyboard to navigate the menus, we show mnemonics
937        * until the menu navigation is over. To that end, we spread
938        * the keyboard mode upwards in the menu hierarchy here.
939        * Also see gtk_menu_popup, where we inherit it downwards.
940        */
941       if (menu_shell->priv->keyboard_mode)
942         target->priv->keyboard_mode = TRUE;
943
944       /* While navigating menus, the first parent menu with an active
945        * item is the one where mnemonics are effective, as can be seen
946        * in gtk_menu_shell_key_press below.
947        * We also show mnemonics in context menus. The grab condition is
948        * necessary to ensure we remove underlines from menu bars when
949        * dismissing menus.
950        */
951       mnemonics_visible = target->priv->keyboard_mode &&
952                           (((target->priv->active_menu_item || priv->in_unselectable_item) && !found) ||
953                            (target == menu_shell &&
954                             !target->priv->parent_menu_shell &&
955                             gtk_widget_has_grab (GTK_WIDGET (target))));
956
957       /* While menus are up, only show underlines inside the menubar,
958        * not in the entire window.
959        */
960       if (GTK_IS_MENU_BAR (target))
961         {
962           gtk_window_set_mnemonics_visible (GTK_WINDOW (toplevel), FALSE);
963           _gtk_label_mnemonics_visible_apply_recursively (GTK_WIDGET (target),
964                                                           mnemonics_visible);
965         }
966       else
967         gtk_window_set_mnemonics_visible (GTK_WINDOW (toplevel), mnemonics_visible);
968
969       if (target->priv->active_menu_item || priv->in_unselectable_item)
970         found = TRUE;
971
972       target = GTK_MENU_SHELL (target->priv->parent_menu_shell);
973     }
974 }
975
976 static gint
977 gtk_menu_shell_key_press (GtkWidget   *widget,
978                           GdkEventKey *event)
979 {
980   GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
981   GtkMenuShellPrivate *priv = menu_shell->priv;
982   gboolean enable_mnemonics;
983
984   priv->keyboard_mode = TRUE;
985
986   if (!(priv->active_menu_item || priv->in_unselectable_item) &&
987       priv->parent_menu_shell)
988     return gtk_widget_event (priv->parent_menu_shell, (GdkEvent *)event);
989
990   if (gtk_bindings_activate_event (G_OBJECT (widget), event))
991     return TRUE;
992
993   g_object_get (gtk_widget_get_settings (widget),
994                 "gtk-enable-mnemonics", &enable_mnemonics,
995                 NULL);
996
997   if (enable_mnemonics)
998     return gtk_menu_shell_activate_mnemonic (menu_shell, event);
999
1000   return FALSE;
1001 }
1002
1003 static gint
1004 gtk_menu_shell_enter_notify (GtkWidget        *widget,
1005                              GdkEventCrossing *event)
1006 {
1007   GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
1008   GtkMenuShellPrivate *priv = menu_shell->priv;
1009
1010   if (event->mode == GDK_CROSSING_GTK_GRAB ||
1011       event->mode == GDK_CROSSING_GTK_UNGRAB ||
1012       event->mode == GDK_CROSSING_STATE_CHANGED)
1013     return TRUE;
1014
1015   if (priv->active)
1016     {
1017       GtkWidget *menu_item;
1018       GtkWidget *parent;
1019
1020       menu_item = gtk_get_event_widget ((GdkEvent*) event);
1021
1022       if (!menu_item)
1023         return TRUE;
1024
1025       if (GTK_IS_MENU_ITEM (menu_item) &&
1026           !_gtk_menu_item_is_selectable (menu_item))
1027         {
1028           priv->in_unselectable_item = TRUE;
1029           return TRUE;
1030         }
1031
1032       parent = gtk_widget_get_parent (menu_item);
1033       if (parent == widget &&
1034           GTK_IS_MENU_ITEM (menu_item))
1035         {
1036           if (priv->ignore_enter)
1037             return TRUE;
1038
1039           if (event->detail != GDK_NOTIFY_INFERIOR)
1040             {
1041               if ((gtk_widget_get_state_flags (menu_item) & GTK_STATE_FLAG_PRELIGHT) == 0)
1042                 gtk_menu_shell_select_item (menu_shell, menu_item);
1043
1044               /* If any mouse button is down, and there is a submenu
1045                * that is not yet visible, activate it. It's sufficient
1046                * to check for any button's mask (not only the one
1047                * matching menu_shell->button), because there is no
1048                * situation a mouse button could be pressed while
1049                * entering a menu item where we wouldn't want to show
1050                * its submenu.
1051                */
1052               if ((event->state & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK)) &&
1053                   GTK_MENU_ITEM (menu_item)->priv->submenu != NULL)
1054                 {
1055                   GTK_MENU_SHELL (parent)->priv->activated_submenu = TRUE;
1056
1057                   if (!gtk_widget_get_visible (GTK_MENU_ITEM (menu_item)->priv->submenu))
1058                     {
1059                       gboolean touchscreen_mode;
1060
1061                       g_object_get (gtk_widget_get_settings (widget),
1062                                     "gtk-touchscreen-mode", &touchscreen_mode,
1063                                     NULL);
1064
1065                       if (touchscreen_mode)
1066                         _gtk_menu_item_popup_submenu (menu_item, TRUE);
1067                     }
1068                 }
1069             }
1070         }
1071       else if (priv->parent_menu_shell)
1072         {
1073           gtk_widget_event (priv->parent_menu_shell, (GdkEvent*) event);
1074         }
1075     }
1076
1077   return TRUE;
1078 }
1079
1080 static gint
1081 gtk_menu_shell_leave_notify (GtkWidget        *widget,
1082                              GdkEventCrossing *event)
1083 {
1084   if (event->mode == GDK_CROSSING_GTK_GRAB ||
1085       event->mode == GDK_CROSSING_GTK_GRAB ||
1086       event->mode == GDK_CROSSING_STATE_CHANGED)
1087     return TRUE;
1088
1089   if (gtk_widget_get_visible (widget))
1090     {
1091       GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
1092       GtkMenuShellPrivate *priv = menu_shell->priv;
1093       GtkWidget *event_widget = gtk_get_event_widget ((GdkEvent*) event);
1094       GtkMenuItem *menu_item;
1095
1096       if (!event_widget || !GTK_IS_MENU_ITEM (event_widget))
1097         return TRUE;
1098
1099       menu_item = GTK_MENU_ITEM (event_widget);
1100
1101       if (!_gtk_menu_item_is_selectable (event_widget))
1102         {
1103           priv->in_unselectable_item = TRUE;
1104           return TRUE;
1105         }
1106
1107       if ((priv->active_menu_item == event_widget) &&
1108           (menu_item->priv->submenu == NULL))
1109         {
1110           if ((event->detail != GDK_NOTIFY_INFERIOR) &&
1111               (gtk_widget_get_state_flags (GTK_WIDGET (menu_item)) & GTK_STATE_FLAG_PRELIGHT) != 0)
1112             {
1113               gtk_menu_shell_deselect (menu_shell);
1114             }
1115         }
1116       else if (priv->parent_menu_shell)
1117         {
1118           gtk_widget_event (priv->parent_menu_shell, (GdkEvent*) event);
1119         }
1120     }
1121
1122   return TRUE;
1123 }
1124
1125 static void
1126 gtk_menu_shell_screen_changed (GtkWidget *widget,
1127                                GdkScreen *previous_screen)
1128 {
1129   gtk_menu_shell_reset_key_hash (GTK_MENU_SHELL (widget));
1130 }
1131
1132 static void
1133 gtk_menu_shell_add (GtkContainer *container,
1134                     GtkWidget    *widget)
1135 {
1136   gtk_menu_shell_append (GTK_MENU_SHELL (container), widget);
1137 }
1138
1139 static void
1140 gtk_menu_shell_remove (GtkContainer *container,
1141                        GtkWidget    *widget)
1142 {
1143   GtkMenuShell *menu_shell = GTK_MENU_SHELL (container);
1144   GtkMenuShellPrivate *priv = menu_shell->priv;
1145   gint was_visible;
1146
1147   was_visible = gtk_widget_get_visible (widget);
1148   priv->children = g_list_remove (priv->children, widget);
1149
1150   if (widget == priv->active_menu_item)
1151     {
1152       g_signal_emit_by_name (priv->active_menu_item, "deselect");
1153       priv->active_menu_item = NULL;
1154     }
1155
1156   gtk_widget_unparent (widget);
1157
1158   /* Queue resize regardless of gtk_widget_get_visible (container),
1159    * since that's what is needed by toplevels.
1160    */
1161   if (was_visible)
1162     gtk_widget_queue_resize (GTK_WIDGET (container));
1163 }
1164
1165 static void
1166 gtk_menu_shell_forall (GtkContainer *container,
1167                        gboolean      include_internals,
1168                        GtkCallback   callback,
1169                        gpointer      callback_data)
1170 {
1171   GtkMenuShell *menu_shell = GTK_MENU_SHELL (container);
1172   GtkWidget *child;
1173   GList *children;
1174
1175   children = menu_shell->priv->children;
1176   while (children)
1177     {
1178       child = children->data;
1179       children = children->next;
1180
1181       (* callback) (child, callback_data);
1182     }
1183 }
1184
1185
1186 static void
1187 gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell)
1188 {
1189   GtkMenuShellPrivate *priv = menu_shell->priv;
1190
1191   if (priv->active)
1192     {
1193
1194       priv->button = 0;
1195       priv->active = FALSE;
1196       priv->activate_time = 0;
1197
1198       if (priv->active_menu_item)
1199         {
1200           gtk_menu_item_deselect (GTK_MENU_ITEM (priv->active_menu_item));
1201           priv->active_menu_item = NULL;
1202         }
1203
1204       if (priv->have_grab)
1205         {
1206           priv->have_grab = FALSE;
1207           gtk_device_grab_remove (GTK_WIDGET (menu_shell), priv->grab_pointer);
1208         }
1209       if (priv->have_xgrab)
1210         {
1211           GdkDevice *keyboard;
1212
1213           gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
1214           keyboard = gdk_device_get_associated_device (priv->grab_pointer);
1215
1216           if (keyboard)
1217             gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
1218
1219           priv->have_xgrab = FALSE;
1220         }
1221
1222       priv->keyboard_mode = FALSE;
1223       _gtk_menu_shell_set_grab_device (menu_shell, NULL);
1224
1225       _gtk_menu_shell_update_mnemonics (menu_shell);
1226     }
1227 }
1228
1229 static gint
1230 gtk_menu_shell_is_item (GtkMenuShell *menu_shell,
1231                         GtkWidget    *child)
1232 {
1233   GtkWidget *parent;
1234
1235   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
1236   g_return_val_if_fail (child != NULL, FALSE);
1237
1238   parent = gtk_widget_get_parent (child);
1239   while (GTK_IS_MENU_SHELL (parent))
1240     {
1241       if (parent == (GtkWidget*) menu_shell)
1242         return TRUE;
1243       parent = GTK_MENU_SHELL (parent)->priv->parent_menu_shell;
1244     }
1245
1246   return FALSE;
1247 }
1248
1249 static GtkWidget*
1250 gtk_menu_shell_get_item (GtkMenuShell *menu_shell,
1251                          GdkEvent     *event)
1252 {
1253   GtkWidget *menu_item;
1254
1255   menu_item = gtk_get_event_widget ((GdkEvent*) event);
1256
1257   while (menu_item && !GTK_IS_MENU_ITEM (menu_item))
1258     menu_item = gtk_widget_get_parent (menu_item);
1259
1260   if (menu_item && gtk_menu_shell_is_item (menu_shell, menu_item))
1261     return menu_item;
1262   else
1263     return NULL;
1264 }
1265
1266 /* Handlers for action signals */
1267
1268 /**
1269  * gtk_menu_shell_select_item:
1270  * @menu_shell: a #GtkMenuShell
1271  * @menu_item: The #GtkMenuItem to select
1272  *
1273  * Selects the menu item from the menu shell.
1274  */
1275 void
1276 gtk_menu_shell_select_item (GtkMenuShell *menu_shell,
1277                             GtkWidget    *menu_item)
1278 {
1279   GtkMenuShellPrivate *priv = menu_shell->priv;
1280   GtkMenuShellClass *class;
1281
1282   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1283   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1284
1285   class = GTK_MENU_SHELL_GET_CLASS (menu_shell);
1286
1287   if (class->select_item &&
1288       !(priv->active &&
1289         priv->active_menu_item == menu_item))
1290     class->select_item (menu_shell, menu_item);
1291 }
1292
1293 void _gtk_menu_item_set_placement (GtkMenuItem         *menu_item,
1294                                    GtkSubmenuPlacement  placement);
1295
1296 static void
1297 gtk_menu_shell_real_select_item (GtkMenuShell *menu_shell,
1298                                  GtkWidget    *menu_item)
1299 {
1300   GtkMenuShellPrivate *priv = menu_shell->priv;
1301   GtkPackDirection pack_dir = PACK_DIRECTION (menu_shell);
1302
1303   if (priv->active_menu_item)
1304     {
1305       gtk_menu_item_deselect (GTK_MENU_ITEM (priv->active_menu_item));
1306       priv->active_menu_item = NULL;
1307     }
1308
1309   if (!_gtk_menu_item_is_selectable (menu_item))
1310     {
1311       priv->in_unselectable_item = TRUE;
1312       _gtk_menu_shell_update_mnemonics (menu_shell);
1313       return;
1314     }
1315
1316   priv->active_menu_item = menu_item;
1317   if (pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT)
1318     _gtk_menu_item_set_placement (GTK_MENU_ITEM (priv->active_menu_item),
1319                                   GTK_LEFT_RIGHT);
1320   else
1321     _gtk_menu_item_set_placement (GTK_MENU_ITEM (priv->active_menu_item),
1322                                   GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement);
1323   gtk_menu_item_select (GTK_MENU_ITEM (priv->active_menu_item));
1324
1325   _gtk_menu_shell_update_mnemonics (menu_shell);
1326
1327   /* This allows the bizarre radio buttons-with-submenus-display-history
1328    * behavior
1329    */
1330   if (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu)
1331     gtk_widget_activate (priv->active_menu_item);
1332 }
1333
1334 /**
1335  * gtk_menu_shell_deselect:
1336  * @menu_shell: a #GtkMenuShell
1337  *
1338  * Deselects the currently selected item from the menu shell,
1339  * if any.
1340  */
1341 void
1342 gtk_menu_shell_deselect (GtkMenuShell *menu_shell)
1343 {
1344   GtkMenuShellPrivate *priv = menu_shell->priv;
1345
1346   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1347
1348   if (priv->active_menu_item)
1349     {
1350       gtk_menu_item_deselect (GTK_MENU_ITEM (priv->active_menu_item));
1351       priv->active_menu_item = NULL;
1352       _gtk_menu_shell_update_mnemonics (menu_shell);
1353     }
1354 }
1355
1356 /**
1357  * gtk_menu_shell_activate_item:
1358  * @menu_shell: a #GtkMenuShell
1359  * @menu_item: the #GtkMenuItem to activate
1360  * @force_deactivate: if %TRUE, force the deactivation of the
1361  *     menu shell after the menu item is activated
1362  *
1363  * Activates the menu item within the menu shell.
1364  */
1365 void
1366 gtk_menu_shell_activate_item (GtkMenuShell *menu_shell,
1367                               GtkWidget    *menu_item,
1368                               gboolean      force_deactivate)
1369 {
1370   GSList *slist, *shells = NULL;
1371   gboolean deactivate = force_deactivate;
1372
1373   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1374   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1375
1376   if (!deactivate)
1377     deactivate = GTK_MENU_ITEM_GET_CLASS (menu_item)->hide_on_activate;
1378
1379   g_object_ref (menu_shell);
1380   g_object_ref (menu_item);
1381
1382   if (deactivate)
1383     {
1384       GtkMenuShell *parent_menu_shell = menu_shell;
1385
1386       do
1387         {
1388           g_object_ref (parent_menu_shell);
1389           shells = g_slist_prepend (shells, parent_menu_shell);
1390           parent_menu_shell = (GtkMenuShell*) parent_menu_shell->priv->parent_menu_shell;
1391         }
1392       while (parent_menu_shell);
1393       shells = g_slist_reverse (shells);
1394
1395       gtk_menu_shell_deactivate (menu_shell);
1396
1397       /* Flush the x-queue, so any grabs are removed and
1398        * the menu is actually taken down
1399        */
1400       gdk_display_sync (gtk_widget_get_display (menu_item));
1401     }
1402
1403   gtk_widget_activate (menu_item);
1404
1405   for (slist = shells; slist; slist = slist->next)
1406     {
1407       g_signal_emit (slist->data, menu_shell_signals[SELECTION_DONE], 0);
1408       g_object_unref (slist->data);
1409     }
1410   g_slist_free (shells);
1411
1412   g_object_unref (menu_shell);
1413   g_object_unref (menu_item);
1414 }
1415
1416 /* Distance should be +/- 1 */
1417 static gboolean
1418 gtk_menu_shell_real_move_selected (GtkMenuShell  *menu_shell,
1419                                    gint           distance)
1420 {
1421   GtkMenuShellPrivate *priv = menu_shell->priv;
1422
1423   if (priv->active_menu_item)
1424     {
1425       GList *node = g_list_find (priv->children, priv->active_menu_item);
1426       GList *start_node = node;
1427       gboolean wrap_around;
1428
1429       g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
1430                     "gtk-keynav-wrap-around", &wrap_around,
1431                     NULL);
1432
1433       if (distance > 0)
1434         {
1435           node = node->next;
1436           while (node != start_node &&
1437                  (!node || !_gtk_menu_item_is_selectable (node->data)))
1438             {
1439               if (node)
1440                 node = node->next;
1441               else if (wrap_around)
1442                 node = priv->children;
1443               else
1444                 {
1445                   gtk_widget_error_bell (GTK_WIDGET (menu_shell));
1446                   break;
1447                 }
1448             }
1449         }
1450       else
1451         {
1452           node = node->prev;
1453           while (node != start_node &&
1454                  (!node || !_gtk_menu_item_is_selectable (node->data)))
1455             {
1456               if (node)
1457                 node = node->prev;
1458               else if (wrap_around)
1459                 node = g_list_last (priv->children);
1460               else
1461                 {
1462                   gtk_widget_error_bell (GTK_WIDGET (menu_shell));
1463                   break;
1464                 }
1465             }
1466         }
1467       
1468       if (node)
1469         gtk_menu_shell_select_item (menu_shell, node->data);
1470     }
1471
1472   return TRUE;
1473 }
1474
1475 /* Distance should be +/- 1 */
1476 static void
1477 gtk_menu_shell_move_selected (GtkMenuShell  *menu_shell,
1478                               gint           distance)
1479 {
1480   gboolean handled = FALSE;
1481
1482   g_signal_emit (menu_shell, menu_shell_signals[MOVE_SELECTED], 0,
1483                  distance, &handled);
1484 }
1485
1486 /**
1487  * gtk_menu_shell_select_first:
1488  * @menu_shell: a #GtkMenuShell
1489  * @search_sensitive: if %TRUE, search for the first selectable
1490  *                    menu item, otherwise select nothing if
1491  *                    the first item isn't sensitive. This
1492  *                    should be %FALSE if the menu is being
1493  *                    popped up initially.
1494  *
1495  * Select the first visible or selectable child of the menu shell;
1496  * don't select tearoff items unless the only item is a tearoff
1497  * item.
1498  *
1499  * Since: 2.2
1500  */
1501 void
1502 gtk_menu_shell_select_first (GtkMenuShell *menu_shell,
1503                              gboolean      search_sensitive)
1504 {
1505   GtkMenuShellPrivate *priv = menu_shell->priv;
1506   GtkWidget *to_select = NULL;
1507   GList *tmp_list;
1508
1509   tmp_list = priv->children;
1510   while (tmp_list)
1511     {
1512       GtkWidget *child = tmp_list->data;
1513
1514       if ((!search_sensitive && gtk_widget_get_visible (child)) ||
1515           _gtk_menu_item_is_selectable (child))
1516         {
1517           to_select = child;
1518           if (!GTK_IS_TEAROFF_MENU_ITEM (child))
1519             break;
1520         }
1521
1522       tmp_list = tmp_list->next;
1523     }
1524
1525   if (to_select)
1526     gtk_menu_shell_select_item (menu_shell, to_select);
1527 }
1528
1529 void
1530 _gtk_menu_shell_select_last (GtkMenuShell *menu_shell,
1531                              gboolean      search_sensitive)
1532 {
1533   GtkMenuShellPrivate *priv = menu_shell->priv;
1534   GtkWidget *to_select = NULL;
1535   GList *tmp_list;
1536
1537   tmp_list = g_list_last (priv->children);
1538   while (tmp_list)
1539     {
1540       GtkWidget *child = tmp_list->data;
1541
1542       if ((!search_sensitive && gtk_widget_get_visible (child)) ||
1543           _gtk_menu_item_is_selectable (child))
1544         {
1545           to_select = child;
1546           if (!GTK_IS_TEAROFF_MENU_ITEM (child))
1547             break;
1548         }
1549
1550       tmp_list = tmp_list->prev;
1551     }
1552
1553   if (to_select)
1554     gtk_menu_shell_select_item (menu_shell, to_select);
1555 }
1556
1557 static gboolean
1558 gtk_menu_shell_select_submenu_first (GtkMenuShell *menu_shell)
1559 {
1560   GtkMenuShellPrivate *priv = menu_shell->priv;
1561   GtkMenuItem *menu_item;
1562
1563   if (priv->active_menu_item == NULL)
1564     return FALSE;
1565
1566   menu_item = GTK_MENU_ITEM (priv->active_menu_item);
1567
1568   if (menu_item->priv->submenu)
1569     {
1570       _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), FALSE);
1571       gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->priv->submenu), TRUE);
1572       if (GTK_MENU_SHELL (menu_item->priv->submenu)->priv->active_menu_item)
1573         return TRUE;
1574     }
1575
1576   return FALSE;
1577 }
1578
1579 static void
1580 gtk_real_menu_shell_move_current (GtkMenuShell         *menu_shell,
1581                                   GtkMenuDirectionType  direction)
1582 {
1583   GtkMenuShellPrivate *priv = menu_shell->priv;
1584   GtkMenuShell *parent_menu_shell = NULL;
1585   gboolean had_selection;
1586   gboolean touchscreen_mode;
1587
1588   priv->in_unselectable_item = FALSE;
1589
1590   had_selection = priv->active_menu_item != NULL;
1591
1592   g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
1593                 "gtk-touchscreen-mode", &touchscreen_mode,
1594                 NULL);
1595
1596   if (priv->parent_menu_shell)
1597     parent_menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
1598
1599   switch (direction)
1600     {
1601     case GTK_MENU_DIR_PARENT:
1602       if (touchscreen_mode &&
1603           priv->active_menu_item &&
1604           GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu &&
1605           gtk_widget_get_visible (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu))
1606         {
1607           /* if we are on a menu item that has an open submenu but the
1608            * focus is not in that submenu (e.g. because it's empty or
1609            * has only insensitive items), close that submenu instead of
1610            * running into the code below which would close *this* menu.
1611            */
1612           _gtk_menu_item_popdown_submenu (priv->active_menu_item);
1613           _gtk_menu_shell_update_mnemonics (menu_shell);
1614         }
1615       else if (parent_menu_shell)
1616         {
1617           if (touchscreen_mode)
1618             {
1619               /* close menu when returning from submenu. */
1620               _gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->priv->parent_menu_item);
1621               _gtk_menu_shell_update_mnemonics (parent_menu_shell);
1622               break;
1623             }
1624
1625           if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
1626               GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
1627             gtk_menu_shell_deselect (menu_shell);
1628           else
1629             {
1630               if (PACK_DIRECTION (parent_menu_shell) == GTK_PACK_DIRECTION_LTR)
1631                 gtk_menu_shell_move_selected (parent_menu_shell, -1);
1632               else
1633                 gtk_menu_shell_move_selected (parent_menu_shell, 1);
1634               gtk_menu_shell_select_submenu_first (parent_menu_shell);
1635             }
1636         }
1637       /* If there is no parent and the submenu is in the opposite direction
1638        * to the menu, then make the PARENT direction wrap around to
1639        * the bottom of the submenu.
1640        */
1641       else if (priv->active_menu_item &&
1642                _gtk_menu_item_is_selectable (priv->active_menu_item) &&
1643                GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu)
1644         {
1645           GtkMenuShell *submenu = GTK_MENU_SHELL (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu);
1646
1647           if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement !=
1648               GTK_MENU_SHELL_GET_CLASS (submenu)->submenu_placement)
1649             _gtk_menu_shell_select_last (submenu, TRUE);
1650         }
1651       break;
1652
1653     case GTK_MENU_DIR_CHILD:
1654       if (priv->active_menu_item &&
1655           _gtk_menu_item_is_selectable (priv->active_menu_item) &&
1656           GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu)
1657         {
1658           if (gtk_menu_shell_select_submenu_first (menu_shell))
1659             break;
1660         }
1661
1662       /* Try to find a menu running the opposite direction */
1663       while (parent_menu_shell &&
1664              (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
1665               GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement))
1666         {
1667           parent_menu_shell = GTK_MENU_SHELL (parent_menu_shell->priv->parent_menu_shell);
1668         }
1669
1670       if (parent_menu_shell)
1671         {
1672           if (PACK_DIRECTION (parent_menu_shell) == GTK_PACK_DIRECTION_LTR)
1673             gtk_menu_shell_move_selected (parent_menu_shell, 1);
1674           else
1675             gtk_menu_shell_move_selected (parent_menu_shell, -1);
1676
1677           gtk_menu_shell_select_submenu_first (parent_menu_shell);
1678         }
1679       break;
1680
1681     case GTK_MENU_DIR_PREV:
1682       gtk_menu_shell_move_selected (menu_shell, -1);
1683       if (!had_selection && !priv->active_menu_item && priv->children)
1684         _gtk_menu_shell_select_last (menu_shell, TRUE);
1685       break;
1686
1687     case GTK_MENU_DIR_NEXT:
1688       gtk_menu_shell_move_selected (menu_shell, 1);
1689       if (!had_selection && !priv->active_menu_item && priv->children)
1690         gtk_menu_shell_select_first (menu_shell, TRUE);
1691       break;
1692     }
1693 }
1694
1695 static void
1696 gtk_real_menu_shell_activate_current (GtkMenuShell *menu_shell,
1697                                       gboolean      force_hide)
1698 {
1699   GtkMenuShellPrivate *priv = menu_shell->priv;
1700
1701   if (priv->active_menu_item &&
1702       _gtk_menu_item_is_selectable (priv->active_menu_item))
1703   {
1704     if (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu == NULL)
1705       gtk_menu_shell_activate_item (menu_shell,
1706                                     priv->active_menu_item,
1707                                     force_hide);
1708     else
1709       _gtk_menu_item_popup_submenu (priv->active_menu_item, FALSE);
1710   }
1711 }
1712
1713 static void
1714 gtk_real_menu_shell_cancel (GtkMenuShell *menu_shell)
1715 {
1716   /* Unset the active menu item so gtk_menu_popdown() doesn't see it. */
1717   gtk_menu_shell_deselect (menu_shell);
1718   gtk_menu_shell_deactivate (menu_shell);
1719   g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
1720 }
1721
1722 static void
1723 gtk_real_menu_shell_cycle_focus (GtkMenuShell     *menu_shell,
1724                                  GtkDirectionType  dir)
1725 {
1726   GtkMenuShellPrivate *priv = menu_shell->priv;
1727
1728   while (menu_shell && !GTK_IS_MENU_BAR (menu_shell))
1729     {
1730       if (priv->parent_menu_shell)
1731         menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
1732       else
1733         menu_shell = NULL;
1734     }
1735
1736   if (menu_shell)
1737     _gtk_menu_bar_cycle_focus (GTK_MENU_BAR (menu_shell), dir);
1738 }
1739
1740 gint
1741 _gtk_menu_shell_get_popup_delay (GtkMenuShell *menu_shell)
1742 {
1743   GtkMenuShellClass *klass = GTK_MENU_SHELL_GET_CLASS (menu_shell);
1744   
1745   if (klass->get_popup_delay)
1746     {
1747       return klass->get_popup_delay (menu_shell);
1748     }
1749   else
1750     {
1751       gint popup_delay;
1752       GtkWidget *widget = GTK_WIDGET (menu_shell);
1753
1754       g_object_get (gtk_widget_get_settings (widget),
1755                     "gtk-menu-popup-delay", &popup_delay,
1756                     NULL);
1757
1758       return popup_delay;
1759     }
1760 }
1761
1762 /**
1763  * gtk_menu_shell_cancel:
1764  * @menu_shell: a #GtkMenuShell
1765  *
1766  * Cancels the selection within the menu shell.
1767  *
1768  * Since: 2.4
1769  */
1770 void
1771 gtk_menu_shell_cancel (GtkMenuShell *menu_shell)
1772 {
1773   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1774
1775   g_signal_emit (menu_shell, menu_shell_signals[CANCEL], 0);
1776 }
1777
1778 static GtkMnemonicHash *
1779 gtk_menu_shell_get_mnemonic_hash (GtkMenuShell *menu_shell,
1780                                   gboolean      create)
1781 {
1782   GtkMenuShellPrivate *priv = menu_shell->priv;
1783
1784   if (!priv->mnemonic_hash && create)
1785     priv->mnemonic_hash = _gtk_mnemonic_hash_new ();
1786   
1787   return priv->mnemonic_hash;
1788 }
1789
1790 static void
1791 menu_shell_add_mnemonic_foreach (guint     keyval,
1792                                  GSList   *targets,
1793                                  gpointer  data)
1794 {
1795   GtkKeyHash *key_hash = data;
1796
1797   _gtk_key_hash_add_entry (key_hash, keyval, 0, GUINT_TO_POINTER (keyval));
1798 }
1799
1800 static GtkKeyHash *
1801 gtk_menu_shell_get_key_hash (GtkMenuShell *menu_shell,
1802                              gboolean      create)
1803 {
1804   GtkMenuShellPrivate *priv = menu_shell->priv;
1805   GtkWidget *widget = GTK_WIDGET (menu_shell);
1806
1807   if (!priv->key_hash && create && gtk_widget_has_screen (widget))
1808     {
1809       GtkMnemonicHash *mnemonic_hash = gtk_menu_shell_get_mnemonic_hash (menu_shell, FALSE);
1810       GdkScreen *screen = gtk_widget_get_screen (widget);
1811       GdkKeymap *keymap = gdk_keymap_get_for_display (gdk_screen_get_display (screen));
1812
1813       if (!mnemonic_hash)
1814         return NULL;
1815
1816       priv->key_hash = _gtk_key_hash_new (keymap, NULL);
1817
1818       _gtk_mnemonic_hash_foreach (mnemonic_hash,
1819                                   menu_shell_add_mnemonic_foreach,
1820                                   priv->key_hash);
1821     }
1822
1823   return priv->key_hash;
1824 }
1825
1826 static void
1827 gtk_menu_shell_reset_key_hash (GtkMenuShell *menu_shell)
1828 {
1829   GtkMenuShellPrivate *priv = menu_shell->priv;
1830
1831   if (priv->key_hash)
1832     {
1833       _gtk_key_hash_free (priv->key_hash);
1834       priv->key_hash = NULL;
1835     }
1836 }
1837
1838 static gboolean
1839 gtk_menu_shell_activate_mnemonic (GtkMenuShell *menu_shell,
1840                                   GdkEventKey  *event)
1841 {
1842   GtkMnemonicHash *mnemonic_hash;
1843   GtkKeyHash *key_hash;
1844   GSList *entries;
1845   gboolean result = FALSE;
1846
1847   mnemonic_hash = gtk_menu_shell_get_mnemonic_hash (menu_shell, FALSE);
1848   if (!mnemonic_hash)
1849     return FALSE;
1850
1851   key_hash = gtk_menu_shell_get_key_hash (menu_shell, TRUE);
1852   if (!key_hash)
1853     return FALSE;
1854
1855   entries = _gtk_key_hash_lookup (key_hash,
1856                                   event->hardware_keycode,
1857                                   event->state,
1858                                   gtk_accelerator_get_default_mod_mask (),
1859                                   event->group);
1860
1861   if (entries)
1862     result = _gtk_mnemonic_hash_activate (mnemonic_hash,
1863                                           GPOINTER_TO_UINT (entries->data));
1864
1865   return result;
1866 }
1867
1868 void
1869 _gtk_menu_shell_add_mnemonic (GtkMenuShell *menu_shell,
1870                               guint         keyval,
1871                               GtkWidget    *target)
1872 {
1873   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1874   g_return_if_fail (GTK_IS_WIDGET (target));
1875
1876   _gtk_mnemonic_hash_add (gtk_menu_shell_get_mnemonic_hash (menu_shell, TRUE),
1877                           keyval, target);
1878   gtk_menu_shell_reset_key_hash (menu_shell);
1879 }
1880
1881 void
1882 _gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell,
1883                                  guint         keyval,
1884                                  GtkWidget    *target)
1885 {
1886   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1887   g_return_if_fail (GTK_IS_WIDGET (target));
1888
1889   _gtk_mnemonic_hash_remove (gtk_menu_shell_get_mnemonic_hash (menu_shell, TRUE),
1890                              keyval, target);
1891   gtk_menu_shell_reset_key_hash (menu_shell);
1892 }
1893
1894 void
1895 _gtk_menu_shell_set_grab_device (GtkMenuShell *menu_shell,
1896                                  GdkDevice    *device)
1897 {
1898   GtkMenuShellPrivate *priv = menu_shell->priv;
1899
1900   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1901   g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
1902
1903   if (!device)
1904     priv->grab_pointer = NULL;
1905   else if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
1906     priv->grab_pointer = gdk_device_get_associated_device (device);
1907   else
1908     priv->grab_pointer = device;
1909 }
1910
1911 GdkDevice *
1912 _gtk_menu_shell_get_grab_device (GtkMenuShell *menu_shell)
1913 {
1914   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), NULL);
1915
1916   return menu_shell->priv->grab_pointer;
1917 }
1918
1919 /**
1920  * gtk_menu_shell_get_take_focus:
1921  * @menu_shell: a #GtkMenuShell
1922  *
1923  * Returns %TRUE if the menu shell will take the keyboard focus on popup.
1924  *
1925  * Returns: %TRUE if the menu shell will take the keyboard focus on popup.
1926  *
1927  * Since: 2.8
1928  */
1929 gboolean
1930 gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell)
1931 {
1932   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
1933
1934   return menu_shell->priv->take_focus;
1935 }
1936
1937 /**
1938  * gtk_menu_shell_set_take_focus:
1939  * @menu_shell: a #GtkMenuShell
1940  * @take_focus: %TRUE if the menu shell should take the keyboard
1941  *     focus on popup
1942  *
1943  * If @take_focus is %TRUE (the default) the menu shell will take
1944  * the keyboard focus so that it will receive all keyboard events
1945  * which is needed to enable keyboard navigation in menus.
1946  *
1947  * Setting @take_focus to %FALSE is useful only for special applications
1948  * like virtual keyboard implementations which should not take keyboard
1949  * focus.
1950  *
1951  * The @take_focus state of a menu or menu bar is automatically
1952  * propagated to submenus whenever a submenu is popped up, so you
1953  * don't have to worry about recursively setting it for your entire
1954  * menu hierarchy. Only when programmatically picking a submenu and
1955  * popping it up manually, the @take_focus property of the submenu
1956  * needs to be set explicitely.
1957  *
1958  * Note that setting it to %FALSE has side-effects:
1959  *
1960  * If the focus is in some other app, it keeps the focus and keynav in
1961  * the menu doesn't work. Consequently, keynav on the menu will only
1962  * work if the focus is on some toplevel owned by the onscreen keyboard.
1963  *
1964  * To avoid confusing the user, menus with @take_focus set to %FALSE
1965  * should not display mnemonics or accelerators, since it cannot be
1966  * guaranteed that they will work.
1967  *
1968  * See also gdk_keyboard_grab()
1969  *
1970  * Since: 2.8
1971  */
1972 void
1973 gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell,
1974                                gboolean      take_focus)
1975 {
1976   GtkMenuShellPrivate *priv = menu_shell->priv;
1977
1978   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1979
1980   if (priv->take_focus != take_focus)
1981     {
1982       priv->take_focus = take_focus;
1983       g_object_notify (G_OBJECT (menu_shell), "take-focus");
1984     }
1985 }
1986
1987 /**
1988  * gtk_menu_shell_get_selected_item:
1989  * @menu_shell: a #GtkMenuShell
1990  *
1991  * Gets the currently selected item.
1992  *
1993  * Returns: the currently selected item
1994  *
1995  * Since: 3.0
1996  */
1997 GtkWidget *
1998 gtk_menu_shell_get_selected_item (GtkMenuShell *menu_shell)
1999 {
2000   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), NULL);
2001
2002   return menu_shell->priv->active_menu_item;
2003 }
2004
2005 /**
2006  * gtk_menu_shell_get_parent_shell:
2007  * @menu_shell: a #GtkMenuShell
2008  *
2009  * Gets the parent menu shell.
2010  *
2011  * The parent menu shell of a submenu is the #GtkMenu or #GtkMenuBar
2012  * from which it was opened up.
2013  *
2014  * Returns: the parent #GtkMenuShell
2015  *
2016  * Since: 3.0
2017  */
2018 GtkWidget *
2019 gtk_menu_shell_get_parent_shell (GtkMenuShell *menu_shell)
2020 {
2021   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), NULL);
2022
2023   return menu_shell->priv->parent_menu_shell;
2024 }