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