--- xorg-integration-tests-0.0.1+git20140508+709412f.orig/tests/server/grab.cpp +++ xorg-integration-tests-0.0.1+git20140508+709412f/tests/server/grab.cpp @@ -1256,6 +1256,137 @@ } +TEST_F(TouchGrabTest, MasterSlaveMixed) +{ + XORG_TESTCASE("Client A has a touch grab on root window\n" + "Client B has no support for touch, and listens on its own window\n" + "Client C uses a dynamic touch grab on the slave device on the root window\n" + "Trigger pointer-emulated button grab\n" + "Client A rejects, pointer emulated to B, C listening on slave device\n" + "Client C calls XIGrabDevice on TouchBegin, XIUngrabDevice on TouchEnd\n" + "Client B should still receive a ButtonRelease event, and pointer\n" + "emulation should continue to work on the next touch.\n" + "https://bugs.freedesktop.org/show_bug.cgi?id=78345\n"); + + ::Display *dpy = Display(); + + ::Display *dpy2 = NewClient(); + ::Display *dpy3 = NewClient(); + Window win3 = DefaultRootWindow(dpy3); + Window win2 = CreateWindow(dpy2, DefaultRootWindow(dpy2), 0, 0, 300, 300); + + XIEventMask mask; + mask.mask_len = XIMaskLen(XI_LASTEVENT); + mask.deviceid = VIRTUAL_CORE_POINTER_ID; + mask.mask = new unsigned char[mask.mask_len](); + + XISetMask(mask.mask, XI_TouchBegin); + XISetMask(mask.mask, XI_TouchUpdate); + XISetMask(mask.mask, XI_TouchEnd); + XISetMask(mask.mask, XI_TouchOwnership); + + XIGrabModifiers mods = {}; + mods.modifiers = XIAnyModifier; + + XIGrabTouchBegin(dpy, VIRTUAL_CORE_POINTER_ID, DefaultRootWindow(dpy), 0, &mask, 1, &mods); + + /* set up client B on the master device */ + memset(mask.mask, 0, mask.mask_len); + XISetMask(mask.mask, XI_ButtonPress); + XISetMask(mask.mask, XI_ButtonRelease); + XISetMask(mask.mask, XI_Motion); + XISelectEvents(dpy2, win2, &mask, 1); + + /* set up client C for touch on the slave device, without ownership events */ + mask.deviceid = 6; + memset(mask.mask, 0, mask.mask_len); + XISetMask(mask.mask, XI_TouchBegin); + XISetMask(mask.mask, XI_TouchUpdate); + XISetMask(mask.mask, XI_TouchEnd); + XISelectEvents(dpy3, win3, &mask, 1); + + /* run test */ + + XSetInputFocus(dpy2, win2, RevertToPointerRoot, CurrentTime); + ASSERT_TRUE(NoEventPending(dpy)); + ASSERT_TRUE(NoEventPending(dpy2)); + ASSERT_TRUE(NoEventPending(dpy3)); + + TouchBegin((int)(150. * 9.375), 20); + ASSERT_EVENT(XIDeviceEvent, tbegin, dpy, GenericEvent, xi2_opcode, XI_TouchBegin); + ASSERT_EVENT(XIDeviceEvent, towner, dpy, GenericEvent, xi2_opcode, XI_TouchOwnership); + ASSERT_TRUE(NoEventPending(dpy)); + + ASSERT_EVENT(XIDeviceEvent, tbegin3, dpy3, GenericEvent, xi2_opcode, XI_TouchBegin); + ASSERT_TRUE(NoEventPending(dpy3)); + + TouchUpdate((int)(200. * 9.375), 20); + ASSERT_EVENT(XIDeviceEvent, tupdate, dpy, GenericEvent, xi2_opcode, XI_TouchUpdate); + ASSERT_TRUE(NoEventPending(dpy)); + + ASSERT_EVENT(XIDeviceEvent, m0_0, dpy2, GenericEvent, xi2_opcode, XI_Motion); + ASSERT_TRUE(NoEventPending(dpy2)); + + XIAllowTouchEvents(dpy, tbegin->deviceid, tbegin->detail, + DefaultRootWindow(dpy), XIRejectTouch); + + ASSERT_EVENT(XIDeviceEvent, tend, dpy, GenericEvent, xi2_opcode, XI_TouchEnd); + ASSERT_TRUE(NoEventPending(dpy)); + + ASSERT_EVENT(XIDeviceEvent, m0_1, dpy2, GenericEvent, xi2_opcode, XI_Motion); + ASSERT_EVENT(XIDeviceEvent, p0, dpy2, GenericEvent, xi2_opcode, XI_ButtonPress); + ASSERT_TRUE(NoEventPending(dpy2)); + + ASSERT_EVENT(XIDeviceEvent, tupdate3, dpy3, GenericEvent, xi2_opcode, XI_TouchUpdate); + ASSERT_TRUE(NoEventPending(dpy3)); + + bool grab = true; // Setting grab to false works as expected, but true fails + + if (grab) + XIGrabDevice(dpy3, tbegin3->deviceid, win3, tbegin3->time, None, GrabModeAsync, GrabModeAsync, true, &mask); + + TouchEnd(); + ASSERT_EVENT(XIDeviceEvent, tend3, dpy3, GenericEvent, xi2_opcode, XI_TouchEnd); + ASSERT_TRUE(NoEventPending(dpy3)); + + if (grab) + XIUngrabDevice(dpy3, tend3->deviceid, tend3->time); + + // XXX: Does this event get received when grab is called? XI_ButtonRelease should + // be received for sure. + EXPECT_EVENT(XIDeviceEvent, m0_2, dpy2, GenericEvent, xi2_opcode, XI_Motion); + EXPECT_EVENT(XIDeviceEvent, r0, dpy2, GenericEvent, xi2_opcode, XI_ButtonRelease); + ASSERT_TRUE(NoEventPending(dpy2)); + +#if 0 + // Not needed, but completely shows the error that pointer emulation no longer works + TouchBegin((int)(256 * 9.375), (256 * 9.375)); + + ASSERT_EVENT(XIDeviceEvent, tbegin2, dpy, GenericEvent, xi2_opcode, XI_TouchBegin); + ASSERT_EVENT(XIDeviceEvent, towner2, dpy, GenericEvent, xi2_opcode, XI_TouchOwnership); + ASSERT_TRUE(NoEventPending(dpy)); + + ASSERT_EVENT(XIDeviceEvent, m1_0, dpy2, GenericEvent, xi2_opcode, XI_Motion); + ASSERT_TRUE(NoEventPending(dpy2)); + + XIAllowTouchEvents(dpy, tbegin2->deviceid, tbegin2->detail, + DefaultRootWindow(dpy), XIRejectTouch); + + ASSERT_EVENT(XIDeviceEvent, tend2, dpy, GenericEvent, xi2_opcode, XI_TouchEnd); + ASSERT_TRUE(NoEventPending(dpy)); + + EXPECT_EVENT(XIDeviceEvent, m1_1, dpy2, GenericEvent, xi2_opcode, XI_Motion); + EXPECT_EVENT(XIDeviceEvent, p1, dpy2, GenericEvent, xi2_opcode, XI_ButtonPress); + ASSERT_TRUE(NoEventPending(dpy2)); + + TouchEnd(); + EXPECT_EVENT(XIDeviceEvent, r1, dpy2, GenericEvent, xi2_opcode, XI_ButtonRelease); + ASSERT_TRUE(NoEventPending(dpy2)); +#endif + + delete[] mask.mask; +} + class TouchGrabTestOnLegacyClient : public TouchGrabTest { virtual void SetUp() { SetDevice("tablets/N-Trig-MultiTouch.desc");