-/* GTK - The GIMP Toolkit
+/* GTK - The GTK+ Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
*/
#define GTK_MENU_INTERNALS
-#include <config.h>
+#include "config.h"
#include <string.h> /* memset */
#include "gdk/gdkkeysyms.h"
#include "gtkaccellabel.h"
enum {
PROP_0,
+ PROP_ACTIVE,
+ PROP_ACCEL_GROUP,
+ PROP_ACCEL_PATH,
+ PROP_ATTACH_WIDGET,
PROP_TEAROFF_STATE,
- PROP_TEAROFF_TITLE
+ PROP_TEAROFF_TITLE,
+ PROP_MONITOR
};
enum {
GValue *value,
GParamSpec *pspec);
static void gtk_menu_destroy (GtkObject *object);
-static void gtk_menu_finalize (GObject *object);
static void gtk_menu_realize (GtkWidget *widget);
static void gtk_menu_unrealize (GtkWidget *widget);
static void gtk_menu_size_request (GtkWidget *widget,
gtk_widget_queue_resize (GTK_WIDGET (menu));
}
+static void
+attach_info_free (AttachInfo *info)
+{
+ g_slice_free (AttachInfo, info);
+}
+
static AttachInfo *
get_attach_info (GtkWidget *child)
{
if (!ai)
{
- ai = g_new0 (AttachInfo, 1);
- g_object_set_data_full (object, I_(ATTACH_INFO_KEY), ai, g_free);
+ ai = g_slice_new0 (AttachInfo);
+ g_object_set_data_full (object, I_(ATTACH_INFO_KEY), ai,
+ (GDestroyNotify) attach_info_free);
}
return ai;
GtkMenuShellClass *menu_shell_class = GTK_MENU_SHELL_CLASS (class);
GtkBindingSet *binding_set;
- gobject_class->finalize = gtk_menu_finalize;
gobject_class->set_property = gtk_menu_set_property;
gobject_class->get_property = gtk_menu_get_property;
_gtk_marshal_VOID__ENUM,
G_TYPE_NONE, 1,
GTK_TYPE_SCROLL_TYPE);
-
+
+ /**
+ * GtkMenu:active:
+ *
+ * The currently selected menu item.
+ *
+ * Since: 2.14
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_ACTIVE,
+ g_param_spec_uint ("active",
+ P_("Active"),
+ P_("The currently selected menu item"),
+ 0, G_MAXUINT, 0,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkMenu:accel-group:
+ *
+ * The accel group holding accelerators for the menu.
+ *
+ * Since: 2.14
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_ACCEL_GROUP,
+ g_param_spec_object ("accel-group",
+ P_("Accel Group"),
+ P_("The accel group holding accelerators for the menu"),
+ GTK_TYPE_ACCEL_GROUP,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkMenu:accel-path:
+ *
+ * An accel path used to conveniently construct accel paths of child items.
+ *
+ * Since: 2.14
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_ACCEL_PATH,
+ g_param_spec_string ("accel-path",
+ P_("Accel Path"),
+ P_("An accel path used to conveniently construct accel paths of child items"),
+ NULL,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GtkMenu:attach-widget:
+ *
+ * The widget the menu is attached to.
+ *
+ * Since: 2.14
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_ACCEL_PATH,
+ g_param_spec_string ("attach-widget",
+ P_("Attach Widget"),
+ P_("The widget the menu is attached to"),
+ NULL,
+ GTK_PARAM_READWRITE));
+
g_object_class_install_property (gobject_class,
PROP_TEAROFF_TITLE,
g_param_spec_string ("tearoff-title",
P_("Tearoff Title"),
P_("A title that may be displayed by the window manager when this menu is torn-off"),
- "",
+ NULL,
GTK_PARAM_READWRITE));
/**
FALSE,
GTK_PARAM_READWRITE));
+ /**
+ * GtkMenu:monitor:
+ *
+ * The monitor the menu will be popped up on.
+ *
+ * Since: 2.14
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_MONITOR,
+ g_param_spec_int ("monitor",
+ P_("Monitor"),
+ P_("The monitor the menu will be popped up on"),
+ -1, G_MAXINT, -1,
+ GTK_PARAM_READWRITE));
+
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("vertical-padding",
P_("Vertical Padding"),
switch (prop_id)
{
+ case PROP_ACTIVE:
+ gtk_menu_set_active (menu, g_value_get_uint (value));
+ break;
+ case PROP_ACCEL_GROUP:
+ gtk_menu_set_accel_group (menu, g_value_get_object (value));
+ break;
+ case PROP_ACCEL_PATH:
+ gtk_menu_set_accel_path (menu, g_value_get_string (value));
+ break;
+ case PROP_ATTACH_WIDGET:
+ gtk_menu_attach (menu, g_value_get_object (value), 0, 0, 0, 0);
+ break;
case PROP_TEAROFF_STATE:
gtk_menu_set_tearoff_state (menu, g_value_get_boolean (value));
break;
case PROP_TEAROFF_TITLE:
gtk_menu_set_title (menu, g_value_get_string (value));
- break;
+ break;
+ case PROP_MONITOR:
+ gtk_menu_set_monitor (menu, g_value_get_int (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
switch (prop_id)
{
+ case PROP_ACTIVE:
+ g_value_set_uint (value, g_list_index (GTK_MENU_SHELL (menu)->children, gtk_menu_get_active (menu)));
+ break;
+ case PROP_ACCEL_GROUP:
+ g_value_set_object (value, gtk_menu_get_accel_group (menu));
+ break;
+ case PROP_ACCEL_PATH:
+ g_value_set_string (value, gtk_menu_get_accel_path (menu));
+ break;
+ case PROP_ATTACH_WIDGET:
+ g_value_set_object (value, gtk_menu_get_attach_widget (menu));
+ break;
case PROP_TEAROFF_STATE:
g_value_set_boolean (value, gtk_menu_get_tearoff_state (menu));
break;
case PROP_TEAROFF_TITLE:
g_value_set_string (value, gtk_menu_get_title (menu));
break;
+ case PROP_MONITOR:
+ g_value_set_int (value, gtk_menu_get_monitor (menu));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
static void
gtk_menu_destroy (GtkObject *object)
{
- GtkMenu *menu;
+ GtkMenu *menu = GTK_MENU (object);
GtkMenuAttachData *data;
GtkMenuPrivate *priv;
- g_return_if_fail (GTK_IS_MENU (object));
-
- menu = GTK_MENU (object);
-
gtk_menu_remove_scroll_timeout (menu);
data = g_object_get_data (G_OBJECT (object), attach_data_key);
GTK_OBJECT_CLASS (gtk_menu_parent_class)->destroy (object);
}
-static void
-gtk_menu_finalize (GObject *object)
-{
- GtkMenu *menu = GTK_MENU (object);
-
- g_free (menu->accel_path);
-
- G_OBJECT_CLASS (gtk_menu_parent_class)->finalize (object);
-}
-
static void
menu_change_screen (GtkMenu *menu,
GdkScreen *new_screen)
g_object_ref_sink (menu);
- data = g_new (GtkMenuAttachData, 1);
+ data = g_slice_new (GtkMenuAttachData);
data->attach_widget = attach_widget;
g_signal_connect (attach_widget, "screen_changed",
{
list = g_list_prepend (list, menu);
}
- g_object_set_data_full (G_OBJECT (attach_widget), I_(ATTACHED_MENUS), list, (GtkDestroyNotify) g_list_free);
-
+ g_object_set_data_full (G_OBJECT (attach_widget), I_(ATTACHED_MENUS), list,
+ (GDestroyNotify) g_list_free);
+
if (GTK_WIDGET_STATE (menu) != GTK_STATE_NORMAL)
gtk_widget_set_state (GTK_WIDGET (menu), GTK_STATE_NORMAL);
list = g_object_steal_data (G_OBJECT (data->attach_widget), ATTACHED_MENUS);
list = g_list_remove (list, menu);
if (list)
- g_object_set_data_full (G_OBJECT (data->attach_widget), I_(ATTACHED_MENUS), list, (GtkDestroyNotify) g_list_free);
+ g_object_set_data_full (G_OBJECT (data->attach_widget), I_(ATTACHED_MENUS), list,
+ (GDestroyNotify) g_list_free);
else
g_object_set_data (G_OBJECT (data->attach_widget), I_(ATTACHED_MENUS), NULL);
if (GTK_WIDGET_REALIZED (menu))
gtk_widget_unrealize (GTK_WIDGET (menu));
- g_free (data);
+ g_slice_free (GtkMenuAttachData, data);
/* Fallback title for menu comes from attach widget */
gtk_menu_update_title (menu);
gtk_menu_remove (GtkContainer *container,
GtkWidget *widget)
{
- GtkMenu *menu;
+ GtkMenu *menu = GTK_MENU (container);
- g_return_if_fail (GTK_IS_MENU (container));
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
- menu = GTK_MENU (container);
-
/* Clear out old_active_menu_item if it matches the item we are removing
*/
if (menu->old_active_menu_item == widget)
* a mouse button press, such as a mouse button release or a keypress,
* @button should be 0.
*
- * The @activate_time parameter should be the time stamp of the event that
- * initiated the popup. If such an event is not available, use
- * gtk_get_current_event_time() instead.
- *
+ * The @activate_time parameter is used to conflict-resolve initiation of
+ * concurrent requests for mouse/keyboard grab requests. To function
+ * properly, this needs to be the time stamp of the user event (such as
+ * a mouse click or key press) that caused the initiation of the popup.
+ * Only if no such event is available, gtk_get_current_event_time() can
+ * be used instead.
*/
void
gtk_menu_popup (GtkMenu *menu,
}
/* Set transient for to get the right window group and parent relationship */
- if (parent_toplevel && GTK_IS_WINDOW (parent_toplevel))
+ if (GTK_IS_WINDOW (parent_toplevel))
gtk_window_set_transient_for (GTK_WINDOW (menu->toplevel),
GTK_WINDOW (parent_toplevel));
gtk_menu_scroll_to (menu, menu->scroll_offset);
+ /* if no item is selected, select the first one */
+ if (!menu_shell->active_menu_item)
+ {
+ gboolean touchscreen_mode;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+ if (touchscreen_mode)
+ gtk_menu_shell_select_first (menu_shell, TRUE);
+ }
+
/* Once everything is set up correctly, map the toplevel window on
the screen.
*/
* Assigning accel paths to menu items then enables the user to change
* their accelerators at runtime. More details about accelerator paths
* and their default setups can be found at gtk_accel_map_add_entry().
+ *
+ * Note that @accel_path string will be stored in a #GQuark. Therefore, if you
+ * pass a static string, you can save some memory by interning it first with
+ * g_intern_static_string().
*/
void
gtk_menu_set_accel_path (GtkMenu *menu,
if (accel_path)
g_return_if_fail (accel_path[0] == '<' && strchr (accel_path, '/')); /* simplistic check */
- g_free (menu->accel_path);
- menu->accel_path = g_strdup (accel_path);
+ /* FIXME: accel_path should be defined as const gchar* */
+ menu->accel_path = (gchar*)g_intern_string (accel_path);
if (menu->accel_path)
_gtk_menu_refresh_accel_paths (menu, FALSE);
}
+/**
+ * gtk_menu_get_accel_path
+ * @menu: a valid #GtkMenu
+ *
+ * Retrieves the accelerator path set on the menu.
+ *
+ * Since: 2.14
+ */
+const gchar*
+gtk_menu_get_accel_path (GtkMenu *menu)
+{
+ g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
+
+ return menu->accel_path;
+}
+
typedef struct {
GtkMenu *menu;
gboolean group_changed;
{
GtkWidget *toplevel;
- menu->tearoff_window = gtk_widget_new (GTK_TYPE_WINDOW,
+ menu->tearoff_window = g_object_new (GTK_TYPE_WINDOW,
"type", GTK_WINDOW_TOPLEVEL,
"screen", gtk_widget_get_screen (menu->toplevel),
"app-paintable", TRUE,
}
}
+static void
+get_arrows_border (GtkMenu *menu, GtkBorder *border)
+{
+ guint scroll_arrow_height;
+
+ gtk_widget_style_get (GTK_WIDGET (menu),
+ "scroll-arrow-vlength", &scroll_arrow_height,
+ NULL);
+
+ border->top = menu->upper_arrow_visible ? scroll_arrow_height : 0;
+ border->bottom = menu->lower_arrow_visible ? scroll_arrow_height : 0;
+
+ border->left = border->right = 0;
+}
+
static void
gtk_menu_realize (GtkWidget *widget)
{
GList *children;
guint vertical_padding;
guint horizontal_padding;
- guint scroll_arrow_height;
+ GtkBorder arrow_border;
g_return_if_fail (GTK_IS_MENU (widget));
gtk_widget_style_get (GTK_WIDGET (menu),
"vertical-padding", &vertical_padding,
"horizontal-padding", &horizontal_padding,
- "scroll-arrow-vlength", &scroll_arrow_height,
NULL);
attributes.x = border_width + widget->style->xthickness + horizontal_padding;
attributes.width = MAX (1, widget->allocation.width - attributes.x * 2);
attributes.height = MAX (1, widget->allocation.height - attributes.y * 2);
- if (menu->upper_arrow_visible)
- {
- attributes.y += scroll_arrow_height;
- attributes.height -= scroll_arrow_height;
- }
-
- if (menu->lower_arrow_visible)
- attributes.height -= scroll_arrow_height;
+ get_arrows_border (menu, &arrow_border);
+ attributes.y += arrow_border.top;
+ attributes.height -= arrow_border.top;
+ attributes.height -= arrow_border.bottom;
menu->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
gdk_window_set_user_data (menu->view_window, menu);
static void
gtk_menu_unrealize (GtkWidget *widget)
{
- GtkMenu *menu;
-
- g_return_if_fail (GTK_IS_MENU (widget));
-
- menu = GTK_MENU (widget);
+ GtkMenu *menu = GTK_MENU (widget);
menu_grab_transfer_window_destroy (menu);
gint width, height;
guint vertical_padding;
guint horizontal_padding;
- gint scroll_arrow_height;
g_return_if_fail (GTK_IS_MENU (widget));
g_return_if_fail (allocation != NULL);
gtk_widget_style_get (GTK_WIDGET (menu),
"vertical-padding", &vertical_padding,
"horizontal-padding", &horizontal_padding,
- "scroll-arrow-vlength", &scroll_arrow_height,
NULL);
x = GTK_CONTAINER (menu)->border_width + widget->style->xthickness + horizontal_padding;
if (menu_shell->active)
gtk_menu_scroll_to (menu, menu->scroll_offset);
- if (menu->upper_arrow_visible && !menu->tearoff_active)
+ if (!menu->tearoff_active)
{
- y += scroll_arrow_height;
- height -= scroll_arrow_height;
- }
+ GtkBorder arrow_border;
- if (menu->lower_arrow_visible && !menu->tearoff_active)
- height -= scroll_arrow_height;
+ get_arrows_border (menu, &arrow_border);
+ y += arrow_border.top;
+ height -= arrow_border.top;
+ height -= arrow_border.bottom;
+ }
if (GTK_WIDGET_REALIZED (widget))
{
}
}
+static void
+get_arrows_visible_area (GtkMenu *menu,
+ GdkRectangle *border,
+ GdkRectangle *upper,
+ GdkRectangle *lower,
+ gint *arrow_space)
+{
+ GtkWidget *widget = GTK_WIDGET (menu);
+ guint vertical_padding;
+ guint horizontal_padding;
+ gint scroll_arrow_height;
+
+ gtk_widget_style_get (widget,
+ "vertical-padding", &vertical_padding,
+ "horizontal-padding", &horizontal_padding,
+ "scroll-arrow-vlength", &scroll_arrow_height,
+ NULL);
+
+ border->x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness + horizontal_padding;
+ border->y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness + vertical_padding;
+ gdk_drawable_get_size (widget->window, &border->width, &border->height);
+
+ upper->x = border->x;
+ upper->y = border->y;
+ upper->width = border->width - 2 * border->x;
+ upper->height = scroll_arrow_height;
+
+ lower->x = border->x;
+ lower->y = border->height - border->y - scroll_arrow_height;
+ lower->width = border->width - 2 * border->x;
+ lower->height = scroll_arrow_height;
+
+ *arrow_space = scroll_arrow_height - 2 * widget->style->ythickness;
+}
+
static void
gtk_menu_paint (GtkWidget *widget,
GdkEventExpose *event)
{
GtkMenu *menu;
GtkMenuPrivate *priv;
- gint width, height;
- gint border_x, border_y;
- guint vertical_padding;
- guint horizontal_padding;
- gint scroll_arrow_height;
+ GdkRectangle border;
+ GdkRectangle upper;
+ GdkRectangle lower;
+ gint arrow_space;
g_return_if_fail (GTK_IS_MENU (widget));
menu = GTK_MENU (widget);
priv = gtk_menu_get_private (menu);
- gtk_widget_style_get (GTK_WIDGET (menu),
- "vertical-padding", &vertical_padding,
- "horizontal-padding", &horizontal_padding,
- "scroll-arrow-vlength", &scroll_arrow_height,
- NULL);
-
- border_x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness + horizontal_padding;
- border_y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness + vertical_padding;
- gdk_drawable_get_size (widget->window, &width, &height);
+ get_arrows_visible_area (menu, &border, &upper, &lower, &arrow_space);
if (event->window == widget->window)
{
- gint arrow_space = scroll_arrow_height - 2 * widget->style->ythickness;
gint arrow_size = 0.7 * arrow_space;
gtk_paint_box (widget->style,
widget->window,
GTK_STATE_NORMAL,
GTK_SHADOW_OUT,
- NULL, widget, "menu",
+ &event->area, widget, "menu",
0, 0, -1, -1);
if (menu->upper_arrow_visible && !menu->tearoff_active)
gtk_paint_box (widget->style,
widget->window,
priv->upper_arrow_state,
- GTK_SHADOW_OUT,
- NULL, widget, "menu",
- border_x,
- border_y,
- width - 2 * border_x,
- scroll_arrow_height);
+ GTK_SHADOW_OUT,
+ &event->area, widget, "menu_scroll_arrow_up",
+ upper.x,
+ upper.y,
+ upper.width,
+ upper.height);
gtk_paint_arrow (widget->style,
widget->window,
priv->upper_arrow_state,
GTK_SHADOW_OUT,
- NULL, widget, "menu_scroll_arrow_up",
+ &event->area, widget, "menu_scroll_arrow_up",
GTK_ARROW_UP,
TRUE,
- (width - arrow_size ) / 2,
- border_y + widget->style->ythickness + (arrow_space - arrow_size)/2,
+ upper.x + (upper.width - arrow_size) / 2,
+ upper.y + widget->style->ythickness + (arrow_space - arrow_size) / 2,
arrow_size, arrow_size);
}
gtk_paint_box (widget->style,
widget->window,
priv->lower_arrow_state,
- GTK_SHADOW_OUT,
- NULL, widget, "menu",
- border_x,
- height - border_y - scroll_arrow_height,
- width - 2*border_x,
- scroll_arrow_height);
+ GTK_SHADOW_OUT,
+ &event->area, widget, "menu_scroll_arrow_down",
+ lower.x,
+ lower.y,
+ lower.width,
+ lower.height);
gtk_paint_arrow (widget->style,
widget->window,
priv->lower_arrow_state,
GTK_SHADOW_OUT,
- NULL, widget, "menu_scroll_arrow_down",
+ &event->area, widget, "menu_scroll_arrow_down",
GTK_ARROW_DOWN,
TRUE,
- (width - arrow_size) / 2,
- height - border_y - scroll_arrow_height +
- widget->style->ythickness + (arrow_space - arrow_size)/2,
+ lower.x + (lower.width - arrow_size) / 2,
+ lower.y + widget->style->ythickness + (arrow_space - arrow_size) / 2,
arrow_size, arrow_size);
}
}
else if (event->window == menu->bin_window)
{
+ gint y = -border.y + menu->scroll_offset;
+
+ if (!menu->tearoff_active)
+ {
+ GtkBorder arrow_border;
+
+ get_arrows_border (menu, &arrow_border);
+ y -= arrow_border.top;
+ }
+
gtk_paint_box (widget->style,
menu->bin_window,
GTK_STATE_NORMAL,
GTK_SHADOW_OUT,
- NULL, widget, "menu",
- - border_x, menu->scroll_offset - border_y,
- width, height);
+ &event->area, widget, "menu",
+ - border.x, y,
+ border.width, border.height);
}
}
}
static gboolean
-gtk_menu_button_scroll (GtkWidget *widget,
+gtk_menu_button_scroll (GtkMenu *menu,
GdkEventButton *event)
{
- if (GTK_IS_MENU (widget))
+ if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
{
- GtkMenu *menu = GTK_MENU (widget);
+ gboolean touchscreen_mode;
- if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
- {
- GtkSettings *settings = gtk_widget_get_settings (widget);
- gboolean touchscreen_mode;
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
- g_object_get (G_OBJECT (settings),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
+ if (touchscreen_mode)
+ gtk_menu_handle_scrolling (menu,
+ event->x_root, event->y_root,
+ event->type == GDK_BUTTON_PRESS,
+ FALSE);
- if (touchscreen_mode)
- gtk_menu_handle_scrolling (menu,
- event->x_root, event->y_root,
- event->type == GDK_BUTTON_PRESS,
- FALSE);
+ return TRUE;
+ }
- return TRUE;
- }
+ return FALSE;
+}
+
+static gboolean
+pointer_in_menu_window (GtkWidget *widget,
+ gdouble x_root,
+ gdouble y_root)
+{
+ GtkMenu *menu = GTK_MENU (widget);
+
+ if (GTK_WIDGET_MAPPED (menu->toplevel))
+ {
+ GtkMenuShell *menu_shell;
+ gint window_x, window_y;
+
+ gdk_window_get_position (menu->toplevel->window, &window_x, &window_y);
+
+ if (x_root >= window_x && x_root < window_x + widget->allocation.width &&
+ y_root >= window_y && y_root < window_y + widget->allocation.height)
+ return TRUE;
+
+ menu_shell = GTK_MENU_SHELL (widget);
+
+ if (GTK_IS_MENU (menu_shell->parent_menu_shell))
+ return pointer_in_menu_window (menu_shell->parent_menu_shell,
+ x_root, y_root);
}
return FALSE;
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
- /* Don't pop down the menu for presses over scroll arrows
+ /* Don't pass down to menu shell for presses over scroll arrows
+ */
+ if (gtk_menu_button_scroll (GTK_MENU (widget), event))
+ return TRUE;
+
+ /* Don't pass down to menu shell if a non-menuitem part of the menu
+ * was clicked. The check for the event_widget being a GtkMenuShell
+ * works because we have the pointer grabbed on menu_shell->window
+ * with owner_events=TRUE, so all events that are either outside
+ * the menu or on its border are delivered relative to
+ * menu_shell->window.
*/
- if (gtk_menu_button_scroll (widget, event))
+ if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
+ pointer_in_menu_window (widget, event->x_root, event->y_root))
return TRUE;
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event);
gtk_menu_button_release (GtkWidget *widget,
GdkEventButton *event)
{
- if (GTK_IS_MENU (widget))
- {
- GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (widget));
+ GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (widget));
- if (priv->ignore_button_release)
- {
- priv->ignore_button_release = FALSE;
- return FALSE;
- }
+ if (priv->ignore_button_release)
+ {
+ priv->ignore_button_release = FALSE;
+ return FALSE;
}
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
- /* Don't pop down the menu for releases over scroll arrows
+ /* Don't pass down to menu shell for releases over scroll arrows
*/
- if (gtk_menu_button_scroll (widget, event))
+ if (gtk_menu_button_scroll (GTK_MENU (widget), event))
return TRUE;
+ /* Don't pass down to menu shell if a non-menuitem part of the menu
+ * was clicked (see comment in button_press()).
+ */
+ if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
+ pointer_in_menu_window (widget, event->x_root, event->y_root))
+ {
+ /* Ugly: make sure menu_shell->button gets reset to 0 when we
+ * bail out early here so it is in a consistent state for the
+ * next button_press/button_release in GtkMenuShell.
+ * See bug #449371.
+ */
+ if (GTK_MENU_SHELL (widget)->active)
+ GTK_MENU_SHELL (widget)->button = 0;
+
+ return TRUE;
+ }
+
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_release_event (widget, event);
}
{
guint keyval = 0;
GdkModifierType mods = 0;
- gboolean handled = FALSE;
gtk_accelerator_parse (accel, &keyval, &mods);
* thing, to properly consider i18n etc., but that probably requires
* AccelGroup changes etc.
*/
- if (event->keyval == keyval &&
- (mods & event->state) == mods)
- gtk_menu_shell_cancel (menu_shell);
-
- g_free (accel);
-
- if (handled)
- return TRUE;
+ if (event->keyval == keyval && (mods & event->state) == mods)
+ {
+ gtk_menu_shell_cancel (menu_shell);
+ g_free (accel);
+ return TRUE;
+ }
}
+
+ g_free (accel);
switch (event->keyval)
{
if (definitely_within_item (menu_item, event->x, event->y))
menu_shell->activate_time = 0;
-
+
need_enter = (menu->navigation_region != NULL || menu_shell->ignore_enter);
/* Check to see if we are within an active submenu's navigation region
send_event->crossing.y_root = event->y_root;
send_event->crossing.x = event->x;
send_event->crossing.y = event->y;
+ send_event->crossing.state = event->state;
/* We send the event to 'widget', the currently active menu,
* instead of 'menu', the menu that the pointer is in. This
gint offset;
gint view_width, view_height;
gboolean double_arrows;
- gint scroll_arrow_height;
+ GtkBorder arrow_border;
widget = GTK_WIDGET (menu);
offset = menu->scroll_offset + step;
- gtk_widget_style_get (GTK_WIDGET (menu),
- "scroll-arrow-vlength", &scroll_arrow_height,
- NULL);
+ get_arrows_border (menu, &arrow_border);
double_arrows = get_double_arrows (menu);
* screen space than just scrolling to the top.
*/
if (!double_arrows)
- if ((step < 0) && (offset < scroll_arrow_height))
+ if ((step < 0) && (offset < arrow_border.top))
offset = 0;
/* Don't scroll over the top if we weren't before: */
/* Don't scroll past the bottom if we weren't before: */
if (menu->scroll_offset > 0)
- view_height -= scroll_arrow_height;
+ view_height -= arrow_border.top;
/* When both arrows are always shown, reduce
* view height even more.
*/
if (double_arrows)
- view_height -= scroll_arrow_height;
+ view_height -= arrow_border.bottom;
if ((menu->scroll_offset + view_height <= widget->requisition.height) &&
(offset + view_height > widget->requisition.height))
}
static gboolean
-gtk_menu_scroll_timeout (gpointer data)
+gtk_menu_scroll_timeout (gpointer data)
{
- GtkMenu *menu;
- GtkSettings *settings;
- gboolean touchscreen_mode;
+ GtkMenu *menu;
+ gboolean touchscreen_mode;
menu = GTK_MENU (data);
- settings = gtk_widget_get_settings (GTK_WIDGET (menu));
- g_object_get (settings,
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
static gboolean
gtk_menu_scroll_timeout_initial (gpointer data)
{
- GtkMenu *menu;
- GtkSettings *settings;
- guint timeout;
- gboolean touchscreen_mode;
+ GtkMenu *menu;
+ guint timeout;
+ gboolean touchscreen_mode;
menu = GTK_MENU (data);
- settings = gtk_widget_get_settings (GTK_WIDGET (menu));
- g_object_get (settings,
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-timeout-repeat", &timeout,
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_remove_scroll_timeout (menu);
- menu->timeout_id = gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu);
+ menu->timeout_id = gdk_threads_add_timeout (timeout,
+ gtk_menu_scroll_timeout,
+ menu);
return FALSE;
}
static void
gtk_menu_start_scrolling (GtkMenu *menu)
{
- GtkSettings *settings;
- guint timeout;
- gboolean touchscreen_mode;
+ guint timeout;
+ gboolean touchscreen_mode;
- settings = gtk_widget_get_settings (GTK_WIDGET (menu));
- g_object_get (settings,
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-timeout-repeat", &timeout,
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
- menu->timeout_id = gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial,
- menu);
+ menu->timeout_id = gdk_threads_add_timeout (timeout,
+ gtk_menu_scroll_timeout_initial,
+ menu);
}
static gboolean
return TRUE;
}
+static void
+get_arrows_sensitive_area (GtkMenu *menu,
+ GdkRectangle *upper,
+ GdkRectangle *lower)
+{
+ gint width, height;
+ gint border;
+ guint vertical_padding;
+ gint win_x, win_y;
+ gint scroll_arrow_height;
+
+ gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height);
+
+ gtk_widget_style_get (GTK_WIDGET (menu),
+ "vertical-padding", &vertical_padding,
+ "scroll-arrow-vlength", &scroll_arrow_height,
+ NULL);
+
+ border = GTK_CONTAINER (menu)->border_width +
+ GTK_WIDGET (menu)->style->ythickness + vertical_padding;
+
+ gdk_window_get_position (GTK_WIDGET (menu)->window, &win_x, &win_y);
+
+ if (upper)
+ {
+ upper->x = win_x;
+ upper->y = win_y;
+ upper->width = width;
+ upper->height = scroll_arrow_height + border;
+ }
+
+ if (lower)
+ {
+ lower->x = win_x;
+ lower->y = win_y + height - border - scroll_arrow_height;
+ lower->width = width;
+ lower->height = scroll_arrow_height + border;
+ }
+}
+
+
static void
gtk_menu_handle_scrolling (GtkMenu *menu,
gint x,
{
GtkMenuShell *menu_shell;
GtkMenuPrivate *priv;
- gint width, height;
- gint border;
GdkRectangle rect;
gboolean in_arrow;
gboolean scroll_fast = FALSE;
- guint vertical_padding;
gint top_x, top_y;
- gint win_x, win_y;
- GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (menu));
gboolean touchscreen_mode;
- gint scroll_arrow_height;
-
+
priv = gtk_menu_get_private (menu);
menu_shell = GTK_MENU_SHELL (menu);
- gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height);
-
- g_object_get (G_OBJECT (settings),
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
- gtk_widget_style_get (GTK_WIDGET (menu),
- "vertical-padding", &vertical_padding,
- "scroll-arrow-vlength", &scroll_arrow_height,
- NULL);
-
- border = GTK_CONTAINER (menu)->border_width +
- GTK_WIDGET (menu)->style->ythickness + vertical_padding;
-
gdk_window_get_position (menu->toplevel->window, &top_x, &top_y);
x -= top_x;
y -= top_y;
- gdk_window_get_position (GTK_WIDGET (menu)->window, &win_x, &win_y);
-
/* upper arrow handling */
- rect.x = win_x;
- rect.y = win_y;
- rect.width = width;
- rect.height = scroll_arrow_height + border;
+ get_arrows_sensitive_area (menu, &rect, NULL);
in_arrow = FALSE;
if (menu->upper_arrow_visible && !menu->tearoff_active &&
if (priv->upper_arrow_state != GTK_STATE_INSENSITIVE)
{
+ gboolean arrow_pressed = FALSE;
+
if (menu->upper_arrow_visible && !menu->tearoff_active)
{
if (touchscreen_mode)
{
- if (enter && menu->upper_arrow_prelight &&
- menu->timeout_id == 0)
+ if (enter && menu->upper_arrow_prelight)
{
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- menu->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
-
- if (!motion)
+ if (menu->timeout_id == 0)
{
- /* Only do stuff on click. */
- gtk_menu_start_scrolling (menu);
- priv->upper_arrow_state = GTK_STATE_ACTIVE;
+ /* Deselect the active item so that
+ * any submenus are popped down
+ */
+ gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_remove_scroll_timeout (menu);
+ menu->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
+
+ if (!motion)
+ {
+ /* Only do stuff on click. */
+ gtk_menu_start_scrolling (menu);
+ arrow_pressed = TRUE;
+ }
+ }
+ else
+ {
+ arrow_pressed = TRUE;
}
-
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
- &rect, FALSE);
}
else if (!enter)
{
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
- &rect, FALSE);
-
gtk_menu_stop_scrolling (menu);
}
}
{
menu->upper_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 popped down
menu->timeout_id =
gdk_threads_add_timeout (scroll_fast ?
- MENU_SCROLL_TIMEOUT2 : MENU_SCROLL_TIMEOUT1,
- gtk_menu_scroll_timeout, menu);
+ MENU_SCROLL_TIMEOUT2 :
+ MENU_SCROLL_TIMEOUT1,
+ gtk_menu_scroll_timeout, menu);
}
else if (!enter && !in_arrow && menu->upper_arrow_prelight)
{
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
- &rect, FALSE);
-
gtk_menu_stop_scrolling (menu);
}
}
}
- priv->upper_arrow_state = menu->upper_arrow_prelight ?
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
+ /* gtk_menu_start_scrolling() might have hit the top of the
+ * menu, so check if the button isn't insensitive before
+ * changing it to something else.
+ */
+ if (priv->upper_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ GtkStateType arrow_state = GTK_STATE_NORMAL;
+
+ if (arrow_pressed)
+ arrow_state = GTK_STATE_ACTIVE;
+ else if (menu->upper_arrow_prelight)
+ arrow_state = GTK_STATE_PRELIGHT;
+
+ if (arrow_state != priv->upper_arrow_state)
+ {
+ priv->upper_arrow_state = arrow_state;
+
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
+ &rect, FALSE);
+ }
+ }
}
/* lower arrow handling */
- rect.x = win_x;
- rect.y = win_y + height - border - scroll_arrow_height;
- rect.width = width;
- rect.height = scroll_arrow_height + border;
+ get_arrows_sensitive_area (menu, NULL, &rect);
in_arrow = FALSE;
if (menu->lower_arrow_visible && !menu->tearoff_active &&
if (priv->lower_arrow_state != GTK_STATE_INSENSITIVE)
{
+ gboolean arrow_pressed = FALSE;
+
if (menu->lower_arrow_visible && !menu->tearoff_active)
{
if (touchscreen_mode)
{
- if (enter && menu->lower_arrow_prelight &&
- menu->timeout_id == 0)
+ if (enter && menu->lower_arrow_prelight)
{
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- menu->scroll_step = MENU_SCROLL_STEP2; /* always fast */
-
- if (!motion)
+ if (menu->timeout_id == 0)
{
- /* Only do stuff on click. */
- gtk_menu_start_scrolling (menu);
- priv->lower_arrow_state = GTK_STATE_ACTIVE;
+ /* Deselect the active item so that
+ * any submenus are popped down
+ */
+ gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_remove_scroll_timeout (menu);
+ menu->scroll_step = MENU_SCROLL_STEP2; /* always fast */
+
+ if (!motion)
+ {
+ /* Only do stuff on click. */
+ gtk_menu_start_scrolling (menu);
+ arrow_pressed = TRUE;
+ }
+ }
+ else
+ {
+ arrow_pressed = TRUE;
}
-
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
- &rect, FALSE);
}
else if (!enter)
{
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
- &rect, FALSE);
-
gtk_menu_stop_scrolling (menu);
}
}
{
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 popped down
menu->timeout_id =
gdk_threads_add_timeout (scroll_fast ?
- MENU_SCROLL_TIMEOUT2 : MENU_SCROLL_TIMEOUT1,
- gtk_menu_scroll_timeout, menu);
+ 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);
}
}
}
- priv->lower_arrow_state = menu->lower_arrow_prelight ?
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
+ /* gtk_menu_start_scrolling() might have hit the bottom of the
+ * menu, so check if the button isn't insensitive before
+ * changing it to something else.
+ */
+ if (priv->lower_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ GtkStateType arrow_state = GTK_STATE_NORMAL;
+
+ if (arrow_pressed)
+ arrow_state = GTK_STATE_ACTIVE;
+ else if (menu->lower_arrow_prelight)
+ arrow_state = GTK_STATE_PRELIGHT;
+
+ if (arrow_state != priv->lower_arrow_state)
+ {
+ priv->lower_arrow_state = arrow_state;
+
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
+ &rect, FALSE);
+ }
+ }
}
}
gtk_menu_enter_notify (GtkWidget *widget,
GdkEventCrossing *event)
{
- GtkSettings *settings = gtk_widget_get_settings (widget);
GtkWidget *menu_item;
- gboolean touchscreen_mode;
+ gboolean touchscreen_mode;
- g_object_get (G_OBJECT (settings),
+ g_object_get (gtk_widget_get_settings (widget),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
NULL);
menu->navigation_timeout = gdk_threads_add_timeout (popdown_delay,
- gtk_menu_stop_navigating_submenu_cb, menu);
+ gtk_menu_stop_navigating_submenu_cb,
+ menu);
#ifdef DRAW_STAY_UP_TRIANGLE
draw_stay_up_triangle (gdk_get_default_root_window(),
GdkScreen *screen;
GdkScreen *pointer_screen;
GdkRectangle monitor;
- gint scroll_arrow_height;
g_return_if_fail (GTK_IS_MENU (menu));
screen = gtk_widget_get_screen (widget);
gdk_display_get_pointer (gdk_screen_get_display (screen),
&pointer_screen, &x, &y, NULL);
-
- gtk_widget_style_get (GTK_WIDGET (menu),
- "scroll-arrow-vlength", &scroll_arrow_height,
- 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 (scroll_offset > 0)
- scroll_offset += scroll_arrow_height;
+ {
+ GtkBorder arrow_border;
+
+ get_arrows_border (menu, &arrow_border);
+ scroll_offset += arrow_border.top;
+ }
gtk_window_move (GTK_WINDOW (GTK_MENU_SHELL (menu)->active ? menu->toplevel : menu->tearoff_window),
x, y);
static void
gtk_menu_stop_scrolling (GtkMenu *menu)
{
- GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (menu));
gboolean touchscreen_mode;
gtk_menu_remove_scroll_timeout (menu);
-
- g_object_get (G_OBJECT (settings),
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
-
+
if (!touchscreen_mode)
{
menu->upper_arrow_prelight = FALSE;
guint vertical_padding;
guint horizontal_padding;
gboolean double_arrows;
- gint scroll_arrow_height;
+ GtkBorder arrow_border;
widget = GTK_WIDGET (menu);
gtk_widget_style_get (GTK_WIDGET (menu),
"vertical-padding", &vertical_padding,
"horizontal-padding", &horizontal_padding,
- "scroll-arrow-vlength", &scroll_arrow_height,
NULL);
double_arrows = get_double_arrows (menu);
if (!menu->upper_arrow_visible || !menu->lower_arrow_visible)
gtk_widget_queue_draw (GTK_WIDGET (menu));
- view_height -= 2 * scroll_arrow_height;
- y += scroll_arrow_height;
-
menu->upper_arrow_visible = menu->lower_arrow_visible = TRUE;
+ get_arrows_border (menu, &arrow_border);
+ y += arrow_border.top;
+ view_height -= arrow_border.top;
+ view_height -= arrow_border.bottom;
+
if (offset <= 0)
priv->upper_arrow_state = GTK_STATE_INSENSITIVE;
- else
+ else if (priv->upper_arrow_state == GTK_STATE_INSENSITIVE)
priv->upper_arrow_state = menu->upper_arrow_prelight ?
GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
if (offset >= menu_height - view_height)
priv->lower_arrow_state = GTK_STATE_INSENSITIVE;
- else
+ else if (priv->lower_arrow_state == GTK_STATE_INSENSITIVE)
priv->lower_arrow_state = menu->lower_arrow_prelight ?
GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
last_visible = menu->upper_arrow_visible;
menu->upper_arrow_visible = offset > 0;
- if (menu->upper_arrow_visible)
- view_height -= scroll_arrow_height;
+ /* upper_arrow_visible may have changed, so requery the border */
+ get_arrows_border (menu, &arrow_border);
+ view_height -= arrow_border.top;
if ((last_visible != menu->upper_arrow_visible) &&
!menu->upper_arrow_visible)
last_visible = menu->lower_arrow_visible;
menu->lower_arrow_visible = offset < menu_height - view_height;
- if (menu->lower_arrow_visible)
- view_height -= scroll_arrow_height;
+ /* lower_arrow_visible may have changed, so requery the border */
+ get_arrows_border (menu, &arrow_border);
+ view_height -= arrow_border.bottom;
if ((last_visible != menu->lower_arrow_visible) &&
!menu->lower_arrow_visible)
}
}
- if (menu->upper_arrow_visible)
- y += scroll_arrow_height;
+ y += arrow_border.top;
}
/* Scroll the menu: */
{
guint vertical_padding;
gboolean double_arrows;
- gint scroll_arrow_height;
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,
- "scroll-arrow-vlength", &scroll_arrow_height,
NULL);
double_arrows = get_double_arrows (menu);
}
else
{
- arrow_height = 0;
- if (menu->upper_arrow_visible && !menu->tearoff_active)
- arrow_height += scroll_arrow_height;
- if (menu->lower_arrow_visible && !menu->tearoff_active)
- arrow_height += scroll_arrow_height;
+ GtkBorder arrow_border;
+
+ arrow_height = 0;
+
+ get_arrows_border (menu, &arrow_border);
+ if (!menu->tearoff_active)
+ arrow_height = arrow_border.top + arrow_border.bottom;
if (child_offset + child_height > y + height - arrow_height)
{
arrow_height = 0;
if ((!last_child && !menu->tearoff_active) || double_arrows)
- arrow_height += scroll_arrow_height;
+ arrow_height += arrow_border.bottom;
y = child_offset + child_height - height + arrow_height;
if (((y > 0) && !menu->tearoff_active) || double_arrows)
{
/* Need upper arrow */
- arrow_height += scroll_arrow_height;
+ arrow_height += arrow_border.top;
y = child_offset + child_height - height + arrow_height;
}
/* Ignore the enter event we might get if the pointer is on the menu
{
GtkWidget *widget = GTK_WIDGET (menu);
GtkContainer *container = GTK_CONTAINER (menu);
- gint scroll_arrow_height;
gint menu_height = (widget->allocation.height
- 2 * (container->border_width
+ widget->style->ythickness));
-
- gtk_widget_style_get (GTK_WIDGET (menu),
- "scroll-arrow-vlength", &scroll_arrow_height,
- NULL);
- if (menu->upper_arrow_visible && !menu->tearoff_active)
- menu_height -= scroll_arrow_height;
- if (menu->lower_arrow_visible && !menu->tearoff_active)
- menu_height -= scroll_arrow_height;
+ if (!menu->tearoff_active)
+ {
+ GtkBorder arrow_border;
+ get_arrows_border (menu, &arrow_border);
+ menu_height -= arrow_border.top;
+ menu_height -= arrow_border.bottom;
+ }
+
return menu_height;
}
{
gint height;
GtkWidget *widget = GTK_WIDGET (menu);
- gint scroll_arrow_height;
- gtk_widget_style_get (GTK_WIDGET (menu),
- "scroll-arrow-vlength", &scroll_arrow_height,
- NULL);
-
height = widget->requisition.height;
height -= (GTK_CONTAINER (widget)->border_width + widget->style->ythickness) * 2;
- if (menu->upper_arrow_visible && !menu->tearoff_active)
- height -= scroll_arrow_height;
+ if (!menu->tearoff_active)
+ {
+ GtkBorder arrow_border;
- if (menu->lower_arrow_visible && !menu->tearoff_active)
- height -= scroll_arrow_height;
+ get_arrows_border (menu, &arrow_border);
+ height -= arrow_border.top;
+ height -= arrow_border.bottom;
+ }
return height;
}
gint page_size = get_visible_size (menu);
gint end_position = get_menu_height (menu);
GtkMenuShell *menu_shell = GTK_MENU_SHELL (menu);
- gint scroll_arrow_height;
-
- gtk_widget_style_get (GTK_WIDGET (menu),
- "scroll-arrow-vlength", &scroll_arrow_height,
- NULL);
switch (type)
{
{
GtkWidget *new_child;
gboolean new_upper_arrow_visible = menu->upper_arrow_visible && !menu->tearoff_active;
+ GtkBorder arrow_border;
+
+ get_arrows_border (menu, &arrow_border);
if (menu->scroll_offset != old_offset)
step = menu->scroll_offset - old_offset;
- step -= (new_upper_arrow_visible - old_upper_arrow_visible) * scroll_arrow_height;
+ step -= (new_upper_arrow_visible - old_upper_arrow_visible) * arrow_border.top;
new_child = child_at (menu, child_offset + step);
if (new_child)
priv->monitor_num = monitor_num;
}
+/**
+ * gtk_menu_get_monitor:
+ * @menu: a #GtkMenu
+ *
+ * Retrieves the number of the monitor on which to show the menu.
+ *
+ * Returns: the number of the monitor on which the menu should
+ * be popped up or -1
+ *
+ * Since: 2.14
+ **/
+gint
+gtk_menu_get_monitor (GtkMenu *menu)
+{
+ GtkMenuPrivate *priv;
+ g_return_val_if_fail (GTK_IS_MENU (menu), -1);
+
+ priv = gtk_menu_get_private (menu);
+
+ return priv->monitor_num;
+}
+
/**
* gtk_menu_get_for_attach_widget:
* @widget: a #GtkWidget