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