]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenuitem.c
corrects a small resize bug in the viewport widget. The viewport widget
[~andy/gtk] / gtk / gtkmenuitem.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include <string.h>
19 #include "gtklabel.h"
20 #include "gtkmain.h"
21 #include "gtkmenu.h"
22 #include "gtkmenuitem.h"
23 #include "gtksignal.h"
24
25
26 #define BORDER_SPACING  3
27 #define SELECT_TIMEOUT  20
28
29 #define MENU_ITEM_CLASS(w)  GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
30
31
32 enum {
33   ACTIVATE,
34   LAST_SIGNAL
35 };
36
37
38 static void gtk_menu_item_class_init     (GtkMenuItemClass *klass);
39 static void gtk_menu_item_init           (GtkMenuItem      *menu_item);
40 static void gtk_menu_item_destroy        (GtkObject        *object);
41 static void gtk_menu_item_size_request   (GtkWidget        *widget,
42                                           GtkRequisition   *requisition);
43 static void gtk_menu_item_size_allocate  (GtkWidget        *widget,
44                                           GtkAllocation    *allocation);
45 static gint gtk_menu_item_install_accel  (GtkWidget        *widget,
46                                           const gchar      *signal_name,
47                                           gchar             key,
48                                           guint8            modifiers);
49 static void gtk_menu_item_remove_accel   (GtkWidget        *widget,
50                                           const gchar      *signal_name);
51 static void gtk_menu_item_paint          (GtkWidget        *widget,
52                                           GdkRectangle     *area);
53 static void gtk_menu_item_draw           (GtkWidget        *widget,
54                                           GdkRectangle     *area);
55 static gint gtk_menu_item_expose         (GtkWidget        *widget,
56                                           GdkEventExpose   *event);
57 static gint gtk_menu_item_enter          (GtkWidget        *widget,
58                                           GdkEventCrossing *event);
59 static gint gtk_menu_item_leave          (GtkWidget        *widget,
60                                           GdkEventCrossing *event);
61 static void gtk_real_menu_item_select    (GtkItem          *item);
62 static void gtk_real_menu_item_deselect  (GtkItem          *item);
63 static gint gtk_menu_item_select_timeout (gpointer          data);
64 static void gtk_menu_item_position_menu  (GtkMenu          *menu,
65                                           gint             *x,
66                                           gint             *y,
67                                           gpointer          user_data);
68 static void gtk_menu_item_show_all       (GtkWidget        *widget);
69 static void gtk_menu_item_hide_all       (GtkWidget        *widget);
70
71 static GtkItemClass *parent_class;
72 static gint menu_item_signals[LAST_SIGNAL] = { 0 };
73
74
75 guint
76 gtk_menu_item_get_type ()
77 {
78   static guint menu_item_type = 0;
79
80   if (!menu_item_type)
81     {
82       GtkTypeInfo menu_item_info =
83       {
84         "GtkMenuItem",
85         sizeof (GtkMenuItem),
86         sizeof (GtkMenuItemClass),
87         (GtkClassInitFunc) gtk_menu_item_class_init,
88         (GtkObjectInitFunc) gtk_menu_item_init,
89         (GtkArgFunc) NULL,
90       };
91
92       menu_item_type = gtk_type_unique (gtk_item_get_type (), &menu_item_info);
93     }
94
95   return menu_item_type;
96 }
97
98 static void
99 gtk_menu_item_class_init (GtkMenuItemClass *klass)
100 {
101   GtkObjectClass *object_class;
102   GtkWidgetClass *widget_class;
103   GtkItemClass *item_class;
104
105   object_class = (GtkObjectClass*) klass;
106   widget_class = (GtkWidgetClass*) klass;
107   item_class = (GtkItemClass*) klass;
108
109   parent_class = gtk_type_class (gtk_item_get_type ());
110
111   menu_item_signals[ACTIVATE] =
112     gtk_signal_new ("activate",
113                     GTK_RUN_FIRST,
114                     object_class->type,
115                     GTK_SIGNAL_OFFSET (GtkMenuItemClass, activate),
116                     gtk_signal_default_marshaller,
117                     GTK_TYPE_NONE, 0);
118
119   gtk_object_class_add_signals (object_class, menu_item_signals, LAST_SIGNAL);
120
121   object_class->destroy = gtk_menu_item_destroy;
122
123   widget_class->activate_signal = menu_item_signals[ACTIVATE];
124   widget_class->size_request = gtk_menu_item_size_request;
125   widget_class->size_allocate = gtk_menu_item_size_allocate;
126   widget_class->install_accelerator = gtk_menu_item_install_accel;
127   widget_class->remove_accelerator = gtk_menu_item_remove_accel;
128   widget_class->draw = gtk_menu_item_draw;
129   widget_class->expose_event = gtk_menu_item_expose;
130   widget_class->enter_notify_event = gtk_menu_item_enter;
131   widget_class->leave_notify_event = gtk_menu_item_leave;
132   widget_class->show_all = gtk_menu_item_show_all;
133   widget_class->hide_all = gtk_menu_item_hide_all;  
134
135   item_class->select = gtk_real_menu_item_select;
136   item_class->deselect = gtk_real_menu_item_deselect;
137
138   klass->activate = NULL;
139
140   klass->toggle_size = 0;
141   klass->shift_text = "Shft";
142   klass->control_text = "Ctl";
143   klass->alt_text = "Alt";
144   klass->separator_text = "+";
145 }
146
147 static void
148 gtk_menu_item_init (GtkMenuItem *menu_item)
149 {
150   menu_item->submenu = NULL;
151   menu_item->accelerator_key = 0;
152   menu_item->accelerator_mods = 0;
153   menu_item->accelerator_size = 0;
154   menu_item->accelerator_signal = 0;
155   menu_item->toggle_size = 0;
156   menu_item->show_toggle_indicator = FALSE;
157   menu_item->show_submenu_indicator = FALSE;
158   menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
159   menu_item->submenu_placement = GTK_TOP_BOTTOM;
160   menu_item->right_justify = FALSE;
161
162   menu_item->timer = 0;
163 }
164
165 GtkWidget*
166 gtk_menu_item_new ()
167 {
168   return GTK_WIDGET (gtk_type_new (gtk_menu_item_get_type ()));
169 }
170
171 GtkWidget*
172 gtk_menu_item_new_with_label (const gchar *label)
173 {
174   GtkWidget *menu_item;
175   GtkWidget *label_widget;
176
177   menu_item = gtk_menu_item_new ();
178   label_widget = gtk_label_new (label);
179   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
180
181   gtk_container_add (GTK_CONTAINER (menu_item), label_widget);
182   gtk_widget_show (label_widget);
183
184   return menu_item;
185 }
186
187 static void
188 gtk_menu_item_destroy (GtkObject *object)
189 {
190   GtkMenuItem *menu_item;
191
192   g_return_if_fail (object != NULL);
193   g_return_if_fail (GTK_IS_MENU_ITEM (object));
194
195   menu_item = GTK_MENU_ITEM (object);
196
197   if (menu_item->submenu)
198     {
199       gtk_object_unref (GTK_OBJECT (menu_item->submenu));
200       /* gtk_widget_destroy (menu_item->submenu); */
201     }
202
203   if (GTK_OBJECT_CLASS (parent_class)->destroy)
204     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
205 }
206
207 void
208 gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
209                            GtkWidget   *submenu)
210 {
211   g_return_if_fail (menu_item != NULL);
212   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
213
214   if (menu_item->submenu != submenu)
215     {
216       if (menu_item->submenu)
217         {
218           g_return_if_fail (!GTK_WIDGET_VISIBLE (menu_item->submenu));
219           gtk_object_unref (GTK_OBJECT (menu_item->submenu));
220         }
221       menu_item->submenu = submenu;
222       if (menu_item->submenu)
223         gtk_object_ref (GTK_OBJECT (menu_item->submenu));
224
225       if (GTK_WIDGET (menu_item)->parent)
226         gtk_widget_queue_resize (GTK_WIDGET (menu_item));
227     }
228 }
229
230 void
231 gtk_menu_item_set_placement (GtkMenuItem         *menu_item,
232                              GtkSubmenuPlacement  placement)
233 {
234   g_return_if_fail (menu_item != NULL);
235   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
236
237   menu_item->submenu_placement = placement;
238 }
239
240 void
241 gtk_menu_item_accelerator_size (GtkMenuItem *menu_item)
242 {
243   char buf[32];
244
245   g_return_if_fail (menu_item != NULL);
246   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
247
248   if (menu_item->accelerator_key)
249     {
250       gtk_menu_item_accelerator_text (menu_item, buf);
251       menu_item->accelerator_size = gdk_string_width (GTK_WIDGET (menu_item)->style->font, buf) + 13;
252     }
253   else if (menu_item->submenu && menu_item->show_submenu_indicator)
254     {
255       menu_item->accelerator_size = 21;
256     }
257   else
258     {
259       menu_item->accelerator_size = 0;
260     }
261 }
262
263 void
264 gtk_menu_item_accelerator_text (GtkMenuItem *menu_item,
265                                 gchar       *buffer)
266 {
267   g_return_if_fail (menu_item != NULL);
268   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
269
270   if (menu_item->accelerator_key)
271     {
272       buffer[0] = '\0';
273       if (menu_item->accelerator_mods & GDK_SHIFT_MASK)
274         {
275           strcat (buffer, MENU_ITEM_CLASS (menu_item)->shift_text);
276           strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text);
277         }
278       if (menu_item->accelerator_mods & GDK_CONTROL_MASK)
279         {
280           strcat (buffer, MENU_ITEM_CLASS (menu_item)->control_text);
281           strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text);
282         }
283       if (menu_item->accelerator_mods & GDK_MOD1_MASK)
284         {
285           strcat (buffer, MENU_ITEM_CLASS (menu_item)->alt_text);
286           strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text);
287         }
288       strncat (buffer, &menu_item->accelerator_key, 1);
289     }
290 }
291
292 void
293 gtk_menu_item_configure (GtkMenuItem *menu_item,
294                          gint         show_toggle_indicator,
295                          gint         show_submenu_indicator)
296 {
297   g_return_if_fail (menu_item != NULL);
298   g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
299
300   menu_item->show_toggle_indicator = (show_toggle_indicator == TRUE);
301   menu_item->show_submenu_indicator = (show_submenu_indicator == TRUE);
302 }
303
304 void
305 gtk_menu_item_select (GtkMenuItem *menu_item)
306 {
307   gtk_item_select (GTK_ITEM (menu_item));
308 }
309
310 void
311 gtk_menu_item_deselect (GtkMenuItem *menu_item)
312 {
313   gtk_item_deselect (GTK_ITEM (menu_item));
314 }
315
316 void
317 gtk_menu_item_activate (GtkMenuItem *menu_item)
318 {
319   gtk_signal_emit (GTK_OBJECT (menu_item), menu_item_signals[ACTIVATE]);
320 }
321
322
323 static void
324 gtk_menu_item_size_request (GtkWidget      *widget,
325                             GtkRequisition *requisition)
326 {
327   GtkBin *bin;
328
329   g_return_if_fail (widget != NULL);
330   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
331   g_return_if_fail (requisition != NULL);
332
333   bin = GTK_BIN (widget);
334
335   gtk_menu_item_accelerator_size (GTK_MENU_ITEM (widget));
336
337   requisition->width = (GTK_CONTAINER (widget)->border_width +
338                         widget->style->klass->xthickness +
339                         BORDER_SPACING) * 2;
340   requisition->height = (GTK_CONTAINER (widget)->border_width +
341                          widget->style->klass->ythickness) * 2;
342
343   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
344     {
345       gtk_widget_size_request (bin->child, &bin->child->requisition);
346
347       requisition->width += bin->child->requisition.width;
348       requisition->height += bin->child->requisition.height;
349     }
350 }
351
352 static void
353 gtk_menu_item_size_allocate (GtkWidget     *widget,
354                              GtkAllocation *allocation)
355 {
356   GtkBin *bin;
357   GtkAllocation child_allocation;
358
359   g_return_if_fail (widget != NULL);
360   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
361   g_return_if_fail (allocation != NULL);
362
363   widget->allocation = *allocation;
364   if (GTK_WIDGET_REALIZED (widget))
365     gdk_window_move_resize (widget->window,
366                             allocation->x, allocation->y,
367                             allocation->width, allocation->height);
368
369   bin = GTK_BIN (widget);
370
371   if (bin->child)
372     {
373       child_allocation.x = (GTK_CONTAINER (widget)->border_width +
374                             widget->style->klass->xthickness +
375                             BORDER_SPACING);
376       child_allocation.y = GTK_CONTAINER (widget)->border_width;
377       child_allocation.width = allocation->width - child_allocation.x * 2;
378       child_allocation.height = allocation->height - child_allocation.y * 2;
379       child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size;
380       child_allocation.width -= (GTK_MENU_ITEM (widget)->toggle_size +
381                                  GTK_MENU_ITEM (widget)->accelerator_size);
382
383       gtk_widget_size_allocate (bin->child, &child_allocation);
384     }
385 }
386
387 static gint
388 gtk_menu_item_install_accel (GtkWidget   *widget,
389                              const gchar *signal_name,
390                              gchar        key,
391                              guint8       modifiers)
392 {
393   GtkMenuItem *menu_item;
394
395   g_return_val_if_fail (widget != NULL, FALSE);
396   g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
397   g_return_val_if_fail (signal_name != NULL, FALSE);
398
399   menu_item = GTK_MENU_ITEM (widget);
400
401   menu_item->accelerator_signal = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (widget));
402   if (menu_item->accelerator_signal > 0)
403     {
404       menu_item->accelerator_key = key;
405       menu_item->accelerator_mods = modifiers;
406
407       if (widget->parent)
408         gtk_widget_queue_resize (widget);
409
410       return TRUE;
411     }
412
413   return FALSE;
414 }
415
416 static void
417 gtk_menu_item_remove_accel (GtkWidget   *widget,
418                             const gchar *signal_name)
419 {
420   GtkMenuItem *menu_item;
421   gint signal_num;
422
423   g_return_if_fail (widget != NULL);
424   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
425   g_return_if_fail (signal_name != NULL);
426
427   menu_item = GTK_MENU_ITEM (widget);
428
429   signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (widget));
430   if (menu_item->accelerator_signal == signal_num)
431     {
432       menu_item->accelerator_key = 0;
433       menu_item->accelerator_mods = 0;
434       menu_item->accelerator_signal = 0;
435
436       if (GTK_WIDGET_VISIBLE (widget))
437         {
438           gtk_widget_queue_draw (widget);
439           GTK_MENU_SHELL (widget->parent)->menu_flag = TRUE;
440         }
441       else
442         gtk_container_need_resize (GTK_CONTAINER (widget->parent));
443     }
444 }
445
446 static void
447 gtk_menu_item_paint (GtkWidget    *widget,
448                      GdkRectangle *area)
449 {
450   GtkMenuItem *menu_item;
451   GtkStateType state_type;
452   GtkShadowType shadow_type;
453   GdkFont *font;
454   gint width, height;
455   gint x, y;
456   char buf[32];
457
458   g_return_if_fail (widget != NULL);
459   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
460
461   if (GTK_WIDGET_DRAWABLE (widget))
462     {
463       menu_item = GTK_MENU_ITEM (widget);
464
465       state_type = widget->state;
466       if (!GTK_WIDGET_IS_SENSITIVE (widget))
467         state_type = GTK_STATE_INSENSITIVE;
468
469       gtk_style_set_background (widget->style, widget->window, state_type);
470       gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
471
472       x = GTK_CONTAINER (menu_item)->border_width;
473       y = GTK_CONTAINER (menu_item)->border_width;
474       width = widget->allocation.width - x * 2;
475       height = widget->allocation.height - y * 2;
476
477       if ((state_type == GTK_STATE_PRELIGHT) &&
478           (GTK_BIN (menu_item)->child))
479         gtk_draw_shadow (widget->style,
480                          widget->window,
481                          GTK_STATE_PRELIGHT,
482                          GTK_SHADOW_OUT,
483                          x, y, width, height);
484
485       if (menu_item->accelerator_key)
486         {
487           gtk_menu_item_accelerator_text (menu_item, buf);
488
489           font = widget->style->font;
490           x = x + width - menu_item->accelerator_size + 13 - 4;
491           y = y + ((height - (font->ascent + font->descent)) / 2) + font->ascent;
492
493           if (state_type == GTK_STATE_INSENSITIVE)
494             gdk_draw_string (widget->window, widget->style->font,
495                              widget->style->white_gc,
496                              x + 1, y + 1, buf);
497
498           gdk_draw_string (widget->window, widget->style->font,
499                            widget->style->fg_gc[state_type],
500                            x, y, buf);
501         }
502       else if (menu_item->submenu && menu_item->show_submenu_indicator)
503         {
504           shadow_type = GTK_SHADOW_OUT;
505           if (state_type == GTK_STATE_PRELIGHT)
506             shadow_type = GTK_SHADOW_IN;
507
508           gtk_draw_arrow (widget->style, widget->window,
509                           state_type, shadow_type, GTK_ARROW_RIGHT, FALSE,
510                           x + width - 15, y + height / 2 - 5, 10, 10);
511         }
512       else if (!GTK_BIN (menu_item)->child)
513         {
514           gtk_draw_hline (widget->style, widget->window, GTK_STATE_NORMAL,
515                           0, widget->allocation.width, 0);
516         }
517     }
518 }
519
520 static void
521 gtk_menu_item_draw (GtkWidget    *widget,
522                     GdkRectangle *area)
523 {
524   GtkBin *bin;
525   GdkRectangle child_area;
526
527   g_return_if_fail (widget != NULL);
528   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
529   g_return_if_fail (area != NULL);
530
531   if (GTK_WIDGET_DRAWABLE (widget))
532     {
533       gtk_menu_item_paint (widget, area);
534
535       bin = GTK_BIN (widget);
536
537       if (bin->child)
538         {
539           if (gtk_widget_intersect (bin->child, area, &child_area))
540             gtk_widget_draw (bin->child, &child_area);
541         }
542     }
543 }
544
545 static gint
546 gtk_menu_item_expose (GtkWidget      *widget,
547                       GdkEventExpose *event)
548 {
549   GtkBin *bin;
550   GdkEventExpose child_event;
551
552   g_return_val_if_fail (widget != NULL, FALSE);
553   g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
554   g_return_val_if_fail (event != NULL, FALSE);
555
556   if (GTK_WIDGET_DRAWABLE (widget))
557     {
558       gtk_menu_item_paint (widget, &event->area);
559
560       bin = GTK_BIN (widget);
561
562       if (bin->child)
563         {
564           child_event = *event;
565
566           if (GTK_WIDGET_NO_WINDOW (bin->child) &&
567               gtk_widget_intersect (bin->child, &event->area, &child_event.area))
568             gtk_widget_event (bin->child, (GdkEvent*) &child_event);
569         }
570     }
571
572   return FALSE;
573 }
574
575 static gint
576 gtk_menu_item_enter (GtkWidget        *widget,
577                      GdkEventCrossing *event)
578 {
579   g_return_val_if_fail (widget != NULL, FALSE);
580   g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
581   g_return_val_if_fail (event != NULL, FALSE);
582
583   return gtk_widget_event (widget->parent, (GdkEvent*) event);
584 }
585
586 static gint
587 gtk_menu_item_leave (GtkWidget        *widget,
588                      GdkEventCrossing *event)
589 {
590   g_return_val_if_fail (widget != NULL, FALSE);
591   g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
592   g_return_val_if_fail (event != NULL, FALSE);
593
594   return gtk_widget_event (widget->parent, (GdkEvent*) event);
595 }
596
597 static void
598 gtk_real_menu_item_select (GtkItem *item)
599 {
600   GtkMenuItem *menu_item;
601
602   g_return_if_fail (item != NULL);
603   g_return_if_fail (GTK_IS_MENU_ITEM (item));
604
605   menu_item = GTK_MENU_ITEM (item);
606
607   if (menu_item->submenu && !GTK_WIDGET_VISIBLE (menu_item->submenu))
608     menu_item->timer = gtk_timeout_add (SELECT_TIMEOUT, gtk_menu_item_select_timeout, menu_item);
609
610   gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
611   gtk_widget_draw (GTK_WIDGET (menu_item), NULL);
612 }
613
614 static void
615 gtk_real_menu_item_deselect (GtkItem *item)
616 {
617   GtkMenuItem *menu_item;
618
619   g_return_if_fail (item != NULL);
620   g_return_if_fail (GTK_IS_MENU_ITEM (item));
621
622   menu_item = GTK_MENU_ITEM (item);
623
624   if (menu_item->submenu)
625     {
626       if (menu_item->timer)
627         gtk_timeout_remove (menu_item->timer);
628       else
629         gtk_menu_popdown (GTK_MENU (menu_item->submenu));
630     }
631
632   gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
633   gtk_widget_draw (GTK_WIDGET (menu_item), NULL);
634 }
635
636 static gint
637 gtk_menu_item_select_timeout (gpointer data)
638 {
639   GtkMenuItem *menu_item;
640
641   menu_item = GTK_MENU_ITEM (data);
642   menu_item->timer = 0;
643
644   gtk_menu_popup (GTK_MENU (menu_item->submenu),
645                   GTK_WIDGET (menu_item)->parent,
646                   GTK_WIDGET (menu_item),
647                   gtk_menu_item_position_menu,
648                   menu_item,
649                   GTK_MENU_SHELL (GTK_WIDGET (menu_item)->parent)->button,
650                   0);
651
652   return FALSE;
653 }
654
655 static void
656 gtk_menu_item_position_menu (GtkMenu  *menu,
657                              gint     *x,
658                              gint     *y,
659                              gpointer  user_data)
660 {
661   GtkMenuItem *menu_item;
662   GtkMenuItem *parent_menu_item;
663   gint screen_width;
664   gint screen_height;
665   gint twidth, theight;
666   gint tx, ty;
667
668   g_return_if_fail (menu != NULL);
669   g_return_if_fail (x != NULL);
670   g_return_if_fail (y != NULL);
671
672   menu_item = GTK_MENU_ITEM (user_data);
673
674   twidth = GTK_WIDGET (menu)->requisition.width;
675   theight = GTK_WIDGET (menu)->requisition.height;
676
677   screen_width = gdk_screen_width ();
678   screen_height = gdk_screen_height ();
679
680   g_return_if_fail (gdk_window_get_origin (GTK_WIDGET (menu_item)->window, &tx, &ty));
681
682   switch (menu_item->submenu_placement)
683     {
684     case GTK_TOP_BOTTOM:
685       if ((ty + GTK_WIDGET (menu_item)->allocation.height + theight) <= screen_height)
686         ty += GTK_WIDGET (menu_item)->allocation.height;
687       else if ((ty - theight) >= 0)
688         ty -= theight;
689       else
690         ty += GTK_WIDGET (menu_item)->allocation.height;
691
692       if ((tx + twidth) > screen_width)
693         {
694           tx -= ((tx + twidth) - screen_width);
695           if (tx < 0)
696             tx = 0;
697         }
698       break;
699
700     case GTK_LEFT_RIGHT:
701       menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
702       parent_menu_item = GTK_MENU_ITEM (GTK_MENU (GTK_WIDGET (menu_item)->parent)->parent_menu_item);
703       if (parent_menu_item)
704         menu_item->submenu_direction = parent_menu_item->submenu_direction;
705
706       switch (menu_item->submenu_direction)
707         {
708         case GTK_DIRECTION_LEFT:
709           if ((tx - twidth) >= 0)
710             tx -= twidth;
711           else
712             {
713               menu_item->submenu_direction = GTK_DIRECTION_RIGHT;
714               tx += GTK_WIDGET (menu_item)->allocation.width - 5;
715             }
716           break;
717
718         case GTK_DIRECTION_RIGHT:
719           if ((tx + GTK_WIDGET (menu_item)->allocation.width + twidth - 5) <= screen_width)
720             tx += GTK_WIDGET (menu_item)->allocation.width - 5;
721           else
722             {
723               menu_item->submenu_direction = GTK_DIRECTION_LEFT;
724               tx -= twidth;
725             }
726           break;
727         }
728
729       if ((ty + GTK_WIDGET (menu_item)->allocation.height / 4 + theight) <= screen_height)
730         ty += GTK_WIDGET (menu_item)->allocation.height / 4;
731       else
732         {
733           ty -= ((ty + theight) - screen_height);
734           if (ty < 0)
735             ty = 0;
736         }
737       break;
738     }
739
740   *x = tx;
741   *y = ty;
742 }
743
744 void
745 gtk_menu_item_right_justify(GtkMenuItem *menuitem)
746 {
747   g_return_if_fail (menuitem != NULL);
748   g_return_if_fail (GTK_IS_MENU_ITEM (menuitem));
749
750   menuitem->right_justify = 1;
751 }
752
753 static void
754 gtk_menu_item_show_all (GtkWidget *widget)
755 {
756   GtkContainer *container;
757   GtkMenuItem  *menu_item;
758
759   g_return_if_fail (widget != NULL);
760   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
761   container = GTK_CONTAINER (widget);
762   menu_item = GTK_MENU_ITEM (widget);
763
764   /* Show children, traverse to submenu, show self. */
765   gtk_container_foreach (container, (GtkCallback) gtk_widget_show_all, NULL);
766   if (menu_item->submenu)
767     gtk_widget_show_all (menu_item->submenu);
768   gtk_widget_show (widget);
769 }
770
771
772 static void
773 gtk_menu_item_hide_all (GtkWidget *widget)
774 {
775   GtkContainer *container;
776   GtkMenuItem  *menu_item;
777
778   g_return_if_fail (widget != NULL);
779   g_return_if_fail (GTK_IS_MENU_ITEM (widget));
780   container = GTK_CONTAINER (widget);
781   menu_item = GTK_MENU_ITEM (widget);
782
783   /* Reverse order of gtk_menu_item_show_all */
784   gtk_widget_hide (widget);
785   if (menu_item->submenu)
786     gtk_widget_hide_all (menu_item->submenu);
787   gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL);
788 }