diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2012-10-23 11:56:42 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2012-10-23 11:56:42 +1000 |
commit | e2c8baf6e9124dab6d15258f1dd6d69b627ddde4 (patch) | |
tree | 668644acf4c2c51ebcf9dea8e9c0533039c690d3 | |
parent | 197ca79abd3324e65e2b9e06de7ae7f451282238 (diff) | |
parent | 7361f8b29b89bb80f384054bc5cce1dea35f376b (diff) |
Merge branch 'wait-for-device-fix'
-rw-r--r-- | src/xserver.cpp | 109 | ||||
-rw-r--r-- | test/xserver-test.cpp | 120 |
2 files changed, 225 insertions, 4 deletions
diff --git a/src/xserver.cpp b/src/xserver.cpp index 1ba4e08..9803e1f 100644 --- a/src/xserver.cpp +++ b/src/xserver.cpp @@ -164,18 +164,117 @@ bool xorg::testing::XServer::WaitForEventOfType(::Display *display, int type, in return false; } +static XIEventMask* set_hierarchy_mask(::Display *display, + int *nmasks_out, + bool *was_set, + bool *was_created) +{ + XIEventMask *masks; + int nmasks; + bool mask_toggled = false; + bool new_mask_created = false; + XIEventMask *all_devices_mask = NULL; + + masks = XIGetSelectedEvents(display, DefaultRootWindow(display), &nmasks); + + /* masks is in a quirky data format (one chunk of memory). Change into a + format easier to manipulate. */ + + /* extra one, in case we have zero masks or no XIAllDevices mask */ + XIEventMask *new_masks = new XIEventMask[nmasks + 1]; + for (int i = 0; i < nmasks; i++) { + XIEventMask *m = &new_masks[i]; + *m = masks[i]; + + if (masks[i].deviceid == XIAllDevices) { + all_devices_mask = m; + if (masks[i].mask_len < XIMaskLen(XI_HierarchyChanged)) { + m->mask_len = XIMaskLen(XI_HierarchyChanged); + mask_toggled = true; + } else + mask_toggled = !XIMaskIsSet(m->mask, XI_HierarchyChanged); + } + + m->mask = new unsigned char[m->mask_len](); + memcpy(m->mask, masks[i].mask, masks[i].mask_len); + + if (mask_toggled && m->deviceid == XIAllDevices) + XISetMask(m->mask, XI_HierarchyChanged); + } + + if (!all_devices_mask) { + all_devices_mask = &new_masks[nmasks++]; + all_devices_mask->deviceid = XIAllDevices; + all_devices_mask->mask_len = XIMaskLen(XI_HierarchyChanged); + all_devices_mask->mask = new unsigned char[all_devices_mask->mask_len](); + XISetMask(all_devices_mask->mask, XI_HierarchyChanged); + new_mask_created = true; + } + + XFree(masks); + masks = NULL; + + if (new_mask_created || mask_toggled) { + XISelectEvents(display, DefaultRootWindow(display), new_masks, nmasks); + XFlush(display); + } + + *was_set = mask_toggled; + *was_created = new_mask_created; + *nmasks_out = nmasks; + + return new_masks; +} + +static void unset_hierarchy_mask(::Display *display, + XIEventMask *masks, int nmasks, + bool was_set, bool was_created) +{ + if (was_set || was_created) { + if (was_set) { + for (int i = 0; i < nmasks; i++) { + if (masks[i].deviceid == XIAllDevices) + XIClearMask(masks[i].mask, XI_HierarchyChanged); + } + } else if (was_created) + masks[nmasks - 1].mask_len = 0; + XISelectEvents(display, DefaultRootWindow(display), masks, nmasks); + XFlush(display); + } + + for (int i = 0; i < nmasks; i++) + delete[] masks[i].mask; + delete[] masks; +} + bool xorg::testing::XServer::WaitForDevice(::Display *display, const std::string &name, time_t timeout) { int opcode; int event_start; int error_start; + bool device_found = false; if (!XQueryExtension(display, "XInputExtension", &opcode, &event_start, &error_start)) throw std::runtime_error("Failed to query XInput extension"); - while (WaitForEventOfType(display, GenericEvent, opcode, + XIEventMask *masks; + int nmasks; + bool mask_set, mask_created; + masks = set_hierarchy_mask(display, &nmasks, &mask_set, &mask_created); + + XIDeviceInfo *info; + int ndevices; + + info = XIQueryDevice(display, XIAllDevices, &ndevices); + for (int i = 0; !device_found && i < ndevices; i++) { + device_found = (name.compare(info[i].name) == 0); + } + XIFreeDeviceInfo(info); + + while (!device_found && + WaitForEventOfType(display, GenericEvent, opcode, XI_HierarchyChanged, timeout)) { XEvent event; if (XNextEvent(display, &event) != Success) @@ -194,7 +293,7 @@ bool xorg::testing::XServer::WaitForDevice(::Display *display, const std::string continue; } - bool device_found = false; + device_found = false; for (int i = 0; i < hierarchy_event->num_info; i++) { if (!(hierarchy_event->info[i].flags & XIDeviceEnabled)) continue; @@ -215,10 +314,12 @@ bool xorg::testing::XServer::WaitForDevice(::Display *display, const std::string XFreeEventData(display, xcookie); if (device_found) - return true; + break; } - return false; + unset_hierarchy_mask(display, masks, nmasks, mask_set, mask_created); + + return device_found; } void xorg::testing::XServer::WaitForConnections(void) { diff --git a/test/xserver-test.cpp b/test/xserver-test.cpp index 5faa6ca..932dff6 100644 --- a/test/xserver-test.cpp +++ b/test/xserver-test.cpp @@ -5,6 +5,7 @@ #include <fstream> #include <xorg/gtest/xorg-gtest.h> +#include <X11/extensions/XInput2.h> using namespace xorg::testing; @@ -71,6 +72,125 @@ TEST(XServer, WaitForSIGUSR1) } } +static void assert_masks_equal(Display *dpy) +{ + int nmasks_before; + XIEventMask *masks_before; + int nmasks_after; + XIEventMask *masks_after; + + masks_before = XIGetSelectedEvents(dpy, DefaultRootWindow(dpy), &nmasks_before); + XServer::WaitForDevice(dpy, "not actually waiting for device", 1); + masks_after = XIGetSelectedEvents(dpy, DefaultRootWindow(dpy), &nmasks_after); + + ASSERT_EQ(nmasks_before, nmasks_after); + + for (int i = 0; i < nmasks_before; i++) { + ASSERT_EQ(masks_before[i].deviceid, masks_after[i].deviceid); + ASSERT_EQ(masks_before[i].mask_len, masks_after[i].mask_len); + ASSERT_EQ(memcmp(masks_before[i].mask, masks_after[i].mask, masks_before[i].mask_len), 0); + } + + XFree(masks_before); + XFree(masks_after); + +} + +TEST(XServer, WaitForDeviceEventMask) +{ + XORG_TESTCASE("The event mask is left as-is by WaitForDevice"); + + XServer server; + server.SetOption("-logfile", "/tmp/Xorg-WaitForDevice.log"); + server.SetOption("-noreset", ""); + server.Start(); + ASSERT_EQ(server.GetState(), Process::RUNNING); + ::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str()); + ASSERT_TRUE(dpy != NULL); + int major = 2, minor = 0; + XIQueryVersion(dpy, &major, &minor); + + /* empty mask */ + assert_masks_equal(dpy); + + /* device specific mask */ + XIEventMask m; + m.deviceid = 2; + m.mask_len = 1; + m.mask = new unsigned char[m.mask_len](); + XISetMask(m.mask, XI_Motion); + XISelectEvents(dpy, DefaultRootWindow(dpy), &m, 1); + + assert_masks_equal(dpy); + delete m.mask; + + /* XIAllDevices mask with short mask */ + m.deviceid = XIAllDevices; + m.mask_len = 1; + m.mask = new unsigned char[m.mask_len](); + XISetMask(m.mask, XI_Motion); + XISelectEvents(dpy, DefaultRootWindow(dpy), &m, 1); + + assert_masks_equal(dpy); + delete m.mask; + + /* XIAllDevices mask with hierarchy bit not set */ + m.deviceid = XIAllDevices; + m.mask_len = XIMaskLen(XI_HierarchyChanged); + m.mask = new unsigned char[m.mask_len](); + XISetMask(m.mask, XI_Motion); + XISelectEvents(dpy, DefaultRootWindow(dpy), &m, 1); + + assert_masks_equal(dpy); + delete m.mask; + + /* XIAllDevices mask with hierarchy bit set */ + m.deviceid = XIAllDevices; + m.mask_len = XIMaskLen(XI_HierarchyChanged); + m.mask = new unsigned char[m.mask_len](); + XISetMask(m.mask, XI_HierarchyChanged); + XISelectEvents(dpy, DefaultRootWindow(dpy), &m, 1); + + assert_masks_equal(dpy); + delete m.mask; +} + +#ifdef HAVE_EVEMU +TEST(XServer, WaitForExistingDevice) +{ + XORG_TESTCASE("WaitForDevice() returns true for already existing device"); + + xorg::testing::evemu::Device d(TEST_ROOT_DIR "PIXART-USB-OPTICAL-MOUSE.desc"); + + XServer server; + server.SetOption("-logfile", "/tmp/Xorg-WaitForDevice.log"); + server.SetOption("-noreset", ""); + server.Start(); + ASSERT_EQ(server.GetState(), Process::RUNNING); + ::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str()); + ASSERT_TRUE(dpy != NULL); + + ASSERT_TRUE(XServer::WaitForDevice(dpy, "PIXART USB OPTICAL MOUSE", 1000)); +} + +TEST(XServer, WaitForNewDevice) +{ + XORG_TESTCASE("WaitForDevice() waits for newly created dvice"); + + XServer server; + server.SetOption("-logfile", "/tmp/Xorg-WaitForDevice.log"); + server.SetOption("-noreset", ""); + server.Start(); + ASSERT_EQ(server.GetState(), Process::RUNNING); + ::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str()); + ASSERT_TRUE(dpy != NULL); + + xorg::testing::evemu::Device d(TEST_ROOT_DIR "PIXART-USB-OPTICAL-MOUSE.desc"); + + ASSERT_TRUE(XServer::WaitForDevice(dpy, "PIXART USB OPTICAL MOUSE", 1000)); +} +#endif + int main(int argc, char *argv[]) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); |