+
+ if (menu->lower_arrow_visible && !menu->tearoff_active)
+ {
+ rect.x = 0;
+ rect.y = height - border - MENU_SCROLL_ARROW_HEIGHT;
+ rect.width = width;
+ rect.height = MENU_SCROLL_ARROW_HEIGHT + border;
+
+ in_arrow = FALSE;
+ if ((x >= rect.x) && (x < rect.x + rect.width) &&
+ (y >= rect.y) && (y < rect.y + rect.height))
+ {
+ in_arrow = TRUE;
+ scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
+ }
+
+ if (enter && in_arrow &&
+ (!menu->lower_arrow_prelight || menu->scroll_fast != scroll_fast))
+ {
+ menu->lower_arrow_prelight = TRUE;
+ menu->scroll_fast = scroll_fast;
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
+
+ /* Deselect the active item so that any submenus are poped down */
+ gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_remove_scroll_timeout (menu);
+ menu->scroll_step = (scroll_fast) ? MENU_SCROLL_STEP2 : MENU_SCROLL_STEP1;
+ menu->timeout_id = g_timeout_add ((scroll_fast) ? MENU_SCROLL_TIMEOUT2 : MENU_SCROLL_TIMEOUT1,
+ gtk_menu_scroll_timeout,
+ menu);
+ }
+ else if (!enter && !in_arrow && menu->lower_arrow_prelight)
+ {
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
+
+ gtk_menu_stop_scrolling (menu);
+ }
+ }
+}
+
+static gboolean
+gtk_menu_enter_notify (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ GtkWidget *menu_item;
+
+ if (widget && GTK_IS_MENU (widget))
+ {
+ GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
+
+ if (!menu_shell->ignore_enter)
+ gtk_menu_handle_scrolling (GTK_MENU (widget), TRUE);
+ }
+
+ /* If this is a faked enter (see gtk_menu_motion_notify), 'widget'
+ * will not correspond to the event widget's parent. Check to see
+ * if we are in the parent's navigation region.
+ */
+ menu_item = gtk_get_event_widget ((GdkEvent*) event);
+ if (menu_item && GTK_IS_MENU_ITEM (menu_item) && GTK_IS_MENU (menu_item->parent) &&
+ gtk_menu_navigating_submenu (GTK_MENU (menu_item->parent), event->x_root, event->y_root))
+ return TRUE;
+
+ return GTK_WIDGET_CLASS (parent_class)->enter_notify_event (widget, event);
+}
+
+static gboolean
+gtk_menu_leave_notify (GtkWidget *widget,
+ GdkEventCrossing *event)
+{
+ GtkMenuShell *menu_shell;
+ GtkMenu *menu;
+ GtkMenuItem *menu_item;
+ GtkWidget *event_widget;
+
+ menu = GTK_MENU (widget);
+ menu_shell = GTK_MENU_SHELL (widget);
+
+ if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
+ return TRUE;
+
+ gtk_menu_handle_scrolling (menu, FALSE);
+
+ event_widget = gtk_get_event_widget ((GdkEvent*) event);
+
+ if (!event_widget || !GTK_IS_MENU_ITEM (event_widget))
+ return TRUE;
+
+ menu_item = GTK_MENU_ITEM (event_widget);
+
+ /* Here we check to see if we're leaving an active menu item with a submenu,
+ * in which case we enter submenu navigation mode.
+ */
+ if (menu_shell->active_menu_item != NULL
+ && menu_item->submenu != NULL
+ && menu_item->submenu_placement == GTK_LEFT_RIGHT)
+ {
+ if (GTK_MENU_SHELL (menu_item->submenu)->active)
+ {
+ gtk_menu_set_submenu_navigation_region (menu, menu_item, event);
+ return TRUE;
+ }
+ }
+
+ return GTK_WIDGET_CLASS (parent_class)->leave_notify_event (widget, event);
+}
+
+static void
+gtk_menu_stop_navigating_submenu (GtkMenu *menu)
+{
+ if (menu->navigation_region)
+ {
+ gdk_region_destroy (menu->navigation_region);
+ menu->navigation_region = NULL;
+ }
+
+ if (menu->navigation_timeout)
+ {
+ g_source_remove (menu->navigation_timeout);
+ menu->navigation_timeout = 0;
+ }
+}
+
+/* When the timeout is elapsed, the navigation region is destroyed
+ * and the menuitem under the pointer (if any) is selected.
+ */
+static gboolean
+gtk_menu_stop_navigating_submenu_cb (gpointer user_data)
+{
+ GtkMenu *menu = user_data;
+ GdkWindow *child_window;
+
+ GDK_THREADS_ENTER ();
+
+ gtk_menu_stop_navigating_submenu (menu);
+
+ if (GTK_WIDGET_REALIZED (menu))
+ {
+ child_window = gdk_window_get_pointer (menu->bin_window, NULL, NULL, NULL);
+
+ if (child_window)
+ {
+ GdkEvent *send_event = gdk_event_new (GDK_ENTER_NOTIFY);
+
+ send_event->crossing.window = g_object_ref (child_window);
+ send_event->crossing.time = GDK_CURRENT_TIME; /* Bogus */
+ send_event->crossing.send_event = TRUE;
+
+ GTK_WIDGET_CLASS (parent_class)->enter_notify_event (GTK_WIDGET (menu), (GdkEventCrossing *)send_event);
+
+ gdk_event_free (send_event);
+ }
+ }
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static gboolean
+gtk_menu_navigating_submenu (GtkMenu *menu,
+ gint event_x,
+ gint event_y)
+{
+ if (menu->navigation_region)
+ {
+ if (gdk_region_point_in (menu->navigation_region, event_x, event_y))
+ return TRUE;
+ else
+ {
+ gtk_menu_stop_navigating_submenu (menu);
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+#undef DRAW_STAY_UP_TRIANGLE
+
+#ifdef DRAW_STAY_UP_TRIANGLE
+
+static void
+draw_stay_up_triangle (GdkWindow *window,
+ GdkRegion *region)
+{
+ /* Draw ugly color all over the stay-up triangle */
+ GdkColor ugly_color = { 0, 50000, 10000, 10000 };
+ GdkGCValues gc_values;
+ GdkGC *ugly_gc;
+ GdkRectangle clipbox;
+
+ gc_values.subwindow_mode = GDK_INCLUDE_INFERIORS;
+ ugly_gc = gdk_gc_new_with_values (window, &gc_values, 0 | GDK_GC_SUBWINDOW);
+ gdk_gc_set_rgb_fg_color (ugly_gc, &ugly_color);
+ gdk_gc_set_clip_region (ugly_gc, region);
+
+ gdk_region_get_clipbox (region, &clipbox);
+
+ gdk_draw_rectangle (window,
+ ugly_gc,
+ TRUE,
+ clipbox.x, clipbox.y,
+ clipbox.width, clipbox.height);
+
+ g_object_unref (ugly_gc);
+}
+#endif
+
+static GdkRegion *
+flip_region (GdkRegion *region,
+ gboolean flip_x,
+ gboolean flip_y)
+{
+ gint n_rectangles;
+ GdkRectangle *rectangles;
+ GdkRectangle clipbox;
+ GdkRegion *new_region;
+ gint i;
+
+ new_region = gdk_region_new ();
+
+ gdk_region_get_rectangles (region, &rectangles, &n_rectangles);
+ gdk_region_get_clipbox (region, &clipbox);
+
+ for (i = 0; i < n_rectangles; ++i)
+ {
+ GdkRectangle rect = rectangles[i];
+
+ if (flip_y)
+ rect.y -= 2 * (rect.y - clipbox.y) + rect.height;
+
+ if (flip_x)
+ rect.x -= 2 * (rect.x - clipbox.x) + rect.width;
+
+ gdk_region_union_with_rect (new_region, &rect);
+ }
+
+ g_free (rectangles);
+
+ return new_region;
+}
+
+static void
+gtk_menu_set_submenu_navigation_region (GtkMenu *menu,
+ GtkMenuItem *menu_item,
+ GdkEventCrossing *event)
+{
+ gint submenu_left = 0;
+ gint submenu_right = 0;
+ gint submenu_top = 0;
+ gint submenu_bottom = 0;
+ gint width = 0;
+ gint height = 0;
+ GdkPoint point[3];
+ GtkWidget *event_widget;
+
+ g_return_if_fail (menu_item->submenu != NULL);
+ g_return_if_fail (event != NULL);
+
+ event_widget = gtk_get_event_widget ((GdkEvent*) event);
+
+ gdk_window_get_origin (menu_item->submenu->window, &submenu_left, &submenu_top);
+ gdk_drawable_get_size (menu_item->submenu->window, &width, &height);
+
+ submenu_right = submenu_left + width;
+ submenu_bottom = submenu_top + height;
+
+ gdk_drawable_get_size (event_widget->window, &width, &height);
+
+ if (event->x >= 0 && event->x < width)
+ {
+ gint popdown_delay;
+ gboolean flip_y = FALSE;
+ gboolean flip_x = FALSE;
+
+ gtk_menu_stop_navigating_submenu (menu);
+
+ if (menu_item->submenu_direction == GTK_DIRECTION_RIGHT)
+ {
+ /* right */
+ point[0].x = event->x_root;
+ point[1].x = submenu_left;
+ }
+ else
+ {
+ /* left */
+ point[0].x = event->x_root + 1;
+ point[1].x = 2 * (event->x_root + 1) - submenu_right;
+
+ flip_x = TRUE;
+ }
+
+ if (event->y < 0)
+ {
+ /* top */
+ point[0].y = event->y_root + 1;
+ point[1].y = 2 * (event->y_root + 1) - submenu_top + NAVIGATION_REGION_OVERSHOOT;
+
+ if (point[0].y >= point[1].y - NAVIGATION_REGION_OVERSHOOT)
+ return;
+
+ flip_y = TRUE;
+ }
+ else
+ {
+ /* bottom */
+ point[0].y = event->y_root;
+ point[1].y = submenu_bottom + NAVIGATION_REGION_OVERSHOOT;
+
+ if (point[0].y >= submenu_bottom)
+ return;
+ }
+
+ point[2].x = point[1].x;
+ point[2].y = point[0].y;
+
+ menu->navigation_region = gdk_region_polygon (point, 3, GDK_WINDING_RULE);
+
+ if (flip_x || flip_y)
+ {
+ GdkRegion *new_region = flip_region (menu->navigation_region, flip_x, flip_y);
+ gdk_region_destroy (menu->navigation_region);
+ menu->navigation_region = new_region;
+ }
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
+ "gtk-menu-popdown-delay", &popdown_delay,
+ NULL);
+
+ menu->navigation_timeout = g_timeout_add (popdown_delay,
+ gtk_menu_stop_navigating_submenu_cb, menu);
+
+#ifdef DRAW_STAY_UP_TRIANGLE
+ draw_stay_up_triangle (gdk_get_default_root_window(),
+ menu->navigation_region);
+#endif
+ }
+}
+
+static void
+gtk_menu_deactivate (GtkMenuShell *menu_shell)
+{
+ GtkWidget *parent;
+
+ g_return_if_fail (GTK_IS_MENU (menu_shell));
+
+ parent = menu_shell->parent_menu_shell;
+
+ menu_shell->activate_time = 0;
+ gtk_menu_popdown (GTK_MENU (menu_shell));
+
+ if (parent)
+ gtk_menu_shell_deactivate (GTK_MENU_SHELL (parent));
+}
+
+static void
+gtk_menu_position (GtkMenu *menu)
+{
+ GtkWidget *widget;
+ GtkRequisition requisition;
+ GtkMenuPrivate *private;
+ gint x, y;
+ gint scroll_offset;
+ gint menu_height;
+ gboolean push_in;
+ GdkScreen *screen;
+ GdkScreen *pointer_screen;
+ GdkRectangle monitor;
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ widget = GTK_WIDGET (menu);
+
+ screen = gtk_widget_get_screen (widget);
+ gdk_display_get_pointer (gdk_screen_get_display (screen),
+ &pointer_screen, &x, &y, NULL);
+
+ /* We need the requisition to figure out the right place to
+ * popup the menu. In fact, we always need to ask here, since
+ * if a size_request was queued while we weren't popped up,
+ * the requisition won't have been recomputed yet.
+ */
+ gtk_widget_size_request (widget, &requisition);
+
+ if (pointer_screen != screen)
+ {
+ /* Pointer is on a different screen; roughly center the
+ * menu on the screen. If someone was using multiscreen
+ * + Xinerama together they'd probably want something
+ * fancier; but that is likely to be vanishingly rare.
+ */
+ x = MAX (0, (gdk_screen_get_width (screen) - requisition.width) / 2);
+ y = MAX (0, (gdk_screen_get_height (screen) - requisition.height) / 2);
+ }
+
+ private = gtk_menu_get_private (menu);
+ private->monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
+
+ push_in = FALSE;
+
+ if (menu->position_func)
+ {
+ (* menu->position_func) (menu, &x, &y, &push_in, menu->position_func_data);
+ gdk_screen_get_monitor_geometry (screen, private->monitor_num, &monitor);
+ }
+ else
+ {
+ gint space_left, space_right, space_above, space_below;
+ gint needed_width;
+ gint needed_height;
+ gint xthickness = widget->style->xthickness;
+ gint ythickness = widget->style->ythickness;
+ gboolean rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
+
+ /* The placement of popup menus horizontally works like this (with
+ * RTL in parentheses)
+ *
+ * - If there is enough room to the right (left) of the mouse cursor,
+ * position the menu there.
+ *
+ * - Otherwise, if if there is enough room to the left (right) of the
+ * mouse cursor, position the menu there.
+ *
+ * - Otherwise if the menu is smaller than the monitor, position it
+ * on the side of the mouse cursor that has the most space available
+ *
+ * - Otherwise (if there is simply not enough room for the menu on the
+ * monitor), position it as far left (right) as possible.
+ *
+ * Positioning in the vertical direction is similar: first try below
+ * mouse cursor, then above.
+ */
+ gdk_screen_get_monitor_geometry (screen, private->monitor_num, &monitor);
+
+ space_left = x - monitor.x;
+ space_right = monitor.x + monitor.width - x - 1;
+ space_above = y - monitor.y;
+ space_below = monitor.y + monitor.height - y - 1;
+
+ /* position horizontally */
+
+ /* the amount of space we need to position the menu. Note the
+ * menu is offset "xthickness" pixels
+ */
+ needed_width = requisition.width - xthickness;
+
+ if (needed_width <= space_left ||
+ needed_width <= space_right)
+ {
+ if ((rtl && needed_width <= space_left) ||
+ (!rtl && needed_width > space_right))
+ {
+ /* position left */
+ x = x + xthickness - requisition.width + 1;
+ }
+ else
+ {
+ /* position right */
+ x = x - xthickness;
+ }
+
+ /* x is clamped on-screen further down */
+ }
+ else if (requisition.width <= monitor.width)
+ {
+ /* the menu is too big to fit on either side of the mouse
+ * cursor, but smaller than the monitor. Position it on
+ * the side that has the most space
+ */
+ if (space_left > space_right)
+ {
+ /* left justify */
+ x = monitor.x;
+ }
+ else
+ {
+ /* right justify */
+ x = monitor.x + monitor.width - requisition.width;
+ }
+ }
+ else /* menu is simply too big for the monitor */
+ {
+ if (rtl)
+ {
+ /* right justify */
+ x = monitor.x + monitor.width - requisition.width;
+ }
+ else
+ {
+ /* left justify */
+ x = monitor.x;
+ }
+ }
+
+ /* Position vertically. The algorithm is the same as above, but
+ * simpler because we don't have to take RTL into account.
+ */
+ needed_height = requisition.height - ythickness;
+
+ if (needed_height <= space_above ||
+ needed_height <= space_below)
+ {
+ if (needed_height <= space_below)
+ y = y - ythickness;
+ else
+ y = y + ythickness - requisition.height + 1;
+
+ y = CLAMP (y, monitor.y,
+ monitor.y + monitor.height - requisition.height);
+ }
+ else if (needed_height > space_below && needed_height > space_above)
+ {
+ if (space_below >= space_above)
+ y = monitor.y + monitor.height - requisition.height;
+ else
+ y = monitor.y;
+ }
+ else
+ {
+ y = monitor.y;
+ }
+ }
+
+ scroll_offset = 0;
+
+ if (push_in)
+ {
+ menu_height = GTK_WIDGET (menu)->requisition.height;
+
+ if (y + menu_height > monitor.y + monitor.height)
+ {
+ scroll_offset -= y + menu_height - (monitor.y + monitor.height);
+ y = (monitor.y + monitor.height) - menu_height;
+ }
+
+ if (y < monitor.y)
+ {
+ scroll_offset += monitor.y - y;
+ y = monitor.y;
+ }
+ }
+
+ /* FIXME: should this be done in the various position_funcs ? */
+ x = CLAMP (x, monitor.x, MAX (monitor.x, monitor.x + monitor.width - requisition.width));
+
+ if (GTK_MENU_SHELL (menu)->active)
+ {
+ private->have_position = TRUE;
+ private->x = x;
+ private->y = y;
+ }
+
+ if (y + requisition.height > monitor.y + monitor.height)
+ requisition.height = (monitor.y + monitor.height) - y;
+
+ if (y < monitor.y)
+ {
+ scroll_offset += monitor.y - y;
+ requisition.height -= monitor.y - y;
+ y = monitor.y;
+ }
+
+ if (scroll_offset > 0)
+ scroll_offset += MENU_SCROLL_ARROW_HEIGHT;
+
+ gtk_window_move (GTK_WINDOW (GTK_MENU_SHELL (menu)->active ? menu->toplevel : menu->tearoff_window),
+ x, y);
+
+ if (!GTK_MENU_SHELL (menu)->active)
+ {
+ gtk_window_resize (GTK_WINDOW (menu->tearoff_window),
+ requisition.width, requisition.height);
+ }
+
+ menu->scroll_offset = scroll_offset;
+}
+
+static void
+gtk_menu_remove_scroll_timeout (GtkMenu *menu)
+{
+ if (menu->timeout_id)
+ {
+ g_source_remove (menu->timeout_id);
+ menu->timeout_id = 0;
+ }
+}
+
+static void
+gtk_menu_stop_scrolling (GtkMenu *menu)
+{
+ gtk_menu_remove_scroll_timeout (menu);
+
+ menu->upper_arrow_prelight = FALSE;
+ menu->lower_arrow_prelight = FALSE;
+}
+
+static void
+gtk_menu_scroll_to (GtkMenu *menu,
+ gint offset)
+{
+ GtkWidget *widget;
+ gint x, y;
+ gint view_width, view_height;
+ gint border_width;
+ gboolean last_visible;
+ gint menu_height;
+ guint vertical_padding;
+
+ widget = GTK_WIDGET (menu);
+
+ if (menu->tearoff_active &&
+ menu->tearoff_adjustment &&
+ (menu->tearoff_adjustment->value != offset))
+ {
+ menu->tearoff_adjustment->value =
+ CLAMP (offset,
+ 0, menu->tearoff_adjustment->upper - menu->tearoff_adjustment->page_size);
+ gtk_adjustment_value_changed (menu->tearoff_adjustment);
+ }
+
+ /* Move/resize the viewport according to arrows: */
+ view_width = widget->allocation.width;
+ view_height = widget->allocation.height;
+
+ gtk_widget_style_get (GTK_WIDGET (menu),
+ "vertical-padding", &vertical_padding,
+ NULL);
+
+ border_width = GTK_CONTAINER (menu)->border_width;
+ view_width -= (border_width + widget->style->xthickness) * 2;
+ view_height -= (border_width + widget->style->ythickness + vertical_padding) * 2;
+ menu_height = widget->requisition.height -
+ (border_width + widget->style->ythickness + vertical_padding) * 2;
+
+ x = border_width + widget->style->xthickness;
+ y = border_width + widget->style->ythickness + vertical_padding;
+
+ if (!menu->tearoff_active)
+ {
+ last_visible = menu->upper_arrow_visible;
+ menu->upper_arrow_visible = offset > 0;
+
+ if (menu->upper_arrow_visible)
+ view_height -= MENU_SCROLL_ARROW_HEIGHT;
+
+ if ( (last_visible != menu->upper_arrow_visible) &&
+ !menu->upper_arrow_visible)
+ {
+ menu->upper_arrow_prelight = FALSE;
+
+ /* If we hid the upper arrow, possibly remove timeout */
+ if (menu->scroll_step < 0)
+ {
+ gtk_menu_stop_scrolling (menu);
+ gtk_widget_queue_draw (GTK_WIDGET (menu));
+ }
+ }
+
+ last_visible = menu->lower_arrow_visible;
+ menu->lower_arrow_visible = offset < menu_height - view_height;
+
+ if (menu->lower_arrow_visible)
+ view_height -= MENU_SCROLL_ARROW_HEIGHT;
+
+ if ( (last_visible != menu->lower_arrow_visible) &&
+ !menu->lower_arrow_visible)
+ {
+ menu->lower_arrow_prelight = FALSE;
+
+ /* If we hid the lower arrow, possibly remove timeout */
+ if (menu->scroll_step > 0)
+ {
+ gtk_menu_stop_scrolling (menu);
+ gtk_widget_queue_draw (GTK_WIDGET (menu));
+ }
+ }
+
+ if (menu->upper_arrow_visible)
+ y += MENU_SCROLL_ARROW_HEIGHT;
+ }
+
+ /* Scroll the menu: */
+ if (GTK_WIDGET_REALIZED (menu))
+ gdk_window_move (menu->bin_window, 0, -offset);
+
+ if (GTK_WIDGET_REALIZED (menu))
+ gdk_window_move_resize (menu->view_window,
+ x,
+ y,
+ view_width,
+ view_height);
+
+ menu->scroll_offset = offset;
+}
+
+static gboolean
+compute_child_offset (GtkMenu *menu,
+ GtkWidget *menu_item,
+ gint *offset,
+ gint *height,
+ gboolean *is_last_child)
+{
+ GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+ guint item_top_attach;
+ guint item_bottom_attach;
+ gint child_offset = 0;
+ gint i;
+
+ gtk_container_child_get (GTK_CONTAINER (menu), menu_item,
+ "top_attach", &item_top_attach,
+ "bottom_attach", &item_bottom_attach,
+ NULL);
+
+ /* there is a possibility that we get called before _size_request, so
+ * check the height table for safety.
+ */
+ if (!priv->heights || priv->heights_length < priv->rows)
+ return FALSE;
+
+ /* when we have a row with only invisible children, it's height will
+ * be zero, so there's no need to check WIDGET_VISIBLE here
+ */
+ for (i = 0; i < item_top_attach; i++)
+ child_offset += priv->heights[i];
+
+ if (is_last_child)
+ *is_last_child = (item_bottom_attach == priv->rows);
+ if (offset)
+ *offset = child_offset;
+ if (height)
+ *height = priv->heights[item_top_attach];
+
+ return TRUE;
+}
+
+static void
+gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
+ GtkWidget *menu_item)
+{
+ GtkMenu *menu;
+ gint child_offset, child_height;
+ gint width, height;
+ gint y;
+ gint arrow_height;
+ gboolean last_child = 0;
+
+ menu = GTK_MENU (menu_shell);
+
+ /* We need to check if the selected item fully visible.
+ * If not we need to scroll the menu so that it becomes fully
+ * visible.
+ */
+
+ if (compute_child_offset (menu, menu_item,
+ &child_offset, &child_height, &last_child))
+ {
+ guint vertical_padding;
+
+ y = menu->scroll_offset;
+ gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height);
+
+ gtk_widget_style_get (GTK_WIDGET (menu),
+ "vertical-padding", &vertical_padding,
+ NULL);
+
+ height -= 2*GTK_CONTAINER (menu)->border_width + 2*GTK_WIDGET (menu)->style->ythickness + 2*vertical_padding;
+
+ if (child_offset < y)
+ {
+ /* Ignore the enter event we might get if the pointer is on the menu
+ */
+ menu_shell->ignore_enter = TRUE;
+ gtk_menu_scroll_to (menu, child_offset);
+ }
+ else
+ {
+ arrow_height = 0;
+ if (menu->upper_arrow_visible && !menu->tearoff_active)
+ arrow_height += MENU_SCROLL_ARROW_HEIGHT;
+ if (menu->lower_arrow_visible && !menu->tearoff_active)
+ arrow_height += MENU_SCROLL_ARROW_HEIGHT;
+
+ if (child_offset + child_height > y + height - arrow_height)
+ {
+ arrow_height = 0;
+ if (!last_child && !menu->tearoff_active)
+ arrow_height += MENU_SCROLL_ARROW_HEIGHT;
+
+ y = child_offset + child_height - height + arrow_height;
+ if ((y > 0) && !menu->tearoff_active)
+ {
+ /* Need upper arrow */
+ arrow_height += MENU_SCROLL_ARROW_HEIGHT;
+ y = child_offset + child_height - height + arrow_height;
+ }
+ /* Ignore the enter event we might get if the pointer is on the menu
+ */
+ menu_shell->ignore_enter = TRUE;
+ gtk_menu_scroll_to (menu, y);
+ }
+ }
+
+ }
+}
+
+static void
+gtk_menu_select_item (GtkMenuShell *menu_shell,
+ GtkWidget *menu_item)
+{
+ GtkMenu *menu = GTK_MENU (menu_shell);
+
+ if (GTK_WIDGET_REALIZED (GTK_WIDGET (menu)))
+ gtk_menu_scroll_item_visible (menu_shell, menu_item);
+
+ GTK_MENU_SHELL_CLASS (parent_class)->select_item (menu_shell, menu_item);
+}
+