Implement gesture processing logic
This commit is contained in:
parent
d3c52df161
commit
5163fc8bc2
174
Xi/exevents.c
174
Xi/exevents.c
|
@ -1743,6 +1743,67 @@ ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
|
||||||
free(ev);
|
free(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
IsAnotherGestureActiveOnMaster(DeviceIntPtr dev, InternalEvent* ev)
|
||||||
|
{
|
||||||
|
GestureClassPtr g = dev->gesture;
|
||||||
|
if (g->gesture.active && g->gesture.sourceid != ev->gesture_event.sourceid) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes and delivers a Gesture{Pinch,Swipe}{Begin,Update,End}.
|
||||||
|
*
|
||||||
|
* Due to having rather different delivery semantics (see the Xi 2.4 protocol
|
||||||
|
* spec for more information), this implements its own grab and event-selection
|
||||||
|
* delivery logic.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ProcessGestureEvent(InternalEvent *ev, DeviceIntPtr dev)
|
||||||
|
{
|
||||||
|
GestureInfoPtr gi;
|
||||||
|
DeviceIntPtr kbd;
|
||||||
|
Bool deactivateGestureGrab = FALSE;
|
||||||
|
|
||||||
|
if (!dev->gesture)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsMaster(dev) && IsAnotherGestureActiveOnMaster(dev, ev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsGestureBeginEvent(ev))
|
||||||
|
gi = GestureBeginGesture(dev, ev);
|
||||||
|
else
|
||||||
|
gi = GestureFindActiveByEventType(dev, ev->any.type);
|
||||||
|
|
||||||
|
if (!gi) {
|
||||||
|
/* This may happen if gesture is no longer active or was never started. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
|
||||||
|
event_set_state_gesture(kbd, &ev->gesture_event);
|
||||||
|
|
||||||
|
if (IsGestureBeginEvent(ev))
|
||||||
|
GestureSetupListener(dev, gi, ev);
|
||||||
|
|
||||||
|
if (IsGestureEndEvent(ev) &&
|
||||||
|
dev->deviceGrab.grab &&
|
||||||
|
dev->deviceGrab.fromPassiveGrab &&
|
||||||
|
GrabIsGestureGrab(dev->deviceGrab.grab))
|
||||||
|
deactivateGestureGrab = TRUE;
|
||||||
|
|
||||||
|
DeliverGestureEventToOwner(dev, gi, ev);
|
||||||
|
|
||||||
|
if (IsGestureEndEvent(ev))
|
||||||
|
GestureEndGesture(gi);
|
||||||
|
|
||||||
|
if (deactivateGestureGrab)
|
||||||
|
(*dev->deviceGrab.DeactivateGrab) (dev);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process DeviceEvents and DeviceChangedEvents.
|
* Process DeviceEvents and DeviceChangedEvents.
|
||||||
*/
|
*/
|
||||||
|
@ -1937,6 +1998,14 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
|
||||||
case ET_BarrierLeave:
|
case ET_BarrierLeave:
|
||||||
ProcessBarrierEvent(ev, device);
|
ProcessBarrierEvent(ev, device);
|
||||||
break;
|
break;
|
||||||
|
case ET_GesturePinchBegin:
|
||||||
|
case ET_GesturePinchUpdate:
|
||||||
|
case ET_GesturePinchEnd:
|
||||||
|
case ET_GestureSwipeBegin:
|
||||||
|
case ET_GestureSwipeUpdate:
|
||||||
|
case ET_GestureSwipeEnd:
|
||||||
|
ProcessGestureEvent(ev, device);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ProcessDeviceEvent(ev, device);
|
ProcessDeviceEvent(ev, device);
|
||||||
break;
|
break;
|
||||||
|
@ -2141,6 +2210,111 @@ DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to deliver a gesture event to the given client.
|
||||||
|
*/
|
||||||
|
static Bool
|
||||||
|
DeliverOneGestureEvent(ClientPtr client, DeviceIntPtr dev, GestureInfoPtr gi,
|
||||||
|
GrabPtr grab, WindowPtr win, InternalEvent *ev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
xEvent *xi2;
|
||||||
|
Mask filter;
|
||||||
|
Window child = DeepestSpriteWin(&gi->sprite)->drawable.id;
|
||||||
|
|
||||||
|
/* If we fail here, we're going to leave a client hanging. */
|
||||||
|
err = EventToXI2(ev, &xi2);
|
||||||
|
if (err != Success)
|
||||||
|
FatalError("[Xi] %s: XI2 conversion failed in %s"
|
||||||
|
" (%d)\n", dev->name, __func__, err);
|
||||||
|
|
||||||
|
FixUpEventFromWindow(&gi->sprite, xi2, win, child, FALSE);
|
||||||
|
filter = GetEventFilter(dev, xi2);
|
||||||
|
if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
|
||||||
|
return FALSE;
|
||||||
|
err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
|
||||||
|
free(xi2);
|
||||||
|
|
||||||
|
/* Returning the value from TryClientEvents isn't useful, since all our
|
||||||
|
* resource-gone cleanups will update the delivery list anyway. */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a gesture event and a potential listener, retrieve info needed for processing the event.
|
||||||
|
*
|
||||||
|
* @param dev The device generating the gesture event.
|
||||||
|
* @param ev The gesture event to process.
|
||||||
|
* @param listener The gesture event listener that may receive the gesture event.
|
||||||
|
* @param[out] client The client that should receive the gesture event.
|
||||||
|
* @param[out] win The window to deliver the event on.
|
||||||
|
* @param[out] grab The grab to deliver the event through, if any.
|
||||||
|
* @return TRUE if an event should be delivered to the listener, FALSE
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
static Bool
|
||||||
|
RetrieveGestureDeliveryData(DeviceIntPtr dev, InternalEvent *ev, GestureListener* listener,
|
||||||
|
ClientPtr *client, WindowPtr *win, GrabPtr *grab)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int evtype;
|
||||||
|
InputClients *iclients = NULL;
|
||||||
|
*grab = NULL;
|
||||||
|
|
||||||
|
if (listener->type == GESTURE_LISTENER_GRAB ||
|
||||||
|
listener->type == GESTURE_LISTENER_NONGESTURE_GRAB) {
|
||||||
|
*grab = listener->grab;
|
||||||
|
|
||||||
|
BUG_RETURN_VAL(!*grab, FALSE);
|
||||||
|
|
||||||
|
*client = rClient(*grab);
|
||||||
|
*win = (*grab)->window;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rc = dixLookupResourceByType((void **) win, listener->listener, listener->resource_type,
|
||||||
|
serverClient, DixSendAccess);
|
||||||
|
if (rc != Success)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* note that we only will have XI2 listeners as
|
||||||
|
listener->type == GESTURE_LISTENER_REGULAR */
|
||||||
|
evtype = GetXI2Type(ev->any.type);
|
||||||
|
|
||||||
|
nt_list_for_each_entry(iclients, wOtherInputMasks(*win)->inputClients, next)
|
||||||
|
if (xi2mask_isset(iclients->xi2mask, dev, evtype))
|
||||||
|
break;
|
||||||
|
|
||||||
|
BUG_RETURN_VAL(!iclients, FALSE);
|
||||||
|
|
||||||
|
*client = rClient(iclients);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delivers a gesture to the owner, if possible and needed. Returns whether
|
||||||
|
* an event was delivered.
|
||||||
|
*/
|
||||||
|
Bool
|
||||||
|
DeliverGestureEventToOwner(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
|
||||||
|
{
|
||||||
|
GrabPtr grab = NULL;
|
||||||
|
ClientPtr client;
|
||||||
|
WindowPtr win;
|
||||||
|
|
||||||
|
if (!gi->has_listener || gi->listener.type == GESTURE_LISTENER_NONGESTURE_GRAB) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RetrieveGestureDeliveryData(dev, ev, &gi->listener, &client, &win, &grab))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ev->gesture_event.deviceid = dev->id;
|
||||||
|
|
||||||
|
return DeliverOneGestureEvent(client, dev, gi, grab, win, ev);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
InitProximityClassDeviceStruct(DeviceIntPtr dev)
|
InitProximityClassDeviceStruct(DeviceIntPtr dev)
|
||||||
{
|
{
|
||||||
|
|
|
@ -458,6 +458,7 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
TouchEndPhysicallyActiveTouches(dev);
|
TouchEndPhysicallyActiveTouches(dev);
|
||||||
|
GestureEndActiveGestures(dev);
|
||||||
ReleaseButtonsAndKeys(dev);
|
ReleaseButtonsAndKeys(dev);
|
||||||
SyncRemoveDeviceIdleTime(dev->idle_counter);
|
SyncRemoveDeviceIdleTime(dev->idle_counter);
|
||||||
dev->idle_counter = NULL;
|
dev->idle_counter = NULL;
|
||||||
|
|
|
@ -3487,6 +3487,7 @@ CloseDownClient(ClientPtr client)
|
||||||
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
|
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
|
||||||
}
|
}
|
||||||
TouchListenerGone(client->clientAsMask);
|
TouchListenerGone(client->clientAsMask);
|
||||||
|
GestureListenerGone(client->clientAsMask);
|
||||||
FreeClientResources(client);
|
FreeClientResources(client);
|
||||||
/* Disable client ID tracking. This must be done after
|
/* Disable client ID tracking. This must be done after
|
||||||
* ClientStateCallback. */
|
* ClientStateCallback. */
|
||||||
|
|
60
dix/events.c
60
dix/events.c
|
@ -1328,6 +1328,15 @@ ComputeFreezes(void)
|
||||||
|
|
||||||
TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
|
TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
|
||||||
}
|
}
|
||||||
|
else if (IsGestureEvent(event)) {
|
||||||
|
GestureInfoPtr gi =
|
||||||
|
GestureFindActiveByEventType(replayDev, event->any.type);
|
||||||
|
if (gi) {
|
||||||
|
GestureEmitGestureEndToOwner(replayDev, gi);
|
||||||
|
GestureEndGesture(gi);
|
||||||
|
}
|
||||||
|
ProcessGestureEvent(event, replayDev);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
WindowPtr w = XYToWindow(replayDev->spriteInfo->sprite,
|
WindowPtr w = XYToWindow(replayDev->spriteInfo->sprite,
|
||||||
event->device_event.root_x,
|
event->device_event.root_x,
|
||||||
|
@ -1509,6 +1518,46 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update gesture records when an explicit grab is activated. Any gestures owned
|
||||||
|
* by the grabbing client are updated so the listener state reflects the new
|
||||||
|
* grab.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
UpdateGesturesForGrab(DeviceIntPtr mouse)
|
||||||
|
{
|
||||||
|
if (!mouse->gesture || mouse->deviceGrab.fromPassiveGrab)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GestureInfoPtr gi = &mouse->gesture->gesture;
|
||||||
|
GestureListener *listener = &gi->listener;
|
||||||
|
GrabPtr grab = mouse->deviceGrab.grab;
|
||||||
|
|
||||||
|
if (gi->active && CLIENT_BITS(listener->listener) == grab->resource) {
|
||||||
|
if (grab->grabtype == CORE || grab->grabtype == XI ||
|
||||||
|
!xi2mask_isset(grab->xi2mask, mouse, GetXI2Type(gi->type))) {
|
||||||
|
|
||||||
|
if (listener->type == GESTURE_LISTENER_REGULAR) {
|
||||||
|
/* if the listener already got any events relating to the gesture, we must send
|
||||||
|
a gesture end because the grab overrides the previous listener and won't
|
||||||
|
itself send any gesture events.
|
||||||
|
*/
|
||||||
|
GestureEmitGestureEndToOwner(mouse, gi);
|
||||||
|
}
|
||||||
|
listener->type = GESTURE_LISTENER_NONGESTURE_GRAB;
|
||||||
|
} else {
|
||||||
|
listener->type = GESTURE_LISTENER_GRAB;
|
||||||
|
}
|
||||||
|
|
||||||
|
listener->listener = grab->resource;
|
||||||
|
listener->window = grab->window;
|
||||||
|
|
||||||
|
if (listener->grab)
|
||||||
|
FreeGrab(listener->grab);
|
||||||
|
listener->grab = AllocGrab(grab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate a pointer grab on the given device. A pointer grab will cause all
|
* Activate a pointer grab on the given device. A pointer grab will cause all
|
||||||
* core pointer events of this device to be delivered to the grabbing client only.
|
* core pointer events of this device to be delivered to the grabbing client only.
|
||||||
|
@ -1559,6 +1608,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
|
||||||
grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
|
grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
|
||||||
PostNewCursor(mouse);
|
PostNewCursor(mouse);
|
||||||
UpdateTouchesForGrab(mouse);
|
UpdateTouchesForGrab(mouse);
|
||||||
|
UpdateGesturesForGrab(mouse);
|
||||||
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
|
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
|
||||||
(Bool) grab->keyboardMode);
|
(Bool) grab->keyboardMode);
|
||||||
if (oldgrab)
|
if (oldgrab)
|
||||||
|
@ -1614,6 +1664,16 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
|
||||||
if (dev->deviceGrab.sync.other == grab)
|
if (dev->deviceGrab.sync.other == grab)
|
||||||
dev->deviceGrab.sync.other = NullGrab;
|
dev->deviceGrab.sync.other = NullGrab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* in case of explicit gesture grab, send end event to the grab client */
|
||||||
|
if (!wasPassive && mouse->gesture) {
|
||||||
|
GestureInfoPtr gi = &mouse->gesture->gesture;
|
||||||
|
if (gi->active && GestureResourceIsOwner(gi, grab_resource)) {
|
||||||
|
GestureEmitGestureEndToOwner(mouse, gi);
|
||||||
|
GestureEndGesture(gi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DoEnterLeaveEvents(mouse, mouse->id, grab->window,
|
DoEnterLeaveEvents(mouse, mouse->id, grab->window,
|
||||||
mouse->spriteInfo->sprite->win, NotifyUngrab);
|
mouse->spriteInfo->sprite->win, NotifyUngrab);
|
||||||
if (grab->confineTo)
|
if (grab->confineTo)
|
||||||
|
|
305
dix/gestures.c
305
dix/gestures.c
|
@ -39,6 +39,8 @@
|
||||||
#include "windowstr.h"
|
#include "windowstr.h"
|
||||||
#include "mi.h"
|
#include "mi.h"
|
||||||
|
|
||||||
|
#define GESTURE_HISTORY_SIZE 100
|
||||||
|
|
||||||
Bool
|
Bool
|
||||||
GestureInitGestureInfo(GestureInfoPtr gi)
|
GestureInitGestureInfo(GestureInfoPtr gi)
|
||||||
{
|
{
|
||||||
|
@ -55,3 +57,306 @@ GestureInitGestureInfo(GestureInfoPtr gi)
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an event type returns the associated gesture event info.
|
||||||
|
*/
|
||||||
|
GestureInfoPtr
|
||||||
|
GestureFindActiveByEventType(DeviceIntPtr dev, int type)
|
||||||
|
{
|
||||||
|
GestureClassPtr g = dev->gesture;
|
||||||
|
enum EventType type_to_expect = GestureTypeToBegin(type);
|
||||||
|
|
||||||
|
if (!g || type_to_expect == 0 || !g->gesture.active ||
|
||||||
|
g->gesture.type != type_to_expect) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &g->gesture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up gesture info for a new gesture. Returns NULL on failure.
|
||||||
|
*/
|
||||||
|
GestureInfoPtr
|
||||||
|
GestureBeginGesture(DeviceIntPtr dev, InternalEvent *ev)
|
||||||
|
{
|
||||||
|
GestureClassPtr g = dev->gesture;
|
||||||
|
enum EventType gesture_type = GestureTypeToBegin(ev->any.type);
|
||||||
|
|
||||||
|
/* Note that we ignore begin events when an existing gesture is active */
|
||||||
|
if (!g || gesture_type == 0 || g->gesture.active)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g->gesture.type = gesture_type;
|
||||||
|
|
||||||
|
if (!GestureBuildSprite(dev, &g->gesture))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g->gesture.active = TRUE;
|
||||||
|
g->gesture.num_touches = ev->gesture_event.num_touches;
|
||||||
|
g->gesture.sourceid = ev->gesture_event.sourceid;
|
||||||
|
g->gesture.has_listener = FALSE;
|
||||||
|
return &g->gesture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases a gesture: this must only be called after all events
|
||||||
|
* related to that gesture have been sent and finalised.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
GestureEndGesture(GestureInfoPtr gi)
|
||||||
|
{
|
||||||
|
if (gi->has_listener) {
|
||||||
|
if (gi->listener.grab) {
|
||||||
|
FreeGrab(gi->listener.grab);
|
||||||
|
gi->listener.grab = NULL;
|
||||||
|
}
|
||||||
|
gi->listener.listener = 0;
|
||||||
|
gi->has_listener = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gi->active = FALSE;
|
||||||
|
gi->num_touches = 0;
|
||||||
|
gi->sprite.spriteTraceGood = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure a window trace is present in gi->sprite, constructing one for
|
||||||
|
* Gesture{Pinch,Swipe}Begin events.
|
||||||
|
*/
|
||||||
|
Bool
|
||||||
|
GestureBuildSprite(DeviceIntPtr sourcedev, GestureInfoPtr gi)
|
||||||
|
{
|
||||||
|
SpritePtr sprite = &gi->sprite;
|
||||||
|
|
||||||
|
if (!sourcedev->spriteInfo->sprite)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!CopySprite(sourcedev->spriteInfo->sprite, sprite))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (sprite->spriteTraceGood <= 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns TRUE if the specified grab or selection is the current owner of
|
||||||
|
* the gesture sequence.
|
||||||
|
*/
|
||||||
|
Bool
|
||||||
|
GestureResourceIsOwner(GestureInfoPtr gi, XID resource)
|
||||||
|
{
|
||||||
|
return (gi->listener.listener == resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GestureAddListener(GestureInfoPtr gi, XID resource, int resource_type,
|
||||||
|
enum GestureListenerType type, WindowPtr window, const GrabPtr grab)
|
||||||
|
{
|
||||||
|
GrabPtr g = NULL;
|
||||||
|
|
||||||
|
BUG_RETURN(gi->has_listener);
|
||||||
|
|
||||||
|
/* We need a copy of the grab, not the grab itself since that may be deleted by
|
||||||
|
* a UngrabButton request and leaves us with a dangling pointer */
|
||||||
|
if (grab)
|
||||||
|
g = AllocGrab(grab);
|
||||||
|
|
||||||
|
gi->listener.listener = resource;
|
||||||
|
gi->listener.resource_type = resource_type;
|
||||||
|
gi->listener.type = type;
|
||||||
|
gi->listener.window = window;
|
||||||
|
gi->listener.grab = g;
|
||||||
|
gi->has_listener = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GestureAddGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, GrabPtr grab)
|
||||||
|
{
|
||||||
|
enum GestureListenerType type;
|
||||||
|
|
||||||
|
/* FIXME: owner_events */
|
||||||
|
|
||||||
|
if (grab->grabtype == XI2) {
|
||||||
|
if (xi2mask_isset(grab->xi2mask, dev, XI_GesturePinchBegin) ||
|
||||||
|
xi2mask_isset(grab->xi2mask, dev, XI_GestureSwipeBegin)) {
|
||||||
|
type = GESTURE_LISTENER_GRAB;
|
||||||
|
} else
|
||||||
|
type = GESTURE_LISTENER_NONGESTURE_GRAB;
|
||||||
|
}
|
||||||
|
else if (grab->grabtype == XI || grab->grabtype == CORE) {
|
||||||
|
type = GESTURE_LISTENER_NONGESTURE_GRAB;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BUG_RETURN_MSG(1, "Unsupported grab type\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grab listeners are always RT_NONE since we keep the grab pointer */
|
||||||
|
GestureAddListener(gi, grab->resource, RT_NONE, type, grab->window, grab);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add one listener if there is a grab on the given window.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
GestureAddPassiveGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
|
||||||
|
{
|
||||||
|
Bool activate = FALSE;
|
||||||
|
Bool check_core = FALSE;
|
||||||
|
|
||||||
|
GrabPtr grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core,
|
||||||
|
activate);
|
||||||
|
if (!grab)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* We'll deliver later in gesture-specific code */
|
||||||
|
ActivateGrabNoDelivery(dev, grab, ev, ev);
|
||||||
|
GestureAddGrabListener(dev, gi, grab);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GestureAddRegularListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
|
||||||
|
{
|
||||||
|
InputClients *iclients = NULL;
|
||||||
|
OtherInputMasks *inputMasks = NULL;
|
||||||
|
uint16_t evtype = GetXI2Type(ev->any.type);
|
||||||
|
int mask;
|
||||||
|
|
||||||
|
mask = EventIsDeliverable(dev, ev->any.type, win);
|
||||||
|
if (!mask)
|
||||||
|
return;
|
||||||
|
|
||||||
|
inputMasks = wOtherInputMasks(win);
|
||||||
|
|
||||||
|
if (mask & EVENT_XI2_MASK) {
|
||||||
|
nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
|
||||||
|
if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
GestureAddListener(gi, iclients->resource, RT_INPUTCLIENT,
|
||||||
|
GESTURE_LISTENER_REGULAR, win, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
SpritePtr sprite = &gi->sprite;
|
||||||
|
WindowPtr win;
|
||||||
|
|
||||||
|
/* Any current grab will consume all gesture events */
|
||||||
|
if (dev->deviceGrab.grab) {
|
||||||
|
GestureAddGrabListener(dev, gi, dev->deviceGrab.grab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find passive grab that would be activated by this event, if any. If we're handling
|
||||||
|
* ReplayDevice then the search starts from the descendant of the grab window, otherwise
|
||||||
|
* the search starts at the root window. The search ends at deepest child window. */
|
||||||
|
i = 0;
|
||||||
|
if (syncEvents.playingEvents) {
|
||||||
|
while (i < dev->spriteInfo->sprite->spriteTraceGood) {
|
||||||
|
if (dev->spriteInfo->sprite->spriteTrace[i++] == syncEvents.replayWin)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < sprite->spriteTraceGood; i++) {
|
||||||
|
win = sprite->spriteTrace[i];
|
||||||
|
GestureAddPassiveGrabListener(dev, gi, win, ev);
|
||||||
|
if (gi->has_listener)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the first client with an applicable event selection,
|
||||||
|
* going from deepest child window back up to the root window. */
|
||||||
|
for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
|
||||||
|
win = sprite->spriteTrace[i];
|
||||||
|
GestureAddRegularListener(dev, gi, win, ev);
|
||||||
|
if (gi->has_listener)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As gesture grabs don't turn into active grabs with their own resources, we
|
||||||
|
* need to walk all the gestures and remove this grab from listener */
|
||||||
|
void
|
||||||
|
GestureListenerGone(XID resource)
|
||||||
|
{
|
||||||
|
GestureInfoPtr gi;
|
||||||
|
DeviceIntPtr dev;
|
||||||
|
InternalEvent *events = InitEventList(GetMaximumEventsNum());
|
||||||
|
|
||||||
|
if (!events)
|
||||||
|
FatalError("GestureListenerGone: couldn't allocate events\n");
|
||||||
|
|
||||||
|
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||||||
|
if (!dev->gesture)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
gi = &dev->gesture->gesture;
|
||||||
|
if (!gi->active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (CLIENT_BITS(gi->listener.listener) == resource)
|
||||||
|
GestureEndGesture(gi);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeEventList(events, GetMaximumEventsNum());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End physically active gestures for a device.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
GestureEndActiveGestures(DeviceIntPtr dev)
|
||||||
|
{
|
||||||
|
GestureClassPtr g = dev->gesture;
|
||||||
|
InternalEvent *eventlist;
|
||||||
|
|
||||||
|
if (!g)
|
||||||
|
return;
|
||||||
|
|
||||||
|
eventlist = InitEventList(GetMaximumEventsNum());
|
||||||
|
|
||||||
|
input_lock();
|
||||||
|
mieqProcessInputEvents();
|
||||||
|
if (g->gesture.active) {
|
||||||
|
int j;
|
||||||
|
int type = GetXI2Type(GestureTypeToEnd(g->gesture.type));
|
||||||
|
int nevents = GetGestureEvents(eventlist, dev, type, g->gesture.num_touches,
|
||||||
|
0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
for (j = 0; j < nevents; j++)
|
||||||
|
mieqProcessDeviceEvent(dev, eventlist + j, NULL);
|
||||||
|
}
|
||||||
|
input_unlock();
|
||||||
|
|
||||||
|
FreeEventList(eventlist, GetMaximumEventsNum());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate and deliver a Gesture{Pinch,Swipe}End event to the owner.
|
||||||
|
*
|
||||||
|
* @param dev The device to deliver the event for.
|
||||||
|
* @param gi The gesture record to deliver the event for.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi)
|
||||||
|
{
|
||||||
|
InternalEvent event;
|
||||||
|
/* We're not processing a gesture end for a frozen device */
|
||||||
|
if (dev->deviceGrab.sync.frozen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DeliverDeviceClassesChangedEvent(gi->sourceid, GetTimeInMillis());
|
||||||
|
InitGestureEvent(&event, dev, GetTimeInMillis(), GestureTypeToEnd(gi->type),
|
||||||
|
0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||||
|
DeliverGestureEventToOwner(dev, gi, &event);
|
||||||
|
}
|
||||||
|
|
|
@ -809,6 +809,24 @@ event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd, DeviceEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_set_state_gesture(DeviceIntPtr kbd, GestureEvent *event)
|
||||||
|
{
|
||||||
|
if (kbd && kbd->key) {
|
||||||
|
XkbStatePtr state= &kbd->key->xkbInfo->state;
|
||||||
|
|
||||||
|
event->mods.base = state->base_mods;
|
||||||
|
event->mods.latched = state->latched_mods;
|
||||||
|
event->mods.locked = state->locked_mods;
|
||||||
|
event->mods.effective = state->mods;
|
||||||
|
|
||||||
|
event->group.base = state->base_group;
|
||||||
|
event->group.latched = state->latched_group;
|
||||||
|
event->group.locked = state->locked_group;
|
||||||
|
event->group.effective = state->group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the event filter mask for the given device and the given core or
|
* Return the event filter mask for the given device and the given core or
|
||||||
* XI1 protocol type.
|
* XI1 protocol type.
|
||||||
|
|
|
@ -421,6 +421,10 @@ DeliverTouchEvents(DeviceIntPtr /* dev */ ,
|
||||||
InternalEvent * /* ev */ ,
|
InternalEvent * /* ev */ ,
|
||||||
XID /* resource */ );
|
XID /* resource */ );
|
||||||
|
|
||||||
|
extern Bool
|
||||||
|
DeliverGestureEventToOwner(DeviceIntPtr dev, GestureInfoPtr gi,
|
||||||
|
InternalEvent *ev);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
InitializeSprite(DeviceIntPtr /* pDev */ ,
|
InitializeSprite(DeviceIntPtr /* pDev */ ,
|
||||||
WindowPtr /* pWin */ );
|
WindowPtr /* pWin */ );
|
||||||
|
|
|
@ -660,6 +660,21 @@ extern void TouchEmitTouchEnd(DeviceIntPtr dev, TouchPointInfoPtr ti, int flags,
|
||||||
extern void TouchAcceptAndEnd(DeviceIntPtr dev, int touchid);
|
extern void TouchAcceptAndEnd(DeviceIntPtr dev, int touchid);
|
||||||
|
|
||||||
extern Bool GestureInitGestureInfo(GestureInfoPtr gesture);
|
extern Bool GestureInitGestureInfo(GestureInfoPtr gesture);
|
||||||
|
extern GestureInfoPtr GestureBeginGesture(DeviceIntPtr dev, InternalEvent *ev);
|
||||||
|
extern GestureInfoPtr GestureFindActiveByEventType(DeviceIntPtr dev, int type);
|
||||||
|
extern void GestureEndGesture(GestureInfoPtr gi);
|
||||||
|
extern Bool GestureResourceIsOwner(GestureInfoPtr gi, XID resource);
|
||||||
|
extern void GestureAddListener(GestureInfoPtr gi, XID resource, int resource_type,
|
||||||
|
enum GestureListenerType type,
|
||||||
|
WindowPtr window, GrabPtr grab);
|
||||||
|
extern void GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi,
|
||||||
|
InternalEvent *ev);
|
||||||
|
extern Bool GestureBuildSprite(DeviceIntPtr sourcedev, GestureInfoPtr gi);
|
||||||
|
extern void GestureListenerGone(XID resource);
|
||||||
|
extern void GestureEndActiveGestures(DeviceIntPtr dev);
|
||||||
|
extern void GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi);
|
||||||
|
extern void ProcessGestureEvent(InternalEvent *ev, DeviceIntPtr dev);
|
||||||
|
|
||||||
/* misc event helpers */
|
/* misc event helpers */
|
||||||
extern Mask GetEventMask(DeviceIntPtr dev, xEvent *ev, InputClientsPtr clients);
|
extern Mask GetEventMask(DeviceIntPtr dev, xEvent *ev, InputClientsPtr clients);
|
||||||
extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event);
|
extern Mask GetEventFilter(DeviceIntPtr dev, xEvent *event);
|
||||||
|
|
|
@ -50,6 +50,7 @@ extern void init_gesture_event(GestureEvent *event, DeviceIntPtr dev, Time ms);
|
||||||
extern int event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd);
|
extern int event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd);
|
||||||
extern void event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd,
|
extern void event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd,
|
||||||
DeviceEvent *event);
|
DeviceEvent *event);
|
||||||
|
extern void event_set_state_gesture(DeviceIntPtr kbd, GestureEvent *event);
|
||||||
extern Mask event_get_filter_from_type(DeviceIntPtr dev, int evtype);
|
extern Mask event_get_filter_from_type(DeviceIntPtr dev, int evtype);
|
||||||
extern Mask event_get_filter_from_xi2type(int evtype);
|
extern Mask event_get_filter_from_xi2type(int evtype);
|
||||||
|
|
||||||
|
|
|
@ -342,6 +342,14 @@ ChangeDeviceID(DeviceIntPtr dev, InternalEvent *event)
|
||||||
case ET_BarrierLeave:
|
case ET_BarrierLeave:
|
||||||
event->barrier_event.deviceid = dev->id;
|
event->barrier_event.deviceid = dev->id;
|
||||||
break;
|
break;
|
||||||
|
case ET_GesturePinchBegin:
|
||||||
|
case ET_GesturePinchUpdate:
|
||||||
|
case ET_GesturePinchEnd:
|
||||||
|
case ET_GestureSwipeBegin:
|
||||||
|
case ET_GestureSwipeUpdate:
|
||||||
|
case ET_GestureSwipeEnd:
|
||||||
|
event->gesture_event.deviceid = dev->id;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
|
ErrorF("[mi] Unknown event type (%d), cannot change id.\n",
|
||||||
event->any.type);
|
event->any.type);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user