* #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.
+ * A #GtkMenu can also be popped up by activating a #GtkComboBox.
* Other composite widgets such as the #GtkNotebook can pop up a
* #GtkMenu as well.
*
#include "gtkaccellabel.h"
#include "gtkaccelmap.h"
+#include "gtkadjustment.h"
#include "gtkbindings.h"
#include "gtkcheckmenuitem.h"
#include "gtkmain.h"
#include "gtkscrollbar.h"
#include "gtksettings.h"
#include "gtkprivate.h"
+#include "gtkwidgetpath.h"
#include "gtkwidgetprivate.h"
#include "gtkdnd.h"
#include "gtkintl.h"
static void gtk_menu_stop_scrolling (GtkMenu *menu);
static void gtk_menu_remove_scroll_timeout (GtkMenu *menu);
static gboolean gtk_menu_scroll_timeout (gpointer data);
-static gboolean gtk_menu_scroll_timeout_initial (gpointer data);
-static void gtk_menu_start_scrolling (GtkMenu *menu);
static void gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
GtkWidget *menu_item);
-1, G_MAXINT, -1,
GTK_PARAM_READWRITE));
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("vertical-padding",
- P_("Vertical Padding"),
- P_("Extra space at the top and bottom of the menu"),
- 0,
- G_MAXINT,
- 1,
- GTK_PARAM_READABLE));
-
/**
* GtkMenu:reserve-toggle-size:
*
TRUE,
GTK_PARAM_READWRITE));
+ /**
+ * GtkMenu:horizontal-padding:
+ *
+ * Extra space at the left and right edges of the menu.
+ *
+ * Deprecated: 3.8: use the standard padding CSS property (through objects
+ * like #GtkStyleContext and #GtkCssProvider); the value of this style
+ * property is ignored.
+ */
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("horizontal-padding",
P_("Horizontal Padding"),
0,
G_MAXINT,
0,
- GTK_PARAM_READABLE));
+ GTK_PARAM_READABLE |
+ G_PARAM_DEPRECATED));
+
+ /**
+ * GtkMenu:vertical-padding:
+ *
+ * Extra space at the top and bottom of the menu.
+ *
+ * Deprecated: 3.8: use the standard padding CSS property (through objects
+ * like #GtkStyleContext and #GtkCssProvider); the value of this style
+ * property is ignored.
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("vertical-padding",
+ P_("Vertical Padding"),
+ P_("Extra space at the top and bottom of the menu"),
+ 0,
+ G_MAXINT,
+ 1,
+ GTK_PARAM_READABLE |
+ G_PARAM_DEPRECATED));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("vertical-offset",
GTK_PARAM_READWRITE));
/**
- * GtkMenu:arrow-scaling
+ * GtkMenu:arrow-scaling:
*
* Arbitrary constant to scale down the size of the scroll arrow.
*
g_object_set_data_full (G_OBJECT (attach_widget), I_(ATTACHED_MENUS), list,
(GDestroyNotify) g_list_free);
- if (gtk_widget_get_state_flags (GTK_WIDGET (menu)) != 0)
- gtk_widget_set_state_flags (GTK_WIDGET (menu), 0, TRUE);
-
/* Attach the widget to the toplevel window. */
gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), attach_widget);
+ _gtk_widget_update_parent_muxer (GTK_WIDGET (menu));
+
/* Fallback title for menu comes from attach widget */
gtk_menu_update_title (menu);
g_slice_free (GtkMenuAttachData, data);
+ _gtk_widget_update_parent_muxer (GTK_WIDGET (menu));
+
/* Fallback title for menu comes from attach widget */
gtk_menu_update_title (menu);
+ g_object_notify (G_OBJECT (menu), "attach-widget");
g_object_unref (menu);
}
if (pointer &&
gdk_device_grab (pointer, window,
GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_SMOOTH_SCROLL_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
GDK_POINTER_MOTION_MASK,
* be used instead.
*
* Since: 3.0
- * Rename to: gtk_menu_popup
*/
void
gtk_menu_popup_for_device (GtkMenu *menu,
GtkMenuShell *menu_shell;
gboolean grab_keyboard;
GtkWidget *parent_toplevel;
- GdkDevice *keyboard, *pointer;
+ GdkDevice *keyboard, *pointer, *source_device = NULL;
g_return_if_fail (GTK_IS_MENU (menu));
g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
(current_event->type != GDK_ENTER_NOTIFY))
menu_shell->priv->ignore_enter = TRUE;
+ source_device = gdk_event_get_source_device (current_event);
gdk_event_free (current_event);
}
else
gtk_menu_scroll_to (menu, priv->scroll_offset);
/* if no item is selected, select the first one */
- if (!menu_shell->priv->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);
- }
+ if (!menu_shell->priv->active_menu_item &&
+ source_device && gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+ gtk_menu_shell_select_first (menu_shell, TRUE);
/* Once everything is set up correctly, map the toplevel */
gtk_widget_show (priv->toplevel);
}
/**
- * gtk_menu_popup: (skip)
+ * gtk_menu_popup:
* @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
+ * @func: (scope async) (allow-none): a user supplied function used to position
* the menu, or %NULL
* @data: user supplied data to be passed to @func.
* @button: the mouse button which was pressed to initiate the event.
* @menu: a #GtkMenu
*
* Returns the selected menu item from the menu. This is used by the
- * #GtkOptionMenu.
+ * #GtkComboBox.
*
* Returns: (transfer none): the #GtkMenuItem that was last selected
* in the menu. If a selection has not yet been made, the
* 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.
+ * the #GtkComboBox and should not be used by anyone else.
*/
void
gtk_menu_set_active (GtkMenu *menu,
}
/**
- * gtk_menu_set_accel_path
+ * gtk_menu_set_accel_path:
* @menu: a valid #GtkMenu
* @accel_path: (allow-none): a valid accelerator path
*
}
/**
- * gtk_menu_get_accel_path
+ * gtk_menu_get_accel_path:
* @menu: a valid #GtkMenu
*
* Retrieves the accelerator path set on the menu.
gint border_width;
GtkWidget *child;
GList *children;
- guint vertical_padding;
- guint horizontal_padding;
GtkBorder arrow_border, padding;
g_return_if_fail (GTK_IS_MENU (widget));
window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, attributes_mask);
gtk_widget_set_window (widget, window);
- gdk_window_set_user_data (window, widget);
+ gtk_widget_register_window (widget, window);
get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
context = gtk_widget_get_style_context (widget);
- gtk_widget_style_get (GTK_WIDGET (menu),
- "vertical-padding", &vertical_padding,
- "horizontal-padding", &horizontal_padding,
- NULL);
-
gtk_widget_get_allocation (widget, &allocation);
- attributes.x = border_width + padding.left + horizontal_padding;
- attributes.y = border_width + padding.top + vertical_padding;
+ attributes.x = border_width + padding.left;
+ attributes.y = border_width + padding.top;
attributes.width = allocation.width -
- (2 * (border_width + horizontal_padding)) - padding.left - padding.right;
+ (2 * border_width) - padding.left - padding.right;
attributes.height = allocation.height -
- (2 * (border_width + vertical_padding)) - padding.top - padding.bottom;
+ (2 * border_width) - padding.top - padding.bottom;
get_arrows_border (menu, &arrow_border);
attributes.y += arrow_border.top;
priv->view_window = gdk_window_new (window,
&attributes, attributes_mask);
- gdk_window_set_user_data (priv->view_window, menu);
+ gtk_widget_register_window (widget, priv->view_window);
gtk_widget_get_allocation (widget, &allocation);
attributes.x = 0;
attributes.y = 0;
- attributes.width = allocation.width + (2 * (border_width + horizontal_padding)) +
+ attributes.width = allocation.width + (2 * border_width) +
padding.left + padding.right;
- attributes.height = priv->requested_height - (2 * (border_width + vertical_padding)) +
+ attributes.height = priv->requested_height - (2 * border_width) +
padding.top + padding.bottom;
attributes.width = MAX (1, attributes.width);
priv->bin_window = gdk_window_new (priv->view_window,
&attributes, attributes_mask);
- gdk_window_set_user_data (priv->bin_window, menu);
+ gtk_widget_register_window (widget, priv->bin_window);
children = GTK_MENU_SHELL (menu)->priv->children;
while (children)
window = gdk_window_new (gtk_widget_get_root_window (GTK_WIDGET (menu)),
&attributes, attributes_mask);
- gdk_window_set_user_data (window, menu);
+ gtk_widget_register_window (GTK_WIDGET (menu), window);
gdk_window_show (window);
GdkWindow *window = g_object_get_data (G_OBJECT (menu), "gtk-menu-transfer-window");
if (window)
{
- gdk_window_set_user_data (window, NULL);
+ gtk_widget_unregister_window (GTK_WIDGET (menu), window);
gdk_window_destroy (window);
g_object_set_data (G_OBJECT (menu), I_("gtk-menu-transfer-window"), NULL);
}
menu_grab_transfer_window_destroy (menu);
- gdk_window_set_user_data (priv->view_window, NULL);
+ gtk_widget_unregister_window (widget, priv->view_window);
gdk_window_destroy (priv->view_window);
priv->view_window = NULL;
- gdk_window_set_user_data (priv->bin_window, NULL);
+ gtk_widget_unregister_window (widget, priv->bin_window);
gdk_window_destroy (priv->bin_window);
priv->bin_window = NULL;
GtkMenuShell *menu_shell;
GtkWidget *child, *widget;
GList *children;
- guint horizontal_padding;
guint border_width;
guint n_columns;
gint n_heights;
n_columns = gtk_menu_get_n_columns (menu);
avail_width = for_width - (2 * priv->toggle_size + priv->accel_size) * n_columns;
- gtk_widget_style_get (GTK_WIDGET (menu),
- "horizontal-padding", &horizontal_padding,
- NULL);
get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
- avail_width -= (border_width + horizontal_padding) * 2 + padding.left + padding.right;
+ avail_width -= (border_width) * 2 + padding.left + padding.right;
for (children = menu_shell->priv->children; children; children = children->next)
{
gint x, y, i;
gint width, height;
guint border_width;
- guint vertical_padding;
- guint horizontal_padding;
GtkBorder padding;
g_return_if_fail (GTK_IS_MENU (widget));
gtk_widget_set_allocation (widget, allocation);
- gtk_widget_style_get (GTK_WIDGET (menu),
- "vertical-padding", &vertical_padding,
- "horizontal-padding", &horizontal_padding,
- NULL);
-
get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
NULL);
/* refresh our cached height request */
- priv->requested_height = (2 * (border_width + vertical_padding)) +
- padding.top + padding.bottom;
+ priv->requested_height = (2 * border_width) + padding.top + padding.bottom;
for (i = 0; i < priv->heights_length; i++)
priv->requested_height += priv->heights[i];
- x = border_width + padding.left + horizontal_padding;
- y = border_width + padding.top + vertical_padding;
- width = allocation->width - (2 * (border_width + horizontal_padding)) -
+ x = border_width + padding.left;
+ y = border_width + padding.top;
+ width = allocation->width - (2 * border_width) -
padding.left - padding.right;
- height = allocation->height - (2 * (border_width + vertical_padding)) -
+ height = allocation->height - (2 * border_width) -
padding.top - padding.bottom;
if (menu_shell->priv->active)
GtkArrowPlacement arrow_placement;
GtkWidget *widget = GTK_WIDGET (menu);
guint border_width;
- guint vertical_padding;
- guint horizontal_padding;
gint scroll_arrow_height;
GtkBorder menu_padding;
gtk_widget_style_get (widget,
- "vertical-padding", &vertical_padding,
- "horizontal-padding", &horizontal_padding,
"scroll-arrow-vlength", &scroll_arrow_height,
"arrow-placement", &arrow_placement,
NULL);
get_menu_padding (widget, &menu_padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
- border->x = border_width + menu_padding.left + horizontal_padding;
- border->y = border_width + menu_padding.top + vertical_padding;
+ border->x = border_width + menu_padding.left;
+ border->y = border_width + menu_padding.top;
border->width = gdk_window_get_width (gtk_widget_get_window (widget));
border->height = gdk_window_get_height (gtk_widget_get_window (widget));
GList *children;
guint max_toggle_size;
guint max_accel_width;
- guint horizontal_padding;
guint border_width;
gint child_min, child_nat;
gint min_width, nat_width;
!priv->no_toggle_size)
{
GtkStyleContext *context;
- GtkWidgetPath *menu_path, *check_path;
+ GtkWidgetPath *check_path;
guint toggle_spacing;
guint indicator_size;
- context = gtk_widget_get_style_context (widget);
- menu_path = gtk_widget_path_copy (gtk_style_context_get_path (context));
+ context = gtk_style_context_new ();
/* Create a GtkCheckMenuItem path, only to query indicator spacing */
- check_path = gtk_widget_path_copy (menu_path);
+ check_path = _gtk_widget_create_path (widget);
gtk_widget_path_append_type (check_path, GTK_TYPE_CHECK_MENU_ITEM);
gtk_style_context_set_path (context, check_path);
gtk_widget_path_free (check_path);
+ gtk_style_context_set_screen (context, gtk_widget_get_screen (widget));
gtk_style_context_get_style (context,
"toggle-spacing", &toggle_spacing,
max_toggle_size = indicator_size + toggle_spacing;
- /* Restore real widget path */
- gtk_style_context_set_path (context, menu_path);
- gtk_widget_path_free (menu_path);
+ g_object_unref (context);
}
min_width += 2 * max_toggle_size + max_accel_width;
nat_width += 2 * max_toggle_size + max_accel_width;
nat_width *= gtk_menu_get_n_columns (menu);
- gtk_widget_style_get (GTK_WIDGET (menu),
- "horizontal-padding", &horizontal_padding,
- NULL);
-
get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
- min_width += (2 * (border_width + horizontal_padding)) +
- padding.left + padding.right;
- nat_width += (2 * (border_width + horizontal_padding)) +
- padding.left + padding.right;
+ min_width += (2 * border_width) + padding.left + padding.right;
+ nat_width += (2 * border_width) + padding.left + padding.right;
priv->toggle_size = max_toggle_size;
priv->accel_size = max_accel_width;
GtkMenu *menu = GTK_MENU (widget);
GtkMenuPrivate *priv = menu->priv;
guint *min_heights, *nat_heights;
- guint vertical_padding, border_width;
+ guint border_width;
gint n_heights, i;
gint min_height, nat_height;
- gtk_widget_style_get (widget, "vertical-padding", &vertical_padding, NULL);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
get_menu_padding (widget, &padding);
- min_height = nat_height = (border_width + vertical_padding) * 2 +
- padding.top + padding.bottom;
+ min_height = nat_height = (2 * border_width) + padding.top + padding.bottom;
n_heights =
calculate_line_heights (menu, for_size, &min_heights, &nat_heights);
gtk_menu_button_press (GtkWidget *widget,
GdkEventButton *event)
{
+ GdkDevice *source_device;
+ GtkWidget *event_widget;
+ GtkMenu *menu;
+
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
+ event_widget = gtk_get_event_widget ((GdkEvent *) event);
+ menu = GTK_MENU (widget);
+
/* 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
* the menu or on its border are delivered relative to
* menu_shell->window.
*/
- if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
+ if (GTK_IS_MENU_SHELL (event_widget) &&
pointer_in_menu_window (widget, event->x_root, event->y_root))
return TRUE;
+ if (GTK_IS_MENU_ITEM (event_widget) &&
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN &&
+ GTK_MENU_ITEM (event_widget)->priv->submenu != NULL &&
+ !gtk_widget_is_drawable (GTK_MENU_ITEM (event_widget)->priv->submenu))
+ menu->priv->ignore_button_release = TRUE;
+
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event);
}
gtk_menu_scroll_to (menu, offset);
}
-static void
-gtk_menu_do_timeout_scroll (GtkMenu *menu,
- gboolean touchscreen_mode)
-{
- GtkMenuPrivate *priv = menu->priv;
- gboolean upper_visible;
- gboolean lower_visible;
-
- upper_visible = priv->upper_arrow_visible;
- lower_visible = priv->lower_arrow_visible;
-
- gtk_menu_scroll_by (menu, priv->scroll_step);
-
- if (touchscreen_mode &&
- (upper_visible != priv->upper_arrow_visible ||
- lower_visible != priv->lower_arrow_visible))
- {
- /* We are about to hide a scroll arrow while the mouse is pressed,
- * this would cause the uncovered menu item to be activated on button
- * release. Therefore we need to ignore button release here
- */
- GTK_MENU_SHELL (menu)->priv->ignore_enter = TRUE;
- priv->ignore_button_release = TRUE;
- }
-}
-
static gboolean
gtk_menu_scroll_timeout (gpointer data)
{
GtkMenu *menu;
- gboolean touchscreen_mode;
menu = GTK_MENU (data);
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
+ gtk_menu_scroll_by (menu, menu->priv->scroll_step);
return TRUE;
}
-static gboolean
-gtk_menu_scroll_timeout_initial (gpointer data)
-{
- GtkMenu *menu;
- guint timeout;
- gboolean touchscreen_mode;
-
- menu = GTK_MENU (data);
-
- 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);
-
- gtk_menu_remove_scroll_timeout (menu);
-
- menu->priv->scroll_timeout =
- gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu);
-
- return FALSE;
-}
-
-static void
-gtk_menu_start_scrolling (GtkMenu *menu)
-{
- guint timeout;
- gboolean touchscreen_mode;
-
- 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->priv->scroll_timeout =
- gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial, menu);
-}
-
static gboolean
gtk_menu_scroll (GtkWidget *widget,
GdkEventScroll *event)
case GDK_SCROLL_UP:
gtk_menu_scroll_by (menu, - MENU_SCROLL_STEP2);
break;
+ case GDK_SCROLL_SMOOTH:
+ gtk_menu_scroll_by (menu, event->delta_y);
+ break;
}
return TRUE;
GdkWindow *window;
gint width, height;
guint border;
- guint vertical_padding;
gint win_x, win_y;
gint scroll_arrow_height;
GtkBorder padding;
height = gdk_window_get_height (window);
gtk_widget_style_get (widget,
- "vertical-padding", &vertical_padding,
"scroll-arrow-vlength", &scroll_arrow_height,
"arrow-placement", &arrow_placement,
NULL);
- border = gtk_container_get_border_width (GTK_CONTAINER (menu)) + vertical_padding;
+ border = gtk_container_get_border_width (GTK_CONTAINER (menu));
get_menu_padding (widget, &padding);
gdk_window_get_position (window, &win_x, &win_y);
gboolean in_arrow;
gboolean scroll_fast = FALSE;
gint top_x, top_y;
- gboolean touchscreen_mode;
menu_shell = GTK_MENU_SHELL (menu);
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
&top_x, &top_y);
x -= top_x;
in_arrow = TRUE;
}
- if (touchscreen_mode)
- priv->upper_arrow_prelight = in_arrow;
-
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
gboolean arrow_pressed = FALSE;
if (priv->upper_arrow_visible && !priv->tearoff_active)
{
- if (touchscreen_mode)
+ scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
+
+ if (enter && in_arrow &&
+ (!priv->upper_arrow_prelight ||
+ priv->scroll_fast != scroll_fast))
{
- if (enter && priv->upper_arrow_prelight)
- {
- if (priv->scroll_timeout == 0)
- {
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->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;
- }
- }
- else if (!enter)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ priv->upper_arrow_prelight = TRUE;
+ priv->scroll_fast = scroll_fast;
+
+ /* Deselect the active item so that
+ * any submenus are popped down
+ */
+ gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_remove_scroll_timeout (menu);
+ priv->scroll_step = scroll_fast
+ ? -MENU_SCROLL_STEP2
+ : -MENU_SCROLL_STEP1;
+
+ priv->scroll_timeout =
+ gdk_threads_add_timeout (scroll_fast
+ ? MENU_SCROLL_TIMEOUT2
+ : MENU_SCROLL_TIMEOUT1,
+ gtk_menu_scroll_timeout, menu);
}
- else /* !touchscreen_mode */
+ else if (!enter && !in_arrow && priv->upper_arrow_prelight)
{
- scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
-
- if (enter && in_arrow &&
- (!priv->upper_arrow_prelight ||
- priv->scroll_fast != scroll_fast))
- {
- priv->upper_arrow_prelight = TRUE;
- priv->scroll_fast = scroll_fast;
-
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->scroll_step = scroll_fast
- ? -MENU_SCROLL_STEP2
- : -MENU_SCROLL_STEP1;
-
- priv->scroll_timeout =
- gdk_threads_add_timeout (scroll_fast
- ? MENU_SCROLL_TIMEOUT2
- : MENU_SCROLL_TIMEOUT1,
- gtk_menu_scroll_timeout, menu);
- }
- else if (!enter && !in_arrow && priv->upper_arrow_prelight)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ gtk_menu_stop_scrolling (menu);
}
}
- /* gtk_menu_start_scrolling() might have hit the top of the
- * menu, so check if the button isn't insensitive before
+ /* check if the button isn't insensitive before
* changing it to something else.
*/
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
in_arrow = TRUE;
}
- if (touchscreen_mode)
- priv->lower_arrow_prelight = in_arrow;
-
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
gboolean arrow_pressed = FALSE;
if (priv->lower_arrow_visible && !priv->tearoff_active)
{
- if (touchscreen_mode)
+ scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
+
+ if (enter && in_arrow &&
+ (!priv->lower_arrow_prelight ||
+ priv->scroll_fast != scroll_fast))
{
- if (enter && priv->lower_arrow_prelight)
- {
- if (priv->scroll_timeout == 0)
- {
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->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;
- }
- }
- else if (!enter)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ priv->lower_arrow_prelight = TRUE;
+ priv->scroll_fast = scroll_fast;
+
+ /* Deselect the active item so that
+ * any submenus are popped down
+ */
+ gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_remove_scroll_timeout (menu);
+ priv->scroll_step = scroll_fast
+ ? MENU_SCROLL_STEP2
+ : MENU_SCROLL_STEP1;
+
+ priv->scroll_timeout =
+ gdk_threads_add_timeout (scroll_fast
+ ? MENU_SCROLL_TIMEOUT2
+ : MENU_SCROLL_TIMEOUT1,
+ gtk_menu_scroll_timeout, menu);
}
- else /* !touchscreen_mode */
+ else if (!enter && !in_arrow && priv->lower_arrow_prelight)
{
- scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
-
- if (enter && in_arrow &&
- (!priv->lower_arrow_prelight ||
- priv->scroll_fast != scroll_fast))
- {
- priv->lower_arrow_prelight = TRUE;
- priv->scroll_fast = scroll_fast;
-
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->scroll_step = scroll_fast
- ? MENU_SCROLL_STEP2
- : MENU_SCROLL_STEP1;
-
- priv->scroll_timeout =
- gdk_threads_add_timeout (scroll_fast
- ? MENU_SCROLL_TIMEOUT2
- : MENU_SCROLL_TIMEOUT1,
- gtk_menu_scroll_timeout, menu);
- }
- else if (!enter && !in_arrow && priv->lower_arrow_prelight)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ gtk_menu_stop_scrolling (menu);
}
}
- /* gtk_menu_start_scrolling() might have hit the bottom of the
- * menu, so check if the button isn't insensitive before
+ /* check if the button isn't insensitive before
* changing it to something else.
*/
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
menu = GTK_MENU (widget);
priv = menu->priv;
- if (!priv->upper_arrow_visible && !priv->lower_arrow_visible)
+ if (!priv->upper_arrow_visible && !priv->lower_arrow_visible && priv->drag_start_y < 0)
return retval;
source_device = gdk_event_get_source_device (event);
break;
case GDK_TOUCH_UPDATE:
case GDK_MOTION_NOTIFY:
- if ((!gdk_event_get_state (event, &state) || (state & GDK_BUTTON1_MASK)
-!= 0) &&
+ if ((!gdk_event_get_state (event, &state) || (state & GDK_BUTTON1_MASK) != 0) &&
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
{
if (!priv->drag_already_pressed)
if (priv->lower_arrow_visible)
view_height -= arrow_border.bottom;
- offset = CLAMP (offset, 0, priv->requested_height - view_height);
+ offset = CLAMP (offset,
+ MIN (priv->scroll_offset, 0),
+ MAX (priv->scroll_offset, priv->requested_height - view_height));
+
gtk_menu_scroll_to (menu, offset);
retval = TRUE;
gtk_menu_stop_scrolling (GtkMenu *menu)
{
GtkMenuPrivate *priv = menu->priv;
- gboolean touchscreen_mode;
gtk_menu_remove_scroll_timeout (menu);
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- if (!touchscreen_mode)
- {
- priv->upper_arrow_prelight = FALSE;
- priv->lower_arrow_prelight = FALSE;
- }
+ priv->upper_arrow_prelight = FALSE;
+ priv->lower_arrow_prelight = FALSE;
}
static void
gint view_width, view_height;
gint border_width;
gint menu_height;
- guint vertical_padding;
- guint horizontal_padding;
gboolean double_arrows;
widget = GTK_WIDGET (menu);
view_width = gtk_widget_get_allocated_width (widget);
view_height = gtk_widget_get_allocated_height (widget);
- gtk_widget_style_get (GTK_WIDGET (menu),
- "vertical-padding", &vertical_padding,
- "horizontal-padding", &horizontal_padding,
- NULL);
-
get_menu_padding (widget, &padding);
double_arrows = get_double_arrows (menu);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
- view_width -= (2 * (border_width + horizontal_padding)) + padding.left + padding.right;
- view_height -= (2 * (border_width + vertical_padding)) + padding.top + padding.bottom;
- menu_height = priv->requested_height - (2 * (border_width + vertical_padding)) -
- padding.top - padding.bottom;
+ view_width -= (2 * border_width) + padding.left + padding.right;
+ view_height -= (2 * border_width) + padding.top + padding.bottom;
+ menu_height = priv->requested_height - (2 * border_width) - padding.top - padding.bottom;
- x = border_width + padding.left + horizontal_padding;
- y = border_width + padding.top + vertical_padding;
+ x = border_width + padding.left;
+ y = border_width + padding.top;
if (double_arrows && !priv->tearoff_active)
{
/* Scroll the menu: */
if (gtk_widget_get_realized (widget))
- gdk_window_move (priv->bin_window, 0, -offset);
-
- if (gtk_widget_get_realized (widget))
- gdk_window_move_resize (priv->view_window, x, y, view_width, view_height);
+ {
+ gdk_window_move (priv->bin_window, 0, -offset);
+ gdk_window_move_resize (priv->view_window, x, y, view_width, view_height);
+ }
priv->scroll_offset = offset;
}
if (compute_child_offset (menu, menu_item,
&child_offset, &child_height, &last_child))
{
- guint vertical_padding;
gboolean double_arrows;
GtkBorder padding;
y = priv->scroll_offset;
height = gdk_window_get_height (gtk_widget_get_window (widget));
- gtk_widget_style_get (widget,
- "vertical-padding", &vertical_padding,
- NULL);
-
double_arrows = get_double_arrows (menu);
get_menu_padding (widget, &padding);
height -= 2 * gtk_container_get_border_width (GTK_CONTAINER (menu)) +
- padding.top + padding.bottom +
- 2 * vertical_padding;
+ padding.top + padding.bottom;
+
if (child_offset < y)
{
/* Ignore the enter event we might get if the pointer
get_menu_height (GtkMenu *menu)
{
GtkMenuPrivate *priv = menu->priv;
- GtkAllocation allocation;
GtkWidget *widget = GTK_WIDGET (menu);
GtkBorder padding;
gint height;
- gtk_widget_get_allocation (widget, &allocation);
get_menu_padding (widget, &padding);
- height = allocation.height;
+ height = priv->requested_height;
height -= (gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2) +
padding.top + padding.bottom;
GtkWidget *new_child;
gboolean new_upper_arrow_visible = priv->upper_arrow_visible && !priv->tearoff_active;
GtkBorder arrow_border;
+
get_arrows_border (menu, &arrow_border);
if (priv->scroll_offset != old_offset)
case GTK_SCROLL_START:
/* Ignore the enter event we might get if the pointer is on the menu */
menu_shell->priv->ignore_enter = TRUE;
- gtk_menu_scroll_to (menu, 0);
gtk_menu_shell_select_first (menu_shell, TRUE);
break;
case GTK_SCROLL_END:
/* Ignore the enter event we might get if the pointer is on the menu */
menu_shell->priv->ignore_enter = TRUE;
- gtk_menu_scroll_to (menu, end_position - page_size);
_gtk_menu_shell_select_last (menu_shell, TRUE);
break;
default:
return !menu->priv->no_toggle_size;
}
+
+/**
+ * gtk_menu_new_from_model:
+ * @model: a #GMenuModel
+ *
+ * Creates a #GtkMenu and populates it with menu items and
+ * submenus according to @model.
+ *
+ * The created menu items are connected to actions found in the
+ * #GtkApplicationWindow to which the menu belongs - typically
+ * by means of being attached to a widget (see gtk_menu_attach_to_widget())
+ * that is contained within the #GtkApplicationWindows widget hierarchy.
+ *
+ * Returns: a new #GtkMenu
+ *
+ * Since: 3.4
+ */
+GtkWidget *
+gtk_menu_new_from_model (GMenuModel *model)
+{
+ GtkWidget *menu;
+
+ g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL);
+
+ menu = gtk_menu_new ();
+ gtk_menu_shell_bind_model (GTK_MENU_SHELL (menu), model, NULL, TRUE);
+
+ return menu;
+}