diff options
Diffstat (limited to 'gtk/gtkmenu.c')
-rw-r--r-- | gtk/gtkmenu.c | 204 |
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; } /** |