]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenubar.c
menubar: Remove unused variable
[~andy/gtk] / gtk / gtkmenubar.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:gtkmenubar
29  * @Title: GtkMenuBar
30  * @Short_description: A subclass of GtkMenuShell which holds GtkMenuItem widgets
31  * @See_also: #GtkMenuShell, #GtkMenu, #GtkMenuItem
32  *
33  * The #GtkMenuBar is a subclass of #GtkMenuShell which contains one or
34  * more #GtkMenuItems. The result is a standard menu bar which can hold
35  * many menu items.
36  */
37
38 #include "config.h"
39
40 #include "gtkmenubar.h"
41
42 #include "gtkbindings.h"
43 #include "gtkmain.h"
44 #include "gtkmarshalers.h"
45 #include "gtkmenuitemprivate.h"
46 #include "gtkmenuprivate.h"
47 #include "gtkmenushellprivate.h"
48 #include "gtksettings.h"
49 #include "gtksizerequest.h"
50 #include "gtkwindow.h"
51 #include "gtkintl.h"
52 #include "gtkprivate.h"
53 #include "gtktypebuiltins.h"
54
55 #define BORDER_SPACING  0
56 #define DEFAULT_IPADDING 1
57
58 /* Properties */
59 enum {
60   PROP_0,
61   PROP_PACK_DIRECTION,
62   PROP_CHILD_PACK_DIRECTION
63 };
64
65 struct _GtkMenuBarPrivate
66 {
67   GtkPackDirection pack_direction;
68   GtkPackDirection child_pack_direction;
69 };
70
71
72 static void gtk_menu_bar_set_property      (GObject             *object,
73                                             guint                prop_id,
74                                             const GValue        *value,
75                                             GParamSpec          *pspec);
76 static void gtk_menu_bar_get_property      (GObject             *object,
77                                             guint                prop_id,
78                                             GValue              *value,
79                                             GParamSpec          *pspec);
80 static void gtk_menu_bar_size_request      (GtkWidget       *widget,
81                                             GtkRequisition  *requisition);
82 static void gtk_menu_bar_get_preferred_width (GtkWidget     *widget,
83                                               gint          *minimum,
84                                               gint          *natural);
85 static void gtk_menu_bar_get_preferred_height (GtkWidget    *widget,
86                                                gint         *minimum,
87                                                gint         *natural);
88 static void gtk_menu_bar_size_allocate     (GtkWidget       *widget,
89                                             GtkAllocation   *allocation);
90 static gint gtk_menu_bar_draw              (GtkWidget       *widget,
91                                             cairo_t         *cr);
92 static void gtk_menu_bar_hierarchy_changed (GtkWidget       *widget,
93                                             GtkWidget       *old_toplevel);
94 static gint gtk_menu_bar_get_popup_delay   (GtkMenuShell    *menu_shell);
95 static void gtk_menu_bar_move_current      (GtkMenuShell     *menu_shell,
96                                             GtkMenuDirectionType direction);
97
98 static GtkShadowType get_shadow_type   (GtkMenuBar      *menubar);
99
100 G_DEFINE_TYPE (GtkMenuBar, gtk_menu_bar, GTK_TYPE_MENU_SHELL)
101
102 static void
103 gtk_menu_bar_class_init (GtkMenuBarClass *class)
104 {
105   GObjectClass *gobject_class;
106   GtkWidgetClass *widget_class;
107   GtkMenuShellClass *menu_shell_class;
108
109   GtkBindingSet *binding_set;
110
111   gobject_class = (GObjectClass*) class;
112   widget_class = (GtkWidgetClass*) class;
113   menu_shell_class = (GtkMenuShellClass*) class;
114
115   gobject_class->get_property = gtk_menu_bar_get_property;
116   gobject_class->set_property = gtk_menu_bar_set_property;
117
118   widget_class->get_preferred_width = gtk_menu_bar_get_preferred_width;
119   widget_class->get_preferred_height = gtk_menu_bar_get_preferred_height;
120   widget_class->size_allocate = gtk_menu_bar_size_allocate;
121   widget_class->draw = gtk_menu_bar_draw;
122   widget_class->hierarchy_changed = gtk_menu_bar_hierarchy_changed;
123   
124   menu_shell_class->submenu_placement = GTK_TOP_BOTTOM;
125   menu_shell_class->get_popup_delay = gtk_menu_bar_get_popup_delay;
126   menu_shell_class->move_current = gtk_menu_bar_move_current;
127
128   binding_set = gtk_binding_set_by_class (class);
129   gtk_binding_entry_add_signal (binding_set,
130                                 GDK_KEY_Left, 0,
131                                 "move-current", 1,
132                                 GTK_TYPE_MENU_DIRECTION_TYPE,
133                                 GTK_MENU_DIR_PREV);
134   gtk_binding_entry_add_signal (binding_set,
135                                 GDK_KEY_KP_Left, 0,
136                                 "move-current", 1,
137                                 GTK_TYPE_MENU_DIRECTION_TYPE,
138                                 GTK_MENU_DIR_PREV);
139   gtk_binding_entry_add_signal (binding_set,
140                                 GDK_KEY_Right, 0,
141                                 "move-current", 1,
142                                 GTK_TYPE_MENU_DIRECTION_TYPE,
143                                 GTK_MENU_DIR_NEXT);
144   gtk_binding_entry_add_signal (binding_set,
145                                 GDK_KEY_KP_Right, 0,
146                                 "move-current", 1,
147                                 GTK_TYPE_MENU_DIRECTION_TYPE,
148                                 GTK_MENU_DIR_NEXT);
149   gtk_binding_entry_add_signal (binding_set,
150                                 GDK_KEY_Up, 0,
151                                 "move-current", 1,
152                                 GTK_TYPE_MENU_DIRECTION_TYPE,
153                                 GTK_MENU_DIR_PARENT);
154   gtk_binding_entry_add_signal (binding_set,
155                                 GDK_KEY_KP_Up, 0,
156                                 "move-current", 1,
157                                 GTK_TYPE_MENU_DIRECTION_TYPE,
158                                 GTK_MENU_DIR_PARENT);
159   gtk_binding_entry_add_signal (binding_set,
160                                 GDK_KEY_Down, 0,
161                                 "move-current", 1,
162                                 GTK_TYPE_MENU_DIRECTION_TYPE,
163                                 GTK_MENU_DIR_CHILD);
164   gtk_binding_entry_add_signal (binding_set,
165                                 GDK_KEY_KP_Down, 0,
166                                 "move-current", 1,
167                                 GTK_TYPE_MENU_DIRECTION_TYPE,
168                                 GTK_MENU_DIR_CHILD);
169
170   /**
171    * GtkMenuBar:pack-direction:
172    *
173    * The pack direction of the menubar. It determines how
174    * menuitems are arranged in the menubar.
175    *
176    * Since: 2.8
177    */
178   g_object_class_install_property (gobject_class,
179                                    PROP_PACK_DIRECTION,
180                                    g_param_spec_enum ("pack-direction",
181                                                       P_("Pack direction"),
182                                                       P_("The pack direction of the menubar"),
183                                                       GTK_TYPE_PACK_DIRECTION,
184                                                       GTK_PACK_DIRECTION_LTR,
185                                                       GTK_PARAM_READWRITE));
186   
187   /**
188    * GtkMenuBar:child-pack-direction:
189    *
190    * The child pack direction of the menubar. It determines how
191    * the widgets contained in child menuitems are arranged.
192    *
193    * Since: 2.8
194    */
195   g_object_class_install_property (gobject_class,
196                                    PROP_CHILD_PACK_DIRECTION,
197                                    g_param_spec_enum ("child-pack-direction",
198                                                       P_("Child Pack direction"),
199                                                       P_("The child pack direction of the menubar"),
200                                                       GTK_TYPE_PACK_DIRECTION,
201                                                       GTK_PACK_DIRECTION_LTR,
202                                                       GTK_PARAM_READWRITE));
203   
204
205   gtk_widget_class_install_style_property (widget_class,
206                                            g_param_spec_enum ("shadow-type",
207                                                               P_("Shadow type"),
208                                                               P_("Style of bevel around the menubar"),
209                                                               GTK_TYPE_SHADOW_TYPE,
210                                                               GTK_SHADOW_OUT,
211                                                               GTK_PARAM_READABLE));
212
213   gtk_widget_class_install_style_property (widget_class,
214                                            g_param_spec_int ("internal-padding",
215                                                              P_("Internal padding"),
216                                                              P_("Amount of border space between the menubar shadow and the menu items"),
217                                                              0,
218                                                              G_MAXINT,
219                                                              DEFAULT_IPADDING,
220                                                              GTK_PARAM_READABLE));
221
222   g_type_class_add_private (gobject_class, sizeof (GtkMenuBarPrivate));
223 }
224
225 static void
226 gtk_menu_bar_init (GtkMenuBar *menu_bar)
227 {
228   GtkStyleContext *context;
229
230   menu_bar->priv = G_TYPE_INSTANCE_GET_PRIVATE (menu_bar,
231                                                 GTK_TYPE_MENU_BAR,
232                                                 GtkMenuBarPrivate);
233
234   context = gtk_widget_get_style_context (GTK_WIDGET (menu_bar));
235   gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUBAR);
236 }
237
238 /**
239  * gtk_menu_bar_new:
240  *
241  * Creates a new #GtkMenuBar
242  *
243  * Returns: the new menu bar, as a #GtkWidget
244  */
245 GtkWidget*
246 gtk_menu_bar_new (void)
247 {
248   return g_object_new (GTK_TYPE_MENU_BAR, NULL);
249 }
250
251 static void
252 gtk_menu_bar_set_property (GObject      *object,
253                            guint         prop_id,
254                            const GValue *value,
255                            GParamSpec   *pspec)
256 {
257   GtkMenuBar *menubar = GTK_MENU_BAR (object);
258   
259   switch (prop_id)
260     {
261     case PROP_PACK_DIRECTION:
262       gtk_menu_bar_set_pack_direction (menubar, g_value_get_enum (value));
263       break;
264     case PROP_CHILD_PACK_DIRECTION:
265       gtk_menu_bar_set_child_pack_direction (menubar, g_value_get_enum (value));
266       break;
267     default:
268       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
269       break;
270     }
271 }
272
273 static void
274 gtk_menu_bar_get_property (GObject    *object,
275                            guint       prop_id,
276                            GValue     *value,
277                            GParamSpec *pspec)
278 {
279   GtkMenuBar *menubar = GTK_MENU_BAR (object);
280   
281   switch (prop_id)
282     {
283     case PROP_PACK_DIRECTION:
284       g_value_set_enum (value, gtk_menu_bar_get_pack_direction (menubar));
285       break;
286     case PROP_CHILD_PACK_DIRECTION:
287       g_value_set_enum (value, gtk_menu_bar_get_child_pack_direction (menubar));
288       break;
289     default:
290       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291       break;
292     }
293 }
294
295 static void
296 gtk_menu_bar_size_request (GtkWidget      *widget,
297                            GtkRequisition *requisition)
298 {
299   GtkMenuBar *menu_bar;
300   GtkMenuBarPrivate *priv;
301   GtkMenuShell *menu_shell;
302   GtkWidget *child;
303   GList *children;
304   GtkRequisition child_requisition;
305   gint ipadding;
306   guint border_width;
307
308   g_return_if_fail (GTK_IS_MENU_BAR (widget));
309   g_return_if_fail (requisition != NULL);
310
311   requisition->width = 0;
312   requisition->height = 0;
313   
314   menu_bar = GTK_MENU_BAR (widget);
315   menu_shell = GTK_MENU_SHELL (widget);
316   priv = menu_bar->priv;
317
318   children = menu_shell->priv->children;
319
320   while (children)
321     {
322       child = children->data;
323       children = children->next;
324
325       if (gtk_widget_get_visible (child))
326         {
327           gint toggle_size;
328
329           gtk_widget_get_preferred_size (child, &child_requisition, NULL);
330           gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child),
331                                              &toggle_size);
332
333           if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR ||
334               priv->child_pack_direction == GTK_PACK_DIRECTION_RTL)
335             child_requisition.width += toggle_size;
336           else
337             child_requisition.height += toggle_size;
338
339           if (priv->pack_direction == GTK_PACK_DIRECTION_LTR ||
340               priv->pack_direction == GTK_PACK_DIRECTION_RTL)
341             {
342               requisition->width += child_requisition.width;
343               requisition->height = MAX (requisition->height, child_requisition.height);
344             }
345           else
346             {
347               requisition->width = MAX (requisition->width, child_requisition.width);
348               requisition->height += child_requisition.height;
349             }
350         }
351     }
352
353   gtk_widget_style_get (widget, "internal-padding", &ipadding, NULL);
354
355   border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_bar));
356   requisition->width += (border_width +
357                          ipadding + 
358                          BORDER_SPACING) * 2;
359   requisition->height += (border_width +
360                           ipadding +
361                           BORDER_SPACING) * 2;
362
363   if (get_shadow_type (menu_bar) != GTK_SHADOW_NONE)
364     {
365       GtkStyleContext *context;
366       GtkBorder *border;
367
368       context = gtk_widget_get_style_context (widget);
369
370       gtk_style_context_get (context, 0,
371                              "border-width", &border,
372                              NULL);
373
374       requisition->width += border->left + border->right;
375       requisition->height += border->top + border->bottom;
376       gtk_border_free (border);
377     }
378 }
379
380 static void
381 gtk_menu_bar_get_preferred_width (GtkWidget *widget,
382                                   gint      *minimum,
383                                   gint      *natural)
384 {
385   GtkRequisition requisition;
386
387   gtk_menu_bar_size_request (widget, &requisition);
388
389   *minimum = *natural = requisition.width;
390 }
391
392 static void
393 gtk_menu_bar_get_preferred_height (GtkWidget *widget,
394                                    gint      *minimum,
395                                    gint      *natural)
396 {
397   GtkRequisition requisition;
398
399   gtk_menu_bar_size_request (widget, &requisition);
400
401   *minimum = *natural = requisition.height;
402 }
403
404 static void
405 gtk_menu_bar_size_allocate (GtkWidget     *widget,
406                             GtkAllocation *allocation)
407 {
408   GtkMenuBar *menu_bar;
409   GtkMenuShell *menu_shell;
410   GtkMenuBarPrivate *priv;
411   GtkWidget *child;
412   GList *children;
413   GtkAllocation child_allocation;
414   GtkRequisition child_requisition;
415   guint offset;
416   GtkTextDirection direction;
417   gint ltr_x, ltr_y;
418   gint ipadding;
419   guint border_width;
420
421   g_return_if_fail (GTK_IS_MENU_BAR (widget));
422   g_return_if_fail (allocation != NULL);
423
424   menu_bar = GTK_MENU_BAR (widget);
425   menu_shell = GTK_MENU_SHELL (widget);
426   priv = menu_bar->priv;
427
428   direction = gtk_widget_get_direction (widget);
429
430   gtk_widget_set_allocation (widget, allocation);
431
432   if (gtk_widget_get_realized (widget))
433     gdk_window_move_resize (gtk_widget_get_window (widget),
434                             allocation->x, allocation->y,
435                             allocation->width, allocation->height);
436
437   gtk_widget_style_get (widget, "internal-padding", &ipadding, NULL);
438   
439   if (menu_shell->priv->children)
440     {
441       border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_bar));
442       child_allocation.x = (border_width +
443                             ipadding + 
444                             BORDER_SPACING);
445       child_allocation.y = (border_width +
446                             BORDER_SPACING);
447       
448       if (get_shadow_type (menu_bar) != GTK_SHADOW_NONE)
449         {
450           GtkStyleContext *context;
451           GtkBorder *border;
452
453           context = gtk_widget_get_style_context (widget);
454           gtk_style_context_get (context, 0,
455                                  "border-width", &border,
456                                  NULL);
457
458           child_allocation.x += border->left;
459           child_allocation.y += border->top;
460
461           gtk_border_free (border);
462         }
463       
464       if (priv->pack_direction == GTK_PACK_DIRECTION_LTR ||
465           priv->pack_direction == GTK_PACK_DIRECTION_RTL)
466         {
467           child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
468
469           offset = child_allocation.x;  /* Window edge to menubar start */
470           ltr_x = child_allocation.x;
471
472           children = menu_shell->priv->children;
473           while (children)
474             {
475               gint toggle_size;
476
477               child = children->data;
478               children = children->next;
479               
480               gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child),
481                                                  &toggle_size);
482               gtk_widget_get_preferred_size (child, &child_requisition, NULL);
483
484               if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR ||
485                   priv->child_pack_direction == GTK_PACK_DIRECTION_RTL)
486                 child_requisition.width += toggle_size;
487               else
488                 child_requisition.height += toggle_size;
489
490               /* Support for the right justified help menu */
491               if (children == NULL &&
492                   GTK_IS_MENU_ITEM (child) &&
493                   GTK_MENU_ITEM (child)->priv->right_justify)
494                 {
495                   ltr_x = allocation->width -
496                     child_requisition.width - offset;
497                 }
498               if (gtk_widget_get_visible (child))
499                 {
500                   if ((direction == GTK_TEXT_DIR_LTR) == (priv->pack_direction == GTK_PACK_DIRECTION_LTR))
501                     child_allocation.x = ltr_x;
502                   else
503                     child_allocation.x = allocation->width -
504                       child_requisition.width - ltr_x; 
505                   
506                   child_allocation.width = child_requisition.width;
507                   
508                   gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child),
509                                                       toggle_size);
510                   gtk_widget_size_allocate (child, &child_allocation);
511                   
512                   ltr_x += child_allocation.width;
513                 }
514             }
515         }
516       else
517         {
518           child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
519
520           offset = child_allocation.y;  /* Window edge to menubar start */
521           ltr_y = child_allocation.y;
522
523           children = menu_shell->priv->children;
524           while (children)
525             {
526               gint toggle_size;
527
528               child = children->data;
529               children = children->next;
530               
531               gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child),
532                                                  &toggle_size);
533               gtk_widget_get_preferred_size (child, &child_requisition, NULL);
534
535               if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR ||
536                   priv->child_pack_direction == GTK_PACK_DIRECTION_RTL)
537                 child_requisition.width += toggle_size;
538               else
539                 child_requisition.height += toggle_size;
540
541               /* Support for the right justified help menu */
542               if (children == NULL &&
543                   GTK_IS_MENU_ITEM (child) &&
544                   GTK_MENU_ITEM (child)->priv->right_justify)
545                 {
546                   ltr_y = allocation->height -
547                     child_requisition.height - offset;
548                 }
549               if (gtk_widget_get_visible (child))
550                 {
551                   if ((direction == GTK_TEXT_DIR_LTR) ==
552                       (priv->pack_direction == GTK_PACK_DIRECTION_TTB))
553                     child_allocation.y = ltr_y;
554                   else
555                     child_allocation.y = allocation->height -
556                       child_requisition.height - ltr_y; 
557                   child_allocation.height = child_requisition.height;
558                   
559                   gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child),
560                                                       toggle_size);
561                   gtk_widget_size_allocate (child, &child_allocation);
562                   
563                   ltr_y += child_allocation.height;
564                 }
565             }
566         }
567     }
568 }
569
570 static gint
571 gtk_menu_bar_draw (GtkWidget *widget,
572                    cairo_t   *cr)
573 {
574   GtkStyleContext *context;
575   GtkStateFlags state;
576   int border;
577
578   border = gtk_container_get_border_width (GTK_CONTAINER (widget));
579   context = gtk_widget_get_style_context (widget);
580
581   state = gtk_widget_get_state_flags (widget);
582   gtk_style_context_set_state (context, state);
583
584   if (get_shadow_type (GTK_MENU_BAR (widget)) != GTK_SHADOW_NONE)
585     gtk_render_background (context, cr,
586                            border, border,
587                            gtk_widget_get_allocated_width (widget) - border * 2,
588                            gtk_widget_get_allocated_height (widget) - border * 2);
589
590   gtk_render_frame (context, cr,
591                     border, border,
592                     gtk_widget_get_allocated_width (widget) - border * 2,
593                     gtk_widget_get_allocated_height (widget) - border * 2);
594
595   GTK_WIDGET_CLASS (gtk_menu_bar_parent_class)->draw (widget, cr);
596
597   return FALSE;
598 }
599
600 static GList *
601 get_menu_bars (GtkWindow *window)
602 {
603   return g_object_get_data (G_OBJECT (window), "gtk-menu-bar-list");
604 }
605
606 static GList *
607 get_viewable_menu_bars (GtkWindow *window)
608 {
609   GList *menu_bars;
610   GList *viewable_menu_bars = NULL;
611
612   for (menu_bars = get_menu_bars (window);
613        menu_bars;
614        menu_bars = menu_bars->next)
615     {
616       GtkWidget *widget = menu_bars->data;
617       gboolean viewable = TRUE;
618       
619       while (widget)
620         {
621           if (!gtk_widget_get_mapped (widget))
622             viewable = FALSE;
623
624           widget = gtk_widget_get_parent (widget);
625         }
626
627       if (viewable)
628         viewable_menu_bars = g_list_prepend (viewable_menu_bars, menu_bars->data);
629     }
630
631   return g_list_reverse (viewable_menu_bars);
632 }
633
634 static void
635 set_menu_bars (GtkWindow *window,
636                GList     *menubars)
637 {
638   g_object_set_data (G_OBJECT (window), I_("gtk-menu-bar-list"), menubars);
639 }
640
641 static gboolean
642 window_key_press_handler (GtkWidget   *widget,
643                           GdkEventKey *event,
644                           gpointer     data)
645 {
646   gchar *accel = NULL;
647   gboolean retval = FALSE;
648   
649   g_object_get (gtk_widget_get_settings (widget),
650                 "gtk-menu-bar-accel", &accel,
651                 NULL);
652
653   if (accel && *accel)
654     {
655       guint keyval = 0;
656       GdkModifierType mods = 0;
657
658       gtk_accelerator_parse (accel, &keyval, &mods);
659
660       if (keyval == 0)
661         g_warning ("Failed to parse menu bar accelerator '%s'\n", accel);
662
663       /* FIXME this is wrong, needs to be in the global accel resolution
664        * thing, to properly consider i18n etc., but that probably requires
665        * AccelGroup changes etc.
666        */
667       if (event->keyval == keyval &&
668           ((event->state & gtk_accelerator_get_default_mod_mask ()) ==
669            (mods & gtk_accelerator_get_default_mod_mask ())))
670         {
671           GList *tmp_menubars = get_viewable_menu_bars (GTK_WINDOW (widget));
672           GList *menubars;
673
674           menubars = _gtk_container_focus_sort (GTK_CONTAINER (widget), tmp_menubars,
675                                                 GTK_DIR_TAB_FORWARD, NULL);
676           g_list_free (tmp_menubars);
677           
678           if (menubars)
679             {
680               GtkMenuShell *menu_shell = GTK_MENU_SHELL (menubars->data);
681
682               _gtk_menu_shell_set_keyboard_mode (menu_shell, TRUE);
683               gtk_menu_shell_select_first (menu_shell, FALSE);
684               
685               g_list_free (menubars);
686               
687               retval = TRUE;          
688             }
689         }
690     }
691
692   g_free (accel);
693
694   return retval;
695 }
696
697 static void
698 add_to_window (GtkWindow  *window,
699                GtkMenuBar *menubar)
700 {
701   GList *menubars = get_menu_bars (window);
702
703   if (!menubars)
704     {
705       g_signal_connect (window,
706                         "key-press-event",
707                         G_CALLBACK (window_key_press_handler),
708                         NULL);
709     }
710
711   set_menu_bars (window, g_list_prepend (menubars, menubar));
712 }
713
714 static void
715 remove_from_window (GtkWindow  *window,
716                     GtkMenuBar *menubar)
717 {
718   GList *menubars = get_menu_bars (window);
719
720   menubars = g_list_remove (menubars, menubar);
721
722   if (!menubars)
723     {
724       g_signal_handlers_disconnect_by_func (window,
725                                             window_key_press_handler,
726                                             NULL);
727     }
728
729   set_menu_bars (window, menubars);
730 }
731
732 static void
733 gtk_menu_bar_hierarchy_changed (GtkWidget *widget,
734                                 GtkWidget *old_toplevel)
735 {
736   GtkWidget *toplevel;  
737   GtkMenuBar *menubar;
738
739   menubar = GTK_MENU_BAR (widget);
740
741   toplevel = gtk_widget_get_toplevel (widget);
742
743   if (old_toplevel)
744     remove_from_window (GTK_WINDOW (old_toplevel), menubar);
745   
746   if (gtk_widget_is_toplevel (toplevel))
747     add_to_window (GTK_WINDOW (toplevel), menubar);
748 }
749
750 /**
751  * _gtk_menu_bar_cycle_focus:
752  * @menubar: a #GtkMenuBar
753  * @dir: direction in which to cycle the focus
754  * 
755  * Move the focus between menubars in the toplevel.
756  **/
757 void
758 _gtk_menu_bar_cycle_focus (GtkMenuBar       *menubar,
759                            GtkDirectionType  dir)
760 {
761   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menubar));
762   GtkMenuItem *to_activate = NULL;
763
764   if (gtk_widget_is_toplevel (toplevel))
765     {
766       GList *tmp_menubars = get_viewable_menu_bars (GTK_WINDOW (toplevel));
767       GList *menubars;
768       GList *current;
769
770       menubars = _gtk_container_focus_sort (GTK_CONTAINER (toplevel), tmp_menubars,
771                                             dir, GTK_WIDGET (menubar));
772       g_list_free (tmp_menubars);
773
774       if (menubars)
775         {
776           current = g_list_find (menubars, menubar);
777
778           if (current && current->next)
779             {
780               GtkMenuShell *new_menushell = GTK_MENU_SHELL (current->next->data);
781               if (new_menushell->priv->children)
782                 to_activate = new_menushell->priv->children->data;
783             }
784         }
785           
786       g_list_free (menubars);
787     }
788
789   gtk_menu_shell_cancel (GTK_MENU_SHELL (menubar));
790
791   if (to_activate)
792     g_signal_emit_by_name (to_activate, "activate_item");
793 }
794
795 static GtkShadowType
796 get_shadow_type (GtkMenuBar *menubar)
797 {
798   GtkShadowType shadow_type = GTK_SHADOW_OUT;
799   
800   gtk_widget_style_get (GTK_WIDGET (menubar),
801                         "shadow-type", &shadow_type,
802                         NULL);
803
804   return shadow_type;
805 }
806
807 static gint
808 gtk_menu_bar_get_popup_delay (GtkMenuShell *menu_shell)
809 {
810   gint popup_delay;
811   
812   g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
813                 "gtk-menu-bar-popup-delay", &popup_delay,
814                 NULL);
815
816   return popup_delay;
817 }
818
819 static void
820 gtk_menu_bar_move_current (GtkMenuShell         *menu_shell,
821                            GtkMenuDirectionType  direction)
822 {
823   GtkMenuBar *menubar = GTK_MENU_BAR (menu_shell);
824   GtkTextDirection text_dir;
825   GtkPackDirection pack_dir;
826
827   text_dir = gtk_widget_get_direction (GTK_WIDGET (menubar));
828   pack_dir = gtk_menu_bar_get_pack_direction (menubar);
829   
830   if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL)
831      {
832       if ((text_dir == GTK_TEXT_DIR_RTL) == (pack_dir == GTK_PACK_DIRECTION_LTR))
833         {
834           switch (direction) 
835             {      
836             case GTK_MENU_DIR_PREV:
837               direction = GTK_MENU_DIR_NEXT;
838               break;
839             case GTK_MENU_DIR_NEXT:
840               direction = GTK_MENU_DIR_PREV;
841               break;
842             default: ;
843             }
844         }
845     }
846   else
847     {
848       switch (direction) 
849         {
850         case GTK_MENU_DIR_PARENT:
851           if ((text_dir == GTK_TEXT_DIR_LTR) == (pack_dir == GTK_PACK_DIRECTION_TTB))
852             direction = GTK_MENU_DIR_PREV;
853           else
854             direction = GTK_MENU_DIR_NEXT;
855           break;
856         case GTK_MENU_DIR_CHILD:
857           if ((text_dir == GTK_TEXT_DIR_LTR) == (pack_dir == GTK_PACK_DIRECTION_TTB))
858             direction = GTK_MENU_DIR_NEXT;
859           else
860             direction = GTK_MENU_DIR_PREV;
861           break;
862         case GTK_MENU_DIR_PREV:
863           if (text_dir == GTK_TEXT_DIR_RTL)       
864             direction = GTK_MENU_DIR_CHILD;
865           else
866             direction = GTK_MENU_DIR_PARENT;
867           break;
868         case GTK_MENU_DIR_NEXT:
869           if (text_dir == GTK_TEXT_DIR_RTL)       
870             direction = GTK_MENU_DIR_PARENT;
871           else
872             direction = GTK_MENU_DIR_CHILD;
873           break;
874         default: ;
875         }
876     }
877   
878   GTK_MENU_SHELL_CLASS (gtk_menu_bar_parent_class)->move_current (menu_shell, direction);
879 }
880
881 /**
882  * gtk_menu_bar_get_pack_direction:
883  * @menubar: a #GtkMenuBar
884  * 
885  * Retrieves the current pack direction of the menubar. 
886  * See gtk_menu_bar_set_pack_direction().
887  *
888  * Return value: the pack direction
889  *
890  * Since: 2.8
891  */
892 GtkPackDirection
893 gtk_menu_bar_get_pack_direction (GtkMenuBar *menubar)
894 {
895   g_return_val_if_fail (GTK_IS_MENU_BAR (menubar), 
896                         GTK_PACK_DIRECTION_LTR);
897
898   return menubar->priv->pack_direction;
899 }
900
901 /**
902  * gtk_menu_bar_set_pack_direction:
903  * @menubar: a #GtkMenuBar
904  * @pack_dir: a new #GtkPackDirection
905  * 
906  * Sets how items should be packed inside a menubar.
907  * 
908  * Since: 2.8
909  */
910 void
911 gtk_menu_bar_set_pack_direction (GtkMenuBar       *menubar,
912                                  GtkPackDirection  pack_dir)
913 {
914   GtkMenuBarPrivate *priv;
915   GList *l;
916
917   g_return_if_fail (GTK_IS_MENU_BAR (menubar));
918
919   priv = menubar->priv;
920
921   if (priv->pack_direction != pack_dir)
922     {
923       priv->pack_direction = pack_dir;
924
925       gtk_widget_queue_resize (GTK_WIDGET (menubar));
926
927       for (l = GTK_MENU_SHELL (menubar)->priv->children; l; l = l->next)
928         gtk_widget_queue_resize (GTK_WIDGET (l->data));
929
930       g_object_notify (G_OBJECT (menubar), "pack-direction");
931     }
932 }
933
934 /**
935  * gtk_menu_bar_get_child_pack_direction:
936  * @menubar: a #GtkMenuBar
937  * 
938  * Retrieves the current child pack direction of the menubar.
939  * See gtk_menu_bar_set_child_pack_direction().
940  *
941  * Return value: the child pack direction
942  *
943  * Since: 2.8
944  */
945 GtkPackDirection
946 gtk_menu_bar_get_child_pack_direction (GtkMenuBar *menubar)
947 {
948   g_return_val_if_fail (GTK_IS_MENU_BAR (menubar), 
949                         GTK_PACK_DIRECTION_LTR);
950
951   return menubar->priv->child_pack_direction;
952 }
953
954 /**
955  * gtk_menu_bar_set_child_pack_direction:
956  * @menubar: a #GtkMenuBar
957  * @child_pack_dir: a new #GtkPackDirection
958  * 
959  * Sets how widgets should be packed inside the children of a menubar.
960  * 
961  * Since: 2.8
962  */
963 void
964 gtk_menu_bar_set_child_pack_direction (GtkMenuBar       *menubar,
965                                        GtkPackDirection  child_pack_dir)
966 {
967   GtkMenuBarPrivate *priv;
968   GList *l;
969
970   g_return_if_fail (GTK_IS_MENU_BAR (menubar));
971
972   priv = menubar->priv;
973
974   if (priv->child_pack_direction != child_pack_dir)
975     {
976       priv->child_pack_direction = child_pack_dir;
977
978       gtk_widget_queue_resize (GTK_WIDGET (menubar));
979
980       for (l = GTK_MENU_SHELL (menubar)->priv->children; l; l = l->next)
981         gtk_widget_queue_resize (GTK_WIDGET (l->data));
982
983       g_object_notify (G_OBJECT (menubar), "child-pack-direction");
984     }
985 }