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.
20 #include "gdk/gdkkeysyms.h"
21 #include "gtkbindings.h"
25 #include "gtkmenuitem.h"
26 #include "gtksignal.h"
27 #include "gtkwindow.h"
30 #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
31 #define MENU_NEEDS_RESIZE(m) GTK_MENU_SHELL (m)->menu_flag
33 typedef struct _GtkMenuAttachData GtkMenuAttachData;
35 struct _GtkMenuAttachData
37 GtkWidget *attach_widget;
38 GtkMenuDetachFunc detacher;
42 static void gtk_menu_class_init (GtkMenuClass *klass);
43 static void gtk_menu_init (GtkMenu *menu);
44 static void gtk_menu_destroy (GtkObject *object);
45 static void gtk_menu_realize (GtkWidget *widget);
46 static void gtk_menu_size_request (GtkWidget *widget,
47 GtkRequisition *requisition);
48 static void gtk_menu_size_allocate (GtkWidget *widget,
49 GtkAllocation *allocation);
50 static void gtk_menu_paint (GtkWidget *widget);
51 static void gtk_menu_draw (GtkWidget *widget,
53 static gint gtk_menu_expose (GtkWidget *widget,
54 GdkEventExpose *event);
55 static gint gtk_menu_key_press (GtkWidget *widget,
57 static gint gtk_menu_motion_notify (GtkWidget *widget,
58 GdkEventMotion *event);
59 static void gtk_menu_deactivate (GtkMenuShell *menu_shell);
60 static void gtk_menu_show_all (GtkWidget *widget);
61 static void gtk_menu_hide_all (GtkWidget *widget);
62 static void gtk_menu_position (GtkMenu *menu);
63 static void gtk_menu_reparent (GtkMenu *menu,
64 GtkWidget *new_parent,
67 static GtkMenuShellClass *parent_class = NULL;
68 static const gchar *attach_data_key = "gtk-menu-attach-data";
72 gtk_menu_get_type (void)
74 static GtkType menu_type = 0;
78 static const GtkTypeInfo menu_info =
82 sizeof (GtkMenuClass),
83 (GtkClassInitFunc) gtk_menu_class_init,
84 (GtkObjectInitFunc) gtk_menu_init,
85 /* reserved_1 */ NULL,
86 /* reserved_2 */ NULL,
87 (GtkClassInitFunc) NULL,
90 menu_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_info);
97 gtk_menu_class_init (GtkMenuClass *class)
99 GtkObjectClass *object_class;
100 GtkWidgetClass *widget_class;
101 GtkContainerClass *container_class;
102 GtkMenuShellClass *menu_shell_class;
104 GtkBindingSet *binding_set;
106 object_class = (GtkObjectClass*) class;
107 widget_class = (GtkWidgetClass*) class;
108 container_class = (GtkContainerClass*) class;
109 menu_shell_class = (GtkMenuShellClass*) class;
110 parent_class = gtk_type_class (gtk_menu_shell_get_type ());
112 object_class->destroy = gtk_menu_destroy;
114 widget_class->realize = gtk_menu_realize;
115 widget_class->draw = gtk_menu_draw;
116 widget_class->size_request = gtk_menu_size_request;
117 widget_class->size_allocate = gtk_menu_size_allocate;
118 widget_class->expose_event = gtk_menu_expose;
119 widget_class->key_press_event = gtk_menu_key_press;
120 widget_class->motion_notify_event = gtk_menu_motion_notify;
121 widget_class->show_all = gtk_menu_show_all;
122 widget_class->hide_all = gtk_menu_hide_all;
124 menu_shell_class->submenu_placement = GTK_LEFT_RIGHT;
125 menu_shell_class->deactivate = gtk_menu_deactivate;
127 binding_set = gtk_binding_set_by_class (class);
128 gtk_binding_entry_add_signal (binding_set,
131 GTK_TYPE_MENU_DIRECTION_TYPE,
133 gtk_binding_entry_add_signal (binding_set,
136 GTK_TYPE_MENU_DIRECTION_TYPE,
138 gtk_binding_entry_add_signal (binding_set,
141 GTK_TYPE_MENU_DIRECTION_TYPE,
142 GTK_MENU_DIR_PARENT);
143 gtk_binding_entry_add_signal (binding_set,
146 GTK_TYPE_MENU_DIRECTION_TYPE,
151 gtk_menu_init (GtkMenu *menu)
153 menu->parent_menu_item = NULL;
154 menu->old_active_menu_item = NULL;
155 menu->accel_group = NULL;
156 menu->position_func = NULL;
157 menu->position_func_data = NULL;
159 menu->toplevel = gtk_window_new (GTK_WINDOW_POPUP);
160 gtk_signal_connect_object (GTK_OBJECT (menu->toplevel), "key_press_event",
161 GTK_SIGNAL_FUNC (gtk_menu_key_press),
163 gtk_window_set_policy (GTK_WINDOW (menu->toplevel),
166 gtk_container_add (GTK_CONTAINER (menu->toplevel), GTK_WIDGET (menu));
168 /* Refloat the menu, so that reference counting for the menu isn't
169 * affected by it being a child of the toplevel
171 GTK_WIDGET_SET_FLAGS (menu, GTK_FLOATING);
173 menu->tearoff_window = NULL;
174 menu->torn_off = FALSE;
176 MENU_NEEDS_RESIZE (menu) = TRUE;
180 gtk_menu_destroy (GtkObject *object)
183 GtkMenuAttachData *data;
185 g_return_if_fail (object != NULL);
186 g_return_if_fail (GTK_IS_MENU (object));
188 menu = GTK_MENU (object);
190 gtk_object_ref (object);
192 data = gtk_object_get_data (object, attach_data_key);
194 gtk_menu_detach (menu);
196 gtk_menu_set_accel_group (menu, NULL);
198 /* Add back the reference count for being a child */
199 gtk_object_ref (object);
201 gtk_widget_destroy (menu->toplevel);
202 if (menu->tearoff_window)
203 gtk_widget_destroy (menu->tearoff_window);
205 if (GTK_OBJECT_CLASS (parent_class)->destroy)
206 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
208 gtk_object_unref (object);
213 gtk_menu_attach_to_widget (GtkMenu *menu,
214 GtkWidget *attach_widget,
215 GtkMenuDetachFunc detacher)
217 GtkMenuAttachData *data;
219 g_return_if_fail (menu != NULL);
220 g_return_if_fail (GTK_IS_MENU (menu));
221 g_return_if_fail (attach_widget != NULL);
222 g_return_if_fail (GTK_IS_WIDGET (attach_widget));
223 g_return_if_fail (detacher != NULL);
225 /* keep this function in sync with gtk_widget_set_parent()
228 data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
231 g_warning ("gtk_menu_attach_to_widget(): menu already attached to %s",
232 gtk_type_name (GTK_OBJECT_TYPE (data->attach_widget)));
236 gtk_object_ref (GTK_OBJECT (menu));
237 gtk_object_sink (GTK_OBJECT (menu));
239 data = g_new (GtkMenuAttachData, 1);
240 data->attach_widget = attach_widget;
241 data->detacher = detacher;
242 gtk_object_set_data (GTK_OBJECT (menu), attach_data_key, data);
244 if (GTK_WIDGET_STATE (menu) != GTK_STATE_NORMAL)
245 gtk_widget_set_state (GTK_WIDGET (menu), GTK_STATE_NORMAL);
247 /* we don't need to set the style here, since
248 * we are a toplevel widget.
253 gtk_menu_get_attach_widget (GtkMenu *menu)
255 GtkMenuAttachData *data;
257 g_return_val_if_fail (menu != NULL, NULL);
258 g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
260 data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
262 return data->attach_widget;
267 gtk_menu_detach (GtkMenu *menu)
269 GtkMenuAttachData *data;
271 g_return_if_fail (menu != NULL);
272 g_return_if_fail (GTK_IS_MENU (menu));
274 /* keep this function in sync with gtk_widget_unparent()
276 data = gtk_object_get_data (GTK_OBJECT (menu), attach_data_key);
279 g_warning ("gtk_menu_detach(): menu is not attached");
282 gtk_object_remove_data (GTK_OBJECT (menu), attach_data_key);
284 data->detacher (data->attach_widget, menu);
286 if (GTK_WIDGET_REALIZED (menu))
287 gtk_widget_unrealize (GTK_WIDGET (menu));
291 gtk_widget_unref (GTK_WIDGET (menu));
297 return GTK_WIDGET (gtk_type_new (gtk_menu_get_type ()));
301 gtk_menu_append (GtkMenu *menu,
304 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
308 gtk_menu_prepend (GtkMenu *menu,
311 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), child);
315 gtk_menu_insert (GtkMenu *menu,
319 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), child, position);
323 gtk_menu_popup (GtkMenu *menu,
324 GtkWidget *parent_menu_shell,
325 GtkWidget *parent_menu_item,
326 GtkMenuPositionFunc func,
329 guint32 activate_time)
332 GtkWidget *xgrab_shell;
334 GdkEvent *current_event;
335 GtkMenuShell *menu_shell;
337 g_return_if_fail (menu != NULL);
338 g_return_if_fail (GTK_IS_MENU (menu));
340 widget = GTK_WIDGET (menu);
341 menu_shell = GTK_MENU_SHELL (menu);
343 menu_shell->parent_menu_shell = parent_menu_shell;
344 menu_shell->active = TRUE;
345 menu_shell->button = button;
347 /* If we are popping up the menu from something other than, a button
348 * press then, as a heuristic, we ignore enter events for the menu
349 * until we get a MOTION_NOTIFY.
352 current_event = gtk_get_current_event();
355 if ((current_event->type != GDK_BUTTON_PRESS) &&
356 (current_event->type != GDK_ENTER_NOTIFY))
357 menu_shell->ignore_enter = TRUE;
358 gdk_event_free(current_event);
365 GdkGCValues gc_values;
367 gc_values.subwindow_mode = GDK_INCLUDE_INFERIORS;
368 gc = gdk_gc_new_with_values (widget->window,
369 &gc_values, GDK_GC_SUBWINDOW);
371 pixmap = gdk_pixmap_new (widget->window,
372 widget->requisition.width,
373 widget->requisition.height,
376 gdk_draw_pixmap (pixmap, gc,
381 gtk_widget_set_usize (menu->tearoff_window,
382 widget->requisition.width,
383 widget->requisition.height);
385 gdk_window_set_back_pixmap (menu->tearoff_window->window, pixmap, FALSE);
386 gdk_pixmap_unref (pixmap);
388 /* We force an unrealize here so that we don't trigger redrawing/
389 * clearing code - we just want to reveal our backing pixmap.
391 gtk_menu_reparent (menu, menu->toplevel, TRUE);
394 menu->parent_menu_item = parent_menu_item;
395 menu->position_func = func;
396 menu->position_func_data = data;
397 menu_shell->activate_time = activate_time;
399 gtk_menu_position (menu);
401 /* We need to show the menu _here_ because code expects to be
402 * able to tell if the menu is onscreen by looking at the
403 * GTK_WIDGET_VISIBLE (menu)
405 gtk_widget_show (GTK_WIDGET (menu));
406 gtk_widget_show (menu->toplevel);
408 /* Find the last viewable ancestor, and make an X grab on it
410 parent = GTK_WIDGET (menu);
414 gboolean viewable = TRUE;
415 GtkWidget *tmp = parent;
419 if (!GTK_WIDGET_MAPPED (tmp))
428 xgrab_shell = parent;
430 parent = GTK_MENU_SHELL (parent)->parent_menu_shell;
433 if (xgrab_shell && (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab))
435 GdkCursor *cursor = gdk_cursor_new (GDK_ARROW);
437 if ((gdk_pointer_grab (xgrab_shell->window, TRUE,
438 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
439 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
440 GDK_POINTER_MOTION_MASK,
441 NULL, cursor, activate_time) == 0))
443 if (gdk_keyboard_grab (xgrab_shell->window, TRUE,
445 GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
448 gdk_pointer_ungrab (activate_time);
452 gdk_cursor_destroy (cursor);
455 gtk_grab_add (GTK_WIDGET (menu));
459 gtk_menu_popdown (GtkMenu *menu)
461 GtkMenuShell *menu_shell;
463 g_return_if_fail (menu != NULL);
464 g_return_if_fail (GTK_IS_MENU (menu));
466 menu_shell = GTK_MENU_SHELL (menu);
468 menu_shell->parent_menu_shell = NULL;
469 menu_shell->active = FALSE;
470 menu_shell->ignore_enter = FALSE;
472 if (menu_shell->active_menu_item)
474 menu->old_active_menu_item = menu_shell->active_menu_item;
475 gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item));
476 menu_shell->active_menu_item = NULL;
479 /* The X Grab, if present, will automatically be removed when we hide
481 gtk_widget_hide (menu->toplevel);
485 if (GTK_BIN (menu->toplevel)->child)
487 gtk_menu_reparent (menu, menu->tearoff_window, FALSE);
491 /* We popped up the menu from the tearoff, so we need to
492 * release the grab - we aren't actually hiding the menu.
494 if (menu_shell->have_xgrab)
496 gdk_pointer_ungrab (GDK_CURRENT_TIME);
497 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
502 gtk_widget_hide (GTK_WIDGET (menu));
504 menu_shell->have_xgrab = FALSE;
505 gtk_grab_remove (GTK_WIDGET (menu));
509 gtk_menu_get_active (GtkMenu *menu)
514 g_return_val_if_fail (menu != NULL, NULL);
515 g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
517 if (!menu->old_active_menu_item)
520 children = GTK_MENU_SHELL (menu)->children;
524 child = children->data;
525 children = children->next;
527 if (GTK_BIN (child)->child)
532 menu->old_active_menu_item = child;
535 return menu->old_active_menu_item;
539 gtk_menu_set_active (GtkMenu *menu,
545 g_return_if_fail (menu != NULL);
546 g_return_if_fail (GTK_IS_MENU (menu));
548 tmp_list = g_list_nth (GTK_MENU_SHELL (menu)->children, index);
551 child = tmp_list->data;
552 if (GTK_BIN (child)->child)
553 menu->old_active_menu_item = child;
558 gtk_menu_set_accel_group (GtkMenu *menu,
559 GtkAccelGroup *accel_group)
561 g_return_if_fail (menu != NULL);
562 g_return_if_fail (GTK_IS_MENU (menu));
564 if (menu->accel_group != accel_group)
566 if (menu->accel_group)
567 gtk_accel_group_unref (menu->accel_group);
568 menu->accel_group = accel_group;
569 if (menu->accel_group)
570 gtk_accel_group_ref (menu->accel_group);
576 gtk_menu_reposition (GtkMenu *menu)
578 g_return_if_fail (menu != NULL);
579 g_return_if_fail (GTK_IS_MENU (menu));
581 if (GTK_WIDGET_DRAWABLE (menu) && !menu->torn_off)
582 gtk_menu_position (menu);
587 gtk_menu_set_tearoff_state (GtkMenu *menu,
590 g_return_if_fail (menu != NULL);
591 g_return_if_fail (GTK_IS_MENU (menu));
593 if (menu->torn_off != torn_off)
595 menu->torn_off = torn_off;
599 if (GTK_WIDGET_VISIBLE (menu))
600 gtk_menu_popdown (menu);
602 if (!menu->tearoff_window)
604 GtkWidget *attach_widget;
606 menu->tearoff_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
607 gtk_widget_set_app_paintable (menu->tearoff_window, TRUE);
608 gtk_signal_connect_object (GTK_OBJECT (menu->tearoff_window),
610 GTK_SIGNAL_FUNC (gtk_menu_key_press),
612 gtk_widget_realize (menu->tearoff_window);
614 attach_widget = gtk_menu_get_attach_widget (menu);
615 if (GTK_IS_MENU_ITEM (attach_widget))
617 GtkWidget *child = GTK_BIN (attach_widget)->child;
618 if (GTK_IS_LABEL (child))
621 gtk_label_get (GTK_LABEL (child), &ret);
622 gdk_window_set_title (menu->tearoff_window->window, ret);
626 gdk_window_set_decorations (menu->tearoff_window->window,
631 gtk_window_set_policy (GTK_WINDOW (menu->tearoff_window),
634 gtk_menu_reparent (menu, menu->tearoff_window, FALSE);
636 gtk_menu_position (menu);
638 gtk_widget_show (GTK_WIDGET (menu));
639 gtk_widget_show (menu->tearoff_window);
643 gtk_widget_hide (menu->tearoff_window);
644 gtk_menu_reparent (menu, menu->toplevel, FALSE);
650 gtk_menu_realize (GtkWidget *widget)
652 GdkWindowAttr attributes;
653 gint attributes_mask;
655 g_return_if_fail (widget != NULL);
656 g_return_if_fail (GTK_IS_MENU (widget));
658 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
660 attributes.window_type = GDK_WINDOW_CHILD;
661 attributes.x = widget->allocation.x;
662 attributes.y = widget->allocation.y;
663 attributes.width = widget->allocation.width;
664 attributes.height = widget->allocation.height;
665 attributes.wclass = GDK_INPUT_OUTPUT;
666 attributes.visual = gtk_widget_get_visual (widget);
667 attributes.colormap = gtk_widget_get_colormap (widget);
668 attributes.event_mask = gtk_widget_get_events (widget);
669 attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK);
671 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
672 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
673 gdk_window_set_user_data (widget->window, widget);
675 widget->style = gtk_style_attach (widget->style, widget->window);
676 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
677 gtk_menu_paint(widget);
681 gtk_menu_size_request (GtkWidget *widget,
682 GtkRequisition *requisition)
685 GtkMenuShell *menu_shell;
688 guint max_toggle_size;
689 guint max_accel_width;
691 g_return_if_fail (widget != NULL);
692 g_return_if_fail (GTK_IS_MENU (widget));
693 g_return_if_fail (requisition != NULL);
695 menu = GTK_MENU (widget);
696 menu_shell = GTK_MENU_SHELL (widget);
698 requisition->width = 0;
699 requisition->height = 0;
704 children = menu_shell->children;
707 child = children->data;
708 children = children->next;
710 if (GTK_WIDGET_VISIBLE (child))
712 GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
713 gtk_widget_size_request (child, &child->requisition);
715 requisition->width = MAX (requisition->width, child->requisition.width);
716 requisition->height += child->requisition.height;
718 max_toggle_size = MAX (max_toggle_size, MENU_ITEM_CLASS (child)->toggle_size);
719 max_accel_width = MAX (max_accel_width, GTK_MENU_ITEM (child)->accelerator_width);
723 requisition->width += max_toggle_size + max_accel_width;
724 requisition->width += (GTK_CONTAINER (menu)->border_width +
725 widget->style->klass->xthickness) * 2;
726 requisition->height += (GTK_CONTAINER (menu)->border_width +
727 widget->style->klass->ythickness) * 2;
729 children = menu_shell->children;
732 child = children->data;
733 children = children->next;
735 GTK_MENU_ITEM (child)->toggle_size = max_toggle_size;
740 gtk_menu_size_allocate (GtkWidget *widget,
741 GtkAllocation *allocation)
744 GtkMenuShell *menu_shell;
746 GtkAllocation child_allocation;
749 g_return_if_fail (widget != NULL);
750 g_return_if_fail (GTK_IS_MENU (widget));
751 g_return_if_fail (allocation != NULL);
753 menu = GTK_MENU (widget);
754 menu_shell = GTK_MENU_SHELL (widget);
756 widget->allocation = *allocation;
757 if (GTK_WIDGET_REALIZED (widget))
758 gdk_window_move_resize (widget->window,
759 allocation->x, allocation->y,
760 allocation->width, allocation->height);
763 if (menu_shell->children)
765 child_allocation.x = (GTK_CONTAINER (menu)->border_width +
766 widget->style->klass->xthickness);
767 child_allocation.y = (GTK_CONTAINER (menu)->border_width +
768 widget->style->klass->ythickness);
769 child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
771 children = menu_shell->children;
774 child = children->data;
775 children = children->next;
777 if (GTK_WIDGET_VISIBLE (child))
779 child_allocation.height = child->requisition.height;
781 gtk_widget_size_allocate (child, &child_allocation);
782 gtk_widget_queue_draw (child);
784 child_allocation.y += child_allocation.height;
791 gtk_menu_paint (GtkWidget *widget)
793 g_return_if_fail (widget != NULL);
794 g_return_if_fail (GTK_IS_MENU (widget));
796 if (GTK_WIDGET_DRAWABLE (widget))
798 gtk_paint_box (widget->style,
802 NULL, widget, "menu",
808 gtk_menu_draw (GtkWidget *widget,
811 GtkMenuShell *menu_shell;
813 GdkRectangle child_area;
816 g_return_if_fail (widget != NULL);
817 g_return_if_fail (GTK_IS_MENU (widget));
818 g_return_if_fail (area != NULL);
820 if (GTK_WIDGET_DRAWABLE (widget))
822 gtk_menu_paint (widget);
824 menu_shell = GTK_MENU_SHELL (widget);
826 children = menu_shell->children;
829 child = children->data;
830 children = children->next;
832 if (gtk_widget_intersect (child, area, &child_area))
833 gtk_widget_draw (child, &child_area);
839 gtk_menu_expose (GtkWidget *widget,
840 GdkEventExpose *event)
842 GtkMenuShell *menu_shell;
844 GdkEventExpose child_event;
847 g_return_val_if_fail (widget != NULL, FALSE);
848 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
849 g_return_val_if_fail (event != NULL, FALSE);
851 if (GTK_WIDGET_DRAWABLE (widget))
853 gtk_menu_paint (widget);
855 menu_shell = GTK_MENU_SHELL (widget);
856 child_event = *event;
858 children = menu_shell->children;
861 child = children->data;
862 children = children->next;
864 if (GTK_WIDGET_NO_WINDOW (child) &&
865 gtk_widget_intersect (child, &event->area, &child_event.area))
866 gtk_widget_event (child, (GdkEvent*) &child_event);
874 gtk_menu_key_press (GtkWidget *widget,
877 GtkMenuShell *menu_shell;
878 gboolean delete = FALSE;
880 g_return_val_if_fail (widget != NULL, FALSE);
881 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
882 g_return_val_if_fail (event != NULL, FALSE);
884 menu_shell = GTK_MENU_SHELL (widget);
886 if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
889 switch (event->keyval)
900 /* Modify the accelerators */
901 if (delete || gtk_accelerator_valid (event->keyval, event->keyval))
903 if (menu_shell->active_menu_item &&
904 GTK_BIN (menu_shell->active_menu_item)->child &&
905 GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL)
907 GtkMenuItem *menu_item;
908 GtkAccelGroup *accel_group;
910 menu_item = GTK_MENU_ITEM (menu_shell->active_menu_item);
912 if (!GTK_MENU (widget)->accel_group)
913 accel_group = gtk_accel_group_get_default ();
915 accel_group = GTK_MENU (widget)->accel_group;
917 gtk_widget_remove_accelerators (GTK_WIDGET (menu_item),
918 gtk_signal_name (menu_item->accelerator_signal),
922 0 == gtk_widget_accelerator_signal (GTK_WIDGET (menu_item),
929 slist = gtk_accel_group_entries_from_object (GTK_OBJECT (menu_item));
932 GtkAccelEntry *ac_entry;
934 ac_entry = slist->data;
936 if (ac_entry->signal_id == menu_item->accelerator_signal)
943 gtk_widget_add_accelerator (GTK_WIDGET (menu_item),
944 gtk_signal_name (menu_item->accelerator_signal),
957 gtk_menu_motion_notify (GtkWidget *widget,
958 GdkEventMotion *event)
960 g_return_val_if_fail (widget != NULL, FALSE);
961 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
963 if (GTK_MENU_SHELL (widget)->ignore_enter)
964 GTK_MENU_SHELL (widget)->ignore_enter = FALSE;
969 send_event.crossing.type = GDK_ENTER_NOTIFY;
970 send_event.crossing.window = event->window;
971 send_event.crossing.time = event->time;
973 gtk_widget_event (widget, &send_event);
980 gtk_menu_deactivate (GtkMenuShell *menu_shell)
984 g_return_if_fail (menu_shell != NULL);
985 g_return_if_fail (GTK_IS_MENU (menu_shell));
987 parent = menu_shell->parent_menu_shell;
989 menu_shell->activate_time = 0;
990 gtk_menu_popdown (GTK_MENU (menu_shell));
993 gtk_menu_shell_deactivate (GTK_MENU_SHELL (parent));
998 gtk_menu_position (GtkMenu *menu)
1003 g_return_if_fail (menu != NULL);
1004 g_return_if_fail (GTK_IS_MENU (menu));
1006 widget = GTK_WIDGET (menu);
1008 gdk_window_get_pointer (NULL, &x, &y, NULL);
1010 /* We need the requisition to figure out the right place to
1011 * popup the menu. In fact, we always need to ask here, since
1012 * if one a size_request was queued while we weren't popped up,
1013 * the requisition won't have been recomputed yet.
1015 gtk_widget_size_request (widget, &widget->requisition);
1017 if (menu->position_func)
1018 (* menu->position_func) (menu, &x, &y, menu->position_func_data);
1024 screen_width = gdk_screen_width ();
1025 screen_height = gdk_screen_height ();
1030 if ((x + widget->requisition.width) > screen_width)
1031 x -= ((x + widget->requisition.width) - screen_width);
1034 if ((y + widget->requisition.height) > screen_height)
1035 y -= ((y + widget->requisition.height) - screen_height);
1040 gtk_widget_set_uposition (GTK_MENU_SHELL (menu)->active ?
1041 menu->toplevel : menu->tearoff_window,
1045 /* Reparent the menu, taking care of the refcounting
1048 gtk_menu_reparent (GtkMenu *menu,
1049 GtkWidget *new_parent,
1052 GtkObject *object = GTK_OBJECT (menu);
1053 GtkWidget *widget = GTK_WIDGET (menu);
1054 gboolean was_floating = GTK_OBJECT_FLOATING (object);
1056 gtk_object_ref (object);
1057 gtk_object_sink (object);
1061 gtk_object_ref (object);
1062 gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
1063 gtk_container_add (GTK_CONTAINER (new_parent), widget);
1064 gtk_object_unref (object);
1067 gtk_widget_reparent (GTK_WIDGET (menu), new_parent);
1070 GTK_OBJECT_SET_FLAGS (object, GTK_FLOATING);
1072 gtk_object_unref (object);
1076 gtk_menu_show_all (GtkWidget *widget)
1078 g_return_if_fail (widget != NULL);
1079 g_return_if_fail (GTK_IS_MENU (widget));
1081 /* Show children, but not self. */
1082 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
1087 gtk_menu_hide_all (GtkWidget *widget)
1089 g_return_if_fail (widget != NULL);
1090 g_return_if_fail (GTK_IS_MENU (widget));
1092 /* Hide children, but not self. */
1093 gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL);