Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • xorg/xserver
  • avolkov/xserver
  • keithp/xserver
  • aplattner/xserver
  • ajax/xserver
  • ofourdan/xserver
  • anholt/xserver
  • abono/xserver
  • airlied/xserver
  • romangg/xserver
  • ross/xserver
  • mupuf/xserver
  • jturney/xserver
  • CendioOssman/xserver
  • kamarul6401/xserver
  • daenzer/xserver
  • afett/xserver
  • coypoop/xserver
  • 3v1n0/xserver
  • llandwerlin/xserver
  • alanc/xserver
  • lyudess/xserver
  • twaik/xserver
  • shadeslayer/xserver
  • djlucas/xserver
  • aditj/xserver
  • dbn/xserver
  • awilfox/xserver
  • rmader/xserver
  • peterh/xserver
  • dk/xserver
  • dslater38/xserver
  • yshui/xserver
  • PaulKocialkowski/xserver
  • dixler/xserver
  • bentiss/xserver
  • mbiebl/xserver
  • rarbab/xserver
  • causztic/xserver
  • agoins/xserver
  • kbrenneman/xserver
  • Hi-Angel/xserver
  • mlankhorst/xserver
  • rgfernandes/xserver
  • topimiettinen/xserver
  • bphaslett/xserver
  • adamjrichter/xserver
  • karolherbst/xserver
  • carlosg/xserver
  • jwrdegoede/xserver
  • mattrope/xserver
  • sthibaul/xserver
  • J-Bu/xserver
  • nacho.resa/xserver
  • emersion/xserver
  • xexaxo/xserver
  • 1480c1/xserver
  • knisht/xserver
  • mattst88/xserver
  • goosen78/xserver
  • zubzub/xserver
  • vsyrjala/xserver
  • gerddie/xserver
  • JeffyCN/xserver
  • gtrentalancia/xserver
  • lostgoat/xserver
  • headrush/xserver
  • jadahl/xserver
  • webi123/xserver
  • zeising/xserver
  • marv/xserver
  • puleglot/xserver
  • zwenna/xserver
  • TAAPArthur/xserver
  • doraskayo/xserver
  • maos20008/xserver
  • tjbp/xserver
  • pq/xserver
  • yarivb/xserver
  • miztake/xserver
  • lynxeye/xserver
  • zboszor/xserver
  • kwg/xserver
  • Gorg/xserver
  • lkundrak/xserver
  • justazarsky/xserver
  • HermannSW/xserver
  • E5ten/xserver
  • bbrezillon/xserver
  • manu/xserver
  • lucyllewy/xserver
  • marvinjr35/xserver
  • jbeich/xserver
  • dirbaio/xserver
  • strassek/xserver
  • mntmn/xserver
  • uvas/xserver
  • azhadchenko/xserver
  • anarsoul/xserver
  • stapelberg/xserver
  • peigongdsd/xserver
  • sjoerd/xserver
  • Ma/xserver
  • mherrb/xserver
  • pichika/xserver
  • qarmin/xserver
  • cooperch/xserver
  • davidriley/xserver
  • lucmann/xserver
  • chema/xserver
  • whot/xserver
  • xdandys/xserver
  • Spintzyk/xserver
  • mikeroyal/xserver
  • ydirson/xserver
  • SimonPilkington/xserver
  • daniels/xserver
  • andrebsguedes/xserver
  • chenhuacai/xserver
  • Vivek/xserver
  • meMuszr/xserver
  • MisterDA/xserver
  • linkmauve/xserver
  • starnight/xserver
  • ekurzinger/xserver
  • DPA/xserver
  • hmazlan/xserver
  • alagner/xserver
  • tagr/xserver
  • alex-tu-cc/xserver
  • kaniini/xserver
  • p12tic/xserver
  • valpackett/xserver
  • Kishore409/xserver
  • bernhardu/xserver
  • kaichuan.hsieh/xserver
  • icenowy/xserver
  • rilian-la-te/xserver
  • smelenius/xserver
  • vfjpl/xserver
  • mvlad/xserver
  • vliaskov/xserver
  • hitong602/xserver
  • haagch/xserver
  • freemangordon/xserver
  • tmlind/xserver
  • vitoux.pascal/xserver
  • luporl/xserver
  • hassoon1986/xserver
  • chengbo7135/xserver
  • sri-ka1ki/xserver
  • kaocher82/xserver
  • heymiaoO/xserver
  • xry111/xserver
  • jcristau/xserver
  • lanodan/xserver
  • jcourreges/xserver
  • dottedmag/xserver
  • jeremyhu/xserver
  • jcherry/xserver
  • Zamundaaa/xserver
  • gsittyz/xserver
  • OlCe/xserver
  • manuelcrack642/xserver
  • kupper.pa/xserver
  • ZhiJie.Zhang/xserver
  • Michaelypk/xserver
  • msizanoen1/xserver
  • andreyknyazev077/xserver
  • christian-rauch/xserver
  • karlosrangel337/xserver
  • niveditharau/xserver
  • antonovitch/xserver
  • galaxytgtabiday/xserver
  • ryanneph/xserver
  • ismailsiege/xserver
  • orbea/xserver
  • FeepingCreature/xserver
  • ydc-dadada/xserver
  • davidedmundson/xserver
  • arichardson/xserver
  • 1740301466jxz/xserver
  • DemiMarie/xserver
  • kennylevinsen/xserver
  • mrisaacb/xserver
  • robclark/xserver
  • JoseExposito/xserver
  • refi_64/xserver
  • kleinerm/xserver
  • Acidburn0zzz/xserver
  • vinilokorlok/xserver
  • cubanismo/xserver
  • n3rdopolis/xserver
  • mwyraz/xserver
  • halfline/xserver
  • cpmichael/modesetting
  • sherrodejjohnson/xserver
  • eschwartz/xserver
  • oreaus/xserver
  • jocelyn/xserver
  • ernstp/xserver
  • LickmeDown/xserver
  • Daasin/xserver
  • huxd1532/xserver
  • cgzones/xserver
  • davidre/xserver
  • jsg/xserver
  • zagursky/xserver
  • thesamesam/xserver
  • ashafer/xserver
  • dengbo/xserver
  • josch/xserver
  • denisfa/xserver
  • benpicco/xserver
  • Tuetuopay/xserver
  • tholin/xserver
  • tzimmermann/xserver
  • Sjecai2/xserver
  • tintou/xserver
  • zaps166/xserver
  • schreibemirhalt/xserver
  • tomty89/xserver
  • contactshashanksharma/xserver-fork-shashank
  • os369510/xserver
  • liyi42/xserver
  • Kyawswat/xserver
  • psyruss85/xserver
  • akihiko.odaki/xserver
  • StarsGreen/xserver
  • klniu/xserver
  • pekdon/xserver
  • pkubaj/xserver
  • kerneltoast/xserver
  • wengxt/xserver
  • vanvugt/xserver
  • cbur201592/xserver
  • bkylerussell/xserver
  • wujiangGitHub/xserver
  • frog/xserver
  • bafanahub/xserver
  • Ivaniku/x-taylan
  • bigon/xserver
  • jrtc27/xserver
  • djacewicz/xserver
  • kylin0061/xserver
  • Fatton1/xserver
  • gmbr3/xserver
  • devin11911191/xserver
  • guillem/xserver
  • mahkoh/xserver
  • acelan/xserver
  • dkorkmazturk/xserver
  • olv/xserver
  • SpikyCaterpillar1/xserver
  • lihongtao/xserver
  • luke-jr/xserver
  • karamjameelmoore/xserver
  • mehdigh419/xserver
  • wiz/xserver
  • ecurtin/xserver
  • muesli4/xserver
  • iv-m/xserver
  • ForTheReallys/xserver
  • BBaoVanC/xserver
  • ccullumbine2018/xserver
  • mgorse1/xserver
  • road2react/xserver
  • mwei/xserver
  • Rui511/xserver
  • ThatMG393/xserver
  • haihao/xserver
  • ipominov/xserver
  • tsutsui/xserver
  • fweimer/xserver
  • gilvbp/xserver
  • themaister/xserver
  • bbeckett/xserver
  • TMR5454/xserver
  • erwinou/xserver
  • aarondill/xserver
  • peng.jin/xserver
  • russellcnv/xserver
  • yangxiaojuan-loongson/xserver
  • LiChenG-P/xserver
  • looi/xserver
  • NSUTanghaixiang/xserver
  • XDXTHX/xserver
  • City-busz/xserver
  • arrowd/xserver
  • zzyiwei/xserver
  • dongwonk/xserver
  • EXtremeExploit/xserver
  • luyn/xserver
  • hexiaodong/xserver
  • sewn/xserver
  • cl91/xserver
  • rnpnr/xserver
  • adamdruppe/xserver
  • RyzenDew/xserver
  • jexposit/xserver
  • svalaskevicius/xserver
  • floppym/xserver
  • metux/xserver
  • YusufKhan-gamedev/xserver
  • Drakulix/xserver
  • wjp/xserver
  • dawnhan/xserver
  • noblock/xserver
  • zzag/xserver
  • catap/xserver
  • trevdave/xserver
  • ids1024/xserver
  • gabifalk/xserver
  • Emantor/xserver
  • sknsean/xserver
  • hongaoo/xserver
  • penguin42/xserver
  • heitbaum/xserver
  • fvalasiad/xserver
  • AkiSakurai/xserver
  • chenx_dust/xserver
  • jmonteiro/xserver
  • gldrk/xserver
  • dougg3/xserver
  • pepp/xserver
  • Julia/xserver
  • nathankidd/xserver
  • jannau/xserver
  • zhangyaning/xserver
  • xinbowang/xserver
  • sergiomb/xserver
  • andy-zetier/xserver
  • jayantpranjal0/xserver
  • zzxyb/xserver
  • dkg/xserver
  • GermanAizek/xserver
  • dougvj/xserver
  • volkanorhan/xserver
  • rbernon/xserver
  • matt335672/xserver
  • gfxstrand/xorg-xserver
  • nicolas-guichard/xserver
  • rc_05/xserver
