]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenu.c
call the base class init fucntions from all parent types upon class
[~andy/gtk] / gtk / gtkmenu.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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include <ctype.h>
20 #include "gdk/gdkkeysyms.h"
21 #include "gtkmain.h"
22 #include "gtkmenu.h"
23 #include "gtkmenuitem.h"
24 #include "gtksignal.h"
25
26
27 #define MENU_ITEM_CLASS(w)   GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
28 #define MENU_NEEDS_RESIZE(m) GTK_MENU_SHELL (m)->menu_flag
29
30 typedef struct _GtkMenuAttachData       GtkMenuAttachData;
31
32 struct _GtkMenuAttachData
33 {
34   GtkWidget *attach_widget;
35   GtkMenuDetachFunc detacher;
36 };
37
38
39 static void gtk_menu_class_init     (GtkMenuClass      *klass);
40 static void gtk_menu_init           (GtkMenu           *menu);
41 static void gtk_menu_destroy        (GtkObject         *object);
42 static void gtk_menu_show           (GtkWidget         *widget);
43 static void gtk_menu_map            (GtkWidget         *widget);
44 static void gtk_menu_unmap          (GtkWidget         *widget);
45 static void gtk_menu_realize        (GtkWidget         *widget);
46 static void gtk_menu_size_request   (GtkWidget         *widget,
47                                      GtkRequisition    *requisition);
48 static void gtk_menu_size_allocate  (GtkWidget         *widget,
49                                      GtkAllocation     *allocation);
50 static void gtk_menu_paint          (GtkWidget         *widget);
51 static void gtk_menu_draw           (GtkWidget         *widget,
52                                      GdkRectangle      *area);
53 static gint gtk_menu_expose         (GtkWidget         *widget,
54                                      GdkEventExpose    *event);
55 static gint gtk_menu_configure      (GtkWidget         *widget,
56                                      GdkEventConfigure *event);
57 static gint gtk_menu_key_press      (GtkWidget         *widget,
58                                      GdkEventKey       *event);
59 static void gtk_menu_check_resize    (GtkContainer      *container);
60 static void gtk_menu_deactivate     (GtkMenuShell      *menu_shell);
61 static void gtk_menu_show_all       (GtkWidget         *widget);
62 static void gtk_menu_hide_all       (GtkWidget         *widget);
63
64 static GtkMenuShellClass *parent_class = NULL;
65 static const gchar      *attach_data_key = "gtk-menu-attach-data";
66
67
68 GtkType
69 gtk_menu_get_type (void)
70 {
71   static GtkType menu_type = 0;
72   
73   if (!menu_type)
74     {
75       GtkTypeInfo menu_info =
76       {
77         "GtkMenu",
78         sizeof (GtkMenu),
79         sizeof (GtkMenuClass),
80         (GtkClassInitFunc) gtk_menu_class_init,
81         (GtkObjectInitFunc) gtk_menu_init,
82         /* reversed_1 */ NULL,
83         /* reversed_2 */ NULL,
84         (GtkClassInitFunc) NULL,
85       };
86       
87       menu_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_info);
88     }
89   
90   return menu_type;
91 }
92
93 static void
94 gtk_menu_class_init (GtkMenuClass *class)
95 {
96   GtkObjectClass *object_class;
97   GtkWidgetClass *widget_class;
98   GtkContainerClass *container_class;
99   GtkMenuShellClass *menu_shell_class;
100   
101   object_class = (GtkObjectClass*) class;
102   widget_class = (GtkWidgetClass*) class;
103   container_class = (GtkContainerClass*) class;
104   menu_shell_class = (GtkMenuShellClass*) class;
105   parent_class = gtk_type_class (gtk_menu_shell_get_type ());
106   
107   object_class->destroy = gtk_menu_destroy;
108   
109   widget_class->show = gtk_menu_show;
110   widget_class->map = gtk_menu_map;
111   widget_class->unmap = gtk_menu_unmap;
112   widget_class->realize = gtk_menu_realize;
113   widget_class->draw = gtk_menu_draw;
114   widget_class->size_request = gtk_menu_size_request;
115   widget_class->size_allocate = gtk_menu_size_allocate;
116   widget_class->expose_event = gtk_menu_expose;
117   widget_class->configure_event = gtk_menu_configure;
118   widget_class->key_press_event = gtk_menu_key_press;
119   widget_class->show_all = gtk_menu_show_all;
120   widget_class->hide_all = gtk_menu_hide_all;  
121   
122   container_class->check_resize = gtk_menu_check_resize;
123   
124   menu_shell_class->submenu_placement = GTK_LEFT_RIGHT;
125   menu_shell_class->deactivate = gtk_menu_deactivate;
126 }
127
128 static void
129 gtk_menu_init (GtkMenu *menu)
130 {
131   GTK_WIDGET_SET_FLAGS (menu, GTK_TOPLEVEL);
132   
133   gtk_container_set_resize_mode (GTK_CONTAINER (menu), GTK_RESIZE_QUEUE);
134   
135   menu->parent_menu_item = NULL;
136   menu->old_active_menu_item = NULL;
137   menu->accel_group = NULL;
138   menu->position_func = NULL;
139   menu->position_func_data = NULL;
140
141   MENU_NEEDS_RESIZE (menu) = TRUE;
142 }
143
144 static void
145 gtk_menu_destroy (GtkObject         *object)
146 {
147   GtkMenuAttachData *data;
148   
149   g_return_if_fail (object != NULL);
150   g_return_if_fail (GTK_IS_MENU (object));
151   
152   gtk_widget_ref (GTK_WIDGET (object));
153   
154   data = gtk_object_get_data (object, attach_data_key);
155   if (data)
156     gtk_menu_detach (GTK_MENU (object));
157   
158   gtk_menu_set_accel_group (GTK_MENU (object), NULL);
159   
160   if (GTK_OBJECT_CLASS (parent_class)->destroy)
161     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
162   
163   gtk_widget_unref (GTK_WIDGET (object));
164 }
165
166
167 void
168 gtk_menu_attach_to_widget (GtkMenu             *menu,
169                            GtkWidget           *attach_widget,
170                            GtkMenuDetachFunc    detacher)
171 {
172   GtkMenuAttachData *data;
173   
174   g_return_if_fail (menu != NULL);
175   g_return_if_fail (GTK_IS_MENU (menu));
176   g_return_if_fail (attach_widget != NULL);
177   g_return_if_fail (GTK_IS_WIDGET (attach_widget));
178   g_return_if_fail (detacher != NULL);
179   
180   /* keep this function in sync with gtk_widget_set_parent()
181    */
182   
183   data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
184   if (data)
185     {
186       g_warning ("gtk_menu_attach_to_widget(): menu already attached to %s",
187                  gtk_type_name (GTK_OBJECT_TYPE (data->attach_widget)));
188       return;
189     }
190   
191   gtk_widget_ref (GTK_WIDGET (menu));
192   gtk_object_sink (GTK_OBJECT (menu));
193   
194   data = g_new (GtkMenuAttachData, 1);
195   data->attach_widget = attach_widget;
196   data->detacher = detacher;
197   gtk_object_set_data (GTK_OBJECT (menu), attach_data_key, data);
198   
199   if (GTK_WIDGET_STATE (menu) != GTK_STATE_NORMAL)
200     gtk_widget_set_state (GTK_WIDGET (menu), GTK_STATE_NORMAL);
201   
202   /* we don't need to set the style here, since
203    * we are a toplevel widget.
204    */
205 }
206
207 GtkWidget*
208 gtk_menu_get_attach_widget (GtkMenu             *menu)
209 {
210   GtkMenuAttachData *data;
211   
212   g_return_val_if_fail (menu != NULL, NULL);
213   g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
214   
215   data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
216   if (data)
217     return data->attach_widget;
218   return NULL;
219 }
220
221 void
222 gtk_menu_detach (GtkMenu             *menu)
223 {
224   GtkMenuAttachData *data;
225   
226   g_return_if_fail (menu != NULL);
227   g_return_if_fail (GTK_IS_MENU (menu));
228   
229   /* keep this function in sync with gtk_widget_unparent()
230    */
231   data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
232   if (!data)
233     {
234       g_warning ("gtk_menu_detach(): menu is not attached");
235       return;
236     }
237   gtk_object_remove_data (GTK_OBJECT (menu), attach_data_key);
238   
239   data->detacher (data->attach_widget, menu);
240   
241   if (GTK_WIDGET_REALIZED (menu))
242     gtk_widget_unrealize (GTK_WIDGET (menu));
243   
244   g_free (data);
245   
246   gtk_widget_unref (GTK_WIDGET (menu));
247 }
248
249 GtkWidget*
250 gtk_menu_new (void)
251 {
252   return GTK_WIDGET (gtk_type_new (gtk_menu_get_type ()));
253 }
254
255 void
256 gtk_menu_append (GtkMenu   *menu,
257                  GtkWidget *child)
258 {
259   gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
260 }
261
262 void
263 gtk_menu_prepend (GtkMenu   *menu,
264                   GtkWidget *child)
265 {
266   gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), child);
267 }
268
269 void
270 gtk_menu_insert (GtkMenu   *menu,
271                  GtkWidget *child,
272                  gint       position)
273 {
274   gtk_menu_shell_insert (GTK_MENU_SHELL (menu), child, position);
275 }
276
277 void
278 gtk_menu_popup (GtkMenu             *menu,
279                 GtkWidget           *parent_menu_shell,
280                 GtkWidget           *parent_menu_item,
281                 GtkMenuPositionFunc  func,
282                 gpointer             data,
283                 guint                button,
284                 guint32              activate_time)
285 {
286   GtkWidget *xgrab_shell;
287   GtkWidget *parent;
288   
289   g_return_if_fail (menu != NULL);
290   g_return_if_fail (GTK_IS_MENU (menu));
291   
292   GTK_MENU_SHELL (menu)->parent_menu_shell = parent_menu_shell;
293   GTK_MENU_SHELL (menu)->active = TRUE;
294   GTK_MENU_SHELL (menu)->button = button;
295   
296   menu->parent_menu_item = parent_menu_item;
297   menu->position_func = func;
298   menu->position_func_data = data;
299   GTK_MENU_SHELL (menu)->activate_time = activate_time;
300   
301   gtk_widget_show (GTK_WIDGET (menu));
302   
303   /* Find the last viewable ancestor, and make an X grab on it
304    */
305   parent = GTK_WIDGET (menu);
306   xgrab_shell = NULL;
307   while (parent)
308     {
309       gboolean viewable = TRUE;
310       GtkWidget *tmp = parent;
311       
312       while (tmp)
313         {
314           if (!GTK_WIDGET_MAPPED (tmp))
315             {
316               viewable = FALSE;
317               break;
318             }
319           tmp = tmp->parent;
320         }
321       
322       if (viewable)
323         xgrab_shell = parent;
324       
325       parent = GTK_MENU_SHELL (parent)->parent_menu_shell;
326     }
327   
328   if (xgrab_shell && (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab))
329     {
330       GdkCursor *cursor = gdk_cursor_new (GDK_ARROW);
331       
332       GTK_MENU_SHELL (xgrab_shell)->have_xgrab = 
333         (gdk_pointer_grab (xgrab_shell->window, TRUE,
334                            GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
335                            GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK,
336                            NULL, cursor, activate_time) == 0);
337       gdk_cursor_destroy (cursor);
338     }
339   
340   gtk_grab_add (GTK_WIDGET (menu));
341 }
342
343 void
344 gtk_menu_popdown (GtkMenu *menu)
345 {
346   GtkMenuShell *menu_shell;
347   
348   g_return_if_fail (menu != NULL);
349   g_return_if_fail (GTK_IS_MENU (menu));
350   
351   menu_shell = GTK_MENU_SHELL (menu);
352   
353   menu_shell->parent_menu_shell = NULL;
354   menu_shell->active = FALSE;
355   
356   if (menu_shell->active_menu_item)
357     {
358       menu->old_active_menu_item = menu_shell->active_menu_item;
359       gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item));
360       menu_shell->active_menu_item = NULL;
361     }
362   
363   /* The X Grab, if present, will automatically be removed when we hide
364    * the window */
365   gtk_widget_hide (GTK_WIDGET (menu));
366   menu_shell->have_xgrab = FALSE;
367   
368   gtk_grab_remove (GTK_WIDGET (menu));
369 }
370
371 GtkWidget*
372 gtk_menu_get_active (GtkMenu *menu)
373 {
374   GtkWidget *child;
375   GList *children;
376   
377   g_return_val_if_fail (menu != NULL, NULL);
378   g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
379   
380   if (!menu->old_active_menu_item)
381     {
382       child = NULL;
383       children = GTK_MENU_SHELL (menu)->children;
384       
385       while (children)
386         {
387           child = children->data;
388           children = children->next;
389           
390           if (GTK_BIN (child)->child)
391             break;
392           child = NULL;
393         }
394       
395       menu->old_active_menu_item = child;
396     }
397   
398   return menu->old_active_menu_item;
399 }
400
401 void
402 gtk_menu_set_active (GtkMenu *menu,
403                      guint    index)
404 {
405   GtkWidget *child;
406   GList *tmp_list;
407   
408   g_return_if_fail (menu != NULL);
409   g_return_if_fail (GTK_IS_MENU (menu));
410   
411   tmp_list = g_list_nth (GTK_MENU_SHELL (menu)->children, index);
412   if (tmp_list)
413     {
414       child = tmp_list->data;
415       if (GTK_BIN (child)->child)
416         menu->old_active_menu_item = child;
417     }
418 }
419
420 void
421 gtk_menu_set_accel_group (GtkMenu       *menu,
422                           GtkAccelGroup *accel_group)
423 {
424   g_return_if_fail (menu != NULL);
425   g_return_if_fail (GTK_IS_MENU (menu));
426   
427   if (menu->accel_group != accel_group)
428     {
429       if (menu->accel_group)
430         gtk_accel_group_unref (menu->accel_group);
431       menu->accel_group = accel_group;
432       if (menu->accel_group)
433         gtk_accel_group_ref (menu->accel_group);
434     }
435 }
436
437
438 static void
439 gtk_menu_show (GtkWidget *widget)
440 {
441   g_return_if_fail (widget != NULL);
442   g_return_if_fail (GTK_IS_MENU (widget));
443   
444   GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
445   if (MENU_NEEDS_RESIZE (widget))
446     gtk_container_check_resize (GTK_CONTAINER (widget));
447   gtk_widget_map (widget);
448 }
449
450 void
451 gtk_menu_reposition (GtkMenu *menu)
452 {
453   GtkWidget *widget;
454
455   g_return_if_fail (menu != NULL);
456   g_return_if_fail (GTK_IS_MENU (menu));
457
458   widget = GTK_WIDGET (menu);
459   
460   if (GTK_WIDGET_DRAWABLE (menu))
461     {
462       gint x, y;
463       
464       gdk_window_get_pointer (NULL, &x, &y, NULL);
465       
466       if (menu->position_func)
467         (* menu->position_func) (menu, &x, &y, menu->position_func_data);
468       else
469         {
470           gint screen_width;
471           gint screen_height;
472           
473           screen_width = gdk_screen_width ();
474           screen_height = gdk_screen_height ();
475           
476           x -= 2;
477           y -= 2;
478           
479           if ((x + widget->requisition.width) > screen_width)
480             x -= ((x + widget->requisition.width) - screen_width);
481           if (x < 0)
482             x = 0;
483           if ((y + widget->requisition.height) > screen_height)
484             y -= ((y + widget->requisition.height) - screen_height);
485           if (y < 0)
486             y = 0;
487         }
488       
489       gdk_window_move (widget->window, x, y);
490     }
491 }
492
493 static void
494 gtk_menu_map (GtkWidget *widget)
495 {
496   GtkMenu *menu;
497   GtkMenuShell *menu_shell;
498   GtkWidget *child;
499   GList *children;
500   
501   g_return_if_fail (widget != NULL);
502   g_return_if_fail (GTK_IS_MENU (widget));
503   
504   menu = GTK_MENU (widget);
505   menu_shell = GTK_MENU_SHELL (widget);
506   GTK_WIDGET_SET_FLAGS (menu_shell, GTK_MAPPED);
507
508   gtk_menu_reposition (menu);
509   
510   children = menu_shell->children;
511   while (children)
512     {
513       child = children->data;
514       children = children->next;
515       
516       if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child))
517         gtk_widget_map (child);
518     }
519   
520   gdk_window_show (widget->window);
521 }
522
523 static void
524 gtk_menu_unmap (GtkWidget *widget)
525 {
526   g_return_if_fail (widget != NULL);
527   g_return_if_fail (GTK_IS_MENU (widget));
528   
529   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
530   gdk_window_hide (widget->window);
531 }
532
533 static void
534 gtk_menu_realize (GtkWidget *widget)
535 {
536   GdkWindowAttr attributes;
537   gint attributes_mask;
538   
539   g_return_if_fail (widget != NULL);
540   g_return_if_fail (GTK_IS_MENU (widget));
541   
542   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
543   
544   attributes.x = widget->allocation.x;
545   attributes.y = widget->allocation.y;
546   attributes.width = widget->allocation.width;
547   attributes.height = widget->allocation.height;
548   attributes.wclass = GDK_INPUT_OUTPUT;
549   attributes.visual = gtk_widget_get_visual (widget);
550   attributes.colormap = gtk_widget_get_colormap (widget);
551   attributes.window_type = GDK_WINDOW_TEMP;
552   attributes.event_mask = gtk_widget_get_events (widget);
553   attributes.event_mask |= (GDK_EXPOSURE_MASK |
554                             GDK_KEY_PRESS_MASK |
555                             GDK_STRUCTURE_MASK);
556   
557   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
558   widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
559   gdk_window_set_user_data (widget->window, widget);
560   
561   widget->style = gtk_style_attach (widget->style, widget->window);
562   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
563 }
564
565 static void
566 gtk_menu_size_request (GtkWidget      *widget,
567                        GtkRequisition *requisition)
568 {
569   GtkMenu *menu;
570   GtkMenuShell *menu_shell;
571   GtkWidget *child;
572   GList *children;
573   guint max_toggle_size;
574   guint max_accel_width;
575   
576   g_return_if_fail (widget != NULL);
577   g_return_if_fail (GTK_IS_MENU (widget));
578   g_return_if_fail (requisition != NULL);
579   
580   menu = GTK_MENU (widget);
581   menu_shell = GTK_MENU_SHELL (widget);
582   
583   requisition->width = 0;
584   requisition->height = 0;
585   
586   max_toggle_size = 0;
587   max_accel_width = 0;
588   
589   children = menu_shell->children;
590   while (children)
591     {
592       child = children->data;
593       children = children->next;
594       
595       if (GTK_WIDGET_VISIBLE (child))
596         {
597           GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
598           gtk_widget_size_request (child, &child->requisition);
599           
600           requisition->width = MAX (requisition->width, child->requisition.width);
601           requisition->height += child->requisition.height;
602           
603           max_toggle_size = MAX (max_toggle_size, MENU_ITEM_CLASS (child)->toggle_size);
604           max_accel_width = MAX (max_accel_width, GTK_MENU_ITEM (child)->accelerator_width);
605         }
606     }
607   
608   requisition->width += max_toggle_size + max_accel_width;
609   requisition->width += (GTK_CONTAINER (menu)->border_width +
610                          widget->style->klass->xthickness) * 2;
611   requisition->height += (GTK_CONTAINER (menu)->border_width +
612                           widget->style->klass->ythickness) * 2;
613   
614   children = menu_shell->children;
615   while (children)
616     {
617       child = children->data;
618       children = children->next;
619       
620       GTK_MENU_ITEM (child)->toggle_size = max_toggle_size;
621     }
622 }
623
624 static void
625 gtk_menu_size_allocate (GtkWidget     *widget,
626                         GtkAllocation *allocation)
627 {
628   GtkMenu *menu;
629   GtkMenuShell *menu_shell;
630   GtkWidget *child;
631   GtkAllocation child_allocation;
632   GList *children;
633   
634   g_return_if_fail (widget != NULL);
635   g_return_if_fail (GTK_IS_MENU (widget));
636   g_return_if_fail (allocation != NULL);
637   
638   menu = GTK_MENU (widget);
639   menu_shell = GTK_MENU_SHELL (widget);
640   
641   widget->allocation = *allocation;
642
643   if (menu_shell->children)
644     {
645       child_allocation.x = (GTK_CONTAINER (menu)->border_width +
646                             widget->style->klass->xthickness);
647       child_allocation.y = (GTK_CONTAINER (menu)->border_width +
648                             widget->style->klass->ythickness);
649       child_allocation.width = MAX (1, allocation->width - child_allocation.x * 2);
650       
651       children = menu_shell->children;
652       while (children)
653         {
654           child = children->data;
655           children = children->next;
656           
657           if (GTK_WIDGET_VISIBLE (child))
658             {
659               child_allocation.height = child->requisition.height;
660               
661               gtk_widget_size_allocate (child, &child_allocation);
662               gtk_widget_queue_draw (child);
663               
664               child_allocation.y += child_allocation.height;
665             }
666         }
667     }
668
669   if (GTK_WIDGET_REALIZED (widget))
670     {
671       gdk_window_resize (widget->window,
672                          widget->requisition.width,
673                          widget->requisition.height);
674     }
675 }
676
677 static void
678 gtk_menu_paint (GtkWidget *widget)
679 {
680   g_return_if_fail (widget != NULL);
681   g_return_if_fail (GTK_IS_MENU (widget));
682   
683   if (GTK_WIDGET_DRAWABLE (widget))
684     {
685       gtk_draw_shadow (widget->style,
686                        widget->window,
687                        GTK_STATE_NORMAL,
688                        GTK_SHADOW_OUT,
689                        0, 0,
690                        widget->allocation.width,
691                        widget->allocation.height);
692     }
693 }
694
695 static void
696 gtk_menu_draw (GtkWidget    *widget,
697                GdkRectangle *area)
698 {
699   GtkMenuShell *menu_shell;
700   GtkWidget *child;
701   GdkRectangle child_area;
702   GList *children;
703   
704   g_return_if_fail (widget != NULL);
705   g_return_if_fail (GTK_IS_MENU (widget));
706   g_return_if_fail (area != NULL);
707   
708   if (GTK_WIDGET_DRAWABLE (widget))
709     {
710       gtk_menu_paint (widget);
711       
712       menu_shell = GTK_MENU_SHELL (widget);
713       
714       children = menu_shell->children;
715       while (children)
716         {
717           child = children->data;
718           children = children->next;
719           
720           if (gtk_widget_intersect (child, area, &child_area))
721             gtk_widget_draw (child, &child_area);
722         }
723     }
724 }
725
726 static gint
727 gtk_menu_expose (GtkWidget      *widget,
728                  GdkEventExpose *event)
729 {
730   GtkMenuShell *menu_shell;
731   GtkWidget *child;
732   GdkEventExpose child_event;
733   GList *children;
734   
735   g_return_val_if_fail (widget != NULL, FALSE);
736   g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
737   g_return_val_if_fail (event != NULL, FALSE);
738   
739   if (GTK_WIDGET_DRAWABLE (widget))
740     {
741       gtk_menu_paint (widget);
742       
743       menu_shell = GTK_MENU_SHELL (widget);
744       child_event = *event;
745       
746       children = menu_shell->children;
747       while (children)
748         {
749           child = children->data;
750           children = children->next;
751           
752           if (GTK_WIDGET_NO_WINDOW (child) &&
753               gtk_widget_intersect (child, &event->area, &child_event.area))
754             gtk_widget_event (child, (GdkEvent*) &child_event);
755         }
756     }
757   
758   return FALSE;
759 }
760
761 static gint
762 gtk_menu_configure (GtkWidget         *widget,
763                     GdkEventConfigure *event)
764 {
765   GtkAllocation allocation;
766   
767   g_return_val_if_fail (widget != NULL, FALSE);
768   g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
769   g_return_val_if_fail (event != NULL, FALSE);
770   
771   /* If the window was merely moved, do nothing */
772   if ((widget->allocation.width == event->width) &&
773       (widget->allocation.height == event->height))
774     return FALSE;
775   
776   if (MENU_NEEDS_RESIZE (widget))
777     {
778       MENU_NEEDS_RESIZE (widget) = FALSE;
779       
780       allocation.x = 0;
781       allocation.y = 0;
782       allocation.width = event->width;
783       allocation.height = event->height;
784       
785       gtk_widget_size_allocate (widget, &allocation);
786     }
787   
788   return FALSE;
789 }
790
791 static gint
792 gtk_menu_key_press (GtkWidget   *widget,
793                     GdkEventKey *event)
794 {
795   gboolean delete;
796   
797   g_return_val_if_fail (widget != NULL, FALSE);
798   g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
799   g_return_val_if_fail (event != NULL, FALSE);
800   
801   delete = (event->keyval == GDK_Delete ||
802             event->keyval == GDK_KP_Delete ||
803             event->keyval == GDK_BackSpace);
804   
805   if (delete || gtk_accelerator_valid (event->keyval, event->keyval))
806     {
807       GtkMenuShell *menu_shell;
808       
809       menu_shell = GTK_MENU_SHELL (widget);
810       
811       if (menu_shell->active_menu_item &&
812           GTK_BIN (menu_shell->active_menu_item)->child &&
813           GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL)
814         {
815           GtkMenuItem *menu_item;
816           GtkAccelGroup *accel_group;
817           
818           menu_item = GTK_MENU_ITEM (menu_shell->active_menu_item);
819           
820           if (!GTK_MENU (widget)->accel_group)
821             accel_group = gtk_accel_group_get_default ();
822           else
823             accel_group = GTK_MENU (widget)->accel_group;
824
825           gtk_widget_remove_accelerators (GTK_WIDGET (menu_item),
826                                           gtk_signal_name (menu_item->accelerator_signal),
827                                           TRUE);
828           
829           if (!delete &&
830               0 == gtk_widget_accelerator_signal (GTK_WIDGET (menu_item),
831                                                   accel_group,
832                                                   event->keyval,
833                                                   event->state))
834             {
835               GSList *slist;
836               
837               slist = gtk_accel_group_entries_from_object (GTK_OBJECT (menu_item));
838               while (slist)
839                 {
840                   GtkAccelEntry *ac_entry;
841                   
842                   ac_entry = slist->data;
843                   
844                   if (ac_entry->signal_id == menu_item->accelerator_signal)
845                     break;
846                   
847                   slist = slist->next;
848                 }
849
850               if (!slist)
851                 gtk_widget_add_accelerator (GTK_WIDGET (menu_item),
852                                             gtk_signal_name (menu_item->accelerator_signal),
853                                             accel_group,
854                                             event->keyval,
855                                             event->state,
856                                             GTK_ACCEL_VISIBLE);
857             }
858         }
859     }
860   
861   return FALSE;
862 }
863
864 static void
865 gtk_menu_check_resize (GtkContainer *container)
866 {
867   GtkAllocation allocation;
868   GtkWidget *widget;
869   
870   g_return_if_fail (container != NULL);
871   g_return_if_fail (GTK_IS_MENU (container));
872
873   widget = GTK_WIDGET (container);
874   
875   if (GTK_WIDGET_VISIBLE (container))
876     {
877       MENU_NEEDS_RESIZE (container) = FALSE;
878       
879       gtk_widget_size_request (widget, &widget->requisition);
880       
881       allocation.x = widget->allocation.x;
882       allocation.y = widget->allocation.y;
883       allocation.width = widget->requisition.width;
884       allocation.height = widget->requisition.height;
885       
886       gtk_widget_size_allocate (widget, &allocation);
887     }
888   else
889     MENU_NEEDS_RESIZE (container) = TRUE;
890 }
891
892 static void
893 gtk_menu_deactivate (GtkMenuShell *menu_shell)
894 {
895   GtkWidget *parent;
896   
897   g_return_if_fail (menu_shell != NULL);
898   g_return_if_fail (GTK_IS_MENU (menu_shell));
899   
900   parent = menu_shell->parent_menu_shell;
901   
902   menu_shell->activate_time = 0;
903   gtk_menu_popdown (GTK_MENU (menu_shell));
904   
905   if (parent)
906     gtk_menu_shell_deactivate (GTK_MENU_SHELL (parent));
907 }
908
909
910 static void
911 gtk_menu_show_all (GtkWidget *widget)
912 {
913   GtkContainer *container;
914   
915   g_return_if_fail (widget != NULL);
916   g_return_if_fail (GTK_IS_MENU (widget));
917   container = GTK_CONTAINER (widget);
918   
919   /* Show children, but not self. */
920   gtk_container_foreach (container, (GtkCallback) gtk_widget_show_all, NULL);
921 }
922
923
924 static void
925 gtk_menu_hide_all (GtkWidget *widget)
926 {
927   GtkContainer *container;
928   
929   g_return_if_fail (widget != NULL);
930   g_return_if_fail (GTK_IS_MENU (widget));
931   container = GTK_CONTAINER (widget);
932   
933   /* Hide children, but not self. */
934   gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL);
935 }