summaryrefslogtreecommitdiff
path: root/tests/server/touch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/server/touch.cpp')
-rw-r--r--tests/server/touch.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/tests/server/touch.cpp b/tests/server/touch.cpp
index 316111f..d21cb05 100644
--- a/tests/server/touch.cpp
+++ b/tests/server/touch.cpp
@@ -601,6 +601,200 @@ TEST_F(TouchTest, TouchEventsButtonState)
XFreeEventData(Display(), &ev.xcookie);
}
+
+static const int WINDOW_HIERARCHY_DEPTH = 5;
+struct event_history_test {
+ int window_depth; /* window hierarchy depth to be created */
+ int grab_window_idx; /* grab window idx in that hierarchy */
+ int event_window_idx; /* event window idx in that hierarchy */
+};
+
+void PrintTo(const struct event_history_test &eht, ::std::ostream *os) {
+ *os << "depth: " << eht.window_depth << " grab window idx: " <<
+ eht.grab_window_idx << " event window idx: " <<
+ eht.event_window_idx;
+}
+
+/**
+ * @tparam depth of window hierarchy
+ */
+class TouchEventHistoryTest : public TouchTest,
+ public ::testing::WithParamInterface<struct event_history_test> {};
+
+std::vector<Window> create_window_hierarchy(Display *dpy, int depth) {
+ Window root = DefaultRootWindow(dpy);
+
+ std::vector<Window> windows;
+
+ windows.push_back(root);
+
+ Window parent = root;
+ Window top_parent = None;
+ while(depth--) {
+ Window win;
+ win = XCreateSimpleWindow(dpy, parent, 0, 0,
+ DisplayWidth(dpy, DefaultScreen(dpy)),
+ DisplayHeight(dpy, DefaultScreen(dpy)),
+ 0, 0, 0);
+ if (top_parent == None)
+ XSelectInput(dpy, win, StructureNotifyMask);
+ XMapWindow(dpy, win);
+
+ windows.push_back(win);
+ parent = win;
+ }
+
+ if (windows.size() > 1) {
+ XSync(dpy, False);
+
+ if (xorg::testing::XServer::WaitForEventOfType(dpy, MapNotify, -1, -1)) {
+ XEvent ev;
+ XNextEvent(dpy, &ev);
+ } else {
+ ADD_FAILURE() << "Failed waiting for Exposure";
+ }
+
+ XSelectInput(dpy, windows[1], 0);
+
+ }
+ XSync(dpy, True);
+
+ return windows;
+}
+
+TEST_P(TouchEventHistoryTest, EventHistoryReplay) {
+ struct event_history_test test_params = GetParam();
+ std::stringstream ss;
+ ss << "Window hierarchy depth: " << test_params.window_depth << "\n";
+ ss << "Grab window is window #" << test_params.grab_window_idx << "\n";
+ ss << "Event window is window #" << test_params.event_window_idx << "\n";
+
+ XORG_TESTCASE("Create a window hierarchy\n"
+ "Create a passive touch grab on one of the windows\n"
+ "Select for touch events on the same or a child window\n"
+ "Trigger touch grab\n"
+ "Receive all touch events\n"
+ "Reject touch grab\n"
+ "Receive replayed touch events\n"
+ "Compare original and replayed touch events for equality\n");
+ SCOPED_TRACE(ss.str());
+
+ std::vector<Window> windows;
+ windows = create_window_hierarchy(Display(), test_params.window_depth);
+ Window grab_window = windows[test_params.grab_window_idx];
+ Window event_window = windows[test_params.event_window_idx];
+
+ XIEventMask mask;
+ mask.deviceid = VIRTUAL_CORE_POINTER_ID;
+ mask.mask_len = XIMaskLen(XI_TouchEnd);
+ mask.mask = new unsigned char[mask.mask_len]();
+ XISetMask(mask.mask, XI_TouchBegin);
+ XISetMask(mask.mask, XI_TouchUpdate);
+ XISetMask(mask.mask, XI_TouchEnd);
+ XISelectEvents(Display(), event_window, &mask, 1);
+ XSync(Display(), False);
+
+ XIGrabModifiers mods = {};
+ mods.modifiers = XIAnyModifier;
+ ASSERT_EQ(Success, XIGrabTouchBegin(Display(), VIRTUAL_CORE_POINTER_ID,
+ grab_window, False, &mask, 1, &mods));
+
+ XSync(Display(), False);
+
+ dev->Play(RECORDINGS_DIR "tablets/N-Trig-MultiTouch.touch_1_begin.events");
+ dev->Play(RECORDINGS_DIR "tablets/N-Trig-MultiTouch.touch_1_end.events");
+
+ ASSERT_TRUE(xorg::testing::XServer::WaitForEventOfType(Display(),
+ GenericEvent,
+ xi2_opcode,
+ XI_TouchBegin));
+
+ std::vector<XIDeviceEvent> events; /* static copy, don't use pointers */
+ int touchid = -1;
+
+ while(XPending(Display())) {
+ XEvent ev;
+ XNextEvent(Display(), &ev);
+ ASSERT_EQ(ev.type, GenericEvent);
+ ASSERT_EQ(ev.xcookie.extension, xi2_opcode);
+
+ ASSERT_TRUE(XGetEventData(Display(), &ev.xcookie));
+ XIDeviceEvent *de = reinterpret_cast<XIDeviceEvent*>(ev.xcookie.data);
+
+ if (touchid < 0)
+ touchid = de->detail;
+ else
+ ASSERT_EQ(de->detail, touchid);
+
+ ASSERT_EQ(de->deviceid, VIRTUAL_CORE_POINTER_ID);
+ ASSERT_EQ(de->event, grab_window);
+
+ events.push_back(*de);
+
+ if (ev.type == XI_TouchEnd)
+ break;
+ }
+
+ ASSERT_GT(events.size(), 0UL);
+ ASSERT_EQ(events.front().evtype, XI_TouchBegin);
+ ASSERT_EQ(events.back().evtype, XI_TouchEnd);
+
+ XIAllowTouchEvents(Display(), VIRTUAL_CORE_POINTER_ID, touchid,
+ grab_window, XIRejectTouch);
+ XSync(Display(), False);
+
+ ASSERT_TRUE(xorg::testing::XServer::WaitForEventOfType(Display(),
+ GenericEvent,
+ xi2_opcode,
+ XI_TouchBegin));
+ for (std::vector<XIDeviceEvent>::const_iterator it = events.begin();
+ it != events.end();
+ it++)
+ {
+ XEvent ev;
+ XNextEvent(Display(), &ev);
+
+ ASSERT_TRUE(XGetEventData(Display(), &ev.xcookie));
+
+ XIDeviceEvent *current;
+ const XIDeviceEvent *old;
+ old = &(*it);
+ current = reinterpret_cast<XIDeviceEvent*>(ev.xcookie.data);
+
+ EXPECT_EQ(old->evtype, current->evtype);
+ EXPECT_EQ(old->deviceid, current->deviceid);
+ EXPECT_EQ(old->detail, current->detail);
+ EXPECT_EQ(old->root_x, current->root_x);
+ EXPECT_EQ(old->root_y, current->root_y);
+ EXPECT_EQ(old->event_x, current->event_x);
+ EXPECT_EQ(old->event_y, current->event_y);
+
+ EXPECT_EQ(current->event, event_window);
+ }
+}
+
+static std::vector<struct event_history_test> generate_event_history_test_cases(int max_depth) {
+ std::vector<struct event_history_test> v;
+
+ for (int wd = 0; wd < max_depth; wd++) {
+ for (int gwidx = 0; gwidx < wd; gwidx++) {
+ for (int ewidx = gwidx; ewidx < wd; ewidx++) {
+ struct event_history_test eht = {
+ .window_depth = wd,
+ .grab_window_idx = gwidx,
+ .event_window_idx = ewidx,
+ };
+ v.push_back(eht);
+ }
+ }
+ }
+ return v;
+}
+
+INSTANTIATE_TEST_CASE_P(, TouchEventHistoryTest,
+ ::testing::ValuesIn(generate_event_history_test_cases(WINDOW_HIERARCHY_DEPTH)));
+
+
#endif /* HAVE_XI22 */
INSTANTIATE_TEST_CASE_P(, TouchTestXI2Version, ::testing::Range(0, XI_2_Minor + 1));