Compare commits

...

11 Commits

Author SHA1 Message Date
Alexander Mikhaylenko
62cf20ab7c tmp 2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
77f4c262c7 scrolledwindow: Port to the new controllers
Make sure the drag code path can handle scrolling without behavior
changes, replace GtkEventControllerScroll with Wheel.
2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
c3da601a66 tmp demo 2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
fe93d6c0a3 Add GtkEventControllerWheel
Gestures handle touchpad and trackpoint scrolling now, but we still need
something for mice. Add a new controller that does just that, without
scroll-begin/end or deceleration handling.
2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
9ddf5892f7 gestureswipe: Allow scroll events 2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
46d743d3f0 gestureswipe: Don't emit :swipe for cancelled gestures
Turns out that it was emitting the :swipe signal when ending the gesture
unconditionally, even if was cancelled. That shouldn't happen.
2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
75f6baa853 gesturedrag: Allow scroll events 2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
63b59e0717 gesturesingle: Pass through scroll events
We want to have them in GtkGestureDrag/Pan/Swipe.

Ignore motion events when no button is pressed - otherwise moving the
widget under the poitner in response to scrolling or a touchpad swipe would
interfere with them.
2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
f20246f65a gesture: Handle scroll events
This is the first step for supporting touchpad scrolling in gestures like
GtkGestureDrag.
2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
7f74b8c8df eventcontroller: Clarify filter_event()
The original intention with this function was to mark events that would
be filtered out - meaning one returns TRUE to skip and even and FALSE to
handle it. While this is docuemnted, it's not particularly clear and a few
controllers use it incorrectly. For example, GtkGesture intends to block
touchpad gesture events by default, yet in reality it allows them instead,
and otherwise chains up to GtkEventController that already enables
everything.

Instead, change it to work the way newer code uses it - skip everything by
default and have controllers explicitly allow events they need, and change
the return type from a boolean to a new enum with values HANDLE and SKIP.
2021-10-14 18:24:48 +05:00
Alexander Mikhaylenko
f0552949c5 events: Give scroll events pointer position
We'll need to have it for parity with touchpad swipes to use in GtkGesture.
2021-10-14 18:24:41 +05:00
31 changed files with 672 additions and 219 deletions

View File

