]> Pileus Git - ~andy/gtk/blob - gtk/gtkoptionmenu.c
9d9a259968d2efdba7c5dad0a5721cba33450cf8
[~andy/gtk] / gtk / gtkoptionmenu.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 #include "gtkmenu.h"
28 #include "gtkmenuitem.h"
29 #include "gtkoptionmenu.h"
30 #include "gtksignal.h"
31 #include "gdk/gdkkeysyms.h"
32
33
34 #define CHILD_LEFT_SPACING        5
35 #define CHILD_RIGHT_SPACING       1
36 #define CHILD_TOP_SPACING         1
37 #define CHILD_BOTTOM_SPACING      1
38 #define OPTION_INDICATOR_WIDTH    12
39 #define OPTION_INDICATOR_HEIGHT   8
40 #define OPTION_INDICATOR_SPACING  2
41
42
43 static void gtk_option_menu_class_init      (GtkOptionMenuClass *klass);
44 static void gtk_option_menu_init            (GtkOptionMenu      *option_menu);
45 static void gtk_option_menu_destroy         (GtkObject          *object);
46 static void gtk_option_menu_size_request    (GtkWidget          *widget,
47                                              GtkRequisition     *requisition);
48 static void gtk_option_menu_size_allocate   (GtkWidget          *widget,
49                                              GtkAllocation      *allocation);
50 static void gtk_option_menu_paint           (GtkWidget          *widget,
51                                              GdkRectangle       *area);
52 static gint gtk_option_menu_expose          (GtkWidget          *widget,
53                                              GdkEventExpose     *event);
54 static gint gtk_option_menu_button_press    (GtkWidget          *widget,
55                                              GdkEventButton     *event);
56 static gint gtk_option_menu_key_press       (GtkWidget          *widget,
57                                              GdkEventKey        *event);
58 static void gtk_option_menu_deactivate      (GtkMenuShell       *menu_shell,
59                                              GtkOptionMenu      *option_menu);
60 static void gtk_option_menu_update_contents (GtkOptionMenu      *option_menu);
61 static void gtk_option_menu_remove_contents (GtkOptionMenu      *option_menu);
62 static void gtk_option_menu_calc_size       (GtkOptionMenu      *option_menu);
63 static void gtk_option_menu_position        (GtkMenu            *menu,
64                                              gint               *x,
65                                              gint               *y,
66                                              gint               *scroll_offet,
67                                              gpointer            user_data);
68 static void gtk_option_menu_show_all        (GtkWidget          *widget);
69 static void gtk_option_menu_hide_all        (GtkWidget          *widget);
70 static GtkType gtk_option_menu_child_type   (GtkContainer       *container);
71
72 enum
73 {
74   CHANGED,
75   LAST_SIGNAL
76 };
77
78 static GtkButtonClass *parent_class = NULL;
79 static guint           signals[LAST_SIGNAL] = { 0 };
80
81
82 GtkType
83 gtk_option_menu_get_type (void)
84 {
85   static GtkType option_menu_type = 0;
86
87   if (!option_menu_type)
88     {
89       static const GtkTypeInfo option_menu_info =
90       {
91         "GtkOptionMenu",
92         sizeof (GtkOptionMenu),
93         sizeof (GtkOptionMenuClass),
94         (GtkClassInitFunc) gtk_option_menu_class_init,
95         (GtkObjectInitFunc) gtk_option_menu_init,
96         /* reserved_1 */ NULL,
97         /* reserved_2 */ NULL,
98         (GtkClassInitFunc) NULL,
99       };
100
101       option_menu_type = gtk_type_unique (gtk_button_get_type (), &option_menu_info);
102     }
103
104   return option_menu_type;
105 }
106
107 static void
108 gtk_option_menu_class_init (GtkOptionMenuClass *class)
109 {
110   GtkObjectClass *object_class;
111   GtkWidgetClass *widget_class;
112   GtkButtonClass *button_class;
113   GtkContainerClass *container_class;
114
115   object_class = (GtkObjectClass*) class;
116   widget_class = (GtkWidgetClass*) class;
117   button_class = (GtkButtonClass*) class;
118   container_class = (GtkContainerClass*) class;
119
120   parent_class = gtk_type_class (gtk_button_get_type ());
121
122   signals[CHANGED] =
123     g_signal_newc ("changed",
124                    G_TYPE_FROM_CLASS (class),
125                    G_SIGNAL_RUN_LAST,
126                    G_STRUCT_OFFSET (GtkOptionMenuClass, changed),
127                    NULL,
128                    gtk_marshal_VOID__VOID,
129                    G_TYPE_NONE, 0);
130   
131   object_class->destroy = gtk_option_menu_destroy;
132   
133   widget_class->size_request = gtk_option_menu_size_request;
134   widget_class->size_allocate = gtk_option_menu_size_allocate;
135   widget_class->expose_event = gtk_option_menu_expose;
136   widget_class->button_press_event = gtk_option_menu_button_press;
137   widget_class->key_press_event = gtk_option_menu_key_press;
138   widget_class->show_all = gtk_option_menu_show_all;
139   widget_class->hide_all = gtk_option_menu_hide_all;
140
141   container_class->child_type = gtk_option_menu_child_type;
142 }
143
144 static GtkType
145 gtk_option_menu_child_type (GtkContainer       *container)
146 {
147   return GTK_TYPE_NONE;
148 }
149
150 static void
151 gtk_option_menu_init (GtkOptionMenu *option_menu)
152 {
153   GTK_WIDGET_SET_FLAGS (option_menu, GTK_CAN_FOCUS);
154   GTK_WIDGET_UNSET_FLAGS (option_menu, GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT);
155
156   option_menu->menu = NULL;
157   option_menu->menu_item = NULL;
158   option_menu->width = 0;
159   option_menu->height = 0;
160 }
161
162 GtkWidget*
163 gtk_option_menu_new (void)
164 {
165   return GTK_WIDGET (gtk_type_new (gtk_option_menu_get_type ()));
166 }
167
168 GtkWidget*
169 gtk_option_menu_get_menu (GtkOptionMenu *option_menu)
170 {
171   g_return_val_if_fail (option_menu != NULL, NULL);
172   g_return_val_if_fail (GTK_IS_OPTION_MENU (option_menu), NULL);
173
174   return option_menu->menu;
175 }
176
177 static void
178 gtk_option_menu_detacher (GtkWidget     *widget,
179                           GtkMenu       *menu)
180 {
181   GtkOptionMenu *option_menu;
182
183   g_return_if_fail (widget != NULL);
184   g_return_if_fail (GTK_IS_OPTION_MENU (widget));
185
186   option_menu = GTK_OPTION_MENU (widget);
187   g_return_if_fail (option_menu->menu == (GtkWidget*) menu);
188
189   gtk_option_menu_remove_contents (option_menu);
190   gtk_signal_disconnect_by_data (GTK_OBJECT (option_menu->menu),
191                                  option_menu);
192   
193   option_menu->menu = NULL;
194 }
195
196 void
197 gtk_option_menu_set_menu (GtkOptionMenu *option_menu,
198                           GtkWidget     *menu)
199 {
200   g_return_if_fail (option_menu != NULL);
201   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
202   g_return_if_fail (menu != NULL);
203   g_return_if_fail (GTK_IS_MENU (menu));
204
205   if (option_menu->menu != menu)
206     {
207       gtk_option_menu_remove_menu (option_menu);
208
209       option_menu->menu = menu;
210       gtk_menu_attach_to_widget (GTK_MENU (menu),
211                                  GTK_WIDGET (option_menu),
212                                  gtk_option_menu_detacher);
213
214       gtk_option_menu_calc_size (option_menu);
215
216       gtk_signal_connect (GTK_OBJECT (option_menu->menu), "deactivate",
217                           (GtkSignalFunc) gtk_option_menu_deactivate,
218                           option_menu);
219       gtk_signal_connect_object (GTK_OBJECT (option_menu->menu), "size_request",
220                                  (GtkSignalFunc) gtk_option_menu_calc_size,
221                                  GTK_OBJECT (option_menu));
222
223       if (GTK_WIDGET (option_menu)->parent)
224         gtk_widget_queue_resize (GTK_WIDGET (option_menu));
225
226       gtk_option_menu_update_contents (option_menu);
227     }
228 }
229
230 void
231 gtk_option_menu_remove_menu (GtkOptionMenu *option_menu)
232 {
233   g_return_if_fail (option_menu != NULL);
234   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
235
236   if (option_menu->menu)
237     gtk_menu_detach (GTK_MENU (option_menu->menu));
238 }
239
240 void
241 gtk_option_menu_set_history (GtkOptionMenu *option_menu,
242                              guint          index)
243 {
244   GtkWidget *menu_item;
245
246   g_return_if_fail (option_menu != NULL);
247   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
248
249   if (option_menu->menu)
250     {
251       gtk_menu_set_active (GTK_MENU (option_menu->menu), index);
252       menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu));
253
254       if (menu_item != option_menu->menu_item)
255         gtk_option_menu_update_contents (option_menu);
256     }
257 }
258
259 /**
260  * gtk_option_menu_get_history:
261  * @option_menu: a #GtkOptionMenu
262  * 
263  * Retrieves the index of the currently selected menu item. The menu
264  * items are numbered from top to bottom, starting with 0. 
265  * 
266  * Return value: index of the selected menu item, or -1 if there are no menu items
267  **/
268 gint
269 gtk_option_menu_get_history (GtkOptionMenu *option_menu)
270 {
271   GtkWidget *active_widget;
272   
273   g_return_val_if_fail (GTK_IS_OPTION_MENU (option_menu), -1);
274
275   if (option_menu->menu)
276     {
277       active_widget = gtk_menu_get_active (GTK_MENU (option_menu->menu));
278
279       if (active_widget)
280         return g_list_index (GTK_MENU_SHELL (option_menu->menu)->children,
281                              active_widget);
282       else
283         return -1;
284     }
285   else
286     return -1;
287 }
288
289 static void
290 gtk_option_menu_destroy (GtkObject *object)
291 {
292   GtkOptionMenu *option_menu;
293
294   g_return_if_fail (object != NULL);
295   g_return_if_fail (GTK_IS_OPTION_MENU (object));
296
297   option_menu = GTK_OPTION_MENU (object);
298
299   if (option_menu->menu)
300     gtk_widget_destroy (option_menu->menu);
301
302   if (GTK_OBJECT_CLASS (parent_class)->destroy)
303     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
304 }
305
306 static void
307 gtk_option_menu_size_request (GtkWidget      *widget,
308                               GtkRequisition *requisition)
309 {
310   GtkOptionMenu *option_menu;
311   gint tmp;
312   GtkRequisition child_requisition = { 0, 0 };
313       
314
315   g_return_if_fail (widget != NULL);
316   g_return_if_fail (GTK_IS_OPTION_MENU (widget));
317   g_return_if_fail (requisition != NULL);
318
319   option_menu = GTK_OPTION_MENU (widget);
320
321   if (GTK_BIN (option_menu)->child && GTK_WIDGET_VISIBLE (GTK_BIN (option_menu)->child))
322     {
323       gtk_widget_size_request (GTK_BIN (option_menu)->child, &child_requisition);
324
325       requisition->width += child_requisition.width;
326       requisition->height += child_requisition.height;
327     }
328   
329   requisition->width = ((GTK_CONTAINER (widget)->border_width +
330                          GTK_WIDGET (widget)->style->xthickness) * 2 +
331                         MAX (child_requisition.width, option_menu->width) +
332                         OPTION_INDICATOR_WIDTH +
333                         OPTION_INDICATOR_SPACING * 5 +
334                         CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING + 2);
335   requisition->height = ((GTK_CONTAINER (widget)->border_width +
336                           GTK_WIDGET (widget)->style->ythickness) * 2 +
337                          MAX (child_requisition.height, option_menu->height) +
338                          CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING + 2);
339
340   tmp = (requisition->height - option_menu->height +
341          OPTION_INDICATOR_HEIGHT + OPTION_INDICATOR_SPACING * 2);
342   requisition->height = MAX (requisition->height, tmp);
343 }
344
345 static void
346 gtk_option_menu_size_allocate (GtkWidget     *widget,
347                                GtkAllocation *allocation)
348 {
349   GtkWidget *child;
350   GtkAllocation child_allocation;
351
352   g_return_if_fail (widget != NULL);
353   g_return_if_fail (GTK_IS_OPTION_MENU (widget));
354   g_return_if_fail (allocation != NULL);
355
356   widget->allocation = *allocation;
357   if (GTK_WIDGET_REALIZED (widget))
358     gdk_window_move_resize (widget->window,
359                             allocation->x, allocation->y,
360                             allocation->width, allocation->height);
361
362   child = GTK_BIN (widget)->child;
363   if (child && GTK_WIDGET_VISIBLE (child))
364     {
365       child_allocation.x = (GTK_CONTAINER (widget)->border_width +
366                             GTK_WIDGET (widget)->style->xthickness) + 1;
367       child_allocation.y = (GTK_CONTAINER (widget)->border_width +
368                             GTK_WIDGET (widget)->style->ythickness) + 1;
369       child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2 -
370                                     OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 5 -
371                                     CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING - 2);
372       child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2 -
373                                      CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING - 2);
374       child_allocation.x += CHILD_LEFT_SPACING;
375       child_allocation.y += CHILD_RIGHT_SPACING;
376
377       gtk_widget_size_allocate (child, &child_allocation);
378     }
379 }
380
381 static void
382 gtk_option_menu_paint (GtkWidget    *widget,
383                        GdkRectangle *area)
384 {
385   GdkRectangle button_area;
386
387   g_return_if_fail (widget != NULL);
388   g_return_if_fail (GTK_IS_OPTION_MENU (widget));
389   g_return_if_fail (area != NULL);
390
391   if (GTK_WIDGET_DRAWABLE (widget))
392     {
393       button_area.x = GTK_CONTAINER (widget)->border_width + 1;
394       button_area.y = GTK_CONTAINER (widget)->border_width + 1;
395       button_area.width = widget->allocation.width - button_area.x * 2;
396       button_area.height = widget->allocation.height - button_area.y * 2;
397
398       /* This is evil, and should be elimated here and in the button
399        * code. The point is to clear the focus, and make it
400        * sort of transparent if it isn't there.
401        */
402       gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
403       gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
404
405       gtk_paint_box(widget->style, widget->window,
406                     GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
407                     area, widget, "optionmenu",
408                     button_area.x, button_area.y,
409                     button_area.width, button_area.height);
410       
411       gtk_paint_tab (widget->style, widget->window,
412                      GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
413                      area, widget, "optionmenutab",
414                      button_area.x + button_area.width - button_area.x -
415                      OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 4,
416                      button_area.y + (button_area.height - OPTION_INDICATOR_HEIGHT) / 2,
417                      OPTION_INDICATOR_WIDTH, OPTION_INDICATOR_HEIGHT);
418       
419       if (GTK_WIDGET_HAS_FOCUS (widget))
420         gtk_paint_focus (widget->style, widget->window,
421                          area, widget, "button",
422                          button_area.x - 1, 
423                          button_area.y - 1, 
424                          button_area.width + 1,
425                          button_area.height + 1);
426     }
427 }
428
429 static gint
430 gtk_option_menu_expose (GtkWidget      *widget,
431                         GdkEventExpose *event)
432 {
433   GtkWidget *child;
434   GdkEventExpose child_event;
435   gint remove_child;
436
437   g_return_val_if_fail (widget != NULL, FALSE);
438   g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE);
439   g_return_val_if_fail (event != NULL, FALSE);
440
441   if (GTK_WIDGET_DRAWABLE (widget))
442     {
443       gtk_option_menu_paint (widget, &event->area);
444
445
446       /* The following code tries to draw the child in two places at
447        * once. It fails miserably for several reasons
448        *
449        * - If the child is not no-window, removing generates
450        *   more expose events. Bad, bad, bad.
451        * 
452        * - Even if the child is no-window, removing it now (properly)
453        *   clears the space where it was, so it does no good
454        */
455       
456 #if 0
457       remove_child = FALSE;
458       child = GTK_BUTTON (widget)->child;
459
460       if (!child)
461         {
462           if (!GTK_OPTION_MENU (widget)->menu)
463             return FALSE;
464           gtk_option_menu_update_contents (GTK_OPTION_MENU (widget));
465           child = GTK_BUTTON (widget)->child;
466           if (!child)
467             return FALSE;
468           remove_child = TRUE;
469         }
470
471       child_event = *event;
472
473       if (GTK_WIDGET_NO_WINDOW (child) &&
474           gtk_widget_intersect (child, &event->area, &child_event.area))
475         gtk_widget_event (child, (GdkEvent*) &child_event);
476
477       if (remove_child)
478         gtk_option_menu_remove_contents (GTK_OPTION_MENU (widget));
479 #else
480       remove_child = FALSE;
481       child = GTK_BIN (widget)->child;
482       child_event = *event;
483       if (child && GTK_WIDGET_NO_WINDOW (child) &&
484           gtk_widget_intersect (child, &event->area, &child_event.area))
485         gtk_widget_event (child, (GdkEvent*) &child_event);
486
487 #endif /* 0 */
488     }
489
490   return FALSE;
491 }
492
493 static gint
494 gtk_option_menu_button_press (GtkWidget      *widget,
495                               GdkEventButton *event)
496 {
497   GtkOptionMenu *option_menu;
498   GtkWidget *menu_item;
499
500   g_return_val_if_fail (widget != NULL, FALSE);
501   g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE);
502   g_return_val_if_fail (event != NULL, FALSE);
503
504   option_menu = GTK_OPTION_MENU (widget);
505
506   if ((event->type == GDK_BUTTON_PRESS) &&
507       (event->button == 1))
508     {
509       gtk_option_menu_remove_contents (option_menu);
510       gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL,
511                       gtk_option_menu_position, option_menu,
512                       event->button, event->time);
513       menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu));
514       if (menu_item)
515         gtk_menu_shell_select_item (GTK_MENU_SHELL (option_menu->menu), menu_item);
516       return TRUE;
517     }
518
519   return FALSE;
520 }
521
522 static gint
523 gtk_option_menu_key_press (GtkWidget   *widget,
524                            GdkEventKey *event)
525 {
526   GtkOptionMenu *option_menu;
527   GtkWidget *menu_item;
528
529   g_return_val_if_fail (widget != NULL, FALSE);
530   g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE);
531   g_return_val_if_fail (event != NULL, FALSE);
532
533   option_menu = GTK_OPTION_MENU (widget);
534
535   switch (event->keyval)
536     {
537     case GDK_space:
538       gtk_option_menu_remove_contents (option_menu);
539       gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL,
540                       gtk_option_menu_position, option_menu,
541                       0, event->time);
542       menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu));
543       if (menu_item)
544         gtk_menu_shell_select_item (GTK_MENU_SHELL (option_menu->menu), menu_item);
545       return TRUE;
546     }
547   
548   return FALSE;
549 }
550
551 static void
552 gtk_option_menu_deactivate (GtkMenuShell  *menu_shell,
553                             GtkOptionMenu *option_menu)
554 {
555   g_return_if_fail (menu_shell != NULL);
556   g_return_if_fail (option_menu != NULL);
557   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
558
559   gtk_option_menu_update_contents (option_menu);
560 }
561
562 static void
563 gtk_option_menu_changed (GtkOptionMenu *option_menu)
564 {
565   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
566
567   g_signal_emit (G_OBJECT (option_menu), signals[CHANGED], 0);
568 }
569
570 static void
571 gtk_option_menu_select_first_sensitive (GtkOptionMenu *option_menu)
572 {
573   if (option_menu->menu)
574     {
575       GList *children = GTK_MENU_SHELL (option_menu->menu)->children;
576       gint index = 0;
577
578       while (children)
579         {
580           if (GTK_WIDGET_SENSITIVE (children->data))
581             {
582               gtk_option_menu_set_history (option_menu, index);
583               return;
584             }
585           
586           children = children->next;
587           index++;
588         }
589     }
590 }
591
592 static void
593 gtk_option_menu_item_state_changed_cb (GtkWidget      *widget,
594                                        GtkStateType    previous_state,
595                                        GtkOptionMenu  *option_menu)
596 {
597   GtkWidget *child = GTK_BIN (option_menu)->child;
598
599   if (child && GTK_WIDGET_SENSITIVE (child) != GTK_WIDGET_IS_SENSITIVE (widget))
600     gtk_widget_set_sensitive (child, GTK_WIDGET_IS_SENSITIVE (widget));
601 }
602
603 static void
604 gtk_option_menu_item_destroy_cb (GtkWidget     *widget,
605                                  GtkOptionMenu *option_menu)
606 {
607   GtkWidget *child = GTK_BIN (option_menu)->child;
608
609   if (child)
610     {
611       gtk_widget_ref (child);
612       gtk_option_menu_remove_contents (option_menu);
613       gtk_widget_destroy (child);
614       gtk_widget_unref (child);
615
616       gtk_option_menu_select_first_sensitive (option_menu);
617     }
618 }
619
620 static void
621 gtk_option_menu_update_contents (GtkOptionMenu *option_menu)
622 {
623   GtkWidget *child;
624   GtkRequisition child_requisition;
625
626   g_return_if_fail (option_menu != NULL);
627   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
628
629   if (option_menu->menu)
630     {
631       GtkWidget *old_item = option_menu->menu_item;
632       
633       gtk_option_menu_remove_contents (option_menu);
634
635       option_menu->menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu));
636       if (option_menu->menu_item)
637         {
638           gtk_widget_ref (option_menu->menu_item);
639           child = GTK_BIN (option_menu->menu_item)->child;
640           if (child)
641             {
642               if (!GTK_WIDGET_IS_SENSITIVE (option_menu->menu_item))
643                 gtk_widget_set_sensitive (child, FALSE);
644               gtk_widget_reparent (child, GTK_WIDGET (option_menu));
645             }
646
647           gtk_signal_connect (GTK_OBJECT (option_menu->menu_item), "state_changed",
648                               GTK_SIGNAL_FUNC (gtk_option_menu_item_state_changed_cb), option_menu);
649           gtk_signal_connect (GTK_OBJECT (option_menu->menu_item), "destroy",
650                               GTK_SIGNAL_FUNC (gtk_option_menu_item_destroy_cb), option_menu);
651
652           gtk_widget_size_request (child, &child_requisition);
653           gtk_widget_size_allocate (GTK_WIDGET (option_menu),
654                                     &(GTK_WIDGET (option_menu)->allocation));
655
656           if (GTK_WIDGET_DRAWABLE (option_menu))
657             gtk_widget_queue_draw (GTK_WIDGET (option_menu));
658         }
659
660       if (old_item != option_menu->menu_item)
661         gtk_option_menu_changed (option_menu);
662     }
663 }
664
665 static void
666 gtk_option_menu_remove_contents (GtkOptionMenu *option_menu)
667 {
668   GtkWidget *child;
669   
670   g_return_if_fail (option_menu != NULL);
671   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
672
673   if (option_menu->menu_item)
674     {
675       child = GTK_BIN (option_menu)->child;
676   
677       if (child)
678         {
679           gtk_widget_set_sensitive (child, TRUE);
680           gtk_widget_reparent (child, option_menu->menu_item);
681         }
682
683       gtk_signal_disconnect_by_func (GTK_OBJECT (option_menu->menu_item),
684                                      GTK_SIGNAL_FUNC (gtk_option_menu_item_state_changed_cb),
685                                      option_menu);                                   
686       gtk_signal_disconnect_by_func (GTK_OBJECT (option_menu->menu_item),
687                                      GTK_SIGNAL_FUNC (gtk_option_menu_item_destroy_cb),
688                                      option_menu);   
689       
690       gtk_widget_unref (option_menu->menu_item);
691       option_menu->menu_item = NULL;
692     }
693 }
694
695 static void
696 gtk_option_menu_calc_size (GtkOptionMenu *option_menu)
697 {
698   GtkWidget *child;
699   GList *children;
700   GtkRequisition child_requisition;
701   gint old_width = option_menu->width;
702   gint old_height = option_menu->height;
703
704   g_return_if_fail (option_menu != NULL);
705   g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
706
707   option_menu->width = 0;
708   option_menu->height = 0;
709
710   if (option_menu->menu)
711     {
712       children = GTK_MENU_SHELL (option_menu->menu)->children;
713       while (children)
714         {
715           child = children->data;
716           children = children->next;
717
718           if (GTK_WIDGET_VISIBLE (child))
719             {
720               gtk_widget_size_request (child, &child_requisition);
721
722               option_menu->width = MAX (option_menu->width, child_requisition.width);
723               option_menu->height = MAX (option_menu->height, child_requisition.height);
724             }
725         }
726     }
727
728   if (old_width != option_menu->width || old_height != option_menu->height)
729     gtk_widget_queue_resize (GTK_WIDGET (option_menu));
730 }
731
732 static void
733 gtk_option_menu_position (GtkMenu  *menu,
734                           gint     *x,
735                           gint     *y,
736                           gboolean *push_in,
737                           gpointer  user_data)
738 {
739   GtkOptionMenu *option_menu;
740   GtkWidget *active;
741   GtkWidget *child;
742   GtkRequisition requisition;
743   GList *children;
744   gint screen_width;
745   gint menu_xpos;
746   gint menu_ypos;
747   gint menu_width;
748
749   g_return_if_fail (user_data != NULL);
750   g_return_if_fail (GTK_IS_OPTION_MENU (user_data));
751
752   option_menu = GTK_OPTION_MENU (user_data);
753
754   gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition);
755   menu_width = requisition.width;
756
757   active = gtk_menu_get_active (GTK_MENU (option_menu->menu));
758   gdk_window_get_origin (GTK_WIDGET (option_menu)->window, &menu_xpos, &menu_ypos);
759
760   menu_ypos += GTK_WIDGET (option_menu)->allocation.height / 2 - 2;
761
762   if (active != NULL)
763     {
764       gtk_widget_get_child_requisition (active, &requisition);
765       menu_ypos -= requisition.height / 2;
766     }
767
768   children = GTK_MENU_SHELL (option_menu->menu)->children;
769   while (children)
770     {
771       child = children->data;
772
773       if (active == child)
774         break;
775
776       if (GTK_WIDGET_VISIBLE (child))
777         {
778           gtk_widget_get_child_requisition (child, &requisition);
779           menu_ypos -= requisition.height;
780         }
781
782       children = children->next;
783     }
784
785   screen_width = gdk_screen_width ();
786   
787   if (menu_xpos < 0)
788     menu_xpos = 0;
789   else if ((menu_xpos + menu_width) > screen_width)
790     menu_xpos -= ((menu_xpos + menu_width) - screen_width);
791
792   *x = menu_xpos;
793   *y = menu_ypos;
794   *push_in = TRUE;
795 }
796
797
798 static void
799 gtk_option_menu_show_all (GtkWidget *widget)
800 {
801   GtkContainer *container;
802   GtkOptionMenu *option_menu;
803   
804   g_return_if_fail (widget != NULL);
805   g_return_if_fail (GTK_IS_OPTION_MENU (widget));
806   container = GTK_CONTAINER (widget);
807   option_menu = GTK_OPTION_MENU (widget);
808
809   gtk_widget_show (widget);
810   gtk_container_foreach (container, (GtkCallback) gtk_widget_show_all, NULL);
811   if (option_menu->menu)
812     gtk_widget_show_all (option_menu->menu);
813   if (option_menu->menu_item)
814     gtk_widget_show_all (option_menu->menu_item);
815 }
816
817
818 static void
819 gtk_option_menu_hide_all (GtkWidget *widget)
820 {
821   GtkContainer *container;
822
823   g_return_if_fail (widget != NULL);
824   g_return_if_fail (GTK_IS_OPTION_MENU (widget));
825   container = GTK_CONTAINER (widget);
826
827   gtk_widget_hide (widget);
828   gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL);
829 }
830