]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenushell.c
GtkMenuShell: always 'activate' menu shells
[~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       priv->button = 0;
1194       priv->active = FALSE;
1195       priv->activate_time = 0;
1196
1197       if (priv->active_menu_item)
1198         {
1199           gtk_menu_item_deselect (GTK_MENU_ITEM (priv->active_menu_item));
1200           priv->active_menu_item = NULL;
1201         }
1202
1203       if (priv->have_grab)
1204         {
1205           priv->have_grab = FALSE;
1206           gtk_device_grab_remove (GTK_WIDGET (menu_shell), priv->grab_pointer);
1207         }
1208       if (priv->have_xgrab)
1209         {
1210           GdkDevice *keyboard;
1211
1212           gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
1213           keyboard = gdk_device_get_associated_device (priv->grab_pointer);
1214
1215           if (keyboard)
1216             gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
1217
1218           priv->have_xgrab = FALSE;
1219         }
1220
1221       priv->keyboard_mode = FALSE;
1222       _gtk_menu_shell_set_grab_device (menu_shell, NULL);
1223
1224       _gtk_menu_shell_update_mnemonics (menu_shell);
1225     }
1226 }
1227
1228 static gint
1229 gtk_menu_shell_is_item (GtkMenuShell *menu_shell,
1230                         GtkWidget    *child)
1231 {
1232   GtkWidget *parent;
1233
1234   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
1235   g_return_val_if_fail (child != NULL, FALSE);
1236
1237   parent = gtk_widget_get_parent (child);
1238   while (GTK_IS_MENU_SHELL (parent))
1239     {
1240       if (parent == (GtkWidget*) menu_shell)
1241         return TRUE;
1242       parent = GTK_MENU_SHELL (parent)->priv->parent_menu_shell;
1243     }
1244
1245   return FALSE;
1246 }
1247
1248 static GtkWidget*
1249 gtk_menu_shell_get_item (GtkMenuShell *menu_shell,
1250                          GdkEvent     *event)
1251 {
1252   GtkWidget *menu_item;
1253
1254   menu_item = gtk_get_event_widget ((GdkEvent*) event);
1255
1256   while (menu_item && !GTK_IS_MENU_ITEM (menu_item))
1257     menu_item = gtk_widget_get_parent (menu_item);
1258
1259   if (menu_item && gtk_menu_shell_is_item (menu_shell, menu_item))
1260     return menu_item;
1261   else
1262     return NULL;
1263 }
1264
1265 /* Handlers for action signals */
1266
1267 /**
1268  * gtk_menu_shell_select_item:
1269  * @menu_shell: a #GtkMenuShell
1270  * @menu_item: The #GtkMenuItem to select
1271  *
1272  * Selects the menu item from the menu shell.
1273  */
1274 void
1275 gtk_menu_shell_select_item (GtkMenuShell *menu_shell,
1276                             GtkWidget    *menu_item)
1277 {
1278   GtkMenuShellPrivate *priv = menu_shell->priv;
1279   GtkMenuShellClass *class;
1280
1281   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1282   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1283
1284   class = GTK_MENU_SHELL_GET_CLASS (menu_shell);
1285
1286   if (class->select_item &&
1287       !(priv->active &&
1288         priv->active_menu_item == menu_item))
1289     class->select_item (menu_shell, menu_item);
1290 }
1291
1292 void _gtk_menu_item_set_placement (GtkMenuItem         *menu_item,
1293                                    GtkSubmenuPlacement  placement);
1294
1295 static void
1296 gtk_menu_shell_real_select_item (GtkMenuShell *menu_shell,
1297                                  GtkWidget    *menu_item)
1298 {
1299   GtkMenuShellPrivate *priv = menu_shell->priv;
1300   GtkPackDirection pack_dir = PACK_DIRECTION (menu_shell);
1301
1302   if (priv->active_menu_item)
1303     {
1304       gtk_menu_item_deselect (GTK_MENU_ITEM (priv->active_menu_item));
1305       priv->active_menu_item = NULL;
1306     }
1307
1308   if (!_gtk_menu_item_is_selectable (menu_item))
1309     {
1310       priv->in_unselectable_item = TRUE;
1311       _gtk_menu_shell_update_mnemonics (menu_shell);
1312       return;
1313     }
1314
1315   _gtk_menu_shell_activate (menu_shell);
1316
1317   priv->active_menu_item = menu_item;
1318   if (pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT)
1319     _gtk_menu_item_set_placement (GTK_MENU_ITEM (priv->active_menu_item),
1320                                   GTK_LEFT_RIGHT);
1321   else
1322     _gtk_menu_item_set_placement (GTK_MENU_ITEM (priv->active_menu_item),
1323                                   GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement);
1324   gtk_menu_item_select (GTK_MENU_ITEM (priv->active_menu_item));
1325
1326   _gtk_menu_shell_update_mnemonics (menu_shell);
1327
1328   /* This allows the bizarre radio buttons-with-submenus-display-history
1329    * behavior
1330    */
1331   if (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu)
1332     gtk_widget_activate (priv->active_menu_item);
1333 }
1334
1335 /**
1336  * gtk_menu_shell_deselect:
1337  * @menu_shell: a #GtkMenuShell
1338  *
1339  * Deselects the currently selected item from the menu shell,
1340  * if any.
1341  */
1342 void
1343 gtk_menu_shell_deselect (GtkMenuShell *menu_shell)
1344 {
1345   GtkMenuShellPrivate *priv = menu_shell->priv;
1346
1347   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1348
1349   if (priv->active_menu_item)
1350     {
1351       gtk_menu_item_deselect (GTK_MENU_ITEM (priv->active_menu_item));
1352       priv->active_menu_item = NULL;
1353       _gtk_menu_shell_update_mnemonics (menu_shell);
1354     }
1355 }
1356
1357 /**
1358  * gtk_menu_shell_activate_item:
1359  * @menu_shell: a #GtkMenuShell
1360  * @menu_item: the #GtkMenuItem to activate
1361  * @force_deactivate: if %TRUE, force the deactivation of the
1362  *     menu shell after the menu item is activated
1363  *
1364  * Activates the menu item within the menu shell.
1365  */
1366 void
1367 gtk_menu_shell_activate_item (GtkMenuShell *menu_shell,
1368                               GtkWidget    *menu_item,
1369                               gboolean      force_deactivate)
1370 {
1371   GSList *slist, *shells = NULL;
1372   gboolean deactivate = force_deactivate;
1373
1374   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1375   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
1376
1377   if (!deactivate)
1378     deactivate = GTK_MENU_ITEM_GET_CLASS (menu_item)->hide_on_activate;
1379
1380   g_object_ref (menu_shell);
1381   g_object_ref (menu_item);
1382
1383   if (deactivate)
1384     {
1385       GtkMenuShell *parent_menu_shell = menu_shell;
1386
1387       do
1388         {
1389           g_object_ref (parent_menu_shell);
1390           shells = g_slist_prepend (shells, parent_menu_shell);
1391           parent_menu_shell = (GtkMenuShell*) parent_menu_shell->priv->parent_menu_shell;
1392         }
1393       while (parent_menu_shell);
1394       shells = g_slist_reverse (shells);
1395
1396       gtk_menu_shell_deactivate (menu_shell);
1397
1398       /* Flush the x-queue, so any grabs are removed and
1399        * the menu is actually taken down
1400        */
1401       gdk_display_sync (gtk_widget_get_display (menu_item));
1402     }
1403
1404   gtk_widget_activate (menu_item);
1405
1406   for (slist = shells; slist; slist = slist->next)
1407     {
1408       g_signal_emit (slist->data, menu_shell_signals[SELECTION_DONE], 0);
1409       g_object_unref (slist->data);
1410     }
1411   g_slist_free (shells);
1412
1413   g_object_unref (menu_shell);
1414   g_object_unref (menu_item);
1415 }
1416
1417 /* Distance should be +/- 1 */
1418 static gboolean
1419 gtk_menu_shell_real_move_selected (GtkMenuShell  *menu_shell,
1420                                    gint           distance)
1421 {
1422   GtkMenuShellPrivate *priv = menu_shell->priv;
1423
1424   if (priv->active_menu_item)
1425     {
1426       GList *node = g_list_find (priv->children, priv->active_menu_item);
1427       GList *start_node = node;
1428       gboolean wrap_around;
1429
1430       g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
1431                     "gtk-keynav-wrap-around", &wrap_around,
1432                     NULL);
1433
1434       if (distance > 0)
1435         {
1436           node = node->next;
1437           while (node != start_node &&
1438                  (!node || !_gtk_menu_item_is_selectable (node->data)))
1439             {
1440               if (node)
1441                 node = node->next;
1442               else if (wrap_around)
1443                 node = priv->children;
1444               else
1445                 {
1446                   gtk_widget_error_bell (GTK_WIDGET (menu_shell));
1447                   break;
1448                 }
1449             }
1450         }
1451       else
1452         {
1453           node = node->prev;
1454           while (node != start_node &&
1455                  (!node || !_gtk_menu_item_is_selectable (node->data)))
1456             {
1457               if (node)
1458                 node = node->prev;
1459               else if (wrap_around)
1460                 node = g_list_last (priv->children);
1461               else
1462                 {
1463                   gtk_widget_error_bell (GTK_WIDGET (menu_shell));
1464                   break;
1465                 }
1466             }
1467         }
1468       
1469       if (node)
1470         gtk_menu_shell_select_item (menu_shell, node->data);
1471     }
1472
1473   return TRUE;
1474 }
1475
1476 /* Distance should be +/- 1 */
1477 static void
1478 gtk_menu_shell_move_selected (GtkMenuShell  *menu_shell,
1479                               gint           distance)
1480 {
1481   gboolean handled = FALSE;
1482
1483   g_signal_emit (menu_shell, menu_shell_signals[MOVE_SELECTED], 0,
1484                  distance, &handled);
1485 }
1486
1487 /**
1488  * gtk_menu_shell_select_first:
1489  * @menu_shell: a #GtkMenuShell
1490  * @search_sensitive: if %TRUE, search for the first selectable
1491  *                    menu item, otherwise select nothing if
1492  *                    the first item isn't sensitive. This
1493  *                    should be %FALSE if the menu is being
1494  *                    popped up initially.
1495  *
1496  * Select the first visible or selectable child of the menu shell;
1497  * don't select tearoff items unless the only item is a tearoff
1498  * item.
1499  *
1500  * Since: 2.2
1501  */
1502 void
1503 gtk_menu_shell_select_first (GtkMenuShell *menu_shell,
1504                              gboolean      search_sensitive)
1505 {
1506   GtkMenuShellPrivate *priv = menu_shell->priv;
1507   GtkWidget *to_select = NULL;
1508   GList *tmp_list;
1509
1510   tmp_list = priv->children;
1511   while (tmp_list)
1512     {
1513       GtkWidget *child = tmp_list->data;
1514
1515       if ((!search_sensitive && gtk_widget_get_visible (child)) ||
1516           _gtk_menu_item_is_selectable (child))
1517         {
1518           to_select = child;
1519           if (!GTK_IS_TEAROFF_MENU_ITEM (child))
1520             break;
1521         }
1522
1523       tmp_list = tmp_list->next;
1524     }
1525
1526   if (to_select)
1527     gtk_menu_shell_select_item (menu_shell, to_select);
1528 }
1529
1530 void
1531 _gtk_menu_shell_select_last (GtkMenuShell *menu_shell,
1532                              gboolean      search_sensitive)
1533 {
1534   GtkMenuShellPrivate *priv = menu_shell->priv;
1535   GtkWidget *to_select = NULL;
1536   GList *tmp_list;
1537
1538   tmp_list = g_list_last (priv->children);
1539   while (tmp_list)
1540     {
1541       GtkWidget *child = tmp_list->data;
1542
1543       if ((!search_sensitive && gtk_widget_get_visible (child)) ||
1544           _gtk_menu_item_is_selectable (child))
1545         {
1546           to_select = child;
1547           if (!GTK_IS_TEAROFF_MENU_ITEM (child))
1548             break;
1549         }
1550
1551       tmp_list = tmp_list->prev;
1552     }
1553
1554   if (to_select)
1555     gtk_menu_shell_select_item (menu_shell, to_select);
1556 }
1557
1558 static gboolean
1559 gtk_menu_shell_select_submenu_first (GtkMenuShell *menu_shell)
1560 {
1561   GtkMenuShellPrivate *priv = menu_shell->priv;
1562   GtkMenuItem *menu_item;
1563
1564   if (priv->active_menu_item == NULL)
1565     return FALSE;
1566
1567   menu_item = GTK_MENU_ITEM (priv->active_menu_item);
1568
1569   if (menu_item->priv->submenu)
1570     {
1571       _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), FALSE);
1572       gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->priv->submenu), TRUE);
1573       if (GTK_MENU_SHELL (menu_item->priv->submenu)->priv->active_menu_item)
1574         return TRUE;
1575     }
1576
1577   return FALSE;
1578 }
1579
1580 static void
1581 gtk_real_menu_shell_move_current (GtkMenuShell         *menu_shell,
1582                                   GtkMenuDirectionType  direction)
1583 {
1584   GtkMenuShellPrivate *priv = menu_shell->priv;
1585   GtkMenuShell *parent_menu_shell = NULL;
1586   gboolean had_selection;
1587   gboolean touchscreen_mode;
1588
1589   priv->in_unselectable_item = FALSE;
1590
1591   had_selection = priv->active_menu_item != NULL;
1592
1593   g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
1594                 "gtk-touchscreen-mode", &touchscreen_mode,
1595                 NULL);
1596
1597   if (priv->parent_menu_shell)
1598     parent_menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
1599
1600   switch (direction)
1601     {
1602     case GTK_MENU_DIR_PARENT:
1603       if (touchscreen_mode &&
1604           priv->active_menu_item &&
1605           GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu &&
1606           gtk_widget_get_visible (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu))
1607         {
1608           /* if we are on a menu item that has an open submenu but the
1609            * focus is not in that submenu (e.g. because it's empty or
1610            * has only insensitive items), close that submenu instead of
1611            * running into the code below which would close *this* menu.
1612            */
1613           _gtk_menu_item_popdown_submenu (priv->active_menu_item);
1614           _gtk_menu_shell_update_mnemonics (menu_shell);
1615         }
1616       else if (parent_menu_shell)
1617         {
1618           if (touchscreen_mode)
1619             {
1620               /* close menu when returning from submenu. */
1621               _gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->priv->parent_menu_item);
1622               _gtk_menu_shell_update_mnemonics (parent_menu_shell);
1623               break;
1624             }
1625
1626           if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
1627               GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
1628             gtk_menu_shell_deselect (menu_shell);
1629           else
1630             {
1631               if (PACK_DIRECTION (parent_menu_shell) == GTK_PACK_DIRECTION_LTR)
1632                 gtk_menu_shell_move_selected (parent_menu_shell, -1);
1633               else
1634                 gtk_menu_shell_move_selected (parent_menu_shell, 1);
1635               gtk_menu_shell_select_submenu_first (parent_menu_shell);
1636             }
1637         }
1638       /* If there is no parent and the submenu is in the opposite direction
1639        * to the menu, then make the PARENT direction wrap around to
1640        * the bottom of the submenu.
1641        */
1642       else if (priv->active_menu_item &&
1643                _gtk_menu_item_is_selectable (priv->active_menu_item) &&
1644                GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu)
1645         {
1646           GtkMenuShell *submenu = GTK_MENU_SHELL (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu);
1647
1648           if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement !=
1649               GTK_MENU_SHELL_GET_CLASS (submenu)->submenu_placement)
1650             _gtk_menu_shell_select_last (submenu, TRUE);
1651         }
1652       break;
1653
1654     case GTK_MENU_DIR_CHILD:
1655       if (priv->active_menu_item &&
1656           _gtk_menu_item_is_selectable (priv->active_menu_item) &&
1657           GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu)
1658         {
1659           if (gtk_menu_shell_select_submenu_first (menu_shell))
1660             break;
1661         }
1662
1663       /* Try to find a menu running the opposite direction */
1664       while (parent_menu_shell &&
1665              (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
1666               GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement))
1667         {
1668           parent_menu_shell = GTK_MENU_SHELL (parent_menu_shell->priv->parent_menu_shell);
1669         }
1670
1671       if (parent_menu_shell)
1672         {
1673           if (PACK_DIRECTION (parent_menu_shell) == GTK_PACK_DIRECTION_LTR)
1674             gtk_menu_shell_move_selected (parent_menu_shell, 1);
1675           else
1676             gtk_menu_shell_move_selected (parent_menu_shell, -1);
1677
1678           gtk_menu_shell_select_submenu_first (parent_menu_shell);
1679         }
1680       break;
1681
1682     case GTK_MENU_DIR_PREV:
1683       gtk_menu_shell_move_selected (menu_shell, -1);
1684       if (!had_selection && !priv->active_menu_item && priv->children)
1685         _gtk_menu_shell_select_last (menu_shell, TRUE);
1686       break;
1687
1688     case GTK_MENU_DIR_NEXT:
1689       gtk_menu_shell_move_selected (menu_shell, 1);
1690       if (!had_selection && !priv->active_menu_item && priv->children)
1691         gtk_menu_shell_select_first (menu_shell, TRUE);
1692       break;
1693     }
1694 }
1695
1696 static void
1697 gtk_real_menu_shell_activate_current (GtkMenuShell *menu_shell,
1698                                       gboolean      force_hide)
1699 {
1700   GtkMenuShellPrivate *priv = menu_shell->priv;
1701
1702   if (priv->active_menu_item &&
1703       _gtk_menu_item_is_selectable (priv->active_menu_item))
1704   {
1705     if (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu == NULL)
1706       gtk_menu_shell_activate_item (menu_shell,
1707                                     priv->active_menu_item,
1708                                     force_hide);
1709     else
1710       _gtk_menu_item_popup_submenu (priv->active_menu_item, FALSE);
1711   }
1712 }
1713
1714 static void
1715 gtk_real_menu_shell_cancel (GtkMenuShell *menu_shell)
1716 {
1717   /* Unset the active menu item so gtk_menu_popdown() doesn't see it. */
1718   gtk_menu_shell_deselect (menu_shell);
1719   gtk_menu_shell_deactivate (menu_shell);
1720   g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
1721 }
1722
1723 static void
1724 gtk_real_menu_shell_cycle_focus (GtkMenuShell     *menu_shell,
1725                                  GtkDirectionType  dir)
1726 {
1727   GtkMenuShellPrivate *priv = menu_shell->priv;
1728
1729   while (menu_shell && !GTK_IS_MENU_BAR (menu_shell))
1730     {
1731       if (priv->parent_menu_shell)
1732         menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
1733       else
1734         menu_shell = NULL;
1735     }
1736
1737   if (menu_shell)
1738     _gtk_menu_bar_cycle_focus (GTK_MENU_BAR (menu_shell), dir);
1739 }
1740
1741 gint
1742 _gtk_menu_shell_get_popup_delay (GtkMenuShell *menu_shell)
1743 {
1744   GtkMenuShellClass *klass = GTK_MENU_SHELL_GET_CLASS (menu_shell);
1745   
1746   if (klass->get_popup_delay)
1747     {
1748       return klass->get_popup_delay (menu_shell);
1749     }
1750   else
1751     {
1752       gint popup_delay;
1753       GtkWidget *widget = GTK_WIDGET (menu_shell);
1754
1755       g_object_get (gtk_widget_get_settings (widget),
1756                     "gtk-menu-popup-delay", &popup_delay,
1757                     NULL);
1758
1759       return popup_delay;
1760     }
1761 }
1762
1763 /**
1764  * gtk_menu_shell_cancel:
1765  * @menu_shell: a #GtkMenuShell
1766  *
1767  * Cancels the selection within the menu shell.
1768  *
1769  * Since: 2.4
1770  */
1771 void
1772 gtk_menu_shell_cancel (GtkMenuShell *menu_shell)
1773 {
1774   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1775
1776   g_signal_emit (menu_shell, menu_shell_signals[CANCEL], 0);
1777 }
1778
1779 static GtkMnemonicHash *
1780 gtk_menu_shell_get_mnemonic_hash (GtkMenuShell *menu_shell,
1781                                   gboolean      create)
1782 {
1783   GtkMenuShellPrivate *priv = menu_shell->priv;
1784
1785   if (!priv->mnemonic_hash && create)
1786     priv->mnemonic_hash = _gtk_mnemonic_hash_new ();
1787   
1788   return priv->mnemonic_hash;
1789 }
1790
1791 static void
1792 menu_shell_add_mnemonic_foreach (guint     keyval,
1793                                  GSList   *targets,
1794                                  gpointer  data)
1795 {
1796   GtkKeyHash *key_hash = data;
1797
1798   _gtk_key_hash_add_entry (key_hash, keyval, 0, GUINT_TO_POINTER (keyval));
1799 }
1800
1801 static GtkKeyHash *
1802 gtk_menu_shell_get_key_hash (GtkMenuShell *menu_shell,
1803                              gboolean      create)
1804 {
1805   GtkMenuShellPrivate *priv = menu_shell->priv;
1806   GtkWidget *widget = GTK_WIDGET (menu_shell);
1807
1808   if (!priv->key_hash && create && gtk_widget_has_screen (widget))
1809     {
1810       GtkMnemonicHash *mnemonic_hash = gtk_menu_shell_get_mnemonic_hash (menu_shell, FALSE);
1811       GdkScreen *screen = gtk_widget_get_screen (widget);
1812       GdkKeymap *keymap = gdk_keymap_get_for_display (gdk_screen_get_display (screen));
1813
1814       if (!mnemonic_hash)
1815         return NULL;
1816
1817       priv->key_hash = _gtk_key_hash_new (keymap, NULL);
1818
1819       _gtk_mnemonic_hash_foreach (mnemonic_hash,
1820                                   menu_shell_add_mnemonic_foreach,
1821                                   priv->key_hash);
1822     }
1823
1824   return priv->key_hash;
1825 }
1826
1827 static void
1828 gtk_menu_shell_reset_key_hash (GtkMenuShell *menu_shell)
1829 {
1830   GtkMenuShellPrivate *priv = menu_shell->priv;
1831
1832   if (priv->key_hash)
1833     {
1834       _gtk_key_hash_free (priv->key_hash);
1835       priv->key_hash = NULL;
1836     }
1837 }
1838
1839 static gboolean
1840 gtk_menu_shell_activate_mnemonic (GtkMenuShell *menu_shell,
1841                                   GdkEventKey  *event)
1842 {
1843   GtkMnemonicHash *mnemonic_hash;
1844   GtkKeyHash *key_hash;
1845   GSList *entries;
1846   gboolean result = FALSE;
1847
1848   mnemonic_hash = gtk_menu_shell_get_mnemonic_hash (menu_shell, FALSE);
1849   if (!mnemonic_hash)
1850     return FALSE;
1851
1852   key_hash = gtk_menu_shell_get_key_hash (menu_shell, TRUE);
1853   if (!key_hash)
1854     return FALSE;
1855
1856   entries = _gtk_key_hash_lookup (key_hash,
1857                                   event->hardware_keycode,
1858                                   event->state,
1859                                   gtk_accelerator_get_default_mod_mask (),
1860                                   event->group);
1861
1862   if (entries)
1863     result = _gtk_mnemonic_hash_activate (mnemonic_hash,
1864                                           GPOINTER_TO_UINT (entries->data));
1865
1866   return result;
1867 }
1868
1869 void
1870 _gtk_menu_shell_add_mnemonic (GtkMenuShell *menu_shell,
1871                               guint         keyval,
1872                               GtkWidget    *target)
1873 {
1874   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1875   g_return_if_fail (GTK_IS_WIDGET (target));
1876
1877   _gtk_mnemonic_hash_add (gtk_menu_shell_get_mnemonic_hash (menu_shell, TRUE),
1878                           keyval, target);
1879   gtk_menu_shell_reset_key_hash (menu_shell);
1880 }
1881
1882 void
1883 _gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell,
1884                                  guint         keyval,
1885                                  GtkWidget    *target)
1886 {
1887   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1888   g_return_if_fail (GTK_IS_WIDGET (target));
1889
1890   _gtk_mnemonic_hash_remove (gtk_menu_shell_get_mnemonic_hash (menu_shell, TRUE),
1891                              keyval, target);
1892   gtk_menu_shell_reset_key_hash (menu_shell);
1893 }
1894
1895 void
1896 _gtk_menu_shell_set_grab_device (GtkMenuShell *menu_shell,
1897                                  GdkDevice    *device)
1898 {
1899   GtkMenuShellPrivate *priv = menu_shell->priv;
1900
1901   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1902   g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
1903
1904   if (!device)
1905     priv->grab_pointer = NULL;
1906   else if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
1907     priv->grab_pointer = gdk_device_get_associated_device (device);
1908   else
1909     priv->grab_pointer = device;
1910 }
1911
1912 GdkDevice *
1913 _gtk_menu_shell_get_grab_device (GtkMenuShell *menu_shell)
1914 {
1915   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), NULL);
1916
1917   return menu_shell->priv->grab_pointer;
1918 }
1919
1920 /**
1921  * gtk_menu_shell_get_take_focus:
1922  * @menu_shell: a #GtkMenuShell
1923  *
1924  * Returns %TRUE if the menu shell will take the keyboard focus on popup.
1925  *
1926  * Returns: %TRUE if the menu shell will take the keyboard focus on popup.
1927  *
1928  * Since: 2.8
1929  */
1930 gboolean
1931 gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell)
1932 {
1933   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
1934
1935   return menu_shell->priv->take_focus;
1936 }
1937
1938 /**
1939  * gtk_menu_shell_set_take_focus:
1940  * @menu_shell: a #GtkMenuShell
1941  * @take_focus: %TRUE if the menu shell should take the keyboard
1942  *     focus on popup
1943  *
1944  * If @take_focus is %TRUE (the default) the menu shell will take
1945  * the keyboard focus so that it will receive all keyboard events
1946  * which is needed to enable keyboard navigation in menus.
1947  *
1948  * Setting @take_focus to %FALSE is useful only for special applications
1949  * like virtual keyboard implementations which should not take keyboard
1950  * focus.
1951  *
1952  * The @take_focus state of a menu or menu bar is automatically
1953  * propagated to submenus whenever a submenu is popped up, so you
1954  * don't have to worry about recursively setting it for your entire
1955  * menu hierarchy. Only when programmatically picking a submenu and
1956  * popping it up manually, the @take_focus property of the submenu
1957  * needs to be set explicitely.
1958  *
1959  * Note that setting it to %FALSE has side-effects:
1960  *
1961  * If the focus is in some other app, it keeps the focus and keynav in
1962  * the menu doesn't work. Consequently, keynav on the menu will only
1963  * work if the focus is on some toplevel owned by the onscreen keyboard.
1964  *
1965  * To avoid confusing the user, menus with @take_focus set to %FALSE
1966  * should not display mnemonics or accelerators, since it cannot be
1967  * guaranteed that they will work.
1968  *
1969  * See also gdk_keyboard_grab()
1970  *
1971  * Since: 2.8
1972  */
1973 void
1974 gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell,
1975                                gboolean      take_focus)
1976 {
1977   GtkMenuShellPrivate *priv = menu_shell->priv;
1978
1979   g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
1980
1981   if (priv->take_focus != take_focus)
1982     {
1983       priv->take_focus = take_focus;
1984       g_object_notify (G_OBJECT (menu_shell), "take-focus");
1985     }
1986 }
1987
1988 /**
1989  * gtk_menu_shell_get_selected_item:
1990  * @menu_shell: a #GtkMenuShell
1991  *
1992  * Gets the currently selected item.
1993  *
1994  * Returns: (transfer none): the currently selected item
1995  *
1996  * Since: 3.0
1997  */
1998 GtkWidget *
1999 gtk_menu_shell_get_selected_item (GtkMenuShell *menu_shell)
2000 {
2001   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), NULL);
2002
2003   return menu_shell->priv->active_menu_item;
2004 }
2005
2006 /**
2007  * gtk_menu_shell_get_parent_shell:
2008  * @menu_shell: a #GtkMenuShell
2009  *
2010  * Gets the parent menu shell.
2011  *
2012  * The parent menu shell of a submenu is the #GtkMenu or #GtkMenuBar
2013  * from which it was opened up.
2014  *
2015  * Returns: (transfer none): the parent #GtkMenuShell
2016  *
2017  * Since: 3.0
2018  */
2019 GtkWidget *
2020 gtk_menu_shell_get_parent_shell (GtkMenuShell *menu_shell)
2021 {
2022   g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), NULL);
2023
2024   return menu_shell->priv->parent_menu_shell;
2025 }