]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenubar.c
Merge ssh://git.gnome.org/git/gtk+
[~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   gint nchildren;
305   GtkRequisition child_requisition;
306   gint ipadding;
307   guint border_width;
308
309   g_return_if_fail (GTK_IS_MENU_BAR (widget));
310   g_return_if_fail (requisition != NULL);
311
312   requisition->width = 0;
313   requisition->height = 0;
314   
315   if (gtk_widget_get_visible (widget))
316     {
317       menu_bar = GTK_MENU_BAR (widget);
318       menu_shell = GTK_MENU_SHELL (widget);
319       priv = menu_bar->priv;
320
321       nchildren = 0;
322       children = menu_shell->priv->children;
323
324       while (children)
325         {
326           child = children->data;
327           children = children->next;
328
329           if (gtk_widget_get_visible (child))
330             {
331               gint toggle_size;
332
333               gtk_widget_get_preferred_size (child, &child_requisition, NULL);
334               gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child),
335                                                  &toggle_size);
336
337               if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR ||
338                   priv->child_pack_direction == GTK_PACK_DIRECTION_RTL)
339                 child_requisition.width += toggle_size;
340               else
341                 child_requisition.height += toggle_size;
342
343               if (priv->pack_direction == GTK_PACK_DIRECTION_LTR ||
344                   priv->pack_direction == GTK_PACK_DIRECTION_RTL)
345                 {
346                   requisition->width += child_requisition.width;
347                   requisition->height = MAX (requisition->height, child_requisition.height);
348                 }
349               else
350                 {
351                   requisition->width = MAX (requisition->width, child_requisition.width);
352                   requisition->height += child_requisition.height;
353                 }
354               nchildren += 1;
355             }
356         }
357
358       gtk_widget_style_get (widget, "internal-padding", &ipadding, NULL);
359
360       border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_bar));
361       requisition->width += (border_width +
362                              ipadding + 
363                              BORDER_SPACING) * 2;
364       requisition->height += (border_width +
365                               ipadding +
366                               BORDER_SPACING) * 2;
367
368       if (get_shadow_type (menu_bar) != GTK_SHADOW_NONE)
369         {
370           GtkStyleContext *context;
371           GtkBorder *border;
372
373           context = gtk_widget_get_style_context (widget);
374
375           gtk_style_context_get (context, 0,
376                                  "border-width", &border,
377                                  NULL);
378
379           requisition->width += border->left + border->right;
380           requisition->height += border->top + border->bottom;
381           gtk_border_free (border);
382         }
383     }
384 }
385
386 static void
387 gtk_menu_bar_get_preferred_width (GtkWidget *widget,
388                                   gint      *minimum,
389                                   gint      *natural)
390 {
391   GtkRequisition requisition;
392
393   gtk_menu_bar_size_request (widget, &requisition);
394
395   *minimum = *natural = requisition.width;
396 }
397
398 static void
399 gtk_menu_bar_get_preferred_height (GtkWidget *widget,
400                                    gint      *minimum,
401                                    gint      *natural)
402 {
403   GtkRequisition requisition;
404
405   gtk_menu_bar_size_request (widget, &requisition);
406
407   *minimum = *natural = requisition.height;
408 }
409
410 static void
411 gtk_menu_bar_size_allocate (GtkWidget     *widget,
412                             GtkAllocation *allocation)
413 {
414   GtkMenuBar *menu_bar;
415   GtkMenuShell *menu_shell;
416   GtkMenuBarPrivate *priv;
417   GtkWidget *child;
418   GList *children;
419   GtkAllocation child_allocation;
420   GtkRequisition child_requisition;
421   guint offset;
422   GtkTextDirection direction;
423   gint ltr_x, ltr_y;
424   gint ipadding;
425   guint border_width;
426
427   g_return_if_fail (GTK_IS_MENU_BAR (widget));
428   g_return_if_fail (allocation != NULL);
429
430   menu_bar = GTK_MENU_BAR (widget);
431   menu_shell = GTK_MENU_SHELL (widget);
432   priv = menu_bar->priv;
433
434   direction = gtk_widget_get_direction (widget);
435
436   gtk_widget_set_allocation (widget, allocation);
437
438   if (gtk_widget_get_realized (widget))
439     gdk_window_move_resize (gtk_widget_get_window (widget),
440                             allocation->x, allocation->y,
441                             allocation->width, allocation->height);
442
443   gtk_widget_style_get (widget, "internal-padding", &ipadding, NULL);
444   
445   if (menu_shell->priv->children)
446     {
447       border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_bar));
448       child_allocation.x = (border_width +
449                             ipadding + 
450                             BORDER_SPACING);
451       child_allocation.y = (border_width +
452                             BORDER_SPACING);
453       
454       if (get_shadow_type (menu_bar) != GTK_SHADOW_NONE)
455         {
456           GtkStyleContext *context;
457           GtkBorder *border;
458
459           context = gtk_widget_get_style_context (widget);
460           gtk_style_context_get (context, 0,
461                                  "border-width", &border,
462                                  NULL);
463
464           child_allocation.x += border->left;
465           child_allocation.y += border->top;
466
467           gtk_border_free (border);
468         }
469       
470       if (priv->pack_direction == GTK_PACK_DIRECTION_LTR ||
471           priv->pack_direction == GTK_PACK_DIRECTION_RTL)
472         {
473           child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2);
474
475           offset = child_allocation.x;  /* Window edge to menubar start */
476           ltr_x = child_allocation.x;
477
478           children = menu_shell->priv->children;
479           while (children)
480             {
481               gint toggle_size;
482
483               child = children->data;
484               children = children->next;
485               
486               gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child),
487                                                  &toggle_size);
488               gtk_widget_get_preferred_size (child, &child_requisition, NULL);
489
490               if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR ||
491                   priv->child_pack_direction == GTK_PACK_DIRECTION_RTL)
492                 child_requisition.width += toggle_size;
493               else
494                 child_requisition.height += toggle_size;
495
496               /* Support for the right justified help menu */
497               if (children == NULL &&
498                   GTK_IS_MENU_ITEM (child) &&
499                   GTK_MENU_ITEM (child)->priv->right_justify)
500                 {
501                   ltr_x = allocation->width -
502                     child_requisition.width - offset;
503                 }
504               if (gtk_widget_get_visible (child))
505                 {
506                   if ((direction == GTK_TEXT_DIR_LTR) == (priv->pack_direction == GTK_PACK_DIRECTION_LTR))
507                     child_allocation.x = ltr_x;
508                   else
509                     child_allocation.x = allocation->width -
510                       child_requisition.width - ltr_x; 
511                   
512                   child_allocation.width = child_requisition.width;
513                   
514                   gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child),
515                                                       toggle_size);
516                   gtk_widget_size_allocate (child, &child_allocation);
517                   
518                   ltr_x += child_allocation.width;
519                 }
520             }
521         }
522       else
523         {
524           child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
525
526           offset = child_allocation.y;  /* Window edge to menubar start */
527           ltr_y = child_allocation.y;
528
529           children = menu_shell->priv->children;
530           while (children)
531             {
532               gint toggle_size;
533
534               child = children->data;
535               children = children->next;
536               
537               gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child),
538                                                  &toggle_size);
539               gtk_widget_get_preferred_size (child, &child_requisition, NULL);
540
541               if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR ||
542                   priv->child_pack_direction == GTK_PACK_DIRECTION_RTL)
543                 child_requisition.width += toggle_size;
544               else
545                 child_requisition.height += toggle_size;
546
547               /* Support for the right justified help menu */
548               if (children == NULL &&
549                   GTK_IS_MENU_ITEM (child) &&
550                   GTK_MENU_ITEM (child)->priv->right_justify)
551                 {
552                   ltr_y = allocation->height -
553                     child_requisition.height - offset;
554                 }
555               if (gtk_widget_get_visible (child))
556                 {
557                   if ((direction == GTK_TEXT_DIR_LTR) ==
558                       (priv->pack_direction == GTK_PACK_DIRECTION_TTB))
559                     child_allocation.y = ltr_y;
560                   else
561                     child_allocation.y = allocation->height -
562                       child_requisition.height - ltr_y; 
563                   child_allocation.height = child_requisition.height;
564                   
565                   gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child),
566                                                       toggle_size);
567                   gtk_widget_size_allocate (child, &child_allocation);
568                   
569                   ltr_y += child_allocation.height;
570                 }
571             }
572         }
573     }
574 }
575
576 static gint
577 gtk_menu_bar_draw (GtkWidget *widget,
578                    cairo_t   *cr)
579 {
580   GtkStyleContext *context;
581   GtkStateFlags state;
582   int border;
583
584   border = gtk_container_get_border_width (GTK_CONTAINER (widget));
585   context = gtk_widget_get_style_context (widget);
586
587   state = gtk_widget_get_state_flags (widget);
588   gtk_style_context_set_state (context, state);
589
590   if (get_shadow_type (GTK_MENU_BAR (widget)) != GTK_SHADOW_NONE)
591     gtk_render_background (context, cr,
592                            border, border,
593                            gtk_widget_get_allocated_width (widget) - border * 2,
594                            gtk_widget_get_allocated_height (widget) - border * 2);
595
596   gtk_render_frame (context, cr,
597                     border, border,
598                     gtk_widget_get_allocated_width (widget) - border * 2,
599                     gtk_widget_get_allocated_height (widget) - border * 2);
600
601   GTK_WIDGET_CLASS (gtk_menu_bar_parent_class)->draw (widget, cr);
602
603   return FALSE;
604 }
605
606 static GList *
607 get_menu_bars (GtkWindow *window)
608 {
609   return g_object_get_data (G_OBJECT (window), "gtk-menu-bar-list");
610 }
611
612 static GList *
613 get_viewable_menu_bars (GtkWindow *window)
614 {
615   GList *menu_bars;
616   GList *viewable_menu_bars = NULL;
617
618   for (menu_bars = get_menu_bars (window);
619        menu_bars;
620        menu_bars = menu_bars->next)
621     {
622       GtkWidget *widget = menu_bars->data;
623       gboolean viewable = TRUE;
624       
625       while (widget)
626         {
627           if (!gtk_widget_get_mapped (widget))
628             viewable = FALSE;
629
630           widget = gtk_widget_get_parent (widget);
631         }
632
633       if (viewable)
634         viewable_menu_bars = g_list_prepend (viewable_menu_bars, menu_bars->data);
635     }
636
637   return g_list_reverse (viewable_menu_bars);
638 }
639
640 static void
641 set_menu_bars (GtkWindow *window,
642                GList     *menubars)
643 {
644   g_object_set_data (G_OBJECT (window), I_("gtk-menu-bar-list"), menubars);
645 }
646
647 static gboolean
648 window_key_press_handler (GtkWidget   *widget,
649                           GdkEventKey *event,
650                           gpointer     data)
651 {
652   gchar *accel = NULL;
653   gboolean retval = FALSE;
654   
655   g_object_get (gtk_widget_get_settings (widget),
656                 "gtk-menu-bar-accel", &accel,
657                 NULL);
658
659   if (accel && *accel)
660     {
661       guint keyval = 0;
662       GdkModifierType mods = 0;
663
664       gtk_accelerator_parse (accel, &keyval, &mods);
665
666       if (keyval == 0)
667         g_warning ("Failed to parse menu bar accelerator '%s'\n", accel);
668
669       /* FIXME this is wrong, needs to be in the global accel resolution
670        * thing, to properly consider i18n etc., but that probably requires
671        * AccelGroup changes etc.
672        */
673       if (event->keyval == keyval &&
674           ((event->state & gtk_accelerator_get_default_mod_mask ()) ==
675            (mods & gtk_accelerator_get_default_mod_mask ())))
676         {
677           GList *tmp_menubars = get_viewable_menu_bars (GTK_WINDOW (widget));
678           GList *menubars;
679
680           menubars = _gtk_container_focus_sort (GTK_CONTAINER (widget), tmp_menubars,
681                                                 GTK_DIR_TAB_FORWARD, NULL);
682           g_list_free (tmp_menubars);
683           
684           if (menubars)
685             {
686               GtkMenuShell *menu_shell = GTK_MENU_SHELL (menubars->data);
687
688               _gtk_menu_shell_set_keyboard_mode (menu_shell, TRUE);
689               _gtk_menu_shell_activate (menu_shell);
690               gtk_menu_shell_select_first (menu_shell, FALSE);
691               
692               g_list_free (menubars);
693               
694               retval = TRUE;          
695             }
696         }
697     }
698
699   g_free (accel);
700
701   return retval;
702 }
703
704 static void
705 add_to_window (GtkWindow  *window,
706                GtkMenuBar *menubar)
707 {
708   GList *menubars = get_menu_bars (window);
709
710   if (!menubars)
711     {
712       g_signal_connect (window,
713                         "key-press-event",
714                         G_CALLBACK (window_key_press_handler),
715                         NULL);
716     }
717
718   set_menu_bars (window, g_list_prepend (menubars, menubar));
719 }
720
721 static void
722 remove_from_window (GtkWindow  *window,
723                     GtkMenuBar *menubar)
724 {
725   GList *menubars = get_menu_bars (window);
726
727   menubars = g_list_remove (menubars, menubar);
728
729   if (!menubars)
730     {
731       g_signal_handlers_disconnect_by_func (window,
732                                             window_key_press_handler,
733                                             NULL);
734     }
735
736   set_menu_bars (window, menubars);
737 }
738
739 static void
740 gtk_menu_bar_hierarchy_changed (GtkWidget *widget,
741                                 GtkWidget *old_toplevel)
742 {
743   GtkWidget *toplevel;  
744   GtkMenuBar *menubar;
745
746   menubar = GTK_MENU_BAR (widget);
747
748   toplevel = gtk_widget_get_toplevel (widget);
749
750   if (old_toplevel)
751     remove_from_window (GTK_WINDOW (old_toplevel), menubar);
752   
753   if (gtk_widget_is_toplevel (toplevel))
754     add_to_window (GTK_WINDOW (toplevel), menubar);
755 }
756
757 /**
758  * _gtk_menu_bar_cycle_focus:
759  * @menubar: a #GtkMenuBar
760  * @dir: direction in which to cycle the focus
761  * 
762  * Move the focus between menubars in the toplevel.
763  **/
764 void
765 _gtk_menu_bar_cycle_focus (GtkMenuBar       *menubar,
766                            GtkDirectionType  dir)
767 {
768   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menubar));
769   GtkMenuItem *to_activate = NULL;
770
771   if (gtk_widget_is_toplevel (toplevel))
772     {
773       GList *tmp_menubars = get_viewable_menu_bars (GTK_WINDOW (toplevel));
774       GList *menubars;
775       GList *current;
776
777       menubars = _gtk_container_focus_sort (GTK_CONTAINER (toplevel), tmp_menubars,
778                                             dir, GTK_WIDGET (menubar));
779       g_list_free (tmp_menubars);
780
781       if (menubars)
782         {
783           current = g_list_find (menubars, menubar);
784
785           if (current && current->next)
786             {
787               GtkMenuShell *new_menushell = GTK_MENU_SHELL (current->next->data);
788               if (new_menushell->priv->children)
789                 to_activate = new_menushell->priv->children->data;
790             }
791         }
792           
793       g_list_free (menubars);
794     }
795
796   gtk_menu_shell_cancel (GTK_MENU_SHELL (menubar));
797
798   if (to_activate)
799     g_signal_emit_by_name (to_activate, "activate_item");
800 }
801
802 static GtkShadowType
803 get_shadow_type (GtkMenuBar *menubar)
804 {
805   GtkShadowType shadow_type = GTK_SHADOW_OUT;
806   
807   gtk_widget_style_get (GTK_WIDGET (menubar),
808                         "shadow-type", &shadow_type,
809                         NULL);
810
811   return shadow_type;
812 }
813
814 static gint
815 gtk_menu_bar_get_popup_delay (GtkMenuShell *menu_shell)
816 {
817   gint popup_delay;
818   
819   g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
820                 "gtk-menu-bar-popup-delay", &popup_delay,
821                 NULL);
822
823   return popup_delay;
824 }
825
826 static void
827 gtk_menu_bar_move_current (GtkMenuShell         *menu_shell,
828                            GtkMenuDirectionType  direction)
829 {
830   GtkMenuBar *menubar = GTK_MENU_BAR (menu_shell);
831   GtkTextDirection text_dir;
832   GtkPackDirection pack_dir;
833
834   text_dir = gtk_widget_get_direction (GTK_WIDGET (menubar));
835   pack_dir = gtk_menu_bar_get_pack_direction (menubar);
836   
837   if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL)
838      {
839       if ((text_dir == GTK_TEXT_DIR_RTL) == (pack_dir == GTK_PACK_DIRECTION_LTR))
840         {
841           switch (direction) 
842             {      
843             case GTK_MENU_DIR_PREV:
844               direction = GTK_MENU_DIR_NEXT;
845               break;
846             case GTK_MENU_DIR_NEXT:
847               direction = GTK_MENU_DIR_PREV;
848               break;
849             default: ;
850             }
851         }
852     }
853   else
854     {
855       switch (direction) 
856         {
857         case GTK_MENU_DIR_PARENT:
858           if ((text_dir == GTK_TEXT_DIR_LTR) == (pack_dir == GTK_PACK_DIRECTION_TTB))
859             direction = GTK_MENU_DIR_PREV;
860           else
861             direction = GTK_MENU_DIR_NEXT;
862           break;
863         case GTK_MENU_DIR_CHILD:
864           if ((text_dir == GTK_TEXT_DIR_LTR) == (pack_dir == GTK_PACK_DIRECTION_TTB))
865             direction = GTK_MENU_DIR_NEXT;
866           else
867             direction = GTK_MENU_DIR_PREV;
868           break;
869         case GTK_MENU_DIR_PREV:
870           if (text_dir == GTK_TEXT_DIR_RTL)       
871             direction = GTK_MENU_DIR_CHILD;
872           else
873             direction = GTK_MENU_DIR_PARENT;
874           break;
875         case GTK_MENU_DIR_NEXT:
876           if (text_dir == GTK_TEXT_DIR_RTL)       
877             direction = GTK_MENU_DIR_PARENT;
878           else
879             direction = GTK_MENU_DIR_CHILD;
880           break;
881         default: ;
882         }
883     }
884   
885   GTK_MENU_SHELL_CLASS (gtk_menu_bar_parent_class)->move_current (menu_shell, direction);
886 }
887
888 /**
889  * gtk_menu_bar_get_pack_direction:
890  * @menubar: a #GtkMenuBar
891  * 
892  * Retrieves the current pack direction of the menubar. 
893  * See gtk_menu_bar_set_pack_direction().
894  *
895  * Return value: the pack direction
896  *
897  * Since: 2.8
898  */
899 GtkPackDirection
900 gtk_menu_bar_get_pack_direction (GtkMenuBar *menubar)
901 {
902   g_return_val_if_fail (GTK_IS_MENU_BAR (menubar), 
903                         GTK_PACK_DIRECTION_LTR);
904
905   return menubar->priv->pack_direction;
906 }
907
908 /**
909  * gtk_menu_bar_set_pack_direction:
910  * @menubar: a #GtkMenuBar
911  * @pack_dir: a new #GtkPackDirection
912  * 
913  * Sets how items should be packed inside a menubar.
914  * 
915  * Since: 2.8
916  */
917 void
918 gtk_menu_bar_set_pack_direction (GtkMenuBar       *menubar,
919                                  GtkPackDirection  pack_dir)
920 {
921   GtkMenuBarPrivate *priv;
922   GList *l;
923
924   g_return_if_fail (GTK_IS_MENU_BAR (menubar));
925
926   priv = menubar->priv;
927
928   if (priv->pack_direction != pack_dir)
929     {
930       priv->pack_direction = pack_dir;
931
932       gtk_widget_queue_resize (GTK_WIDGET (menubar));
933
934       for (l = GTK_MENU_SHELL (menubar)->priv->children; l; l = l->next)
935         gtk_widget_queue_resize (GTK_WIDGET (l->data));
936
937       g_object_notify (G_OBJECT (menubar), "pack-direction");
938     }
939 }
940
941 /**
942  * gtk_menu_bar_get_child_pack_direction:
943  * @menubar: a #GtkMenuBar
944  * 
945  * Retrieves the current child pack direction of the menubar.
946  * See gtk_menu_bar_set_child_pack_direction().
947  *
948  * Return value: the child pack direction
949  *
950  * Since: 2.8
951  */
952 GtkPackDirection
953 gtk_menu_bar_get_child_pack_direction (GtkMenuBar *menubar)
954 {
955   g_return_val_if_fail (GTK_IS_MENU_BAR (menubar), 
956                         GTK_PACK_DIRECTION_LTR);
957
958   return menubar->priv->child_pack_direction;
959 }
960
961 /**
962  * gtk_menu_bar_set_child_pack_direction:
963  * @menubar: a #GtkMenuBar
964  * @child_pack_dir: a new #GtkPackDirection
965  * 
966  * Sets how widgets should be packed inside the children of a menubar.
967  * 
968  * Since: 2.8
969  */
970 void
971 gtk_menu_bar_set_child_pack_direction (GtkMenuBar       *menubar,
972                                        GtkPackDirection  child_pack_dir)
973 {
974   GtkMenuBarPrivate *priv;
975   GList *l;
976
977   g_return_if_fail (GTK_IS_MENU_BAR (menubar));
978
979   priv = menubar->priv;
980
981   if (priv->child_pack_direction != child_pack_dir)
982     {
983       priv->child_pack_direction = child_pack_dir;
984
985       gtk_widget_queue_resize (GTK_WIDGET (menubar));
986
987       for (l = GTK_MENU_SHELL (menubar)->priv->children; l; l = l->next)
988         gtk_widget_queue_resize (GTK_WIDGET (l->data));
989
990       g_object_notify (G_OBJECT (menubar), "child-pack-direction");
991     }
992 }