summaryrefslogtreecommitdiff
path: root/gtk/gtkmenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/gtkmenu.c')
-rw-r--r--gtk/gtkmenu.c204
1 files changed, 161 insertions, 43 deletions
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index faa6896160..f1571d972b 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -108,8 +108,10 @@
#include "gtksettings.h"
#include "gtkprivate.h"
#include "gtkwidgetprivate.h"
+#include "gtkdnd.h"
#include "gtkintl.h"
#include "gtktypebuiltins.h"
+#include "gtkwidgetprivate.h"
#include "deprecated/gtktearoffmenuitem.h"
@@ -225,6 +227,9 @@ static void gtk_menu_scroll_to (GtkMenu *menu,
gint offset);
static void gtk_menu_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
+static gboolean gtk_menu_captured_event (GtkWidget *widget,
+ GdkEvent *event);
+
static void gtk_menu_stop_scrolling (GtkMenu *menu);
static void gtk_menu_remove_scroll_timeout (GtkMenu *menu);
@@ -1064,9 +1069,12 @@ gtk_menu_init (GtkMenu *menu)
priv->needs_destruction_ref = TRUE;
priv->monitor_num = -1;
+ priv->drag_start_y = -1;
context = gtk_widget_get_style_context (GTK_WIDGET (menu));
gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENU);
+
+ _gtk_widget_set_captured_event_handler (GTK_WIDGET (menu), gtk_menu_captured_event);
}
static void
@@ -3323,34 +3331,6 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget,
g_free (nat_heights);
}
-
-
-static gboolean
-gtk_menu_button_scroll (GtkMenu *menu,
- GdkEventButton *event)
-{
- GtkMenuPrivate *priv = menu->priv;
-
- if (priv->upper_arrow_prelight || priv->lower_arrow_prelight)
- {
- gboolean touchscreen_mode;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "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);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
static gboolean
pointer_in_menu_window (GtkWidget *widget,
gdouble x_root,
@@ -3390,11 +3370,6 @@ gtk_menu_button_press (GtkWidget *widget,
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
- /* 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
@@ -3424,11 +3399,6 @@ gtk_menu_button_release (GtkWidget *widget,
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
- /* Don't pass down to menu shell for releases 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 (see comment in button_press()).
*/
@@ -3672,10 +3642,14 @@ gtk_menu_motion_notify (GtkWidget *widget,
GtkMenu *menu;
GtkMenuShell *menu_shell;
GtkWidget *parent;
+ GdkDevice *source_device;
gboolean need_enter;
- if (GTK_IS_MENU (widget))
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
+
+ if (GTK_IS_MENU (widget) &&
+ gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
{
GtkMenuPrivate *priv = GTK_MENU(widget)->priv;
@@ -4293,10 +4267,11 @@ gtk_menu_enter_notify (GtkWidget *widget,
event->mode == GDK_CROSSING_STATE_CHANGED)
return TRUE;
- source_device = gdk_event_get_source_device (event);
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
menu_item = gtk_get_event_widget ((GdkEvent*) event);
- if (GTK_IS_MENU (widget))
+ if (GTK_IS_MENU (widget) &&
+ gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
{
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
@@ -4363,6 +4338,7 @@ gtk_menu_leave_notify (GtkWidget *widget,
GtkMenu *menu;
GtkMenuItem *menu_item;
GtkWidget *event_widget;
+ GdkDevice *source_device;
if (event->mode == GDK_CROSSING_GTK_GRAB ||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
@@ -4375,7 +4351,10 @@ gtk_menu_leave_notify (GtkWidget *widget,
if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
return TRUE;
- gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
+
+ if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
+ gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
event_widget = gtk_get_event_widget ((GdkEvent*) event);
@@ -4410,6 +4389,142 @@ gtk_menu_leave_notify (GtkWidget *widget,
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->leave_notify_event (widget, event);
}
+static gboolean
+pointer_on_menu_widget (GtkMenu *menu,
+ gdouble x_root,
+ gdouble y_root)
+{
+ GtkMenuPrivate *priv = menu->priv;
+ GtkAllocation allocation;
+ gint window_x, window_y;
+
+ gtk_widget_get_allocation (GTK_WIDGET (menu), &allocation);
+ gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
+ &window_x, &window_y);
+
+ if (x_root >= window_x && x_root < window_x + allocation.width &&
+ y_root >= window_y && y_root < window_y + allocation.height)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+gtk_menu_captured_event (GtkWidget *widget,
+ GdkEvent *event)
+{
+ GdkDevice *source_device;
+ gboolean retval = FALSE;
+ GtkMenuPrivate *priv;
+ GtkMenu *menu;
+ gdouble x_root, y_root;
+ guint button;
+ GdkModifierType state;
+
+ menu = GTK_MENU (widget);
+ priv = menu->priv;
+
+ if (!priv->upper_arrow_visible && !priv->lower_arrow_visible)
+ return retval;
+
+ source_device = gdk_event_get_source_device (event);
+ gdk_event_get_root_coords (event, &x_root, &y_root);
+
+ switch (event->type)
+ {
+ case GDK_TOUCH_BEGIN:
+ case GDK_BUTTON_PRESS:
+ if ((!gdk_event_get_button (event, &button) || button == 1) &&
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN &&
+ pointer_on_menu_widget (menu, x_root, y_root))
+ {
+ priv->drag_start_y = event->button.y_root;
+ priv->initial_drag_offset = priv->scroll_offset;
+ priv->drag_scroll_started = FALSE;
+ }
+ else
+ priv->drag_start_y = -1;
+
+ priv->drag_already_pressed = TRUE;
+ break;
+ case GDK_TOUCH_END:
+ case GDK_BUTTON_RELEASE:
+ if (priv->drag_scroll_started)
+ {
+ priv->drag_scroll_started = FALSE;
+ priv->drag_start_y = -1;
+ priv->drag_already_pressed = FALSE;
+ retval = TRUE;
+ }
+ break;
+ case GDK_TOUCH_UPDATE:
+ case GDK_MOTION_NOTIFY:
+ 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 (pointer_on_menu_widget (menu, x_root, y_root))
+ {
+ priv->drag_start_y = y_root;
+ priv->initial_drag_offset = priv->scroll_offset;
+ priv->drag_scroll_started = FALSE;
+ }
+ else
+ priv->drag_start_y = -1;
+
+ priv->drag_already_pressed = TRUE;
+ }
+
+ if (priv->drag_start_y < 0 && !priv->drag_scroll_started)
+ break;
+
+ if (priv->drag_scroll_started)
+ {
+ gint offset, view_height;
+ GtkBorder arrow_border;
+ gdouble y_diff;
+
+ y_diff = y_root - priv->drag_start_y;
+ offset = priv->initial_drag_offset - y_diff;
+
+ view_height = gdk_window_get_height (gtk_widget_get_window (widget));
+ get_arrows_border (menu, &arrow_border);
+
+ if (priv->upper_arrow_visible)
+ view_height -= arrow_border.top;
+
+ if (priv->lower_arrow_visible)
+ view_height -= arrow_border.bottom;
+
+ offset = CLAMP (offset, 0, priv->requested_height - view_height);
+ gtk_menu_scroll_to (menu, offset);
+
+ retval = TRUE;
+ }
+ else if (gtk_drag_check_threshold (widget,
+ 0, priv->drag_start_y,
+ 0, y_root))
+ {
+ priv->drag_scroll_started = TRUE;
+ gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
+ retval = TRUE;
+ }
+ }
+ break;
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ if (priv->drag_scroll_started)
+ retval = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return retval;
+}
+
static void
gtk_menu_stop_navigating_submenu (GtkMenu *menu)
{
@@ -5670,7 +5785,6 @@ gtk_menu_real_move_scroll (GtkMenu *menu,
}
}
-
/**
* gtk_menu_set_monitor:
* @menu: a #GtkMenu
@@ -5747,11 +5861,13 @@ static void
gtk_menu_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
+ GtkMenu *menu;
GtkWidget *toplevel;
GtkWindowGroup *group;
GtkWidget *grab;
GdkDevice *pointer;
+ menu = GTK_MENU (widget);
pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (widget));
if (!pointer ||
@@ -5768,6 +5884,8 @@ gtk_menu_grab_notify (GtkWidget *widget,
if (GTK_MENU_SHELL (widget)->priv->active && !GTK_IS_MENU_SHELL (grab))
gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
+
+ menu->priv->drag_scroll_started = FALSE;
}
/**