source: trunk/third/gtk/gtk/gtkoptionmenu.c @ 15781

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