@@ -46,17 +46,26 @@ static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *swindow;
GtkWidget *box;
GtkWidget *image;
GtkWidget *label;
swindow = gtk_scrolled_window_new ();
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (swindow), box);
gtk_widget_set_size_request (box, 1000, 200);
image = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
gtk_box_append (GTK_BOX (box), image);
label = gtk_label_new ("");
gtk_box_append (GTK_BOX (box), label);
gtk_list_item_set_child (list_item, box);
gtk_list_item_set_child (list_item, swindow);
g_object_set_data (G_OBJECT (list_item), "image", image);
g_object_set_data (G_OBJECT (list_item), "label", label);
}
/* Here we need to prepare the listitem for displaying its item. We get the
@@ -73,12 +82,12 @@ bind_listitem_cb (GtkListItemFactory *factory,
GtkWidget *label;
GAppInfo *app_info;
image = gtk_widget_get_first_child (gtk_list_item_get_child (list_item));
label = gtk_widget_get_next_sibling (image);
image = g_object_get_data (G_OBJECT (list_item), "image");
label = g_object_get_data (G_OBJECT (list_item), "label");
app_info = gtk_list_item_get_item (list_item);
gtk_image_set_from_gicon (GTK_IMAGE (image), g_app_info_get_icon (app_info));
gtk_label_set_label (GTK_LABEL (label), g_app_info_get_display_name (app_info));
gtk_label_set_label (GTK_LABEL (label), g_strdup_printf ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. ut enim ad sapientiam perveniri potest, non paranda nobis solum ea, sed fruenda etiam sapientia est; sive hoc difficile est, tamen nec modus ullus nec finis inveniri potest. Quodsi. %s", g_app_info_get_display_name (app_info)));
}
/* In more complex code, we would also need functions to unbind and teardown

View File

@@ -603,9 +603,11 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
GList *l;
GdkSurface *surface = NULL;
GdkDevice *device = NULL;
double x = 0.0, y = 0.0;
GdkEvent *last_event = NULL;
GList *scrolls = NULL;
double delta_x, delta_y;
gboolean has_coords = FALSE;
GArray *history = NULL;
GdkTimeCoord hist;
@@ -614,6 +616,7 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
while (l)
{
GdkEvent *event = l->data;
double event_x, event_y;
if (event->flags & GDK_EVENT_PENDING)
break;
@@ -630,11 +633,22 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
device != event->device)
break;
gdk_event_get_position (event, &event_x, &event_y);
if (has_coords && x != event_x)
break;
if (has_coords && y != event_y)
break;
if (!last_event)
last_event = event;
surface = event->surface;
device = event->device;
has_coords = TRUE;
x = event_x;
y = event_y;
scrolls = l;
l = l->prev;
@@ -681,6 +695,8 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
gdk_event_get_device_tool (old_event),
gdk_event_get_time (old_event),
gdk_event_get_modifier_state (old_event),
x,
y,
delta_x + dx,
delta_y + dy,
gdk_scroll_event_is_stop (old_event));
@@ -2273,6 +2289,19 @@ gdk_scroll_event_get_state (GdkEvent *event)
return self->state;
}
static gboolean
gdk_scroll_event_get_position (GdkEvent *event,
double *x,
double *y)
{
GdkScrollEvent *self = (GdkScrollEvent *) event;
*x = self->x;
*y = self->y;
return TRUE;
}
static GdkDeviceTool *
gdk_scroll_event_get_tool (GdkEvent *event)
{
@@ -2286,7 +2315,7 @@ static const GdkEventTypeInfo gdk_scroll_event_info = {
NULL,
gdk_scroll_event_finalize,
gdk_scroll_event_get_state,
NULL,
gdk_scroll_event_get_position,
NULL,
gdk_scroll_event_get_tool,
NULL,
@@ -2302,6 +2331,8 @@ gdk_scroll_event_new (GdkSurface *surface,
GdkDeviceTool *tool,
guint32 time,
GdkModifierType state,
double x,
double y,
double delta_x,
double delta_y,
gboolean is_stop)
@@ -2311,6 +2342,8 @@ gdk_scroll_event_new (GdkSurface *surface,
self->tool = tool != NULL ? g_object_ref (tool) : NULL;
self->state = state;
self->direction = GDK_SCROLL_SMOOTH;
self->x = x;
self->y = y;
self->delta_x = delta_x;
self->delta_y = delta_y;
self->is_stop = is_stop;
@@ -2324,6 +2357,8 @@ gdk_scroll_event_new_discrete (GdkSurface *surface,
GdkDeviceTool *tool,
guint32 time,
GdkModifierType state,
double x,
double y,
GdkScrollDirection direction,
gboolean emulated)
{
@@ -2331,6 +2366,8 @@ gdk_scroll_event_new_discrete (GdkSurface *surface,
self->tool = tool != NULL ? g_object_ref (tool) : NULL;
self->state = state;
self->x = x;
self->y = y;
self->direction = direction;
self->pointer_emulated = emulated;

View File

@@ -226,6 +226,8 @@ struct _GdkScrollEvent
{
GdkEvent parent_instance;
double x;
double y;
GdkModifierType state;
GdkScrollDirection direction;
double delta_x;
@@ -483,6 +485,8 @@ GdkEvent * gdk_scroll_event_new (GdkSurface *surface,
GdkDeviceTool *tool,
guint32 time,
GdkModifierType state,
double x,
double y,
double delta_x,
double delta_y,
gboolean is_stop);
@@ -492,6 +496,8 @@ GdkEvent * gdk_scroll_event_new_discrete (GdkSurface *surface,
GdkDeviceTool *tool,
guint32 time,
GdkModifierType state,
double x,
double y,
GdkScrollDirection direction,
gboolean emulated);

View File

@@ -637,6 +637,8 @@ fill_scroll_event (GdkMacosDisplay *self,
NULL,
get_time_from_ns_event (nsevent),
state,
x,
y,
-sx,
-sy,
FALSE);
@@ -674,6 +676,8 @@ fill_scroll_event (GdkMacosDisplay *self,
NULL,
get_time_from_ns_event (nsevent),
state,
x,
y,
direction,
TRUE);
_gdk_event_queue_append (GDK_DISPLAY (self), emulated);
@@ -687,6 +691,8 @@ fill_scroll_event (GdkMacosDisplay *self,
NULL,
get_time_from_ns_event (nsevent),
state,
x,
y,
dx,
dy,
FALSE);

View File

@@ -1392,6 +1392,8 @@ flush_discrete_scroll_event (GdkWaylandSeat *seat,
NULL,
seat->pointer_info.time,
device_get_modifiers (seat->logical_pointer),
seat->pointer_info.surface_x,
seat->pointer_info.surface_y,
direction,
TRUE);
@@ -1413,6 +1415,8 @@ flush_smooth_scroll_event (GdkWaylandSeat *seat,
NULL,
seat->pointer_info.time,
device_get_modifiers (seat->logical_pointer),
seat->pointer_info.surface_x,
seat->pointer_info.surface_y,
delta_x, delta_y,
is_stop);
@@ -3889,6 +3893,8 @@ tablet_tool_handle_wheel (void *data,
tablet->current_tool->tool,
tablet->pointer_info.time,
device_get_modifiers (tablet->logical_device),
tablet->pointer_info.surface_x,
tablet->pointer_info.surface_y,
0, clicks,
FALSE);
@@ -3900,6 +3906,8 @@ tablet_tool_handle_wheel (void *data,
tablet->current_tool->tool,
tablet->pointer_info.time,
device_get_modifiers (tablet->logical_device),
tablet->pointer_info.surface_x,
tablet->pointer_info.surface_y,
clicks > 0 ? GDK_SCROLL_DOWN : GDK_SCROLL_UP,
TRUE);

View File

@@ -2773,6 +2773,8 @@ gdk_event_translate (MSG *msg,
NULL,
_gdk_win32_get_next_tick (msg->time),
build_pointer_event_state (msg),
point.x,
point.y,
delta_x,
delta_y,
FALSE);
@@ -2793,6 +2795,8 @@ gdk_event_translate (MSG *msg,
NULL,
_gdk_win32_get_next_tick (msg->time),
build_pointer_event_state (msg),
point.x,
point.y,
direction,
TRUE);

View File

@@ -1643,6 +1643,8 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
NULL,
xev->time,
_gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group),
(double) xev->event_x / scale,
(double) xev->event_x / scale,
direction,
FALSE);
@@ -1746,6 +1748,8 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
NULL,
xev->time,
state,
(double) xev->event_x / scale,
(double) xev->event_y / scale,
direction,
FALSE);
}
@@ -1756,6 +1760,8 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
NULL,
xev->time,
state,
(double) xev->event_x / scale,
(double) xev->event_y / scale,
delta_x,
delta_y,
delta_x == 0.0 && delta_y == 0.0);

View File

@@ -114,6 +114,7 @@
#include <gtk/gtkeventcontrollerlegacy.h>
#include <gtk/gtkeventcontrollermotion.h>
#include <gtk/gtkeventcontrollerscroll.h>
#include <gtk/gtkeventcontrollerwheel.h>
#include <gtk/gtkexpander.h>
#include <gtk/gtkexpression.h>
#include <gtk/gtkfixed.h>

View File

@@ -243,7 +243,7 @@ gtk_drag_source_get_property (GObject *object,
}
}
static gboolean
static GtkFilterEventStatus
gtk_drag_source_filter_event (GtkEventController *controller,
GdkEvent *event)
{
@@ -257,9 +257,9 @@ gtk_drag_source_filter_event (GtkEventController *controller,
n_fingers = gdk_touchpad_event_get_n_fingers (event);
if (n_fingers == n_points)
return FALSE;
return GTK_EVENT_HANDLE;
else
return TRUE;
return GTK_EVENT_SKIP;
}
return GTK_EVENT_CONTROLLER_CLASS (gtk_drag_source_parent_class)->filter_event (controller, event);

View File

@@ -77,22 +77,27 @@ static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE (GtkDropControllerMotion, gtk_drop_controller_motion, GTK_TYPE_EVENT_CONTROLLER)
static GtkFilterEventStatus
gtk_drop_controller_motion_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
if (event_type == GDK_DRAG_MOTION)
return GTK_EVENT_HANDLE;
return GTK_EVENT_SKIP;
}
static gboolean
gtk_drop_controller_motion_handle_event (GtkEventController *controller,
GdkEvent *event,
double x,
double y)
{
GtkEventControllerClass *parent_class;
GdkEventType type;
g_signal_emit (controller, signals[MOTION], 0, x, y);
type = gdk_event_get_event_type (event);
if (type == GDK_DRAG_MOTION)
g_signal_emit (controller, signals[MOTION], 0, x, y);
parent_class = GTK_EVENT_CONTROLLER_CLASS (gtk_drop_controller_motion_parent_class);
return parent_class->handle_event (controller, event, x, y);
return GDK_EVENT_PROPAGATE;
}
static void
@@ -204,6 +209,7 @@ gtk_drop_controller_motion_class_init (GtkDropControllerMotionClass *klass)
object_class->get_property = gtk_drop_controller_motion_get_property;
controller_class->filter_event = gtk_drop_controller_motion_filter_event;
controller_class->handle_event = gtk_drop_controller_motion_handle_event;
controller_class->handle_crossing = gtk_drop_controller_motion_handle_crossing;

View File

@@ -387,7 +387,7 @@ gtk_drop_target_drop (GtkDropTarget *self,
return FALSE;
}
static gboolean
static GtkFilterEventStatus
gtk_drop_target_filter_event (GtkEventController *controller,
GdkEvent *event)
{
@@ -397,12 +397,12 @@ gtk_drop_target_filter_event (GtkEventController *controller,
case GDK_DRAG_LEAVE:
case GDK_DRAG_MOTION:
case GDK_DROP_START:
return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->filter_event (controller, event);
return GTK_EVENT_HANDLE;
default:;
}
return TRUE;
return GTK_EVENT_SKIP;
}
static gboolean

View File

@@ -183,7 +183,7 @@ gtk_drop_target_async_drop (GtkDropTargetAsync *self,
return FALSE;
}
static gboolean
static GtkFilterEventStatus
gtk_drop_target_async_filter_event (GtkEventController *controller,
GdkEvent *event)
{
@@ -193,12 +193,12 @@ gtk_drop_target_async_filter_event (GtkEventController *controller,
case GDK_DRAG_LEAVE:
case GDK_DRAG_MOTION:
case GDK_DROP_START:
return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_async_parent_class)->filter_event (controller, event);
return GTK_EVENT_HANDLE;
default:;
}
return TRUE;
return GTK_EVENT_SKIP;
}
static gboolean

View File

@@ -87,11 +87,11 @@ gtk_event_controller_unset_widget (GtkEventController *self)
priv->widget = NULL;
}
static gboolean
static GtkFilterEventStatus
gtk_event_controller_filter_event_default (GtkEventController *self,
GdkEvent *event)
{
return FALSE;
return GTK_EVENT_SKIP;
}
static gboolean
@@ -273,7 +273,7 @@ same_native (GtkWidget *widget,
return native == native2;
}
static gboolean
static GtkFilterEventStatus
gtk_event_controller_filter_event (GtkEventController *controller,
GdkEvent *event,
GtkWidget *target)
@@ -284,11 +284,11 @@ gtk_event_controller_filter_event (GtkEventController *controller,
priv = gtk_event_controller_get_instance_private (controller);
if (priv->widget && !gtk_widget_is_sensitive (priv->widget))
return TRUE;
return GTK_EVENT_SKIP;
if (priv->limit == GTK_LIMIT_SAME_NATIVE &&
!same_native (priv->widget, target))
return TRUE;
return GTK_EVENT_SKIP;
controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
@@ -357,7 +357,7 @@ gtk_event_controller_handle_event (GtkEventController *controller,
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if (gtk_event_controller_filter_event (controller, event, target))
if (gtk_event_controller_filter_event (controller, event, target) == GTK_EVENT_SKIP)
return retval;
controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);

View File

@@ -80,6 +80,18 @@ gtk_event_controller_key_finalize (GObject *object)
G_OBJECT_CLASS (gtk_event_controller_key_parent_class)->finalize (object);
}
static GtkFilterEventStatus
gtk_event_controller_key_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
if (event_type == GDK_KEY_PRESS || event_type == GDK_KEY_RELEASE)
return GTK_EVENT_HANDLE;
return GTK_EVENT_SKIP;
}
static gboolean
gtk_event_controller_key_handle_event (GtkEventController *controller,
GdkEvent *event,
@@ -93,9 +105,6 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
guint keyval;
gboolean handled = FALSE;
if (event_type != GDK_KEY_PRESS && event_type != GDK_KEY_RELEASE)
return FALSE;
if (key->im_context &&
gtk_im_context_filter_keypress (key->im_context, event))
{
@@ -186,6 +195,7 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_event_controller_key_finalize;
controller_class->filter_event = gtk_event_controller_key_filter_event;
controller_class->handle_event = gtk_event_controller_key_handle_event;
controller_class->handle_crossing = gtk_event_controller_key_handle_crossing;

View File

@@ -55,6 +55,13 @@ static guint signals[N_SIGNALS] = { 0, };
G_DEFINE_TYPE (GtkEventControllerLegacy, gtk_event_controller_legacy,
GTK_TYPE_EVENT_CONTROLLER)
static GtkFilterEventStatus
gtk_event_controller_legacy_filter_event (GtkEventController *controller,
GdkEvent *event)
{
return GTK_EVENT_HANDLE;
}
static gboolean
gtk_event_controller_legacy_handle_event (GtkEventController *controller,
GdkEvent *event,
@@ -73,6 +80,7 @@ gtk_event_controller_legacy_class_init (GtkEventControllerLegacyClass *klass)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
controller_class->filter_event = gtk_event_controller_legacy_filter_event;
controller_class->handle_event = gtk_event_controller_legacy_handle_event;
/**

View File

@@ -73,22 +73,27 @@ static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE (GtkEventControllerMotion, gtk_event_controller_motion, GTK_TYPE_EVENT_CONTROLLER)
static GtkFilterEventStatus
gtk_event_controller_motion_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
if (event_type == GDK_MOTION_NOTIFY)
return GTK_EVENT_HANDLE;
return GTK_EVENT_SKIP;
}
static gboolean
gtk_event_controller_motion_handle_event (GtkEventController *controller,
GdkEvent *event,
double x,
double y)
{
GtkEventControllerClass *parent_class;
GdkEventType type;
g_signal_emit (controller, signals[MOTION], 0, x, y);
type = gdk_event_get_event_type (event);
if (type == GDK_MOTION_NOTIFY)
g_signal_emit (controller, signals[MOTION], 0, x, y);
parent_class = GTK_EVENT_CONTROLLER_CLASS (gtk_event_controller_motion_parent_class);
return parent_class->handle_event (controller, event, x, y);
return GDK_EVENT_PROPAGATE;
}
static void
@@ -191,6 +196,7 @@ gtk_event_controller_motion_class_init (GtkEventControllerMotionClass *klass)
object_class->get_property = gtk_event_controller_motion_get_property;
controller_class->filter_event = gtk_event_controller_motion_filter_event;
controller_class->handle_event = gtk_event_controller_motion_handle_event;
controller_class->handle_crossing = gtk_event_controller_motion_handle_crossing;

View File

@@ -22,6 +22,16 @@
#include "gtkeventcontroller.h"
/*
* GtkFilterEventStatus:
* @GTK_EVENT_HANDLE: the event will be used by the controller
* @GTK_EVENT_SKIP: the event will be skipped
*/
typedef enum {
GTK_EVENT_HANDLE,
GTK_EVENT_SKIP
} GtkFilterEventStatus;
/* GdkCrossingType:
* @GTK_CROSSING_FOCUS: Focus moved from one widget to another
* @GTK_CROSSING_ACTIVE: The active window changed (the crossing
@@ -108,11 +118,11 @@ struct _GtkEventControllerClass
/*<private>*/
/* Tells whether the event is filtered out, %TRUE makes
* the event unseen by the handle_event vfunc.
/* Tells whether the event will be processed or filtered out.
* By default all events are skipped, subclasses will need to list them.
*/
gboolean (* filter_event) (GtkEventController *controller,
GdkEvent *event);
GtkFilterEventStatus (* filter_event) (GtkEventController *controller,
GdkEvent *event);
gpointer padding[10];
};

