1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
28 #include "gdk/gdkkeysyms.h"
29 #include "gtkbindings.h"
33 #include "gtkmenuitem.h"
34 #include "gtksignal.h"
35 #include "gtkwindow.h"
38 #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
39 #define MENU_NEEDS_RESIZE(m) GTK_MENU_SHELL (m)->menu_flag
41 typedef struct _GtkMenuAttachData GtkMenuAttachData;
43 struct _GtkMenuAttachData
45 GtkWidget *attach_widget;
46 GtkMenuDetachFunc detacher;
50 static void gtk_menu_class_init (GtkMenuClass *klass);
51 static void gtk_menu_init (GtkMenu *menu);
52 static void gtk_menu_destroy (GtkObject *object);
53 static void gtk_menu_realize (GtkWidget *widget);
54 static void gtk_menu_size_request (GtkWidget *widget,
55 GtkRequisition *requisition);
56 static void gtk_menu_size_allocate (GtkWidget *widget,
57 GtkAllocation *allocation);
58 static void gtk_menu_paint (GtkWidget *widget);
59 static void gtk_menu_draw (GtkWidget *widget,
61 static gint gtk_menu_expose (GtkWidget *widget,
62 GdkEventExpose *event);
63 static gint gtk_menu_key_press (GtkWidget *widget,
65 static gint gtk_menu_motion_notify (GtkWidget *widget,
66 GdkEventMotion *event);
67 static void gtk_menu_deactivate (GtkMenuShell *menu_shell);
68 static void gtk_menu_show_all (GtkWidget *widget);
69 static void gtk_menu_hide_all (GtkWidget *widget);
70 static void gtk_menu_position (GtkMenu *menu);
71 static void gtk_menu_reparent (GtkMenu *menu,
72 GtkWidget *new_parent,
75 static GtkMenuShellClass *parent_class = NULL;
76 static const gchar *attach_data_key = "gtk-menu-attach-data";
80 gtk_menu_get_type (void)
82 static GtkType menu_type = 0;
86 static const GtkTypeInfo menu_info =
90 sizeof (GtkMenuClass),
91 (GtkClassInitFunc) gtk_menu_class_init,
92 (GtkObjectInitFunc) gtk_menu_init,
93 /* reserved_1 */ NULL,
94 /* reserved_2 */ NULL,
95 (GtkClassInitFunc) NULL,
98 menu_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_info);
105 gtk_menu_class_init (GtkMenuClass *class)
107 GtkObjectClass *object_class;
108 GtkWidgetClass *widget_class;
109 GtkContainerClass *container_class;
110 GtkMenuShellClass *menu_shell_class;
112 GtkBindingSet *binding_set;
114 object_class = (GtkObjectClass*) class;
115 widget_class = (GtkWidgetClass*) class;
116 container_class = (GtkContainerClass*) class;
117 menu_shell_class = (GtkMenuShellClass*) class;
118 parent_class = gtk_type_class (gtk_menu_shell_get_type ());
120 object_class->destroy = gtk_menu_destroy;
122 widget_class->realize = gtk_menu_realize;
123 widget_class->draw = gtk_menu_draw;
124 widget_class->size_request = gtk_menu_size_request;
125 widget_class->size_allocate = gtk_menu_size_allocate;
126 widget_class->expose_event = gtk_menu_expose;
127 widget_class->key_press_event = gtk_menu_key_press;
128 widget_class->motion_notify_event = gtk_menu_motion_notify;
129 widget_class->show_all = gtk_menu_show_all;
130 widget_class->hide_all = gtk_menu_hide_all;
132 menu_shell_class->submenu_placement = GTK_LEFT_RIGHT;
133 menu_shell_class->deactivate = gtk_menu_deactivate;
135 binding_set = gtk_binding_set_by_class (class);
136 gtk_binding_entry_add_signal (binding_set,
139 GTK_TYPE_MENU_DIRECTION_TYPE,
141 gtk_binding_entry_add_signal (binding_set,
144 GTK_TYPE_MENU_DIRECTION_TYPE,
146 gtk_binding_entry_add_signal (binding_set,
149 GTK_TYPE_MENU_DIRECTION_TYPE,
150 GTK_MENU_DIR_PARENT);
151 gtk_binding_entry_add_signal (binding_set,
154 GTK_TYPE_MENU_DIRECTION_TYPE,
159 gtk_menu_init (GtkMenu *menu)
161 menu->parent_menu_item = NULL;
162 menu->old_active_menu_item = NULL;
163 menu->accel_group = NULL;
164 menu->position_func = NULL;
165 menu->position_func_data = NULL;
167 menu->toplevel = gtk_window_new (GTK_WINDOW_POPUP);
168 gtk_signal_connect_object (GTK_OBJECT (menu->toplevel), "key_press_event",
169 GTK_SIGNAL_FUNC (gtk_menu_key_press),
171 gtk_window_set_policy (GTK_WINDOW (menu->toplevel),
174 gtk_container_add (GTK_CONTAINER (menu->toplevel), GTK_WIDGET (menu));
176 /* Refloat the menu, so that reference counting for the menu isn't
177 * affected by it being a child of the toplevel
179 GTK_WIDGET_SET_FLAGS (menu, GTK_FLOATING);
181 menu->tearoff_window = NULL;
182 menu->torn_off = FALSE;
184 MENU_NEEDS_RESIZE (menu) = TRUE;
188 gtk_menu_destroy (GtkObject *object)
191 GtkMenuAttachData *data;
193 g_return_if_fail (object != NULL);
194 g_return_if_fail (GTK_IS_MENU (object));
196 menu = GTK_MENU (object);
198 gtk_object_ref (object);
200 data = gtk_object_get_data (object, attach_data_key);
202 gtk_menu_detach (menu);
204 gtk_menu_set_accel_group (menu, NULL);
206 /* Add back the reference count for being a child */
207 gtk_object_ref (object);
209 gtk_widget_destroy (menu->toplevel);
210 if (menu->tearoff_window)
211 gtk_widget_destroy (menu->tearoff_window);
213 if (GTK_OBJECT_CLASS (parent_class)->destroy)
214 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
216 gtk_object_unref (object);
221 gtk_menu_attach_to_widget (GtkMenu *menu,
222 GtkWidget *attach_widget,
223 GtkMenuDetachFunc detacher)
225 GtkMenuAttachData *data;
227 g_return_if_fail (menu != NULL);
228 g_return_if_fail (GTK_IS_MENU (menu));
229 g_return_if_fail (attach_widget != NULL);
230 g_return_if_fail (GTK_IS_WIDGET (attach_widget));
231 g_return_if_fail (detacher != NULL);
233 /* keep this function in sync with gtk_widget_set_parent()
236 data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
239 g_warning ("gtk_menu_attach_to_widget(): menu already attached to %s",
240 gtk_type_name (GTK_OBJECT_TYPE (data->attach_widget)));
244 gtk_object_ref (GTK_OBJECT (menu));
245 gtk_object_sink (GTK_OBJECT (menu));
247 data = g_new (GtkMenuAttachData, 1);
248 data->attach_widget = attach_widget;
249 data->detacher = detacher;
250 gtk_object_set_data (GTK_OBJECT (menu), attach_data_key, data);
252 if (GTK_WIDGET_STATE (menu) != GTK_STATE_NORMAL)
253 gtk_widget_set_state (GTK_WIDGET (menu), GTK_STATE_NORMAL);
255 /* we don't need to set the style here, since
256 * we are a toplevel widget.
261 gtk_menu_get_attach_widget (GtkMenu *menu)
263 GtkMenuAttachData *data;
265 g_return_val_if_fail (menu != NULL, NULL);
266 g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
268 data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
270 return data->attach_widget;
275 gtk_menu_detach (GtkMenu *menu)
277 GtkMenuAttachData *data;
279 g_return_if_fail (menu != NULL);
280 g_return_if_fail (GTK_IS_MENU (menu));
282 /* keep this function in sync with gtk_widget_unparent()
284 data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
287 g_warning ("gtk_menu_detach(): menu is not attached");
290 gtk_object_remove_data (GTK_OBJECT (menu), attach_data_key);
292 data->detacher (data->attach_widget, menu);
294 if (GTK_WIDGET_REALIZED (menu))
295 gtk_widget_unrealize (GTK_WIDGET (menu));
299 gtk_widget_unref (GTK_WIDGET (menu));
305 return GTK_WIDGET (gtk_type_new (gtk_menu_get_type ()));
309 gtk_menu_append (GtkMenu *menu,
312 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
316 gtk_menu_prepend (GtkMenu *menu,
319 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), child);
323 gtk_menu_insert (GtkMenu *menu,
327 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), child, position);
331 gtk_menu_popup (GtkMenu *menu,
332 GtkWidget *parent_menu_shell,
333 GtkWidget *parent_menu_item,
334 GtkMenuPositionFunc func,
337 guint32 activate_time)
340 GtkWidget *xgrab_shell;
342 GdkEvent *current_event;
343 GtkMenuShell *menu_shell;
345 g_return_if_fail (menu != NULL);
346 g_return_if_fail (GTK_IS_MENU (menu));
348 widget = GTK_WIDGET (menu);
349 menu_shell = GTK_MENU_SHELL (menu);
351 menu_shell->parent_menu_shell = parent_menu_shell;
352 menu_shell->active = TRUE;
353 menu_shell->button = button;
355 /* If we are popping up the menu from something other than, a button
356 * press then, as a heuristic, we ignore enter events for the menu
357 * until we get a MOTION_NOTIFY.
360 current_event = gtk_get_current_event();
363 if ((current_event->type != GDK_BUTTON_PRESS) &&
364 (current_event->type != GDK_ENTER_NOTIFY))
365 menu_shell->ignore_enter = TRUE;
366 gdk_event_free(current_event);
373 GdkGCValues gc_values;
375 gc_values.subwindow_mode = GDK_INCLUDE_INFERIORS;
376 gc = gdk_gc_new_with_values (widget->window,
377 &gc_values, GDK_GC_SUBWINDOW);
379 pixmap = gdk_pixmap_new (widget->window,
380 widget->requisition.width,
381 widget->requisition.height,
384 gdk_draw_pixmap (pixmap, gc,
389 gtk_widget_set_usize (menu->tearoff_window,
390 widget->requisition.width,
391 widget->requisition.height);
393 gdk_window_set_back_pixmap (menu->tearoff_window->window, pixmap, FALSE);
394 gdk_pixmap_unref (pixmap);
396 /* We force an unrealize here so that we don't trigger redrawing/
397 * clearing code - we just want to reveal our backing pixmap.
399 gtk_menu_reparent (menu, menu->toplevel, TRUE);
402 menu->parent_menu_item = parent_menu_item;
403 menu->position_func = func;
404 menu->position_func_data = data;
405 menu_shell->activate_time = activate_time;
407 gtk_menu_position (menu);
409 /* We need to show the menu _here_ because code expects to be
410 * able to tell if the menu is onscreen by looking at the
411 * GTK_WIDGET_VISIBLE (menu)
413 gtk_widget_show (GTK_WIDGET (menu));
414 gtk_widget_show (menu->toplevel);
416 /* Find the last viewable ancestor, and make an X grab on it
418 parent = GTK_WIDGET (menu);
422 gboolean viewable = TRUE;
423 GtkWidget *tmp = parent;
427 if (!GTK_WIDGET_MAPPED (tmp))
436 xgrab_shell = parent;
438 parent = GTK_MENU_SHELL (parent)->parent_menu_shell;
441 if (xgrab_shell && (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab))
443 GdkCursor *cursor = gdk_cursor_new (GDK_ARROW);
445 if ((gdk_pointer_grab (xgrab_shell->window, TRUE,
446 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
447 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
448 GDK_POINTER_MOTION_MASK,
449 NULL, cursor, activate_time) == 0))
451 if (gdk_keyboard_grab (xgrab_shell->window, TRUE,
453 GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
456 gdk_pointer_ungrab (activate_time);
460 gdk_cursor_destroy (cursor);
463 gtk_grab_add (GTK_WIDGET (menu));
467 gtk_menu_popdown (GtkMenu *menu)
469 GtkMenuShell *menu_shell;
471 g_return_if_fail (menu != NULL);
472 g_return_if_fail (GTK_IS_MENU (menu));
474 menu_shell = GTK_MENU_SHELL (menu);
476 menu_shell->parent_menu_shell = NULL;
477 menu_shell->active = FALSE;
478 menu_shell->ignore_enter = FALSE;
480 if (menu_shell->active_menu_item)
482 menu->old_active_menu_item = menu_shell->active_menu_item;
483 gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item));
484 menu_shell->active_menu_item = NULL;
487 /* The X Grab, if present, will automatically be removed when we hide
489 gtk_widget_hide (menu->toplevel);
493 if (GTK_BIN (menu->toplevel)->child)
495 gtk_menu_reparent (menu, menu->tearoff_window, FALSE);
499 /* We popped up the menu from the tearoff, so we need to
500 * release the grab - we aren't actually hiding the menu.
502 if (menu_shell->have_xgrab)
504 gdk_pointer_ungrab (GDK_CURRENT_TIME);
505 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
510 gtk_widget_hide (GTK_WIDGET (menu));
512 menu_shell->have_xgrab = FALSE;
513 gtk_grab_remove (GTK_WIDGET (menu));
517 gtk_menu_get_active (GtkMenu *menu)
522 g_return_val_if_fail (menu != NULL, NULL);
523 g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
525 if (!menu->old_active_menu_item)
528 children = GTK_MENU_SHELL (menu)->children;
532 child = children->data;
533 children = children->next;
535 if (GTK_BIN (child)->child)
540 menu->old_active_menu_item = child;
543 return menu->old_active_menu_item;
547 gtk_menu_set_active (GtkMenu *menu,
553 g_return_if_fail (menu != NULL);
554 g_return_if_fail (GTK_IS_MENU (menu));
556 tmp_list = g_list_nth (GTK_MENU_SHELL (menu)->children, index);
559 child = tmp_list->data;
560 if (GTK_BIN (child)->child)
561 menu->old_active_menu_item = child;
566 gtk_menu_set_accel_group (GtkMenu *menu,
567 GtkAccelGroup *accel_group)
569 g_return_if_fail (menu != NULL);
570 g_return_if_fail (GTK_IS_MENU (menu));
572 if (menu->accel_group != accel_group)
574 if (menu->accel_group)
575 gtk_accel_group_unref (menu->accel_group);
576 menu->accel_group = accel_group;
577 if (menu->accel_group)
578 gtk_accel_group_ref (menu->accel_group);
584 gtk_menu_reposition (GtkMenu *menu)
586 g_return_if_fail (menu != NULL);
587 g_return_if_fail (GTK_IS_MENU (menu));
589 if (GTK_WIDGET_DRAWABLE (menu) && !menu->torn_off)
590 gtk_menu_position (menu);
595 gtk_menu_set_tearoff_state (GtkMenu *menu,
598 g_return_if_fail (menu != NULL);
599 g_return_if_fail (GTK_IS_MENU (menu));
601 if (menu->torn_off != torn_off)
603 menu->torn_off = torn_off;
607 if (GTK_WIDGET_VISIBLE (menu))
608 gtk_menu_popdown (menu);
610 if (!menu->tearoff_window)
612 GtkWidget *attach_widget;
615 menu->tearoff_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
616 gtk_widget_set_app_paintable (menu->tearoff_window, TRUE);
617 gtk_signal_connect_object (GTK_OBJECT (menu->tearoff_window),
619 GTK_SIGNAL_FUNC (gtk_menu_key_press),
621 gtk_widget_realize (menu->tearoff_window);
623 title = gtk_object_get_data (GTK_OBJECT (menu), "gtk-menu-title");
626 attach_widget = gtk_menu_get_attach_widget (menu);
627 if (GTK_IS_MENU_ITEM (attach_widget))
629 GtkWidget *child = GTK_BIN (attach_widget)->child;
630 if (GTK_IS_LABEL (child))
631 gtk_label_get (GTK_LABEL (child), &title);
636 gdk_window_set_title (menu->tearoff_window->window, title);
638 gdk_window_set_decorations (menu->tearoff_window->window,
643 gtk_window_set_policy (GTK_WINDOW (menu->tearoff_window),
646 gtk_menu_reparent (menu, menu->tearoff_window, FALSE);
648 gtk_menu_position (menu);
650 gtk_widget_show (GTK_WIDGET (menu));
651 gtk_widget_show (menu->tearoff_window);
655 gtk_widget_hide (menu->tearoff_window);
656 gtk_menu_reparent (menu, menu->toplevel, FALSE);
662 gtk_menu_set_title (GtkMenu *menu,
665 g_return_if_fail (menu != NULL);
666 g_return_if_fail (GTK_IS_MENU (menu));
668 gtk_object_set_data_full (GTK_OBJECT (menu), "gtk-menu-title",
669 g_strdup (title), (GtkDestroyNotify) g_free);
673 gtk_menu_reorder_child (GtkMenu *menu,
677 GtkMenuShell *menu_shell;
678 g_return_if_fail (GTK_IS_MENU (menu));
679 g_return_if_fail (GTK_IS_MENU_ITEM (child));
680 menu_shell = GTK_MENU_SHELL (menu);
681 if (g_list_find (menu_shell->children, child))
683 menu_shell->children = g_list_remove (menu_shell->children, child);
684 menu_shell->children = g_list_insert (menu_shell->children, child, position);
685 if (GTK_WIDGET_VISIBLE (menu_shell))
686 gtk_widget_queue_resize (GTK_WIDGET (menu_shell));
691 gtk_menu_realize (GtkWidget *widget)
693 GdkWindowAttr attributes;
694 gint attributes_mask;
696 g_return_if_fail (widget != NULL);
697 g_return_if_fail (GTK_IS_MENU (widget));
699 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
701 attributes.window_type = GDK_WINDOW_CHILD;
702 attributes.x = widget->allocation.x;
703 attributes.y = widget->allocation.y;
704 attributes.width = widget->allocation.width;
705 attributes.height = widget->allocation.height;
706 attributes.wclass = GDK_INPUT_OUTPUT;
707 attributes.visual = gtk_widget_get_visual (widget);
708 attributes.colormap = gtk_widget_get_colormap (widget);
709 attributes.event_mask = gtk_widget_get_events (widget);
710 attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK);
712 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
713 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
714 gdk_window_set_user_data (widget->window, widget);
716 widget->style = gtk_style_attach (widget->style, widget->window);
717 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
718 gtk_menu_paint(widget);
722 gtk_menu_size_request (GtkWidget *widget,
723 GtkRequisition *requisition)
726 GtkMenuShell *menu_shell;
729 guint max_toggle_size;
730 guint max_accel_width;
731 GtkRequisition child_requisition;
733 g_return_if_fail (widget != NULL);
734 g_return_if_fail (GTK_IS_MENU (widget));
735 g_return_if_fail (requisition != NULL);
737 menu = GTK_MENU (widget);
738 menu_shell = GTK_MENU_SHELL (widget);
740 requisition->width = 0;
741 requisition->height = 0;
746 children = menu_shell->children;
749 child = children->data;
750 children = children->next;
752 if (GTK_WIDGET_VISIBLE (child))
754 GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
755 gtk_widget_size_request (child, &child_requisition);
757 requisition->width = MAX (requisition->width, child_requisition.width);
758 requisition->height += child_requisition.height;
760 max_toggle_size = MAX (max_toggle_size, MENU_ITEM_CLASS (child)->toggle_size);
761 max_accel_width = MAX (max_accel_width, GTK_MENU_ITEM (child)->accelerator_width);
765 requisition->width += max_toggle_size + max_accel_width;
766 requisition->width += (GTK_CONTAINER (menu)->border_width +
767 widget->style->klass->xthickness) * 2;
768 requisition->height += (GTK_CONTAINER (menu)->border_width +
769 widget->style->klass->ythickness) * 2;
771 children = menu_shell->children;
774 child = children->data;
775 children = children->next;
777 GTK_MENU_ITEM (child)->toggle_size = max_toggle_size;
782 gtk_menu_size_allocate (GtkWidget *widget,
783 GtkAllocation *allocation)
786 GtkMenuShell *menu_shell;
788 GtkAllocation child_allocation;
791 g_return_if_fail (widget != NULL);
792 g_return_if_fail (GTK_IS_MENU (widget));
793 g_return_if_fail (allocation != NULL);
795 menu = GTK_MENU (widget);
796 menu_shell = GTK_MENU_SHELL (widget);
798 widget->allocation = *allocation;
799 if (GTK_WIDGET_REALIZED (widget))
800 gdk_window_move_resize (widget->window,
801 allocation->x, allocation->y,
802 allocation->width, allocation->height);
805 if (menu_shell->children)
807 child_allocation.x = (GTK_CONTAINER (menu)->border_width +
808 widget->style->klass->xthickness);
809 child_allocation.y = (GTK_CONTAINER (menu)->border_width +
810 widget->style->klass->ythickness);
811 child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
813 children = menu_shell->children;
816 child = children->data;
817 children = children->next;
819 if (GTK_WIDGET_VISIBLE (child))
821 GtkRequisition child_requisition;
822 gtk_widget_get_child_requisition (child, &child_requisition);
824 child_allocation.height = child_requisition.height;
826 gtk_widget_size_allocate (child, &child_allocation);
827 gtk_widget_queue_draw (child);
829 child_allocation.y += child_allocation.height;
836 gtk_menu_paint (GtkWidget *widget)
838 g_return_if_fail (widget != NULL);
839 g_return_if_fail (GTK_IS_MENU (widget));
841 if (GTK_WIDGET_DRAWABLE (widget))
843 gtk_paint_box (widget->style,
847 NULL, widget, "menu",
853 gtk_menu_draw (GtkWidget *widget,
856 GtkMenuShell *menu_shell;
858 GdkRectangle child_area;
861 g_return_if_fail (widget != NULL);
862 g_return_if_fail (GTK_IS_MENU (widget));
863 g_return_if_fail (area != NULL);
865 if (GTK_WIDGET_DRAWABLE (widget))
867 gtk_menu_paint (widget);
869 menu_shell = GTK_MENU_SHELL (widget);
871 children = menu_shell->children;
874 child = children->data;
875 children = children->next;
877 if (gtk_widget_intersect (child, area, &child_area))
878 gtk_widget_draw (child, &child_area);
884 gtk_menu_expose (GtkWidget *widget,
885 GdkEventExpose *event)
887 GtkMenuShell *menu_shell;
889 GdkEventExpose child_event;
892 g_return_val_if_fail (widget != NULL, FALSE);
893 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
894 g_return_val_if_fail (event != NULL, FALSE);
896 if (GTK_WIDGET_DRAWABLE (widget))
898 gtk_menu_paint (widget);
900 menu_shell = GTK_MENU_SHELL (widget);
901 child_event = *event;
903 children = menu_shell->children;
906 child = children->data;
907 children = children->next;
909 if (GTK_WIDGET_NO_WINDOW (child) &&
910 gtk_widget_intersect (child, &event->area, &child_event.area))
911 gtk_widget_event (child, (GdkEvent*) &child_event);
919 gtk_menu_key_press (GtkWidget *widget,
922 GtkMenuShell *menu_shell;
923 gboolean delete = FALSE;
925 g_return_val_if_fail (widget != NULL, FALSE);
926 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
927 g_return_val_if_fail (event != NULL, FALSE);
929 menu_shell = GTK_MENU_SHELL (widget);
931 if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
934 switch (event->keyval)
945 /* Modify the accelerators */
946 if (delete || gtk_accelerator_valid (event->keyval, event->keyval))
948 if (menu_shell->active_menu_item &&
949 GTK_BIN (menu_shell->active_menu_item)->child &&
950 GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL)
952 GtkMenuItem *menu_item;
953 GtkAccelGroup *accel_group;
955 menu_item = GTK_MENU_ITEM (menu_shell->active_menu_item);
957 if (!GTK_MENU (widget)->accel_group)
958 accel_group = gtk_accel_group_get_default ();
960 accel_group = GTK_MENU (widget)->accel_group;
962 gtk_widget_remove_accelerators (GTK_WIDGET (menu_item),
963 gtk_signal_name (menu_item->accelerator_signal),
967 0 == gtk_widget_accelerator_signal (GTK_WIDGET (menu_item),
974 slist = gtk_accel_group_entries_from_object (GTK_OBJECT (menu_item));
977 GtkAccelEntry *ac_entry;
979 ac_entry = slist->data;
981 if (ac_entry->signal_id == menu_item->accelerator_signal)
988 gtk_widget_add_accelerator (GTK_WIDGET (menu_item),
989 gtk_signal_name (menu_item->accelerator_signal),
1002 gtk_menu_motion_notify (GtkWidget *widget,
1003 GdkEventMotion *event)
1005 g_return_val_if_fail (widget != NULL, FALSE);
1006 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
1008 if (GTK_MENU_SHELL (widget)->ignore_enter)
1009 GTK_MENU_SHELL (widget)->ignore_enter = FALSE;
1012 GdkEvent send_event;
1014 send_event.crossing.type = GDK_ENTER_NOTIFY;
1015 send_event.crossing.window = event->window;
1016 send_event.crossing.time = event->time;
1018 gtk_widget_event (widget, &send_event);
1025 gtk_menu_deactivate (GtkMenuShell *menu_shell)
1029 g_return_if_fail (menu_shell != NULL);
1030 g_return_if_fail (GTK_IS_MENU (menu_shell));
1032 parent = menu_shell->parent_menu_shell;
1034 menu_shell->activate_time = 0;
1035 gtk_menu_popdown (GTK_MENU (menu_shell));
1038 gtk_menu_shell_deactivate (GTK_MENU_SHELL (parent));
1043 gtk_menu_position (GtkMenu *menu)
1046 GtkRequisition requisition;
1049 g_return_if_fail (menu != NULL);
1050 g_return_if_fail (GTK_IS_MENU (menu));
1052 widget = GTK_WIDGET (menu);
1054 gdk_window_get_pointer (NULL, &x, &y, NULL);
1056 /* We need the requisition to figure out the right place to
1057 * popup the menu. In fact, we always need to ask here, since
1058 * if one a size_request was queued while we weren't popped up,
1059 * the requisition won't have been recomputed yet.
1061 gtk_widget_size_request (widget, &requisition);
1063 if (menu->position_func)
1064 (* menu->position_func) (menu, &x, &y, menu->position_func_data);
1070 screen_width = gdk_screen_width ();
1071 screen_height = gdk_screen_height ();
1076 if ((x + requisition.width) > screen_width)
1077 x -= ((x + requisition.width) - screen_width);
1080 if ((y + requisition.height) > screen_height)
1081 y -= ((y + requisition.height) - screen_height);
1086 gtk_widget_set_uposition (GTK_MENU_SHELL (menu)->active ?
1087 menu->toplevel : menu->tearoff_window,
1091 /* Reparent the menu, taking care of the refcounting
1094 gtk_menu_reparent (GtkMenu *menu,
1095 GtkWidget *new_parent,
1098 GtkObject *object = GTK_OBJECT (menu);
1099 GtkWidget *widget = GTK_WIDGET (menu);
1100 gboolean was_floating = GTK_OBJECT_FLOATING (object);
1102 gtk_object_ref (object);
1103 gtk_object_sink (object);
1107 gtk_object_ref (object);
1108 gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
1109 gtk_container_add (GTK_CONTAINER (new_parent), widget);
1110 gtk_object_unref (object);
1113 gtk_widget_reparent (GTK_WIDGET (menu), new_parent);
1116 GTK_OBJECT_SET_FLAGS (object, GTK_FLOATING);
1118 gtk_object_unref (object);
1122 gtk_menu_show_all (GtkWidget *widget)
1124 g_return_if_fail (widget != NULL);
1125 g_return_if_fail (GTK_IS_MENU (widget));
1127 /* Show children, but not self. */
1128 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1133 gtk_menu_hide_all (GtkWidget *widget)
1135 g_return_if_fail (widget != NULL);
1136 g_return_if_fail (GTK_IS_MENU (widget));
1138 /* Hide children, but not self. */
1139 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);