343 results
Show changes
Commits on Source (23)
......@@ -11,7 +11,7 @@ variables:
UPSTREAM_REPO: xorg/xserver
FDO_DISTRIBUTION_VERSION: buster-slim
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash .gitlab-ci/debian-install.sh'
FDO_DISTRIBUTION_TAG: "2021-04-06"
FDO_DISTRIBUTION_TAG: "2021-05-17"
include:
- project: 'freedesktop/ci-templates'
......
......@@ -49,7 +49,7 @@ build 'https://gitlab.freedesktop.org/pixman/pixman.git' 'pixman-0.38.4'
build 'https://gitlab.freedesktop.org/xorg/lib/pthread-stubs.git' '0.4'
# we can't use the xorgproto pkgconfig files from /usr/share/pkgconfig, because
# these would add -I/usr/include to CFLAGS, which breaks cross-compilation
build 'https://gitlab.freedesktop.org/xorg/proto/xorgproto.git' 'xorgproto-2019.1' '--datadir=/lib'
build 'https://gitlab.freedesktop.org/xorg/proto/xorgproto.git' 'xorgproto-2021.4.99.2' '--datadir=/lib'
build 'https://gitlab.freedesktop.org/xorg/lib/libXau.git' 'libXau-1.0.9'
build 'https://gitlab.freedesktop.org/xorg/proto/xcbproto.git' 'xcb-proto-1.14'
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb.git' 'libxcb-1.14'
......
......@@ -98,7 +98,6 @@ apt-get install -y \
python3-mako \
python3-numpy \
python3-six \
x11proto-dev \
xfonts-utils \
xkb-data \
xtrans-dev \
......@@ -108,6 +107,14 @@ apt-get install -y \
cd /root
# xserver requires xorgproto >= 2021.4.99.2 for XI 2.3.99.1
git clone https://gitlab.freedesktop.org/xorg/proto/xorgproto.git --depth 1 --branch=xorgproto-2021.4.99.2
pushd xorgproto
./autogen.sh
make -j${FDO_CI_CONCURRENT:-4} install
popd
rm -rf xorgproto
# weston 9.0 requires libwayland >= 1.18
git clone https://gitlab.freedesktop.org/wayland/wayland.git --depth 1 --branch=1.18.0
cd wayland
......
......@@ -95,6 +95,7 @@ SOFTWARE.
#include "exevents.h"
#include "extnsionst.h"
#include "exglobals.h"
#include "eventstr.h"
#include "dixevents.h" /* DeliverFocusedEvent */
#include "dixgrabs.h" /* CreateGrab() */
#include "scrnintstr.h"
......@@ -168,6 +169,49 @@ IsTouchEvent(InternalEvent *event)
return FALSE;
}
Bool
IsGestureEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return TRUE;
default:
break;
}
return FALSE;
}
Bool
IsGestureBeginEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchBegin:
case ET_GestureSwipeBegin:
return TRUE;
default:
break;
}
return FALSE;
}
Bool
IsGestureEndEvent(InternalEvent *event)
{
switch (event->any.type) {
case ET_GesturePinchEnd:
case ET_GestureSwipeEnd:
return TRUE;
default:
break;
}
return FALSE;
}
/**
* @return the device matching the deviceid of the device set in the event, or
* NULL if the event is not an XInput event.
......@@ -647,6 +691,25 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
/* Don't remove touch class if from->touch is non-existent. The to device
* may have an active touch grab, so we need to keep the touch class record
* around. */
if (from->gesture) {
if (!to->gesture) {
classes = to->unused_classes;
to->gesture = classes->gesture;
if (!to->gesture) {
if (!InitGestureClassDeviceStruct(to, from->gesture->max_touches))
FatalError("[Xi] no memory for class shift.\n");
}
else
classes->gesture = NULL;
}
to->gesture->sourceid = from->gesture->sourceid;
/* to->gesture->gesture is separate on the master, don't copy */
}
/* Don't remove gesture class if from->gesture is non-existent. The to device
* may have an active gesture grab, so we need to keep the gesture class record
* around. */
}
/**
......@@ -1680,6 +1743,72 @@ ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
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;
Bool delivered = 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;
delivered = DeliverGestureEventToOwner(dev, gi, ev);
if (delivered && !deactivateGestureGrab &&
(IsGestureBeginEvent(ev) || IsGestureEndEvent(ev)))
FreezeThisEventIfNeededForSyncGrab(dev, ev);
if (IsGestureEndEvent(ev))
GestureEndGesture(gi);
if (deactivateGestureGrab)
(*dev->deviceGrab.DeactivateGrab) (dev);
}
/**
* Process DeviceEvents and DeviceChangedEvents.
*/
......@@ -1874,6 +2003,14 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
case ET_BarrierLeave:
ProcessBarrierEvent(ev, device);
break;
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
ProcessGestureEvent(ev, device);
break;
default:
ProcessDeviceEvent(ev, device);
break;
......@@ -2078,6 +2215,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
InitProximityClassDeviceStruct(DeviceIntPtr dev)
{
......@@ -2383,8 +2625,8 @@ GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
/* Touch grab */
int
GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
GrabParameters *param, GrabMask *mask)
GrabTouchOrGesture(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
int type, GrabParameters *param, GrabMask *mask)
{
WindowPtr pWin;
GrabPtr grab;
......@@ -2402,7 +2644,7 @@ GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
return rc;
grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
mask, param, type, 0, NullWindow, NullCursor);
if (!grab)
return BadAlloc;
......
......@@ -850,6 +850,74 @@ SBarrierEvent(xXIBarrierEvent * from,
swapl(&to->eventid);
}
static void
SGesturePinchEvent(xXIGesturePinchEvent* from,
xXIGesturePinchEvent* to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
swaps(&to->deviceid);
swapl(&to->time);
swapl(&to->detail);
swapl(&to->root);
swapl(&to->event);
swapl(&to->child);
swapl(&to->root_x);
swapl(&to->root_y);
swapl(&to->event_x);
swapl(&to->event_y);
swapl(&to->delta_x);
swapl(&to->delta_y);
swapl(&to->delta_unaccel_x);
swapl(&to->delta_unaccel_y);
swapl(&to->scale);
swapl(&to->delta_angle);
swaps(&to->sourceid);
swapl(&to->mods.base_mods);
swapl(&to->mods.latched_mods);
swapl(&to->mods.locked_mods);
swapl(&to->mods.effective_mods);
swapl(&to->flags);
}
static void
SGestureSwipeEvent(xXIGestureSwipeEvent* from,
xXIGestureSwipeEvent* to)
{
*to = *from;
swaps(&to->sequenceNumber);
swapl(&to->length);
swaps(&to->evtype);
swaps(&to->deviceid);
swapl(&to->time);
swapl(&to->detail);
swapl(&to->root);
swapl(&to->event);
swapl(&to->child);
swapl(&to->root_x);
swapl(&to->root_y);
swapl(&to->event_x);
swapl(&to->event_y);
swapl(&to->delta_x);
swapl(&to->delta_y);
swapl(&to->delta_unaccel_x);
swapl(&to->delta_unaccel_y);
swaps(&to->sourceid);
swapl(&to->mods.base_mods);
swapl(&to->mods.latched_mods);
swapl(&to->mods.locked_mods);
swapl(&to->mods.effective_mods);
swapl(&to->flags);
}
/** Event swapping function for XI2 events. */
void _X_COLD
XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
......@@ -901,6 +969,18 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
SBarrierEvent((xXIBarrierEvent *) from,
(xXIBarrierEvent *) to);
break;
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
SGesturePinchEvent((xXIGesturePinchEvent*) from,
(xXIGesturePinchEvent*) to);
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
SGestureSwipeEvent((xXIGestureSwipeEvent*) from,
(xXIGestureSwipeEvent*) to);
break;
default:
ErrorF("[Xi] Unknown event type to swap. This is a bug.\n");
break;
......
......@@ -114,14 +114,18 @@ ProcXIPassiveGrabDevice(ClientPtr client)
stuff->grab_type != XIGrabtypeKeycode &&
stuff->grab_type != XIGrabtypeEnter &&
stuff->grab_type != XIGrabtypeFocusIn &&
stuff->grab_type != XIGrabtypeTouchBegin) {
stuff->grab_type != XIGrabtypeTouchBegin &&
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
client->errorValue = stuff->grab_type;
return BadValue;
}
if ((stuff->grab_type == XIGrabtypeEnter ||
stuff->grab_type == XIGrabtypeFocusIn ||
stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
stuff->grab_type == XIGrabtypeTouchBegin ||
stuff->grab_type == XIGrabtypeGesturePinchBegin ||
stuff->grab_type == XIGrabtypeGestureSwipeBegin) && stuff->detail != 0) {
client->errorValue = stuff->detail;
return BadValue;
}
......@@ -217,7 +221,16 @@ ProcXIPassiveGrabDevice(ClientPtr client)
status = GrabWindow(client, dev, stuff->grab_type, &param, &mask);
break;
case XIGrabtypeTouchBegin:
status = GrabTouch(client, dev, mod_dev, &param, &mask);
status = GrabTouchOrGesture(client, dev, mod_dev, XI_TouchBegin,
&param, &mask);
break;
case XIGrabtypeGesturePinchBegin:
status = GrabTouchOrGesture(client, dev, mod_dev,
XI_GesturePinchBegin, &param, &mask);
break;
case XIGrabtypeGestureSwipeBegin:
status = GrabTouchOrGesture(client, dev, mod_dev,
XI_GestureSwipeBegin, &param, &mask);
break;
}
......@@ -307,7 +320,9 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
stuff->grab_type != XIGrabtypeKeycode &&
stuff->grab_type != XIGrabtypeEnter &&
stuff->grab_type != XIGrabtypeFocusIn &&
stuff->grab_type != XIGrabtypeTouchBegin) {
stuff->grab_type != XIGrabtypeTouchBegin &&
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
client->errorValue = stuff->grab_type;
return BadValue;
}
......@@ -348,6 +363,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
case XIGrabtypeTouchBegin:
tempGrab->type = XI_TouchBegin;
break;
case XIGrabtypeGesturePinchBegin:
tempGrab->type = XI_GesturePinchBegin;
break;
case XIGrabtypeGestureSwipeBegin:
tempGrab->type = XI_GestureSwipeBegin;
break;
}
tempGrab->grabtype = XI2;
tempGrab->modifierDevice = mod_dev;
......
......@@ -43,6 +43,9 @@
#include "xace.h"
#include "inpututils.h"
#include "exglobals.h"
#include "privates.h"
#include "xiquerydevice.h"
static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
......@@ -234,6 +237,9 @@ SizeDeviceClasses(DeviceIntPtr dev)
if (dev->touch)
len += sizeof(xXITouchInfo);
if (dev->gesture)
len += sizeof(xXIGestureInfo);
return len;
}
......@@ -464,6 +470,46 @@ SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
swaps(&touch->sourceid);
}
static Bool ShouldListGestureInfo(ClientPtr client)
{
/* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not
* properly ignore unknown device classes. Since breaking libxcb would break quite a lot of
* applications, we instead report Gesture device class only if the client advertised support
* for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support
* and then a completely separate module within the client uses broken libxcb to call
* XIQueryDevice.
*/
XIClientPtr pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
if (pXIClient->major_version) {
return version_compare(pXIClient->major_version, pXIClient->minor_version, 2, 4) >= 0;
}
return FALSE;
}
/**
* List gesture information
*
* @return The number of bytes written into info.
*/
static int
ListGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
{
gesture->type = XIGestureClass;
gesture->length = sizeof(xXIGestureInfo) >> 2;
gesture->sourceid = dev->gesture->sourceid;
gesture->num_touches = dev->gesture->max_touches;
return gesture->length << 2;
}
static void
SwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
{
swaps(&gesture->type);
swaps(&gesture->length);
swaps(&gesture->sourceid);
}
int
GetDeviceUse(DeviceIntPtr dev, uint16_t * attachment)
{
......@@ -567,6 +613,13 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
total_len += len;
}
if (dev->gesture && ShouldListGestureInfo(client)) {
(*nclasses)++;
len = ListGestureInfo(dev, (xXIGestureInfo *) any);
any += len;
total_len += len;
}
return total_len;
}
......@@ -598,7 +651,9 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info)
case XITouchClass:
SwapTouchInfo(dev, (xXITouchInfo *) any);
break;
case XIGestureClass:
SwapGestureInfo(dev, (xXIGestureInfo *) any);
break;
}
any += len * 4;
......
......@@ -226,8 +226,41 @@ ProcXISelectEvents(ClientPtr client)
return BadValue;
}
/* Only one client per window may select for touch events on the
* same devices, including master devices.
/* All three pinch gesture events must be selected at once */
if ((BitIsOn(bits, XI_GesturePinchBegin) ||
BitIsOn(bits, XI_GesturePinchUpdate) ||
BitIsOn(bits, XI_GesturePinchEnd)) &&
(!BitIsOn(bits, XI_GesturePinchBegin) ||
!BitIsOn(bits, XI_GesturePinchUpdate) ||
!BitIsOn(bits, XI_GesturePinchEnd))) {
client->errorValue = XI_GesturePinchBegin;
return BadValue;
}
/* All three swipe gesture events must be selected at once. Note
that the XI_GestureSwipeEnd is at index 32 which is on the next
4-byte mask element */
if (evmask->mask_len == 1 &&
(BitIsOn(bits, XI_GestureSwipeBegin) ||
BitIsOn(bits, XI_GestureSwipeUpdate)))
{
client->errorValue = XI_GestureSwipeBegin;
return BadValue;
}
if (evmask->mask_len >= 2 &&
(BitIsOn(bits, XI_GestureSwipeBegin) ||
BitIsOn(bits, XI_GestureSwipeUpdate) ||
BitIsOn(bits, XI_GestureSwipeEnd)) &&
(!BitIsOn(bits, XI_GestureSwipeBegin) ||
!BitIsOn(bits, XI_GestureSwipeUpdate) ||
!BitIsOn(bits, XI_GestureSwipeEnd))) {
client->errorValue = XI_GestureSwipeBegin;
return BadValue;
}
/* Only one client per window may select for touch or gesture events
* on the same devices, including master devices.
* XXX: This breaks if a device goes from floating to attached. */
if (BitIsOn(bits, XI_TouchBegin)) {
rc = check_for_touch_selection_conflicts(client,
......@@ -237,6 +270,22 @@ ProcXISelectEvents(ClientPtr client)
if (rc != Success)
return rc;
}
if (BitIsOn(bits, XI_GesturePinchBegin)) {
rc = check_for_touch_selection_conflicts(client,
win,
evmask->deviceid,
XI_GesturePinchBegin);
if (rc != Success)
return rc;
}
if (BitIsOn(bits, XI_GestureSwipeBegin)) {
rc = check_for_touch_selection_conflicts(client,
win,
evmask->deviceid,
XI_GestureSwipeBegin);
if (rc != Success)
return rc;
}
}
if (XICheckInvalidMaskBits(client, (unsigned char *) &evmask[1],
......
......@@ -23,6 +23,7 @@ libdix_la_SOURCES = \
extension.c \
gc.c \
getevents.c \
gestures.c \
globals.c \
glyphcurs.c \
grabs.c \
......
......@@ -458,6 +458,7 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent)
return FALSE;
TouchEndPhysicallyActiveTouches(dev);
GestureEndActiveGestures(dev);
ReleaseButtonsAndKeys(dev);
SyncRemoveDeviceIdleTime(dev->idle_counter);
dev->idle_counter = NULL;
......@@ -1670,6 +1671,32 @@ InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
return FALSE;
}
/**
* Sets up gesture capabilities on @device.
*
* @max_touches The maximum number of simultaneous touches, or 0 for unlimited.
*/
Bool
InitGestureClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches)
{
GestureClassPtr g;
BUG_RETURN_VAL(device == NULL, FALSE);
BUG_RETURN_VAL(device->gesture != NULL, FALSE);
g = calloc(1, sizeof(*g));
if (!g)
return FALSE;
g->sourceid = device->id;
g->max_touches = max_touches;
GestureInitGestureInfo(&g->gesture);
device->gesture = g;
return TRUE;
}
/*
* Check if the given buffer contains elements between low (inclusive) and
* high (inclusive) only.
......
......@@ -3487,6 +3487,7 @@ CloseDownClient(ClientPtr client)
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
}
TouchListenerGone(client->clientAsMask);
GestureListenerGone(client->clientAsMask);
FreeClientResources(client);
/* Disable client ID tracking. This must be done after
* ClientStateCallback. */
......
......@@ -59,6 +59,8 @@ static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
static int eventToBarrierEvent(BarrierEvent *ev, xEvent **xi);
static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi);
static int eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi);
static int eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi);
/* Do not use, read comments below */
BOOL EventIsKeyRepeat(xEvent *event);
......@@ -163,6 +165,12 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
ret = BadMatch;
break;
default:
......@@ -221,6 +229,12 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
case ET_TouchOwnership:
case ET_BarrierHit:
case ET_BarrierLeave:
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
*count = 0;
*xi = NULL;
return BadMatch;
......@@ -285,6 +299,14 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
case ET_BarrierHit:
case ET_BarrierLeave:
return eventToBarrierEvent(&ev->barrier_event, xi);
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return eventToGesturePinchEvent(&ev->gesture_event, xi);
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return eventToGestureSwipeEvent(&ev->gesture_event, xi);
default:
break;
}
......@@ -816,6 +838,88 @@ eventToBarrierEvent(BarrierEvent *ev, xEvent **xi)
return Success;
}
int
eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGesturePinchEvent);
xXIGesturePinchEvent *xpe;
*xi = calloc(1, len);
xpe = (xXIGesturePinchEvent *) * xi;
xpe->type = GenericEvent;
xpe->extension = IReqCode;
xpe->evtype = GetXI2Type(ev->type);
xpe->time = ev->time;
xpe->length = bytes_to_int32(len - sizeof(xEvent));
xpe->detail = ev->num_touches;
xpe->root = ev->root;
xpe->deviceid = ev->deviceid;
xpe->sourceid = ev->sourceid;
xpe->root_x = double_to_fp1616(ev->root_x);
xpe->root_y = double_to_fp1616(ev->root_y);
xpe->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGesturePinchEventCancelled : 0;
xpe->delta_x = double_to_fp1616(ev->delta_x);
xpe->delta_y = double_to_fp1616(ev->delta_y);
xpe->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xpe->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xpe->scale = double_to_fp1616(ev->scale);
xpe->delta_angle = double_to_fp1616(ev->delta_angle);
xpe->mods.base_mods = ev->mods.base;
xpe->mods.latched_mods = ev->mods.latched;
xpe->mods.locked_mods = ev->mods.locked;
xpe->mods.effective_mods = ev->mods.effective;
xpe->group.base_group = ev->group.base;
xpe->group.latched_group = ev->group.latched;
xpe->group.locked_group = ev->group.locked;
xpe->group.effective_group = ev->group.effective;
return Success;
}
int
eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi)
{
int len = sizeof(xXIGestureSwipeEvent);
xXIGestureSwipeEvent *xde;
*xi = calloc(1, len);
xde = (xXIGestureSwipeEvent *) * xi;
xde->type = GenericEvent;
xde->extension = IReqCode;
xde->evtype = GetXI2Type(ev->type);
xde->time = ev->time;
xde->length = bytes_to_int32(len - sizeof(xEvent));
xde->detail = ev->num_touches;
xde->root = ev->root;
xde->deviceid = ev->deviceid;
xde->sourceid = ev->sourceid;
xde->root_x = double_to_fp1616(ev->root_x);
xde->root_y = double_to_fp1616(ev->root_y);
xde->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGestureSwipeEventCancelled : 0;
xde->delta_x = double_to_fp1616(ev->delta_x);
xde->delta_y = double_to_fp1616(ev->delta_y);
xde->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
xde->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
xde->mods.base_mods = ev->mods.base;
xde->mods.latched_mods = ev->mods.latched;
xde->mods.locked_mods = ev->mods.locked;
xde->mods.effective_mods = ev->mods.effective;
xde->group.base_group = ev->group.base;
xde->group.latched_group = ev->group.latched;
xde->group.locked_group = ev->group.locked;
xde->group.effective_group = ev->group.effective;
return Success;
}
/**
* Return the corresponding core type for the given event or 0 if no core
* equivalent exists.
......@@ -969,8 +1073,68 @@ GetXI2Type(enum EventType type)
case ET_BarrierLeave:
xi2type = XI_BarrierLeave;
break;
case ET_GesturePinchBegin:
xi2type = XI_GesturePinchBegin;
break;
case ET_GesturePinchUpdate:
xi2type = XI_GesturePinchUpdate;
break;
case ET_GesturePinchEnd:
xi2type = XI_GesturePinchEnd;
break;
case ET_GestureSwipeBegin:
xi2type = XI_GestureSwipeBegin;
break;
case ET_GestureSwipeUpdate:
xi2type = XI_GestureSwipeUpdate;
break;
case ET_GestureSwipeEnd:
xi2type = XI_GestureSwipeEnd;
break;
default:
break;
}
return xi2type;
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}Begin.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToBegin(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchBegin;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeBegin;
default:
return 0;
}
}
/**
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}End.
* Returns 0 if the input type is not a gesture.
*/
enum EventType
GestureTypeToEnd(enum EventType type)
{
switch (type) {
case ET_GesturePinchBegin:
case ET_GesturePinchUpdate:
case ET_GesturePinchEnd:
return ET_GesturePinchEnd;
case ET_GestureSwipeBegin:
case ET_GestureSwipeUpdate:
case ET_GestureSwipeEnd:
return ET_GestureSwipeEnd;
default:
return 0;
}
}
......@@ -1328,6 +1328,15 @@ ComputeFreezes(void)
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 {
WindowPtr w = XYToWindow(replayDev->spriteInfo->sprite,
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
* 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;
PostNewCursor(mouse);
UpdateTouchesForGrab(mouse);
UpdateGesturesForGrab(mouse);
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
(Bool) grab->keyboardMode);
if (oldgrab)
......@@ -1614,6 +1664,16 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
if (dev->deviceGrab.sync.other == grab)
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,
mouse->spriteInfo->sprite->win, NotifyUngrab);
if (grab->confineTo)
......@@ -2545,6 +2605,44 @@ FixUpXI2DeviceEventFromWindow(SpritePtr pSprite, int evtype,
(pSprite->hot.pScreen == pWin->drawable.pScreen);
}
static void
FixUpXI2PinchEventFromWindow(SpritePtr pSprite, xXIGesturePinchEvent *event,
WindowPtr pWin, Window child)
{
event->root = RootWindow(pSprite)->drawable.id;
event->event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
event->child = child;
}
else {
event->event_x = 0;
event->event_y = 0;
event->child = None;
}
}
static void
FixUpXI2SwipeEventFromWindow(SpritePtr pSprite, xXIGestureSwipeEvent *event,
WindowPtr pWin, Window child)
{
event->root = RootWindow(pSprite)->drawable.id;
event->event = pWin->drawable.id;
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
event->child = child;
}
else {
event->event_x = 0;
event->event_y = 0;
event->child = None;
}
}
/**
* Adjust event fields to comply with the window properties.
*
......@@ -2578,6 +2676,18 @@ FixUpEventFromWindow(SpritePtr pSprite,
case XI_BarrierHit:
case XI_BarrierLeave:
return;
case XI_GesturePinchBegin:
case XI_GesturePinchUpdate:
case XI_GesturePinchEnd:
FixUpXI2PinchEventFromWindow(pSprite,
(xXIGesturePinchEvent*) xE, pWin, child);
break;
case XI_GestureSwipeBegin:
case XI_GestureSwipeUpdate:
case XI_GestureSwipeEnd:
FixUpXI2SwipeEventFromWindow(pSprite,
(xXIGestureSwipeEvent*) xE, pWin, child);
break;
default:
FixUpXI2DeviceEventFromWindow(pSprite, evtype,
(xXIDeviceEvent*) xE, pWin, child);
......
/*
* Copyright © 2011 Collabra Ltd.
* Copyright © 2011 Red Hat, Inc.
* Copyright © 2020 Povilas Kanapickas <povilas@radix.lt>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "inputstr.h"
#include "scrnintstr.h"
#include "dixgrabs.h"
#include "eventstr.h"
#include "exevents.h"
#include "exglobals.h"
#include "inpututils.h"
#include "eventconvert.h"
#include "windowstr.h"
#include "mi.h"
#define GESTURE_HISTORY_SIZE 100
Bool
GestureInitGestureInfo(GestureInfoPtr gi)
{
memset(gi, 0, sizeof(*gi));
gi->sprite.spriteTrace = calloc(32, sizeof(*gi->sprite.spriteTrace));
if (!gi->sprite.spriteTrace) {
return FALSE;
}
gi->sprite.spriteTraceSize = 32;
gi->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
gi->sprite.hot.pScreen = screenInfo.screens[0];
gi->sprite.hotPhys.pScreen = screenInfo.screens[0];
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);
}
......@@ -2099,3 +2099,139 @@ PostSyntheticMotion(DeviceIntPtr pDev,
/* FIXME: MD/SD considerations? */
(*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev);
}
void
InitGestureEvent(InternalEvent *ievent, DeviceIntPtr dev, CARD32 ms,
int type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x, double delta_unaccel_y,
double scale, double delta_angle)
{
ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
GestureEvent *event = &ievent->gesture_event;
double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
init_gesture_event(event, dev, ms);
screenx = dev->spriteInfo->sprite->hotPhys.x;
screeny = dev->spriteInfo->sprite->hotPhys.y;
event->type = type;
event->root = scr->root->drawable.id;
event->root_x = screenx - scr->x;
event->root_y = screeny - scr->y;
event->num_touches = num_touches;
event->flags = flags;
event->delta_x = delta_x;
event->delta_y = delta_y;
event->delta_unaccel_x = delta_unaccel_x;
event->delta_unaccel_y = delta_unaccel_y;
event->scale = scale;
event->delta_angle = delta_angle;
}
/**
* Get events for a pinch or swipe gesture.
*
* events is not NULL-terminated; the return value is the number of events.
* The DDX is responsible for allocating the event structure in the first
* place via GetMaximumEventsNum(), and for freeing it.
*
* @param[out] events The list of events generated
* @param dev The device to generate the events for
* @param type XI_Gesture{Pinch,Swipe}{Begin,Update,End}
* @prama num_touches The number of touches in the gesture
* @param flags Event flags
* @param delta_x,delta_y accelerated relative motion delta
* @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta
* @param scale (valid only to pinch events) absolute scale of a pinch gesture
* @param delta_angle (valid only to pinch events) the ange delta in degrees between the last and
* the current pinch event.
*/
int
GetGestureEvents(InternalEvent *events, DeviceIntPtr dev,
uint16_t type, uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x, double delta_unaccel_y,
double scale, double delta_angle)
{
GestureClassPtr g = dev->gesture;
CARD32 ms = GetTimeInMillis();
enum EventType evtype;
int num_events = 0;
uint32_t evflags = 0;
if (!dev->enabled || !g)
return 0;
if (!IsMaster(dev))
events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT,
&num_events);
switch (type) {
case XI_GesturePinchBegin:
evtype = ET_GesturePinchBegin;
break;
case XI_GesturePinchUpdate:
evtype = ET_GesturePinchUpdate;
break;
case XI_GesturePinchEnd:
evtype = ET_GesturePinchEnd;
if (flags & XIGesturePinchEventCancelled)
evflags |= GESTURE_CANCELLED;
break;
case XI_GestureSwipeBegin:
evtype = ET_GestureSwipeBegin;
break;
case XI_GestureSwipeUpdate:
evtype = ET_GestureSwipeUpdate;
break;
case XI_GestureSwipeEnd:
evtype = ET_GestureSwipeEnd;
if (flags & XIGestureSwipeEventCancelled)
evflags |= GESTURE_CANCELLED;
break;
default:
return 0;
}
InitGestureEvent(events, dev, ms, evtype, num_touches, evflags,
delta_x, delta_y, delta_unaccel_x, delta_unaccel_y,
scale, delta_angle);
num_events++;
return num_events;
}
void
QueueGesturePinchEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y,
double scale, double delta_angle)
{
int nevents;
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
delta_x, delta_y,
delta_unaccel_x, delta_unaccel_y,
scale, delta_angle);
queueEventList(dev, InputEventList, nevents);
}
void
QueueGestureSwipeEvents(DeviceIntPtr dev, uint16_t type,
uint16_t num_touches, uint32_t flags,
double delta_x, double delta_y,
double delta_unaccel_x,
double delta_unaccel_y)
{
int nevents;
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
delta_x, delta_y,
delta_unaccel_x, delta_unaccel_y,
0.0, 0.0);
queueEventList(dev, InputEventList, nevents);
}
......@@ -716,3 +716,10 @@ GrabIsKeyboardGrab(GrabPtr grab)
return (grab->type == KeyPress ||
grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
}
Bool
GrabIsGestureGrab(GrabPtr grab)
{
return (grab->type == XI_GesturePinchBegin ||
grab->type == XI_GestureSwipeBegin);
}
......@@ -746,6 +746,21 @@ init_device_event(DeviceEvent *event, DeviceIntPtr dev, Time ms,
event->source_type = source_type;
}
/**
* Initializes the given gesture event to zero (or default values),
* for the given device.
*/
void
init_gesture_event(GestureEvent *event, DeviceIntPtr dev, Time ms)
{
memset(event, 0, sizeof(GestureEvent));
event->header = ET_Internal;
event->length = sizeof(GestureEvent);
event->time = ms;
event->deviceid = dev->id;
event->sourceid = dev->id;
}
int
event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd)
{
......@@ -794,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
* XI1 protocol type.
......
......@@ -12,6 +12,7 @@ srcs_dix = [
'eventconvert.c',
'extension.c',
'gc.c',
'gestures.c',
'getevents.c',
'globals.c',
'glyphcurs.c',
......
......@@ -1873,7 +1873,7 @@ DoGetDrawableAttributes(__GLXclientState * cl, XID drawId)
int err = dixLookupWindow((WindowPtr *)&pDraw, drawId, client,
DixGetAttrAccess);
if (err != Success)
return error;
return __glXError(GLXBadDrawable);
}
if (pGlxDraw)
pDraw = pGlxDraw->pDraw;
......
......@@ -75,7 +75,7 @@
*/
#define ABI_ANSIC_VERSION SET_ABI_VERSION(0, 4)
#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(25, 2)
#define ABI_XINPUT_VERSION SET_ABI_VERSION(24, 3)
#define ABI_XINPUT_VERSION SET_ABI_VERSION(24, 4)
#define ABI_EXTENSION_VERSION SET_ABI_VERSION(10, 0)
#define MODINFOSTRING1 0xef23fdc5
......