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