]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmenu.c
Minor documentation improvements
[~andy/gtk] / gtk / gtkmenu.c
index 59e94ae1c6680b2983e2ecdac9e0b75fd352e000..94ba3cd1080866ac861a5bd9e3942ff933699fc4 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
  */
 
+/**
+ * SECTION:gtkmenu
+ * @Short_description: A menu widget
+ * @Title: GtkMenu
+ *
+ * A #GtkMenu is a #GtkMenuShell that implements a drop down menu
+ * consisting of a list of #GtkMenuItem objects which can be navigated
+ * and activated by the user to perform application functions.
+ *
+ * A #GtkMenu is most commonly dropped down by activating a
+ * #GtkMenuItem in a #GtkMenuBar or popped up by activating a
+ * #GtkMenuItem in another #GtkMenu.
+ *
+ * A #GtkMenu can also be popped up by activating a #GtkOptionMenu.
+ * Other composite widgets such as the #GtkNotebook can pop up a
+ * #GtkMenu as well.
+ *
+ * Applications can display a #GtkMenu as a popup menu by calling the 
+ * gtk_menu_popup() function.  The example below shows how an application
+ * can pop up a menu when the 3rd mouse button is pressed.  
+ *
+ * <example>
+ * <title>Connecting the popup signal handler.</title>
+ * <programlisting>
+ *   /<!---->* connect our handler which will popup the menu *<!---->/
+ *   g_signal_connect_swapped (window, "button_press_event",
+ *     G_CALLBACK (my_popup_handler), menu);
+ * </programlisting>
+ * </example>
+ *
+ * <example>
+ * <title>Signal handler which displays a popup menu.</title>
+ * <programlisting>
+ * static gint
+ * my_popup_handler (GtkWidget *widget, GdkEvent *event)
+ * {
+ *   GtkMenu *menu;
+ *   GdkEventButton *event_button;
+ *
+ *   g_return_val_if_fail (widget != NULL, FALSE);
+ *   g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
+ *   g_return_val_if_fail (event != NULL, FALSE);
+ *
+ *   /<!---->* The "widget" is the menu that was supplied when 
+ *    * g_signal_connect_swapped() was called.
+ *    *<!---->/
+ *   menu = GTK_MENU (widget);
+ *
+ *   if (event->type == GDK_BUTTON_PRESS)
+ *     {
+ *       event_button = (GdkEventButton *) event;
+ *       if (event_button->button == 3)
+ *         {
+ *           gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 
+ *                           event_button->button, event_button->time);
+ *           return TRUE;
+ *         }
+ *     }
+ * 
+ *   return FALSE;
+ * }
+ * </programlisting>
+ * </example>
+ */
+
 #include "config.h"
 
 #include <string.h>
 #include "gtksettings.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
+#include "gtktypebuiltins.h"
 
 #define NAVIGATION_REGION_OVERSHOOT 50  /* How much the navigation region
                                          * extends below the submenu
@@ -273,12 +339,6 @@ static const gchar attach_data_key[] = "gtk-menu-attach-data";
 
 static guint menu_signals[LAST_SIGNAL] = { 0 };
 
-static GtkMenuPrivate *
-gtk_menu_get_private (GtkMenu *menu)
-{
-  return G_TYPE_INSTANCE_GET_PRIVATE (menu, GTK_TYPE_MENU, GtkMenuPrivate);
-}
-
 G_DEFINE_TYPE (GtkMenu, gtk_menu, GTK_TYPE_MENU_SHELL)
 
 static void
