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