View File

@@ -235,6 +235,18 @@ gtk_event_controller_scroll_get_property (GObject *object,
}
}
static GtkFilterEventStatus
gtk_event_controller_scroll_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
if (event_type == GDK_SCROLL)
return GTK_EVENT_HANDLE;
return GTK_EVENT_SKIP;
}
static gboolean
gtk_event_controller_scroll_handle_event (GtkEventController *controller,
GdkEvent *event,
@@ -246,9 +258,6 @@ gtk_event_controller_scroll_handle_event (GtkEventController *controller,
double dx = 0, dy = 0;
gboolean handled = GDK_EVENT_PROPAGATE;
if (gdk_event_get_event_type (event) != GDK_SCROLL)
return FALSE;
if ((scroll->flags & (GTK_EVENT_CONTROLLER_SCROLL_VERTICAL |
GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL)) == 0)
return FALSE;
@@ -360,6 +369,7 @@ gtk_event_controller_scroll_class_init (GtkEventControllerScrollClass *klass)
object_class->set_property = gtk_event_controller_scroll_set_property;
object_class->get_property = gtk_event_controller_scroll_get_property;
controller_class->filter_event = gtk_event_controller_scroll_filter_event;
controller_class->handle_event = gtk_event_controller_scroll_handle_event;
/**

View File

@@ -0,0 +1,195 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2017, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
/**
* GtkEventControllerWheel:
*
* `GtkEventControllerWheel` is an event controller that handles mouse scroll
* events.
*
* It is capable of handling both discrete and continuous scroll
* events from mice or touchpads, abstracting them both with the
* [signal@Gtk.EventControllerScroll::scroll] signal. Deltas in
* the discrete case are multiples of 1.
*
* In the case of continuous scroll events, `GtkEventControllerScroll`
* encloses all [signal@Gtk.EventControllerScroll::scroll] emissions
* between two [signal@Gtk.EventControllerScroll::scroll-begin] and
* [signal@Gtk.EventControllerScroll::scroll-end] signals.
*
* The behavior of the event controller can be modified by the flags
* given at creation time, or modified at a later point through
* [method@Gtk.EventControllerScroll.set_flags] (e.g. because the scrolling
* conditions of the widget changed).
*
* The controller can be set up to emit motion for either/both vertical
* and horizontal scroll events through %GTK_EVENT_CONTROLLER_SCROLL_VERTICAL,
* %GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL and %GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES.
* If any axis is disabled, the respective [signal@Gtk.EventControllerScroll::scroll]
* delta will be 0. Vertical scroll events will be translated to horizontal
* motion for the devices incapable of horizontal scrolling.
*
* The event controller can also be forced to emit discrete events on all
* devices through %GTK_EVENT_CONTROLLER_SCROLL_DISCRETE. This can be used
* to implement discrete actions triggered through scroll events (e.g.
* switching across combobox options).
*
* The %GTK_EVENT_CONTROLLER_SCROLL_KINETIC flag toggles the emission of the
* [signal@Gtk.EventControllerScroll::decelerate] signal, emitted at the end
* of scrolling with two X/Y velocity arguments that are consistent with the
* motion that was received.
*/
#include "config.h"
#include "gtkintl.h"
#include "gtkeventcontrollerprivate.h"
#include "gtkeventcontrollerwheel.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
struct _GtkEventControllerWheel
{
GtkEventController parent_instance;
};
struct _GtkEventControllerWheelClass
{
GtkEventControllerClass parent_class;
};
enum {
SCROLL,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE (GtkEventControllerWheel, gtk_event_controller_wheel,
GTK_TYPE_EVENT_CONTROLLER)
static GtkFilterEventStatus
gtk_event_controller_wheel_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
if (event_type == GDK_SCROLL) {
GdkDevice *source_device = gdk_event_get_device (event);
GdkInputSource source = gdk_device_get_source (source_device);
if (source == GDK_SOURCE_MOUSE)
return GTK_EVENT_HANDLE;
}
return GTK_EVENT_SKIP;
}
static gboolean
gtk_event_controller_wheel_handle_event (GtkEventController *controller,
GdkEvent *event,
double x,
double y)
{
GdkScrollDirection direction = GDK_SCROLL_SMOOTH;
double dx = 0, dy = 0;
gboolean handled = GDK_EVENT_PROPAGATE;
/* FIXME: Handle device changes */
direction = gdk_scroll_event_get_direction (event);
if (direction == GDK_SCROLL_SMOOTH)
gdk_scroll_event_get_deltas (event, &dx, &dy);
else
{
switch (direction)
{
case GDK_SCROLL_UP:
dy -= 1;
break;
case GDK_SCROLL_DOWN:
dy += 1;
break;
case GDK_SCROLL_LEFT:
dx -= 1;
break;
case GDK_SCROLL_RIGHT:
dx += 1;
break;
case GDK_SCROLL_SMOOTH:
default:
g_assert_not_reached ();
break;
}
}
if (dx != 0 || dy != 0)
g_signal_emit (controller, signals[SCROLL], 0, dx, dy, &handled);
return handled;
}
static void
gtk_event_controller_wheel_class_init (GtkEventControllerWheelClass *klass)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
controller_class->filter_event = gtk_event_controller_wheel_filter_event;
controller_class->handle_event = gtk_event_controller_wheel_handle_event;
/**
* GtkEventControllerWheel:scroll:
* @controller: The object that received the signal
* @dx: X delta
* @dy: Y delta
*
* Signals that the widget should scroll by the
* amount specified by @dx and @dy.
*
* Returns: %TRUE if the scroll event was handled,
* %FALSE otherwise.
*/
signals[SCROLL] =
g_signal_new (I_("scroll"),
GTK_TYPE_EVENT_CONTROLLER_WHEEL,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
_gtk_marshal_BOOLEAN__DOUBLE_DOUBLE,
G_TYPE_BOOLEAN, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
g_signal_set_va_marshaller (signals[SCROLL],
G_TYPE_FROM_CLASS (klass),
_gtk_marshal_BOOLEAN__DOUBLE_DOUBLEv);
}
static void
gtk_event_controller_wheel_init (GtkEventControllerWheel *self)
{
}
/**
* gtk_event_controller_wheel_new:
*
* Creates a new event controller that will handle scroll events.
*
* Returns: a new `GtkEventControllerWheel`
*/
GtkEventController *
gtk_event_controller_wheel_new (void)
{
return g_object_new (GTK_TYPE_EVENT_CONTROLLER_WHEEL,
NULL);
}

View File

@@ -0,0 +1,47 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2017, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#pragma once
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include <gtk/gtkeventcontroller.h>
G_BEGIN_DECLS
#define GTK_TYPE_EVENT_CONTROLLER_WHEEL (gtk_event_controller_wheel_get_type ())
#define GTK_EVENT_CONTROLLER_WHEEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_EVENT_CONTROLLER_WHEEL, GtkEventControllerWheel))
#define GTK_EVENT_CONTROLLER_WHEEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_EVENT_CONTROLLER_WHEEL, GtkEventControllerWheelClass))
#define GTK_IS_EVENT_CONTROLLER_WHEEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_EVENT_CONTROLLER_WHEEL))
#define GTK_IS_EVENT_CONTROLLER_WHEEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_EVENT_CONTROLLER_WHEEL))
#define GTK_EVENT_CONTROLLER_WHEEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER_WHEEL, GtkEventControllerWheelClass))
typedef struct _GtkEventControllerWheel GtkEventControllerWheel;
typedef struct _GtkEventControllerWheelClass GtkEventControllerWheelClass;
GDK_AVAILABLE_IN_ALL
GType gtk_event_controller_wheel_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkEventController *gtk_event_controller_wheel_new (void);
G_END_DECLS

View File

@@ -164,6 +164,7 @@ struct _GtkGesturePrivate
guint n_points;
guint recognized : 1;
guint touchpad : 1;
guint scrolling : 1;
};
static guint signals[N_SIGNALS] = { 0 };
@@ -227,6 +228,31 @@ gtk_gesture_finalize (GObject *object)
G_OBJECT_CLASS (gtk_gesture_parent_class)->finalize (object);
}
static guint
_gtk_gesture_get_n_scroll_points (GtkGesture *gesture,
gboolean only_active)
{
GtkGesturePrivate *priv;
PointData *data;
priv = gtk_gesture_get_instance_private (gesture);
if (!priv->scrolling)
return 0;
data = g_hash_table_lookup (priv->points, NULL);
if (!data)
return 0;
if (only_active &&
(data->state == GTK_EVENT_SEQUENCE_DENIED ||
gdk_scroll_event_is_stop (data->event)))
return 0;
return 1;
}
static guint
_gtk_gesture_get_n_touchpad_points (GtkGesture *gesture,
gboolean only_active)
@@ -301,7 +327,9 @@ _gtk_gesture_get_n_physical_points (GtkGesture *gesture,
priv = gtk_gesture_get_instance_private (gesture);
if (priv->touchpad)
if (priv->scrolling)
return _gtk_gesture_get_n_scroll_points (gesture, only_active);
else if (priv->touchpad)
return _gtk_gesture_get_n_touchpad_points (gesture, only_active);
else
return _gtk_gesture_get_n_touch_points (gesture, only_active);
@@ -408,6 +436,13 @@ _update_touchpad_deltas (PointData *data)
data->accum_dy += dy;
}
}
else if (gdk_event_get_event_type (event) == GDK_SCROLL)
{
gdk_scroll_event_get_deltas (event, &dx, &dy);
data->accum_dx -= dx;
data->accum_dy -= dy;
}
}
static GtkEventSequenceState
@@ -444,7 +479,7 @@ _gtk_gesture_update_point (GtkGesture *gesture,
GdkEventSequence *sequence;
GtkGesturePrivate *priv;
GdkDevice *device;
gboolean existed, touchpad;
gboolean existed, touchpad, scrolling;
PointData *data;
device = gdk_event_get_device (event);
@@ -454,6 +489,7 @@ _gtk_gesture_update_point (GtkGesture *gesture,
priv = gtk_gesture_get_instance_private (gesture);
touchpad = EVENT_IS_TOUCHPAD_GESTURE (event);
scrolling = gdk_event_get_event_type (event) == GDK_SCROLL;
if (add)
{
@@ -464,10 +500,12 @@ _gtk_gesture_update_point (GtkGesture *gesture,
return FALSE;
/* Make touchpad and touchscreen gestures mutually exclusive */
if (touchpad && g_hash_table_size (priv->points) > 0)
if ((touchpad || scrolling) && g_hash_table_size (priv->points) > 0)
return FALSE;
else if (!touchpad && priv->touchpad)
return FALSE;
else if (!scrolling && priv->scrolling)
return FALSE;
}
else if (!priv->device)
return FALSE;
@@ -484,6 +522,7 @@ _gtk_gesture_update_point (GtkGesture *gesture,
{
priv->device = device;
priv->touchpad = touchpad;
priv->scrolling = scrolling;
}
data = g_new0 (PointData, 1);
@@ -530,8 +569,13 @@ _gtk_gesture_check_empty (GtkGesture *gesture)
if (g_hash_table_size (priv->points) == 0)
{
if (priv->scrolling)
g_object_steal_data (G_OBJECT (priv->device),
"gtk-gesture-is-device-scrolling");
priv->device = NULL;
priv->touchpad = FALSE;
priv->scrolling = FALSE;
}
}
@@ -584,19 +628,27 @@ gesture_within_surface (GtkGesture *gesture,
return surface == gtk_native_get_surface (gtk_widget_get_native (widget));
}
static gboolean
static GtkFilterEventStatus
gtk_gesture_filter_event (GtkEventController *controller,
GdkEvent *event)
{
/* Even though GtkGesture handles these events, we want
* touchpad gestures disabled by default, it will be
* subclasses which punch the holes in for the events
* they can possibly handle.
*/
if (EVENT_IS_TOUCHPAD_GESTURE (event))
return FALSE;
GdkEventType event_type = gdk_event_get_event_type (event);
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_parent_class)->filter_event (controller, event);
/* Even though GtkGesture handles touchpad and scroll events, we want to skip
* them by default, it will be subclasses which punch the holes in for the
* events they can possibly handle.
*/
if (event_type == GDK_BUTTON_PRESS ||
event_type == GDK_BUTTON_RELEASE ||
event_type == GDK_MOTION_NOTIFY ||
event_type == GDK_TOUCH_BEGIN ||
event_type == GDK_TOUCH_UPDATE ||
event_type == GDK_TOUCH_END ||
event_type == GDK_TOUCH_CANCEL ||
event_type == GDK_GRAB_BROKEN)
return GTK_EVENT_HANDLE;
return GTK_EVENT_SKIP;
}
static gboolean
@@ -614,6 +666,7 @@ gtk_gesture_handle_event (GtkEventController *controller,
GdkTouchpadGesturePhase phase = 0;
GdkModifierType state;
GtkWidget *target;
gboolean was_scrolling, is_scroll_stop;
source_device = gdk_event_get_device (event);
@@ -628,6 +681,19 @@ gtk_gesture_handle_event (GtkEventController *controller,
if (EVENT_IS_TOUCHPAD_GESTURE (event))
phase = gdk_touchpad_event_get_gesture_phase (event);
if (event_type == GDK_SCROLL)
{
GdkInputSource source = gdk_device_get_source (source_device);
if (source != GDK_SOURCE_TOUCHPAD &&
source != GDK_SOURCE_TRACKPOINT)
return FALSE;
is_scroll_stop = gdk_scroll_event_is_stop (event);
was_scrolling = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (source_device),
"gtk-gesture-is-device-scrolling"));
}
target = gtk_event_controller_get_target (controller);
if (gtk_gesture_get_sequence_state (gesture, sequence) != GTK_EVENT_SEQUENCE_DENIED)
@@ -636,7 +702,8 @@ gtk_gesture_handle_event (GtkEventController *controller,
if (event_type == GDK_BUTTON_PRESS ||
event_type == GDK_TOUCH_BEGIN ||
(event_type == GDK_TOUCHPAD_SWIPE && phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) ||
(event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN))
(event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) ||
(event_type == GDK_SCROLL && !priv->scrolling && !is_scroll_stop && !was_scrolling))
{
if (_gtk_gesture_update_point (gesture, event, target, x, y, TRUE))
{
@@ -668,7 +735,8 @@ gtk_gesture_handle_event (GtkEventController *controller,
else if (event_type == GDK_BUTTON_RELEASE ||
event_type == GDK_TOUCH_END ||
(event_type == GDK_TOUCHPAD_SWIPE && phase == GDK_TOUCHPAD_GESTURE_PHASE_END) ||
(event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_END))
(event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_END) ||
(event_type == GDK_SCROLL && priv->scrolling && is_scroll_stop))
{
gboolean was_claimed = FALSE;
@@ -689,7 +757,8 @@ gtk_gesture_handle_event (GtkEventController *controller,
else if (event_type == GDK_MOTION_NOTIFY ||
event_type == GDK_TOUCH_UPDATE ||
(event_type == GDK_TOUCHPAD_SWIPE && phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE) ||
(event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE))
(event_type == GDK_TOUCHPAD_PINCH && phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE) ||
(event_type == GDK_SCROLL && priv->scrolling))
{
if (event_type == GDK_MOTION_NOTIFY)
{
@@ -703,7 +772,7 @@ gtk_gesture_handle_event (GtkEventController *controller,
}
else if (event_type == GDK_TOUCH_CANCEL)
{
if (!priv->touchpad)
if (!priv->touchpad && !priv->scrolling)
_gtk_gesture_cancel_sequence (gesture, sequence);
}
else if ((event_type == GDK_TOUCHPAD_SWIPE && phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL) ||
@@ -1051,6 +1120,15 @@ gtk_gesture_set_sequence_state (GtkGesture *gesture,
current_state == GTK_EVENT_SEQUENCE_CLAIMED)
_gtk_gesture_cancel_sequence (gesture, sequence);
if (priv->scrolling && state == GTK_EVENT_SEQUENCE_CLAIMED)
{
GdkDevice *source_device = gdk_event_get_device (data->event);
g_object_set_data (G_OBJECT (source_device),
"gtk-gesture-is-device-scrolling",
GINT_TO_POINTER (TRUE));
}
gtk_widget_cancel_event_sequence (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)),
gesture, sequence, state);
g_signal_emit (gesture, signals[SEQUENCE_STATE_CHANGED], 0,
@@ -1383,7 +1461,8 @@ gtk_gesture_get_bounding_box_center (GtkGesture *gesture,
sequence = gtk_gesture_get_last_updated_sequence (gesture);
last_event = gtk_gesture_get_last_event (gesture, sequence);
if (EVENT_IS_TOUCHPAD_GESTURE (last_event))
if (EVENT_IS_TOUCHPAD_GESTURE (last_event) ||
gdk_event_get_event_type (last_event) == GDK_SCROLL)
return gtk_gesture_get_point (gesture, sequence, x, y);
else if (!gtk_gesture_get_bounding_box (gesture, &rect))
return FALSE;

View File

@@ -58,12 +58,14 @@ static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureDrag, gtk_gesture_drag, GTK_TYPE_GESTURE_SINGLE)
static gboolean
static GtkFilterEventStatus
gtk_gesture_drag_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
/* Let touchpad swipe events go through, only if they match n-points */
if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_SWIPE)
if (event_type == GDK_TOUCHPAD_SWIPE)
{
guint n_points;
guint n_fingers;
@@ -72,11 +74,14 @@ gtk_gesture_drag_filter_event (GtkEventController *controller,
n_fingers = gdk_touchpad_event_get_n_fingers (event);
if (n_fingers == n_points)
return FALSE;
return GTK_EVENT_HANDLE;
else
return TRUE;
return GTK_EVENT_SKIP;
}
if (event_type == GDK_SCROLL)
return GTK_EVENT_HANDLE;
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_drag_parent_class)->filter_event (controller, event);
}

View File

@@ -168,7 +168,7 @@ gtk_gesture_rotate_update (GtkGesture *gesture,
_gtk_gesture_rotate_check_emit (GTK_GESTURE_ROTATE (gesture));
}
static gboolean
static GtkFilterEventStatus
gtk_gesture_rotate_filter_event (GtkEventController *controller,
GdkEvent *event)
{
@@ -180,9 +180,9 @@ gtk_gesture_rotate_filter_event (GtkEventController *controller,
n_fingers = gdk_touchpad_event_get_n_fingers (event);
if (n_fingers == 2)
return FALSE;
return GTK_EVENT_HANDLE;
else
return TRUE;
return GTK_EVENT_SKIP;
}
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_rotate_parent_class)->filter_event (controller, event);

View File

@@ -196,10 +196,14 @@ gtk_gesture_single_handle_event (GtkEventController *controller,
}
}
if (button == 0)
return FALSE;
break;
case GDK_TOUCH_CANCEL:
case GDK_GRAB_BROKEN:
case GDK_TOUCHPAD_SWIPE:
case GDK_SCROLL:
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_single_parent_class)->handle_event (controller, event, x, y);
break;
default:

View File

@@ -58,6 +58,7 @@ struct _EventData
struct _GtkGestureSwipePrivate
{
GArray *events;
gboolean cancelled;
};
enum {
@@ -80,12 +81,14 @@ gtk_gesture_swipe_finalize (GObject *object)
G_OBJECT_CLASS (gtk_gesture_swipe_parent_class)->finalize (object);
}
static gboolean
static GtkFilterEventStatus
gtk_gesture_swipe_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
/* Let touchpad swipe events go through, only if they match n-points */
if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_SWIPE)
if (event_type == GDK_TOUCHPAD_SWIPE)
{
guint n_points;
guint n_fingers;
@@ -95,11 +98,14 @@ gtk_gesture_swipe_filter_event (GtkEventController *controller,
n_fingers = gdk_touchpad_event_get_n_fingers (event);
if (n_fingers == n_points)
return FALSE;
return GTK_EVENT_HANDLE;
else
return TRUE;
return GTK_EVENT_SKIP;
}
if (event_type == GDK_SCROLL)
return GTK_EVENT_HANDLE;
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_swipe_parent_class)->filter_event (controller, event);
}
@@ -148,6 +154,16 @@ gtk_gesture_swipe_append_event (GtkGestureSwipe *swipe,
g_array_append_val (priv->events, new);
}
static void
gtk_gesture_swipe_begin (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureSwipe *swipe = GTK_GESTURE_SWIPE (gesture);
GtkGestureSwipePrivate *priv = gtk_gesture_swipe_get_instance_private (swipe);
priv->cancelled = FALSE;
}
static void
gtk_gesture_swipe_update (GtkGesture *gesture,
GdkEventSequence *sequence)
@@ -198,10 +214,13 @@ gtk_gesture_swipe_end (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureSwipe *swipe = GTK_GESTURE_SWIPE (gesture);
GtkGestureSwipePrivate *priv;
GtkGestureSwipePrivate *priv = gtk_gesture_swipe_get_instance_private (swipe);
double velocity_x, velocity_y;
GdkEventSequence *seq;
if (priv->cancelled)
return;
seq = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (gtk_gesture_get_sequence_state (gesture, seq) == GTK_EVENT_SEQUENCE_DENIED)
@@ -212,7 +231,6 @@ gtk_gesture_swipe_end (GtkGesture *gesture,
gtk_gesture_swipe_append_event (swipe, sequence);
priv = gtk_gesture_swipe_get_instance_private (swipe);
_gtk_gesture_swipe_calculate_velocity (swipe, &velocity_x, &velocity_y);
g_signal_emit (gesture, signals[SWIPE], 0, velocity_x, velocity_y);
@@ -220,6 +238,18 @@ gtk_gesture_swipe_end (GtkGesture *gesture,
g_array_remove_range (priv->events, 0, priv->events->len);
}
static void
gtk_gesture_swipe_cancel (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureSwipe *swipe = GTK_GESTURE_SWIPE (gesture);
GtkGestureSwipePrivate *priv = gtk_gesture_swipe_get_instance_private (swipe);
priv->cancelled = TRUE;
GTK_GESTURE_CLASS (gtk_gesture_swipe_parent_class)->cancel (gesture, sequence);
}
static void
gtk_gesture_swipe_class_init (GtkGestureSwipeClass *klass)
{
@@ -231,8 +261,10 @@ gtk_gesture_swipe_class_init (GtkGestureSwipeClass *klass)
event_controller_class->filter_event = gtk_gesture_swipe_filter_event;
gesture_class->begin = gtk_gesture_swipe_begin;
gesture_class->update = gtk_gesture_swipe_update;
gesture_class->end = gtk_gesture_swipe_end;
gesture_class->cancel = gtk_gesture_swipe_cancel;
/**
* GtkGestureSwipe::swipe:

View File

@@ -145,7 +145,7 @@ _gtk_gesture_zoom_check_emit (GtkGestureZoom *gesture)
return TRUE;
}
static gboolean
static GtkFilterEventStatus
gtk_gesture_zoom_filter_event (GtkEventController *controller,
GdkEvent *event)
{
@@ -157,9 +157,9 @@ gtk_gesture_zoom_filter_event (GtkEventController *controller,
n_fingers = gdk_touchpad_event_get_n_fingers (event);
if (n_fingers == 2)
return FALSE;
return GTK_EVENT_HANDLE;
else
return TRUE;
return GTK_EVENT_SKIP;
}
return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_zoom_parent_class)->filter_event (controller, event);

View File

@@ -198,7 +198,7 @@ gtk_pad_controller_handle_mode_switch (GtkPadController *controller,
#endif
}
static gboolean
static GtkFilterEventStatus
gtk_pad_controller_filter_event (GtkEventController *controller,
GdkEvent *event)
{
@@ -210,13 +210,13 @@ gtk_pad_controller_filter_event (GtkEventController *controller,
event_type != GDK_PAD_RING &&
event_type != GDK_PAD_STRIP &&
event_type != GDK_PAD_GROUP_MODE)
return TRUE;
return GTK_EVENT_SKIP;
if (pad_controller->pad &&
gdk_event_get_device (event) != pad_controller->pad)
return TRUE;
return GTK_EVENT_SKIP;
return FALSE;
return GTK_EVENT_HANDLE;
}
static gboolean

View File

@@ -32,7 +32,7 @@
#include "gtkcolorscaleprivate.h"
#include "gtkenums.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkeventcontrollerwheel.h"
#include "gtkgesturedrag.h"
#include "gtkgesturelongpressprivate.h"
#include "gtkgestureclick.h"
@@ -237,10 +237,10 @@ static void gtk_range_allocate_trough (GtkGizmo *gi
static void gtk_range_render_trough (GtkGizmo *gizmo,
GtkSnapshot *snapshot);
static gboolean gtk_range_scroll_controller_scroll (GtkEventControllerScroll *scroll,
double dx,
double dy,
GtkRange *range);
static gboolean gtk_range_scroll_controller_scroll (GtkEventControllerWheel *controller,
double dx,
double dy,
GtkRange *range);
static void gtk_range_set_orientation (GtkRange *range,
GtkOrientation orientation);
@@ -583,7 +583,7 @@ gtk_range_init (GtkRange *range)
gtk_widget_add_controller (GTK_WIDGET (range), GTK_EVENT_CONTROLLER (gesture));
gtk_gesture_group (gesture, priv->drag_gesture);
controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES);
controller = gtk_event_controller_wheel_new ();
g_signal_connect (controller, "scroll",
G_CALLBACK (gtk_range_scroll_controller_scroll), range);
gtk_widget_add_controller (GTK_WIDGET (range), controller);
@@ -2196,10 +2196,10 @@ stop_scrolling (GtkRange *range)
}
static gboolean
gtk_range_scroll_controller_scroll (GtkEventControllerScroll *scroll,
double dx,
double dy,
GtkRange *range)
gtk_range_scroll_controller_scroll (GtkEventControllerWheel *controller,
double dx,
double dy,
GtkRange *range)
{
GtkRangePrivate *priv = gtk_range_get_instance_private (range);
double scroll_unit, delta;
@@ -2282,8 +2282,9 @@ gtk_range_drag_gesture_update (GtkGestureDrag *gesture,
{
GtkRangePrivate *priv = gtk_range_get_instance_private (range);
double start_x, start_y;
gboolean scroll = gdk_event_get_event_type (gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture))) == GDK_SCROLL;
if (priv->grab_location == priv->slider_widget)
if (priv->grab_location == priv->slider_widget || scroll)
{
int mouse_x, mouse_y;
@@ -2293,7 +2294,7 @@ gtk_range_drag_gesture_update (GtkGestureDrag *gesture,
priv->in_drag = TRUE;
update_autoscroll_mode (range, mouse_x, mouse_y);
if (priv->autoscroll_mode == GTK_SCROLL_NONE)
if (priv->autoscroll_mode == GTK_SCROLL_NONE || scroll)
update_slider_position (range, mouse_x, mouse_y);
}
}
@@ -2306,7 +2307,8 @@ gtk_range_drag_gesture_begin (GtkGestureDrag *gesture,
{
GtkRangePrivate *priv = gtk_range_get_instance_private (range);
if (priv->grab_location == priv->slider_widget)
if (priv->grab_location == priv->slider_widget ||
gdk_event_get_event_type (gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture))) == GDK_SCROLL)
gtk_gesture_set_state (priv->drag_gesture, GTK_EVENT_SEQUENCE_CLAIMED);
}

View File

@@ -31,8 +31,8 @@
#include "gtkbuildable.h"
#include "gtkdragsourceprivate.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkeventcontrollerprivate.h"
#include "gtkeventcontrollerwheel.h"
#include "gtkgesturedrag.h"
#include "gtkgesturelongpress.h"
#include "gtkgesturepan.h"
@@ -265,7 +265,6 @@ typedef struct
guint auto_added_viewport : 1;
guint propagate_natural_width : 1;
guint propagate_natural_height : 1;
guint smooth_scroll : 1;
int min_content_width;
int min_content_height;
@@ -287,9 +286,12 @@ typedef struct
double drag_start_x;
double drag_start_y;
double last_drag_offset_x;
double last_drag_offset_y;
guint kinetic_scrolling : 1;
guint in_drag : 1;
guint drag_active : 1;
guint deceleration_id;
@@ -401,10 +403,8 @@ static void indicator_start_fade (Indicator *indicator,
static void indicator_set_over (Indicator *indicator,
gboolean over);
static void scrolled_window_scroll (GtkScrolledWindow *scrolled_window,
double delta_x,
double delta_y,
GtkEventControllerScroll *scroll);
static double get_scroll_unit (GtkScrolledWindow *sw,
GtkOrientation orientation);
static guint signals[LAST_SIGNAL] = {0};
static GParamSpec *properties[NUM_PROPERTIES];
@@ -953,7 +953,8 @@ scrolled_window_drag_begin_cb (GtkScrolledWindow *scrolled_window,
priv->in_drag = FALSE;
priv->drag_start_x = priv->unclamped_hadj_value;
priv->drag_start_y = priv->unclamped_vadj_value;
gtk_scrolled_window_cancel_deceleration (scrolled_window);
priv->last_drag_offset_x = 0;
priv->last_drag_offset_y = 0;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
event_widget = gtk_gesture_get_last_target (gesture, sequence);
@@ -991,10 +992,21 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
GtkAdjustment *hadjustment;
GtkAdjustment *vadjustment;
double dx, dy;
GdkEventType event_type;
gboolean scroll;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
event_type = gdk_event_get_event_type (gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture)));
scroll = event_type == GDK_SCROLL;
if (gtk_gesture_get_sequence_state (gesture, sequence) != GTK_EVENT_SEQUENCE_CLAIMED &&
if (!priv->drag_active)
{
gtk_scrolled_window_cancel_deceleration (scrolled_window);
priv->drag_active = TRUE;
}
if (!scroll &&
gtk_gesture_get_sequence_state (gesture, sequence) != GTK_EVENT_SEQUENCE_CLAIMED &&
!gtk_drag_check_threshold_double (GTK_WIDGET (scrolled_window),
0, 0, offset_x, offset_y))
return;
@@ -1005,7 +1017,15 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
hadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
if (hadjustment && may_hscroll (scrolled_window))
{
dx = priv->drag_start_x - offset_x;
if (scroll)
{
double scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
dx = priv->unclamped_hadj_value - (offset_x - priv->last_drag_offset_x) * scroll_unit;
}
else
dx = priv->drag_start_x - offset_x;
_gtk_scrolled_window_set_adjustment_value (scrolled_window,
hadjustment, dx);
}
@@ -1013,12 +1033,23 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
vadjustment = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
if (vadjustment && may_vscroll (scrolled_window))
{
dy = priv->drag_start_y - offset_y;
if (scroll)
{
double scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
dy = priv->unclamped_vadj_value - (offset_y - priv->last_drag_offset_y) * scroll_unit;
}
else
dy = priv->drag_start_y - offset_y;
_gtk_scrolled_window_set_adjustment_value (scrolled_window,
vadjustment, dy);
}
gtk_scrolled_window_invalidate_overshoot (scrolled_window);
priv->last_drag_offset_x = offset_x;
priv->last_drag_offset_y = offset_y;
}
static void
@@ -1030,6 +1061,8 @@ scrolled_window_drag_end_cb (GtkScrolledWindow *scrolled_window,
if (!priv->in_drag || !gtk_gesture_handles_sequence (gesture, sequence))
gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
priv->drag_active = FALSE;
}
static void
@@ -1060,9 +1093,23 @@ gtk_scrolled_window_decelerate (GtkScrolledWindow *scrolled_window,
static void
scrolled_window_swipe_cb (GtkScrolledWindow *scrolled_window,
double x_velocity,
double y_velocity)
double y_velocity,
GtkGesture *gesture)
{
gtk_scrolled_window_decelerate (scrolled_window, -x_velocity, -y_velocity);
double unit_x, unit_y;
GdkEventType event_type;
event_type = gdk_event_get_event_type (gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (gesture)));
if (event_type == GDK_SCROLL)
{
unit_x = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
unit_y = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
}
else
unit_x = unit_y = 1.0;
gtk_scrolled_window_decelerate (scrolled_window, -x_velocity * unit_x, -y_velocity * unit_y);
}
static void
@@ -1254,26 +1301,6 @@ get_scroll_unit (GtkScrolledWindow *sw,
return scroll_unit;
}
static gboolean
captured_scroll_cb (GtkEventControllerScroll *scroll,
double delta_x,
double delta_y,
GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv =
gtk_scrolled_window_get_instance_private (scrolled_window);
gtk_scrolled_window_cancel_deceleration (scrolled_window);
if (priv->smooth_scroll)
{
scrolled_window_scroll (scrolled_window, delta_x, delta_y, scroll);
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
static void
captured_motion (GtkEventController *controller,
double x,
@@ -1341,29 +1368,21 @@ start_scroll_deceleration_cb (gpointer user_data)
return FALSE;
}
static void
scroll_controller_scroll_begin (GtkEventControllerScroll *scroll,
GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
priv->smooth_scroll = TRUE;
}
static void
scrolled_window_scroll (GtkScrolledWindow *scrolled_window,
double delta_x,
double delta_y,
GtkEventControllerScroll *scroll)
static gboolean
scroll_controller_scroll (GtkEventControllerWheel *controller,
double delta_x,
double delta_y,
GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv =
gtk_scrolled_window_get_instance_private (scrolled_window);
gboolean shifted;
GdkModifierType state;
state = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (scroll));
state = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (controller));
shifted = (state & GDK_SHIFT_MASK) != 0;
gtk_scrolled_window_cancel_deceleration (scrolled_window);
gtk_scrolled_window_invalidate_overshoot (scrolled_window);
if (shifted)
@@ -1407,72 +1426,17 @@ scrolled_window_scroll (GtkScrolledWindow *scrolled_window,
g_clear_handle_id (&priv->scroll_events_overshoot_id, g_source_remove);
if (!priv->smooth_scroll &&
_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
{
priv->scroll_events_overshoot_id =
g_timeout_add (50, start_scroll_deceleration_cb, scrolled_window);
gdk_source_set_static_name_by_id (priv->scroll_events_overshoot_id,
"[gtk] start_scroll_deceleration_cb");
}
}
static gboolean
scroll_controller_scroll (GtkEventControllerScroll *scroll,
double delta_x,
double delta_y,
GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv =
gtk_scrolled_window_get_instance_private (scrolled_window);
if (!priv->smooth_scroll)
scrolled_window_scroll (scrolled_window, delta_x, delta_y, scroll);
return GDK_EVENT_STOP;
}
static void
scroll_controller_scroll_end (GtkEventControllerScroll *scroll,
GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
priv->smooth_scroll = FALSE;
}
static void
scroll_controller_decelerate (GtkEventControllerScroll *scroll,
double initial_vel_x,
double initial_vel_y,
GtkScrolledWindow *scrolled_window)
{
double unit_x, unit_y;
gboolean shifted;
GdkModifierType state;
state = gtk_event_controller_get_current_event_state (GTK_EVENT_CONTROLLER (scroll));
shifted = (state & GDK_SHIFT_MASK) != 0;
unit_x = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
unit_y = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
if (shifted)
{
gtk_scrolled_window_decelerate (scrolled_window,
initial_vel_y * unit_x,
initial_vel_x * unit_y);
}
else
{
gtk_scrolled_window_decelerate (scrolled_window,
initial_vel_x * unit_x,
initial_vel_y * unit_y);
}
}
static void
gtk_scrolled_window_update_scrollbar_visibility_flags (GtkScrolledWindow *scrolled_window,
GtkWidget *scrollbar)
@@ -2102,23 +2066,9 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
gtk_css_node_set_state (priv->junction_node, gtk_css_node_get_state (widget_node));
g_object_unref (priv->junction_node);
controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES |
GTK_EVENT_CONTROLLER_SCROLL_KINETIC);
g_signal_connect (controller, "scroll-begin",
G_CALLBACK (scroll_controller_scroll_begin), scrolled_window);
controller = gtk_event_controller_wheel_new ();
g_signal_connect (controller, "scroll",
G_CALLBACK (scroll_controller_scroll), scrolled_window);
g_signal_connect (controller, "scroll-end",
G_CALLBACK (scroll_controller_scroll_end), scrolled_window);
gtk_widget_add_controller (widget, controller);
controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES |
GTK_EVENT_CONTROLLER_SCROLL_KINETIC);
gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
g_signal_connect (controller, "scroll",
G_CALLBACK (captured_scroll_cb), scrolled_window);
g_signal_connect (controller, "decelerate",
G_CALLBACK (scroll_controller_decelerate), scrolled_window);
gtk_widget_add_controller (widget, controller);
controller = gtk_event_controller_motion_new ();

View File

@@ -422,6 +422,18 @@ gtk_shortcut_controller_run_controllers (GtkEventController *controller,
return retval;
}
static GtkFilterEventStatus
gtk_shortcut_controller_filter_event (GtkEventController *controller,
GdkEvent *event)
{
GdkEventType event_type = gdk_event_get_event_type (event);
if (event_type == GDK_KEY_PRESS || event_type == GDK_KEY_RELEASE)
return GTK_EVENT_HANDLE;
return GTK_EVENT_SKIP;
}
static gboolean
gtk_shortcut_controller_handle_event (GtkEventController *controller,
GdkEvent *event,
@@ -435,9 +447,6 @@ gtk_shortcut_controller_handle_event (GtkEventController *controller,
if (self->scope != GTK_SHORTCUT_SCOPE_LOCAL)
return FALSE;
if (event_type != GDK_KEY_PRESS && event_type != GDK_KEY_RELEASE)
return FALSE;
if (event_type == GDK_KEY_PRESS)
{
GdkModifierType modifiers, consumed_modifiers;
@@ -558,6 +567,7 @@ gtk_shortcut_controller_class_init (GtkShortcutControllerClass *klass)
object_class->set_property = gtk_shortcut_controller_set_property;
object_class->get_property = gtk_shortcut_controller_get_property;
controller_class->filter_event = gtk_shortcut_controller_filter_event;
controller_class->handle_event = gtk_shortcut_controller_handle_event;
controller_class->set_widget = gtk_shortcut_controller_set_widget;
controller_class->unset_widget = gtk_shortcut_controller_unset_widget;

View File

@@ -240,6 +240,7 @@ gtk_public_sources = files([
'gtkeventcontrollerlegacy.c',
'gtkeventcontrollermotion.c',
'gtkeventcontrollerscroll.c',
'gtkeventcontrollerwheel.c',
'gtkexpander.c',
'gtkexpression.c',
'gtkfilechooser.c',
@@ -529,6 +530,7 @@ gtk_public_headers = files([
'gtkeventcontrollerscroll.h',
'gtkeventcontrollermotion.h',
'gtkeventcontrollerlegacy.h',
'gtkeventcontrollerwheel.h',
'gtkexpander.h',
'gtkexpression.h',
'gtkfilechooser.h',