@@ -324,7 +384,7 @@ is_grid_attached (AttachInfo *ai)
 static void
 menu_ensure_layout (GtkMenu *menu)
 {
-  GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+  GtkMenuPrivate *priv = menu->priv;
 
   if (!priv->have_layout)
     {
@@ -410,7 +470,7 @@ menu_ensure_layout (GtkMenu *menu)
 static gint
 gtk_menu_get_n_columns (GtkMenu *menu)
 {
-  GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+  GtkMenuPrivate *priv = menu->priv;
 
   menu_ensure_layout (menu);
 
@@ -420,7 +480,7 @@ gtk_menu_get_n_columns (GtkMenu *menu)
 static gint
 gtk_menu_get_n_rows (GtkMenu *menu)
 {
-  GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+  GtkMenuPrivate *priv = menu->priv;
 
   menu_ensure_layout (menu);
 
@@ -497,6 +557,11 @@ gtk_menu_class_init (GtkMenuClass *class)
   menu_shell_class->get_popup_delay = gtk_menu_get_popup_delay;
   menu_shell_class->move_current = gtk_menu_move_current;
 
+  /**
+   * GtkMenu::move-scroll:
+   * @menu: a #GtkMenu
+   * @scroll_type: a #GtkScrollType
+   */
   menu_signals[MOVE_SCROLL] =
     g_signal_new_class_handler (I_("move-scroll"),
                                 G_OBJECT_CLASS_TYPE (gobject_class),
@@ -720,7 +785,7 @@ gtk_menu_class_init (GtkMenuClass *class)
                                                                GTK_PARAM_READWRITE));
 
  /**
-  * GtkMenu::arrow-scaling
+  * GtkMenu:arrow-scaling
   *
   * Arbitrary constant to scale down the size of the scroll arrow.
   *
@@ -1118,6 +1183,17 @@ attach_widget_screen_changed (GtkWidget *attach_widget,
     menu_change_screen (menu, gtk_widget_get_screen (attach_widget));
 }
 
+/**
+ * gtk_menu_attach_to_widget: (skip)
+ * @menu: a #GtkMenu
+ * @attach_widget: the #GtkWidget that the menu will be attached to
+ * @detacher: the user supplied callback function that will be called
+ *            when the menu calls gtk_menu_detach()
+ *
+ * Attaches the menu to the widget and provides a callback function
+ * that will be invoked when the menu calls gtk_menu_detach() during
+ * its destruction.
+ */
 void
 gtk_menu_attach_to_widget (GtkMenu           *menu,
                            GtkWidget         *attach_widget,
@@ -1169,6 +1245,14 @@ gtk_menu_attach_to_widget (GtkMenu           *menu,
   g_object_notify (G_OBJECT (menu), "attach-widget");
 }
 
+/**
+ * gtk_menu_get_attach_widget:
+ * @menu: a #GtkMenu
+ *
+ * Returns the #GtkWidget that the menu is attached to.
+ *
+ * Returns: (transfer none): the #GtkWidget that the menu is attached to
+ */
 GtkWidget*
 gtk_menu_get_attach_widget (GtkMenu *menu)
 {
@@ -1182,6 +1266,14 @@ gtk_menu_get_attach_widget (GtkMenu *menu)
   return NULL;
 }
 
+/**
+ * gtk_menu_detach:
+ * @menu: a #GtkMenu
+ *
+ * Detaches the menu from the widget to which it had been attached.
+ * This function will call the callback function, @detacher, provided
+ * when the gtk_menu_attach_to_widget() function was called.
+ */
 void
 gtk_menu_detach (GtkMenu *menu)
 {
@@ -1242,6 +1334,13 @@ gtk_menu_remove (GtkContainer *container,
   menu_queue_resize (menu);
 }
 
+/**
+ * gtk_menu_new:
+ *
+ * Creates a new #GtkMenu
+ *
+ * Returns: a new #GtkMenu
+ */
 GtkWidget*
 gtk_menu_new (void)
 {
@@ -1274,11 +1373,8 @@ static void
 gtk_menu_tearoff_bg_copy (GtkMenu *menu)
 {
   GtkMenuPrivate *priv = menu->priv;
-  GtkWidget *widget;
   gint width, height;
 
-  widget = GTK_WIDGET (menu);
-
   if (priv->torn_off)
     {
       GdkWindow *window;
@@ -1345,7 +1441,7 @@ popup_grab_on_window (GdkWindow *window,
 
 /**
  * gtk_menu_popup_for_device:
- * @menu: a #GtkMenu.
+ * @menu: a #GtkMenu
  * @device: (allow-none): a #GdkDevice
  * @parent_menu_shell: (allow-none): the menu shell containing the triggering
  *     menu item, or %NULL
@@ -1638,15 +1734,15 @@ gtk_menu_popup_for_device (GtkMenu             *menu,
 }
 
 /**
- * gtk_menu_popup:
- * @menu: a #GtkMenu.
+ * gtk_menu_popup: (skip)
+ * @menu: a #GtkMenu
  * @parent_menu_shell: (allow-none): the menu shell containing the
  *     triggering menu item, or %NULL
  * @parent_menu_item: (allow-none): the menu item whose activation
  *     triggered the popup, or %NULL
  * @func: (allow-none): a user supplied function used to position
  *     the menu, or %NULL
- * @data: (allow-none): user supplied data to be passed to @func.
+ * @data: user supplied data to be passed to @func.
  * @button: the mouse button which was pressed to initiate the event.
  * @activate_time: the time at which the activation event occurred.
  *
@@ -1689,6 +1785,12 @@ gtk_menu_popup (GtkMenu             *menu,
                              button, activate_time);
 }
 
+/**
+ * gtk_menu_popdown:
+ * @menu: a #GtkMenu
+ *
+ * Removes the menu from the screen.
+ */
 void
 gtk_menu_popdown (GtkMenu *menu)
 {
@@ -1777,6 +1879,17 @@ gtk_menu_popdown (GtkMenu *menu)
   menu_grab_transfer_window_destroy (menu);
 }
 
+/**
+ * gtk_menu_get_active:
+ * @menu: a #GtkMenu
+ *
+ * Returns the selected menu item from the menu.  This is used by the
+ * #GtkOptionMenu.
+ *
+ * Returns: (transfer none): the #GtkMenuItem that was last selected
+ *          in the menu.  If a selection has not yet been made, the
+ *          first menu item is selected.
+ */
 GtkWidget*
 gtk_menu_get_active (GtkMenu *menu)
 {
@@ -1809,6 +1922,15 @@ gtk_menu_get_active (GtkMenu *menu)
   return priv->old_active_menu_item;
 }
 
+/**
+ * gtk_menu_set_active:
+ * @menu: a #GtkMenu
+ * @index: the index of the menu item to select.  Iindex values are
+ *         from 0 to n-1
+ *
+ * Selects the specified menu item within the menu.  This is used by
+ * the #GtkOptionMenu and should not be used by anyone else.
+ */
 void
 gtk_menu_set_active (GtkMenu *menu,
                      guint    index)
@@ -1835,7 +1957,15 @@ gtk_menu_set_active (GtkMenu *menu,
 
 /**
  * gtk_menu_set_accel_group:
- * @accel_group: (allow-none):
+ * @menu: a #GtkMenu
+ * @accel_group: (allow-none): the #GtkAccelGroup to be associated
+ *               with the menu.
+ *
+ * Set the #GtkAccelGroup which holds global accelerators for the
+ * menu.  This accelerator group needs to also be added to all windows
+ * that this menu is being used in with gtk_window_add_accel_group(),
+ * in order for those windows to support all the accelerators
+ * contained in this group.
  */
 void
 gtk_menu_set_accel_group (GtkMenu       *menu,
@@ -1855,6 +1985,15 @@ gtk_menu_set_accel_group (GtkMenu       *menu,
     }
 }
 
+/**
+ * gtk_menu_get_accel_group:
+ * @menu: a #GtkMenu
+ *
+ * Gets the #GtkAccelGroup which holds global accelerators for the
+ * menu. See gtk_menu_set_accel_group().
+ *
+ * Returns: (transfer none): the #GtkAccelGroup associated with the menu
+ */
 GtkAccelGroup*
 gtk_menu_get_accel_group (GtkMenu *menu)
 {
@@ -1983,6 +2122,12 @@ _gtk_menu_refresh_accel_paths (GtkMenu  *menu,
     }
 }
 
+/**
+ * gtk_menu_reposition:
+ * @menu: a #GtkMenu
+ *
+ * Repositions the menu according to its position function.
+ */
 void
 gtk_menu_reposition (GtkMenu *menu)
 {
@@ -1996,10 +2141,11 @@ static void
 gtk_menu_scrollbar_changed (GtkAdjustment *adjustment,
                             GtkMenu       *menu)
 {
-  g_return_if_fail (GTK_IS_MENU (menu));
+  double value;
 
-  if (adjustment->value != menu->priv->scroll_offset)
-    gtk_menu_scroll_to (menu, adjustment->value);
+  value = gtk_adjustment_get_value (adjustment);
+  if (menu->priv->scroll_offset != value)
+    gtk_menu_scroll_to (menu, value);
 }
 
 static void
@@ -2089,6 +2235,16 @@ tearoff_window_destroyed (GtkWidget *widget,
   gtk_menu_set_tearoff_state (menu, FALSE);
 }
 
+/**
+ * gtk_menu_set_tearoff_state:
+ * @menu: a #GtkMenu
+ * @torn_off: If %TRUE, menu is displayed as a tearoff menu.
+ *
+ * Changes the tearoff state of the menu.  A menu is normally
+ * displayed as drop down menu which persists as long as the menu is
+ * active.  It can also be displayed as a tearoff menu which persists
+ * until it is closed or reattached.
+ */
 void
 gtk_menu_set_tearoff_state (GtkMenu  *menu,
                             gboolean  torn_off)
@@ -2154,7 +2310,7 @@ gtk_menu_set_tearoff_state (GtkMenu  *menu,
                                 priv->tearoff_scrollbar,
                                 FALSE, FALSE, 0);
 
-              if (priv->tearoff_adjustment->upper > height)
+              if (gtk_adjustment_get_upper (priv->tearoff_adjustment) > height)
                 gtk_widget_show (priv->tearoff_scrollbar);
 
               gtk_widget_show (priv->tearoff_hbox);
@@ -2258,6 +2414,16 @@ gtk_menu_get_title (GtkMenu *menu)
   return menu->priv->title;
 }
 
+/**
+ * gtk_menu_reorder_child:
+ * @menu: a #GtkMenu
+ * @child: the #GtkMenuItem to move
+ * @position: the new position to place @child.
+ *     Positions are numbered from 0 to n - 1
+ *
+ * Moves @child to a new @position in the list of @menu
+ * children.
+ */
 void
 gtk_menu_reorder_child (GtkMenu   *menu,
                         GtkWidget *child,
@@ -2282,6 +2448,8 @@ gtk_menu_reorder_child (GtkMenu   *menu,
 static void
 gtk_menu_style_updated (GtkWidget *widget)
 {
+  GTK_WIDGET_CLASS (gtk_menu_parent_class)->style_updated (widget);
+
   if (gtk_widget_get_realized (widget))
     {
       GtkMenu *menu = GTK_MENU (widget);
@@ -2338,17 +2506,18 @@ get_menu_border (GtkWidget *widget,
 {
   GtkStyleContext *context;
   GtkStateFlags state;
-  GtkBorder *border_width;
+  GtkBorder padding, border_width;
 
   context = gtk_widget_get_style_context (widget);
   state = gtk_widget_get_state_flags (widget);
 
-  gtk_style_context_get (context, state,
-                         "border-width", &border_width,
-                         NULL);
+  gtk_style_context_get_padding (context, state, &padding);
+  gtk_style_context_get_border (context, state, &border_width);
 
-  *border = *border_width;
-  gtk_border_free (border_width);
+  border->left = border_width.left + padding.left;
+  border->right = border_width.right + padding.right;
+  border->top = border_width.top + padding.top;
+  border->bottom = border_width.bottom + padding.bottom;
 }
 
 static void
@@ -2539,6 +2708,9 @@ calculate_line_heights (GtkMenu *menu,
                         guint  **ret_min_heights,
                         guint  **ret_nat_heights)
 {
+  GtkStyleContext *context;
+  GtkStateFlags   state;
+  GtkBorder       padding;
   GtkMenuPrivate *priv;
   GtkMenuShell   *menu_shell;
   GtkWidget      *child, *widget;
@@ -2565,8 +2737,12 @@ calculate_line_heights (GtkMenu *menu,
                         "horizontal-padding", &horizontal_padding,
                         NULL);
 
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+  gtk_style_context_get_padding (context, state, &padding);
+
   border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
-  avail_width -= (border_width + horizontal_padding + gtk_widget_get_style (widget)->xthickness) * 2;
+  avail_width -= (border_width + horizontal_padding) * 2 + padding.left + padding.right;
 
   for (children = menu_shell->priv->children; children; children = children->next)
     {
@@ -2761,20 +2937,13 @@ gtk_menu_size_allocate (GtkWidget     *widget,
             }
           else
             {
-              priv->tearoff_adjustment->upper = priv->requested_height;
-              priv->tearoff_adjustment->page_size = allocation->height;
-
-              if (priv->tearoff_adjustment->value + priv->tearoff_adjustment->page_size >
-                  priv->tearoff_adjustment->upper)
-                {
-                  gint value;
-                  value = priv->tearoff_adjustment->upper - priv->tearoff_adjustment->page_size;
-                  if (value < 0)
-                    value = 0;
-                  gtk_menu_scroll_to (menu, value);
-                }
-
-              gtk_adjustment_changed (priv->tearoff_adjustment);
+              gtk_adjustment_configure (priv->tearoff_adjustment,
+                                        gtk_adjustment_get_value (priv->tearoff_adjustment),
+                                        0,
+                                        priv->requested_height,
+                                        gtk_adjustment_get_step_increment (priv->tearoff_adjustment),
+                                        gtk_adjustment_get_page_increment (priv->tearoff_adjustment),
+                                        allocation->height);
 
               if (!gtk_widget_get_visible (priv->tearoff_scrollbar))
                 {
@@ -2872,16 +3041,12 @@ gtk_menu_draw (GtkWidget *widget,
   GdkRectangle border;
   GdkRectangle upper;
   GdkRectangle lower;
-  GdkWindow *window;
   gint arrow_space;
-  GtkStateFlags state;
   GtkBorder menu_border;
 
   menu = GTK_MENU (widget);
-  priv = gtk_menu_get_private (menu);
+  priv = menu->priv;
   context = gtk_widget_get_style_context (widget);
-  window = gtk_widget_get_window (widget);
-  state = gtk_widget_get_state_flags (widget);
 
   get_arrows_visible_area (menu, &border, &upper, &lower, &arrow_space);
   get_menu_border (widget, &menu_border);
@@ -2917,9 +3082,9 @@ gtk_menu_draw (GtkWidget *widget,
                             upper.width, upper.height);
 
           gtk_render_arrow (context, cr, 0,
-                           upper.x + (upper.width - arrow_size) / 2,
-                           upper.y + menu_border.top + (arrow_space - arrow_size) / 2,
-                           arrow_size);
+                            upper.x + (upper.width - arrow_size) / 2,
+                            upper.y + menu_border.top + (arrow_space - arrow_size) / 2,
+                            arrow_size);
 
           gtk_style_context_restore (context);
         }
@@ -3138,6 +3303,9 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget,
                                          gint      *minimum_size,
                                          gint      *natural_size)
 {
+  GtkStyleContext *context;
+  GtkStateFlags   state;
+  GtkBorder       padding, border;
   GtkMenu        *menu = GTK_MENU (widget);
   GtkMenuPrivate *priv = menu->priv;
   guint          *min_heights, *nat_heights;
@@ -3148,7 +3316,13 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget,
   gtk_widget_style_get (widget, "vertical-padding", &vertical_padding, NULL);
   border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
 
-  min_height = nat_height = (border_width + vertical_padding + gtk_widget_get_style (widget)->ythickness) * 2;
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+  gtk_style_context_get_padding (context, state, &padding);
+  gtk_style_context_get_border (context, state, &border);
+
+  min_height = nat_height = (border_width + vertical_padding) * 2 +
+         padding.left + padding.right + border.left + border.right;
 
   n_heights =
     calculate_line_heights (menu, for_size, &min_heights, &nat_heights);
@@ -3821,6 +3995,9 @@ get_arrows_sensitive_area (GtkMenu      *menu,
   guint vertical_padding;
   gint win_x, win_y;
   gint scroll_arrow_height;
+  GtkStyleContext *context;
+  GtkStateFlags state;
+  GtkBorder padding;
 
   window = gtk_widget_get_window (widget);
   width = gdk_window_get_width (window);
@@ -3832,8 +4009,11 @@ get_arrows_sensitive_area (GtkMenu      *menu,
                         "arrow-placement", &arrow_placement,
                         NULL);
 
-  border = gtk_container_get_border_width (GTK_CONTAINER (menu)) +
-           gtk_widget_get_style (widget)->ythickness + vertical_padding;
+  border = gtk_container_get_border_width (GTK_CONTAINER (menu)) + vertical_padding;
+
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+  gtk_style_context_get_padding (context, state, &padding);
 
   gdk_window_get_position (window, &win_x, &win_y);
 
@@ -3845,15 +4025,15 @@ get_arrows_sensitive_area (GtkMenu      *menu,
           upper->x = win_x;
           upper->y = win_y;
           upper->width = width;
-          upper->height = scroll_arrow_height + border;
+          upper->height = scroll_arrow_height + border + padding.top;
         }
 
       if (lower)
         {
           lower->x = win_x;
-          lower->y = win_y + height - border - scroll_arrow_height;
+          lower->y = win_y + height - border - padding.bottom - scroll_arrow_height;
           lower->width = width;
-          lower->height = scroll_arrow_height + border;
+          lower->height = scroll_arrow_height + border + padding.bottom;
         }
       break;
 
@@ -3863,7 +4043,7 @@ get_arrows_sensitive_area (GtkMenu      *menu,
           upper->x = win_x;
           upper->y = win_y;
           upper->width = width / 2;
-          upper->height = scroll_arrow_height + border;
+          upper->height = scroll_arrow_height + border + padding.top;
         }
 
       if (lower)
@@ -3871,7 +4051,7 @@ get_arrows_sensitive_area (GtkMenu      *menu,
           lower->x = win_x + width / 2;
           lower->y = win_y;
           lower->width = width / 2;
-          lower->height = scroll_arrow_height + border;
+          lower->height = scroll_arrow_height + border + padding.bottom;
         }
       break;
 
@@ -3881,7 +4061,7 @@ get_arrows_sensitive_area (GtkMenu      *menu,
           upper->x = win_x;
           upper->y = win_y + height - border - scroll_arrow_height;
           upper->width = width / 2;
-          upper->height = scroll_arrow_height + border;
+          upper->height = scroll_arrow_height + border + padding.top;
         }
 
       if (lower)
@@ -3889,7 +4069,7 @@ get_arrows_sensitive_area (GtkMenu      *menu,
           lower->x = win_x + width / 2;
           lower->y = win_y + height - border - scroll_arrow_height;
           lower->width = width / 2;
-          lower->height = scroll_arrow_height + border;
+          lower->height = scroll_arrow_height + border + padding.bottom;
         }
       break;
     }
@@ -4176,7 +4356,7 @@ gtk_menu_enter_notify (GtkWidget        *widget,
 
       if (GTK_IS_MENU (menu))
         {
-          GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (menu));
+          GtkMenuPrivate *priv = (GTK_MENU (menu))->priv;
           GtkMenuShell *menu_shell = GTK_MENU_SHELL (menu);
 
           if (priv->seen_item_enter)
@@ -4386,7 +4566,6 @@ gtk_menu_set_submenu_navigation_region (GtkMenu          *menu,
   gint submenu_top = 0;
   gint submenu_bottom = 0;
   gint width = 0;
-  gint height = 0;
   GtkWidget *event_widget;
   GtkMenuPopdownData *popdown_data;
   GdkWindow *window;
@@ -4403,7 +4582,6 @@ gtk_menu_set_submenu_navigation_region (GtkMenu          *menu,
   submenu_bottom = submenu_top + gdk_window_get_height (window);
 
   width = gdk_window_get_width (gtk_widget_get_window (event_widget));
-  height = gdk_window_get_height (gtk_widget_get_window (event_widget));
 
   if (event->x >= 0 && event->x < width)
     {
@@ -4764,15 +4942,8 @@ gtk_menu_scroll_to (GtkMenu *menu,
 
   widget = GTK_WIDGET (menu);
 
-  if (priv->tearoff_active &&
-      priv->tearoff_adjustment &&
-      (priv->tearoff_adjustment->value != offset))
-    {
-      priv->tearoff_adjustment->value =
-        CLAMP (offset,
-               0, priv->tearoff_adjustment->upper - priv->tearoff_adjustment->page_size);
-      gtk_adjustment_value_changed (priv->tearoff_adjustment);
-    }
+  if (priv->tearoff_active && priv->tearoff_adjustment)
+    gtk_adjustment_set_value (priv->tearoff_adjustment, offset);
 
   /* Move/resize the viewport according to arrows: */
   gtk_widget_get_allocation (widget, &allocation);
@@ -4956,7 +5127,7 @@ compute_child_offset (GtkMenu   *menu,
   if (!priv->heights || priv->heights_length < gtk_menu_get_n_rows (menu))
     return FALSE;
 
-  /* when we have a row with only invisible children, it's height will
+  /* when we have a row with only invisible children, its height will
    * be zero, so there's no need to check WIDGET_VISIBLE here
    */
   for (i = 0; i < item_top_attach; i++)
@@ -4980,7 +5151,7 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
   GtkMenuPrivate *priv = menu->priv;
   GtkWidget *widget = GTK_WIDGET (menu_shell);
   gint child_offset, child_height;
-  gint width, height;
+  gint height;
   gint y;
   gint arrow_height;
   gboolean last_child = 0;
@@ -4989,15 +5160,16 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
    * 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;
       gboolean double_arrows;
+      GtkStyleContext *context;
+      GtkStateFlags state;
+      GtkBorder padding;
 
       y = priv->scroll_offset;
-      width = gdk_window_get_width (gtk_widget_get_window (widget));
       height = gdk_window_get_height (gtk_widget_get_window (widget));
 
       gtk_widget_style_get (widget,
@@ -5006,8 +5178,12 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
 
       double_arrows = get_double_arrows (menu);
 
+      context = gtk_widget_get_style_context (widget);
+      state = gtk_widget_get_state_flags (widget);
+      gtk_style_context_get_padding (context, state, &padding);
+
       height -= 2 * gtk_container_get_border_width (GTK_CONTAINER (menu)) +
-                2 * gtk_widget_get_style (widget)->ythickness +
+                padding.top + padding.bottom +
                 2 * vertical_padding;
       if (child_offset < y)
         {
@@ -5384,12 +5560,20 @@ get_visible_size (GtkMenu *menu)
   GtkAllocation allocation;
   GtkWidget *widget = GTK_WIDGET (menu);
   GtkContainer *container = GTK_CONTAINER (menu);
+  GtkStyleContext *context;
+  GtkStateFlags state;
+  GtkBorder padding;
   gint menu_height;
 
   gtk_widget_get_allocation (widget, &allocation);
-  menu_height = (allocation.height
-                 - 2 * (gtk_container_get_border_width (container)
-                        + gtk_widget_get_style (widget)->ythickness));
+
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+  gtk_style_context_get_padding (context, state, &padding);
+
+  menu_height = (allocation.height -
+                 (2 * gtk_container_get_border_width (container)) -
+                 padding.top - padding.bottom);
 
   if (!priv->tearoff_active)
     {
@@ -5455,12 +5639,21 @@ get_menu_height (GtkMenu *menu)
   GtkMenuPrivate *priv = menu->priv;
   GtkAllocation allocation;
   GtkWidget *widget = GTK_WIDGET (menu);
+  GtkStyleContext *context;
+  GtkStateFlags state;
+  GtkBorder padding, border;
   gint height;
 
   gtk_widget_get_allocation (widget, &allocation);
 
+  context = gtk_widget_get_style_context (widget);
+  state = gtk_widget_get_state_flags (widget);
+  gtk_style_context_get_padding (context, state, &padding);
+  gtk_style_context_get_border (context, state, &border);
+
   height = allocation.height;
-  height -= (gtk_container_get_border_width (GTK_CONTAINER (widget)) + gtk_widget_get_style (widget)->ythickness) * 2;
+  height -= (gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2) +
+    padding.top + padding.bottom + border.top + border.bottom;
 
   if (!priv->tearoff_active)
     {