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_realize (GtkWidget *widget)
675 GdkWindowAttr attributes;
676 gint attributes_mask;
678 g_return_if_fail (widget != NULL);
679 g_return_if_fail (GTK_IS_MENU (widget));
681 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
683 attributes.window_type = GDK_WINDOW_CHILD;
684 attributes.x = widget->allocation.x;
685 attributes.y = widget->allocation.y;
686 attributes.width = widget->allocation.width;
687 attributes.height = widget->allocation.height;
688 attributes.wclass = GDK_INPUT_OUTPUT;
689 attributes.visual = gtk_widget_get_visual (widget);
690 attributes.colormap = gtk_widget_get_colormap (widget);
691 attributes.event_mask = gtk_widget_get_events (widget);
692 attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK);
694 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
695 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
696 gdk_window_set_user_data (widget->window, widget);
698 widget->style = gtk_style_attach (widget->style, widget->window);
699 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
700 gtk_menu_paint(widget);
704 gtk_menu_size_request (GtkWidget *widget,
705 GtkRequisition *requisition)
708 GtkMenuShell *menu_shell;
711 guint max_toggle_size;
712 guint max_accel_width;
713 GtkRequisition child_requisition;
715 g_return_if_fail (widget != NULL);
716 g_return_if_fail (GTK_IS_MENU (widget));
717 g_return_if_fail (requisition != NULL);
719 menu = GTK_MENU (widget);
720 menu_shell = GTK_MENU_SHELL (widget);
722 requisition->width = 0;
723 requisition->height = 0;
728 children = menu_shell->children;
731 child = children->data;
732 children = children->next;
734 if (GTK_WIDGET_VISIBLE (child))
736 GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
737 gtk_widget_size_request (child, &child_requisition);
739 requisition->width = MAX (requisition->width, child_requisition.width);
740 requisition->height += child_requisition.height;
742 max_toggle_size = MAX (max_toggle_size, MENU_ITEM_CLASS (child)->toggle_size);
743 max_accel_width = MAX (max_accel_width, GTK_MENU_ITEM (child)->accelerator_width);
747 requisition->width += max_toggle_size + max_accel_width;
748 requisition->width += (GTK_CONTAINER (menu)->border_width +
749 widget->style->klass->xthickness) * 2;
750 requisition->height += (GTK_CONTAINER (menu)->border_width +
751 widget->style->klass->ythickness) * 2;
753 children = menu_shell->children;
756 child = children->data;
757 children = children->next;
759 GTK_MENU_ITEM (child)->toggle_size = max_toggle_size;
764 gtk_menu_size_allocate (GtkWidget *widget,
765 GtkAllocation *allocation)
768 GtkMenuShell *menu_shell;
770 GtkAllocation child_allocation;
773 g_return_if_fail (widget != NULL);
774 g_return_if_fail (GTK_IS_MENU (widget));
775 g_return_if_fail (allocation != NULL);
777 menu = GTK_MENU (widget);
778 menu_shell = GTK_MENU_SHELL (widget);
780 widget->allocation = *allocation;
781 if (GTK_WIDGET_REALIZED (widget))
782 gdk_window_move_resize (widget->window,
783 allocation->x, allocation->y,
784 allocation->width, allocation->height);
787 if (menu_shell->children)
789 child_allocation.x = (GTK_CONTAINER (menu)->border_width +
790 widget->style->klass->xthickness);
791 child_allocation.y = (GTK_CONTAINER (menu)->border_width +
792 widget->style->klass->ythickness);
793 child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
795 children = menu_shell->children;
798 child = children->data;
799 children = children->next;
801 if (GTK_WIDGET_VISIBLE (child))
803 GtkRequisition child_requisition;
804 gtk_widget_get_child_requisition (child, &child_requisition);
806 child_allocation.height = child_requisition.height;
808 gtk_widget_size_allocate (child, &child_allocation);
809 gtk_widget_queue_draw (child);
811 child_allocation.y += child_allocation.height;
818 gtk_menu_paint (GtkWidget *widget)
820 g_return_if_fail (widget != NULL);
821 g_return_if_fail (GTK_IS_MENU (widget));
823 if (GTK_WIDGET_DRAWABLE (widget))
825 gtk_paint_box (widget->style,
829 NULL, widget, "menu",
835 gtk_menu_draw (GtkWidget *widget,
838 GtkMenuShell *menu_shell;
840 GdkRectangle child_area;
843 g_return_if_fail (widget != NULL);
844 g_return_if_fail (GTK_IS_MENU (widget));
845 g_return_if_fail (area != NULL);
847 if (GTK_WIDGET_DRAWABLE (widget))
849 gtk_menu_paint (widget);
851 menu_shell = GTK_MENU_SHELL (widget);
853 children = menu_shell->children;
856 child = children->data;
857 children = children->next;
859 if (gtk_widget_intersect (child, area, &child_area))
860 gtk_widget_draw (child, &child_area);
866 gtk_menu_expose (GtkWidget *widget,
867 GdkEventExpose *event)
869 GtkMenuShell *menu_shell;
871 GdkEventExpose child_event;
874 g_return_val_if_fail (widget != NULL, FALSE);
875 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
876 g_return_val_if_fail (event != NULL, FALSE);
878 if (GTK_WIDGET_DRAWABLE (widget))
880 gtk_menu_paint (widget);
882 menu_shell = GTK_MENU_SHELL (widget);
883 child_event = *event;
885 children = menu_shell->children;
888 child = children->data;
889 children = children->next;
891 if (GTK_WIDGET_NO_WINDOW (child) &&
892 gtk_widget_intersect (child, &event->area, &child_event.area))
893 gtk_widget_event (child, (GdkEvent*) &child_event);
901 gtk_menu_key_press (GtkWidget *widget,
904 GtkMenuShell *menu_shell;
905 gboolean delete = FALSE;
907 g_return_val_if_fail (widget != NULL, FALSE);
908 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
909 g_return_val_if_fail (event != NULL, FALSE);
911 menu_shell = GTK_MENU_SHELL (widget);
913 if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
916 switch (event->keyval)
927 /* Modify the accelerators */
928 if (delete || gtk_accelerator_valid (event->keyval, event->keyval))
930 if (menu_shell->active_menu_item &&
931 GTK_BIN (menu_shell->active_menu_item)->child &&
932 GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL)
934 GtkMenuItem *menu_item;
935 GtkAccelGroup *accel_group;
937 menu_item = GTK_MENU_ITEM (menu_shell->active_menu_item);
939 if (!GTK_MENU (widget)->accel_group)
940 accel_group = gtk_accel_group_get_default ();
942 accel_group = GTK_MENU (widget)->accel_group;
944 gtk_widget_remove_accelerators (GTK_WIDGET (menu_item),
945 gtk_signal_name (menu_item->accelerator_signal),
949 0 == gtk_widget_accelerator_signal (GTK_WIDGET (menu_item),
956 slist = gtk_accel_group_entries_from_object (GTK_OBJECT (menu_item));
959 GtkAccelEntry *ac_entry;
961 ac_entry = slist->data;
963 if (ac_entry->signal_id == menu_item->accelerator_signal)
970 gtk_widget_add_accelerator (GTK_WIDGET (menu_item),
971 gtk_signal_name (menu_item->accelerator_signal),
984 gtk_menu_motion_notify (GtkWidget *widget,
985 GdkEventMotion *event)
987 g_return_val_if_fail (widget != NULL, FALSE);
988 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
990 if (GTK_MENU_SHELL (widget)->ignore_enter)
991 GTK_MENU_SHELL (widget)->ignore_enter = FALSE;
996 send_event.crossing.type = GDK_ENTER_NOTIFY;
997 send_event.crossing.window = event->window;
998 send_event.crossing.time = event->time;
1000 gtk_widget_event (widget, &send_event);
1007 gtk_menu_deactivate (GtkMenuShell *menu_shell)
1011 g_return_if_fail (menu_shell != NULL);
1012 g_return_if_fail (GTK_IS_MENU (menu_shell));
1014 parent = menu_shell->parent_menu_shell;
1016 menu_shell->activate_time = 0;
1017 gtk_menu_popdown (GTK_MENU (menu_shell));
1020 gtk_menu_shell_deactivate (GTK_MENU_SHELL (parent));
1025 gtk_menu_position (GtkMenu *menu)
1028 GtkRequisition requisition;
1031 g_return_if_fail (menu != NULL);
1032 g_return_if_fail (GTK_IS_MENU (menu));
1034 widget = GTK_WIDGET (menu);
1036 gdk_window_get_pointer (NULL, &x, &y, NULL);
1038 /* We need the requisition to figure out the right place to
1039 * popup the menu. In fact, we always need to ask here, since
1040 * if one a size_request was queued while we weren't popped up,
1041 * the requisition won't have been recomputed yet.
1043 gtk_widget_size_request (widget, &requisition);
1045 if (menu->position_func)
1046 (* menu->position_func) (menu, &x, &y, menu->position_func_data);
1052 screen_width = gdk_screen_width ();
1053 screen_height = gdk_screen_height ();
1058 if ((x + requisition.width) > screen_width)
1059 x -= ((x + requisition.width) - screen_width);
1062 if ((y + requisition.height) > screen_height)
1063 y -= ((y + requisition.height) - screen_height);
1068 gtk_widget_set_uposition (GTK_MENU_SHELL (menu)->active ?
1069 menu->toplevel : menu->tearoff_window,
1073 /* Reparent the menu, taking care of the refcounting
1076 gtk_menu_reparent (GtkMenu *menu,
1077 GtkWidget *new_parent,
1080 GtkObject *object = GTK_OBJECT (menu);
1081 GtkWidget *widget = GTK_WIDGET (menu);
1082 gboolean was_floating = GTK_OBJECT_FLOATING (object);
1084 gtk_object_ref (object);
1085 gtk_object_sink (object);
1089 gtk_object_ref (object);
1090 gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
1091 gtk_container_add (GTK_CONTAINER (new_parent), widget);
1092 gtk_object_unref (object);
1095 gtk_widget_reparent (GTK_WIDGET (menu), new_parent);
1098 GTK_OBJECT_SET_FLAGS (object, GTK_FLOATING);
1100 gtk_object_unref (object);
1104 gtk_menu_show_all (GtkWidget *widget)
1106 g_return_if_fail (widget != NULL);
1107 g_return_if_fail (GTK_IS_MENU (widget));
1109 /* Show children, but not self. */
1110 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1115 gtk_menu_hide_all (GtkWidget *widget)
1117 g_return_if_fail (widget != NULL);
1118 g_return_if_fail (GTK_IS_MENU (widget));
1120 /* Hide children, but not self. */
1121 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);