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