dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * Automated test of the X11 seamless Additions code.
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync * @todo Better separate test data from implementation details!
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2007-2011 Oracle Corporation
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * available from http://www.virtualbox.org. This file is free software;
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * you can redistribute it and/or modify it under the terms of the GNU
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * General Public License (GPL) as published by the Free Software
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/******************************************************
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync* Mock X11 functions needed by the seamless X11 class *
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync******************************************************/
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Display *XOpenDisplay(const char *display_name);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Atom XInternAtom(Display *display, const char *atom_name,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncAtom XInternAtom(Display *display, const char *atom_name, Bool only_if_exists)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/** The window (if any) on which the WM_TYPE_PROP property is set to the
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * WM_TYPE_DESKTOP_PROP atom. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" int XGetWindowProperty(Display *display, Window w, Atom property,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned long *nitems_return,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned long *bytes_after_return,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned char **prop_return);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncint XGetWindowProperty(Display *display, Window w, Atom property,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned long *nitems_return,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned long *bytes_after_return,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned char **prop_return)
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync Atom atomType = XInternAtom (display, WM_TYPE_PROP, true);
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync Atom atomTypeDesktop = XInternAtom (display, WM_TYPE_DESKTOP_PROP, true);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /* We only handle things we expect. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync AssertReturn((req_type == XA_ATOM) || (req_type == AnyPropertyType),
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync if ((w != g_hSmlsDesktopWindow) || (g_hSmlsDesktopWindow == 0))
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync pProp = (unsigned char *)RTMemDup(&atomTypeDesktop,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/** Sets the current set of properties for all mock X11 windows */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Bool XShapeQueryExtension (Display *dpy, int *event_basep,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncBool XShapeQueryExtension (Display *dpy, int *event_basep, int *error_basep)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync return true;
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/* We silently ignore this for now. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" int XSelectInput(Display *display, Window w, long event_mask);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncint XSelectInput(Display *display, Window w, long event_mask)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/* We silently ignore this for now. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" void XShapeSelectInput(Display *display, Window w,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned long event_mask);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncvoid XShapeSelectInput(Display *display, Window w, unsigned long event_mask)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Window XDefaultRootWindow(Display *display);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncstatic XWindowAttributes *g_paSmlsWinAttribs = NULL;
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Status XQueryTree(Display *display, Window w, Window *root_return,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned int *nchildren_return);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncStatus XQueryTree(Display *display, Window w, Window *root_return,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync unsigned int *nchildren_return)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync AssertReturn(w == TEST_ROOT, False); /* We support nothing else */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync *children_return = (Window *)RTMemDup(g_paSmlsWindows,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync return (g_cSmlsWindows != 0);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Window XmuClientWindow(Display *dpy, Window win);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Status XGetWindowAttributes(Display *display, Window w,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncStatus XGetWindowAttributes(Display *display, Window w,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync for (unsigned i = 0; i < g_cSmlsWindows; ++i)
9cba9a10f12ba5184ad5d2a3ce05b0caba8d09favboxsyncextern "C" Status XGetWMNormalHints(Display *display, Window w,
9cba9a10f12ba5184ad5d2a3ce05b0caba8d09favboxsyncStatus XGetWMNormalHints(Display *display, Window w,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncstatic void smlsSetWindowAttributes(XWindowAttributes *pAttribs,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync const char **paNames)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" XRectangle *XShapeGetRectangles (Display *dpy, Window window,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncXRectangle *XShapeGetRectangles (Display *dpy, Window window, int kind,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync if ((window != g_SmlsShapedWindow) || (window == 0))
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync return NULL; /* Probably not correct, but works for us. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync return (XRectangle *)RTMemDup(g_pSmlsShapeRectangles,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncstatic void smlsSetShapeRectangles(Window window, int cRects,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/* This should not be needed in the bits of the code we test. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" int XNextEvent(Display *display, XEvent *event_return);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncint XNextEvent(Display *display, XEvent *event_return)
938e0729a8e58abec28ef5e9cdb7bf1fabac6b58vboxsyncstatic void smlsSetNextEvent(int type, Window window)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/* This should not be needed in the bits of the code we test. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncextern "C" Status XSendEvent(Display *display, Window w, Bool propagate,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncStatus XSendEvent(Display *display, Window w, Bool propagate,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/* This should not be needed in the bits of the code we test. */
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsync/** Global "received a notification" flag. */
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsync/** Dummy host call-back. */
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsyncstatic void sendRegionUpdate(RTRECT *pRects, size_t cRects)
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsync return false;
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsync return true;
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/*****************************
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync* The actual tests to be run *
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync*****************************/
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/** The name of the unit test */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/*** Test fixture data and data structures ***/
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/** A structure describing a test fixture to be run through. Each fixture
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * describes the state of the windows visible (and unmapped) on the X server
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * before and after a particular event is delivered, and the expected
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * on-screen positions of all interesting visible windows at the end of the
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * fixture as reported by the code (currently in the order it is likely to
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * report them in, @todo sort this). We expect that the set of visible
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * windows will be the same whether we start the code before the event and
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * handle it or start the code after the event.
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The number of windows visible before the event */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** An array of Window IDs for the visible and unmapped windows before
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * the event */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The window attributes matching the windows in @a paWindowsBefore */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The window names matching the windows in @a paWindowsBefore */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The shaped window before the event - we allow at most one of these.
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * Zero for none. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The number of rectangles in the shaped window before the event. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The rectangles in the shaped window before the event */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The number of windows visible after the event */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** An array of Window IDs for the visible and unmapped windows after
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * the event */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The window attributes matching the windows in @a paWindowsAfter */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The window names matching the windows in @a paWindowsAfter */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The shaped window after the event - we allow at most one of these.
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * Zero for none. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The number of rectangles in the shaped window after the event. */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The rectangles in the shaped window after the event */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The event to delivered */
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync /** The window for which the event in @enmEvent is delivered */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The number of windows expected to be reported at the end of the
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync * fixture */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync /** The onscreen positions of those windows. */
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsync /** Do we expect notification after the event? */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/*** Test fixture to test the code against X11 configure (move) events ***/
7f581f9444a4d569475da724d7fde45b9a225899vboxsync{ { 100, 200, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsViewable }
7f581f9444a4d569475da724d7fde45b9a225899vboxsync{ { 200, 300, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsViewable }
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncstatic const char *g_apszNames1[] = { "Test Window" };
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncAssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib1Before));
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncAssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib1After));
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncAssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_apszNames1));
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/*** Test fixture to test the code against X11 configure (resize) events ***/
7f581f9444a4d569475da724d7fde45b9a225899vboxsync{ { 100, 200, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsViewable }
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncAssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib2Before));
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/*** Test fixture to test the code against X11 map events ***/
7f581f9444a4d569475da724d7fde45b9a225899vboxsync{ { 200, 300, 200, 300, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsUnmapped }
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncAssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib3Before));
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync/*** Test fixtures to test the code against X11 unmap events ***/
7f581f9444a4d569475da724d7fde45b9a225899vboxsync{ { 100, 200, 300, 400, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IsUnmapped }
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncAssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib4After));
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync/*** A window we are not monitoring has been unmapped. Nothing should
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync *** happen, especially nothing bad. ***/
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/*** Test fixture to test the code against X11 shape events ***/
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/*** And the test code proper ***/
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/** Compare two RTRECT structures */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncstatic bool smlsCompRect(RTRECT *pFirst, RTRECT *pSecond)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncstatic void smlsPrintDiffRects(RTRECT *pExp, RTRECT *pGot)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync RTPrintf(" Expected: %d, %d, %d, %d. Got: %d, %d, %d, %d\n",
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync pExp->xLeft, pExp->yTop, pExp->xRight, pExp->yBottom,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync pGot->xLeft, pGot->yTop, pGot->xRight, pGot->yBottom);
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync/** Run through a test fixture */
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsyncstatic unsigned smlsDoFixture(SMLSFIXTURE *pFixture, const char *pszDesc)
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync smlsSetShapeRectangles(pFixture->hShapeWindowBefore,
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync smlsSetShapeRectangles(pFixture->hShapeWindowAfter,
938e0729a8e58abec28ef5e9cdb7bf1fabac6b58vboxsync smlsSetNextEvent(pFixture->x11EventType, pFixture->hEventWindow);
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsync if (gotNotification()) /* Initial window tree rebuild */
938e0729a8e58abec28ef5e9cdb7bf1fabac6b58vboxsync RTPrintf("%s: fixture: %s. Notification was set before the first event!!!\n",
938e0729a8e58abec28ef5e9cdb7bf1fabac6b58vboxsync RTPrintf("%s: fixture: %s. No notification was sent for the initial window tree rebuild.\n",
d94f612deb40b0526d5752b3bfd04707d3f7ff2bvboxsync if (pFixture->fExpectNotification && !gotNotification())
938e0729a8e58abec28ef5e9cdb7bf1fabac6b58vboxsync RTPrintf("%s: fixture: %s. No notification was sent after the event.\n",
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync RTPrintf("%s: fixture: %s. Wrong number of rectangles reported after processing event (expected %u, got %u).\n",
133ac536a3d32062cf6b4c076da39da9e80f91a5vboxsync for (unsigned i = 0; i < cRects; ++i)
133ac536a3d32062cf6b4c076da39da9e80f91a5vboxsync if (!smlsCompRect(&pRects[i], &pFixture->paReportedRects[i]))
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync RTPrintf("%s: fixture: %s. Rectangle %u wrong after processing event.\n",
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync RTPrintf("%s: fixture: %s. Wrong number of rectangles reported without processing event (expected %u, got %u).\n",
133ac536a3d32062cf6b4c076da39da9e80f91a5vboxsync for (unsigned i = 0; i < cRects; ++i)
133ac536a3d32062cf6b4c076da39da9e80f91a5vboxsync if (!smlsCompRect(&pRects[i], &pFixture->paReportedRects[i]))
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync RTPrintf("%s: fixture: %s. Rectangle %u wrong without processing event.\n",
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync "ConfigureNotify event (window moved)");
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync // Currently not working
b65d53aa41a5d4f584a5ae6833c741dad0a4da43vboxsync "ConfigureNotify event (window resized)");
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync cErrs += smlsDoFixture(&g_testMap, "MapNotify event");
dab2041a9c063e43814b7b69538c2856cd78bd18vboxsync cErrs += smlsDoFixture(&g_testUnmap, "UnmapNotify event");
b6415accd33648174afbfd16edc4dc0f894a6bf2vboxsync "UnmapNotify event for unmonitored window");
d6e0f6a5d8642c681e6d12d43fc0069da7a5dff6vboxsync cErrs += smlsDoFixture(&g_testShape, "ShapeNotify event");