VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/VBoxClient/testcase/tstSeamlessX11-auto.cpp@ 21638

Last change on this file since 21638 was 21638, checked in by vboxsync, 15 years ago

Additions/x11/seamless: make moving windows in KDE guests work correctly

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.5 KB
Line 
1/** @file
2 * Automated test of the X11 seamless Additions code.
3 */
4
5/*
6 * Copyright (C) 2007 Sun Microsystems, Inc.
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20
21#include <iostream>
22#include <stdlib.h> /* exit() */
23
24#include <X11/Xatom.h>
25#include <X11/Xmu/WinUtil.h>
26
27#include <iprt/initterm.h>
28#include <iprt/mem.h>
29#include <iprt/path.h>
30#include <iprt/semaphore.h>
31#include <iprt/stream.h>
32#include <iprt/string.h>
33
34#include "../seamless.h"
35
36#undef DefaultRootWindow
37
38/******************************************************
39* Mock X11 functions needed by the seamless X11 class *
40******************************************************/
41
42int XFree(void *data)
43{
44 RTMemFree(data);
45 return 0;
46}
47
48#define TEST_DISPLAY ((Display *)0xffff)
49#define TEST_ROOT ((Window)1)
50
51extern "C" Display *XOpenDisplay(const char *display_name);
52Display *XOpenDisplay(const char *display_name)
53{
54 return TEST_DISPLAY;
55}
56
57extern "C" int XCloseDisplay(Display *display);
58int XCloseDisplay(Display *display)
59{
60 Assert(display == TEST_DISPLAY);
61 return 0;
62}
63
64enum
65{
66 ATOM_PROP = 1,
67 ATOM_DESKTOP_PROP
68};
69
70extern "C" Atom XInternAtom(Display *display, const char *atom_name,
71 Bool only_if_exists);
72Atom XInternAtom(Display *display, const char *atom_name, Bool only_if_exists)
73{
74 if (!RTStrCmp(atom_name, WM_TYPE_PROP))
75 return (Atom) ATOM_PROP;
76 if (!RTStrCmp(atom_name, WM_TYPE_DESKTOP_PROP))
77 return (Atom) ATOM_DESKTOP_PROP;
78 AssertFailed();
79 return (Atom)0;
80}
81
82/** The window (if any) on which the WM_TYPE_PROP property is set to the
83 * WM_TYPE_DESKTOP_PROP atom. */
84static Window g_hSmlsDesktopWindow = 0;
85
86extern "C" int XGetWindowProperty(Display *display, Window w, Atom property,
87 long long_offset, long long_length,
88 Bool delProp, Atom req_type,
89 Atom *actual_type_return,
90 int *actual_format_return,
91 unsigned long *nitems_return,
92 unsigned long *bytes_after_return,
93 unsigned char **prop_return);
94int XGetWindowProperty(Display *display, Window w, Atom property,
95 long long_offset, long long_length, Bool delProp,
96 Atom req_type, Atom *actual_type_return,
97 int *actual_format_return,
98 unsigned long *nitems_return,
99 unsigned long *bytes_after_return,
100 unsigned char **prop_return)
101{
102 Atom atomType = XInternAtom (NULL, WM_TYPE_PROP, true);
103 Atom atomTypeDesktop = XInternAtom (NULL, WM_TYPE_DESKTOP_PROP, true);
104 /* We only handle things we expect. */
105 AssertReturn((req_type == XA_ATOM) || (req_type == AnyPropertyType),
106 0xffff);
107 AssertReturn(property == atomType, 0xffff);
108 *actual_type_return = XA_ATOM;
109 *actual_format_return = sizeof(Atom) * 8;
110 *nitems_return = 0;
111 *bytes_after_return = sizeof(Atom);
112 *prop_return = NULL;
113 if ((w != g_hSmlsDesktopWindow) || (g_hSmlsDesktopWindow == 0))
114 return Success;
115 AssertReturn(long_offset == 0, 0);
116 AssertReturn(delProp == false, 0);
117 unsigned char *pProp;
118 pProp = (unsigned char *)RTMemDup(&atomTypeDesktop,
119 sizeof(atomTypeDesktop));
120 AssertReturn(pProp, 0xffff);
121 *nitems_return = 1;
122 *prop_return = pProp;
123 *bytes_after_return = 0;
124 return 0;
125}
126
127/** Sets the current set of properties for all mock X11 windows */
128static void smlsSetDesktopWindow(Window hWin)
129{
130 g_hSmlsDesktopWindow = hWin;
131}
132
133extern "C" Bool XShapeQueryExtension (Display *dpy, int *event_basep,
134 int *error_basep);
135Bool XShapeQueryExtension (Display *dpy, int *event_basep, int *error_basep)
136{
137 return true;
138}
139
140/* We silently ignore this for now. */
141extern "C" int XSelectInput(Display *display, Window w, long event_mask);
142int XSelectInput(Display *display, Window w, long event_mask)
143{
144 return 0;
145}
146
147/* We silently ignore this for now. */
148extern "C" void XShapeSelectInput(Display *display, Window w,
149 unsigned long event_mask);
150void XShapeSelectInput(Display *display, Window w, unsigned long event_mask)
151{}
152
153extern "C" Window XDefaultRootWindow(Display *display);
154Window XDefaultRootWindow(Display *display)
155{
156 return TEST_ROOT;
157}
158
159static unsigned g_cSmlsWindows = 0;
160static Window *g_paSmlsWindows = NULL;
161static XWindowAttributes *g_paSmlsWinAttribs = NULL;
162static const char **g_papszSmlsWinNames = NULL;
163
164extern "C" Status XQueryTree(Display *display, Window w, Window *root_return,
165 Window *parent_return, Window **children_return,
166 unsigned int *nchildren_return);
167Status XQueryTree(Display *display, Window w, Window *root_return,
168 Window *parent_return, Window **children_return,
169 unsigned int *nchildren_return)
170{
171 AssertReturn(w == TEST_ROOT, False); /* We support nothing else */
172 AssertPtrReturn(children_return, False);
173 AssertReturn(g_paSmlsWindows, False);
174 if (root_return)
175 *root_return = TEST_ROOT;
176 if (parent_return)
177 *parent_return = TEST_ROOT;
178 *children_return = (Window *)RTMemDup(g_paSmlsWindows,
179 g_cSmlsWindows * sizeof(Window));
180 if (nchildren_return)
181 *nchildren_return = g_cSmlsWindows;
182 return (g_cSmlsWindows != 0);
183}
184
185extern "C" Window XmuClientWindow(Display *dpy, Window win);
186Window XmuClientWindow(Display *dpy, Window win)
187{
188 return win;
189}
190
191extern "C" Status XGetWindowAttributes(Display *display, Window w,
192 XWindowAttributes *window_attributes_return);
193Status XGetWindowAttributes(Display *display, Window w,
194 XWindowAttributes *window_attributes_return)
195{
196 AssertPtrReturn(window_attributes_return, 1);
197 for (unsigned i = 0; i < g_cSmlsWindows; ++i)
198 if (g_paSmlsWindows[i] == w)
199 {
200 *window_attributes_return = g_paSmlsWinAttribs[i];
201 return 1;
202 }
203 return 0;
204}
205
206extern "C" Status XFetchName(Display *display, Window w,
207 char **window_name_return);
208Status XFetchName(Display *display, Window w, char **window_name_return)
209{
210 AssertPtrReturn(window_name_return, 1);
211 for (unsigned i = 0; i < g_cSmlsWindows; ++i)
212 if (g_paSmlsWindows[i] == w)
213 {
214 *window_name_return = (char *)RTMemDup(g_papszSmlsWinNames[i],
215 strlen(g_papszSmlsWinNames[i]) + 1);
216 return *window_name_return != NULL;
217 }
218 return 0;
219}
220
221extern "C" Status XGetWMNormalHints(Display *display, Window w,
222 XSizeHints *hints_return,
223 long *supplied_return);
224
225Status XGetWMNormalHints(Display *display, Window w,
226 XSizeHints *hints_return, long *supplied_return)
227{
228 return 1;
229}
230
231static void smlsSetWindowAttributes(XWindowAttributes *pAttribs,
232 Window *pWindows, unsigned cAttribs,
233 const char **paNames)
234{
235 g_paSmlsWinAttribs = pAttribs;
236 g_paSmlsWindows = pWindows;
237 g_cSmlsWindows = cAttribs;
238 g_papszSmlsWinNames = paNames;
239}
240
241static Window g_SmlsShapedWindow = 0;
242static int g_cSmlsShapeRectangles = 0;
243static XRectangle *g_pSmlsShapeRectangles = NULL;
244
245extern "C" XRectangle *XShapeGetRectangles (Display *dpy, Window window,
246 int kind, int *count,
247 int *ordering);
248XRectangle *XShapeGetRectangles (Display *dpy, Window window, int kind,
249 int *count, int *ordering)
250{
251 if ((window != g_SmlsShapedWindow) || (window == 0))
252 return NULL; /* Probably not correct, but works for us. */
253 *count = g_cSmlsShapeRectangles;
254 *ordering = 0;
255 return (XRectangle *)RTMemDup(g_pSmlsShapeRectangles,
256 sizeof(XRectangle)
257 * g_cSmlsShapeRectangles);
258}
259
260static void smlsSetShapeRectangles(Window window, int cRects,
261 XRectangle *pRects)
262{
263 g_SmlsShapedWindow = window;
264 g_cSmlsShapeRectangles = cRects;
265 g_pSmlsShapeRectangles = pRects;
266}
267
268/* This should not be needed in the bits of the code we test. */
269extern "C" int XNextEvent(Display *display, XEvent *event_return);
270int XNextEvent(Display *display, XEvent *event_return)
271{
272 AssertFailedReturn(0);
273}
274
275/* This should not be needed in the bits of the code we test. */
276extern "C" Status XSendEvent(Display *display, Window w, Bool propagate,
277 long event_mask, XEvent *event_send);
278Status XSendEvent(Display *display, Window w, Bool propagate,
279 long event_mask, XEvent *event_send)
280{
281 AssertFailedReturn(0);
282}
283
284/* This should not be needed in the bits of the code we test. */
285extern "C" int XFlush(Display *display);
286int XFlush(Display *display)
287{
288 AssertFailedReturn(0);
289}
290
291/*****************************
292* The actual tests to be run *
293*****************************/
294
295/** The name of the unit test */
296static const char *g_pszTestName = NULL;
297
298/*** Test fixture data and data structures ***/
299
300/** A structure describing a test fixture to be run through. Each fixture
301 * describes the state of the windows visible (and unmapped) on the X server
302 * before and after a particular event is delivered, and the expected
303 * on-screen positions of all interesting visible windows at the end of the
304 * fixture as reported by the code (currently in the order it is likely to
305 * report them in, @todo sort this). We expect that the set of visible
306 * windows will be the same whether we start the code before the event and
307 * handle it or start the code after the event.
308 *
309 * If it is ever needed I could write a small tool to record a fixture on
310 * a live guest, but I will put that off as long as I can.
311 */
312struct SMLSFIXTURE
313{
314 /** The number of windows visible before the event */
315 unsigned cWindowsBefore;
316 /** An array of Window IDs for the visible and unmapped windows before
317 * the event */
318 Window *pahWindowsBefore;
319 /** The window attributes matching the windows in @a paWindowsBefore */
320 XWindowAttributes *paAttribsBefore;
321 /** The window names matching the windows in @a paWindowsBefore */
322 const char **papszNamesBefore;
323 /** The shaped window before the event - we allow at most one of these.
324 * Zero for none. */
325 Window hShapeWindowBefore;
326 /** The number of rectangles in the shaped window before the event. */
327 int cShapeRectsBefore;
328 /** The rectangles in the shaped window before the event */
329 XRectangle *paShapeRectsBefore;
330 /** The number of windows visible after the event */
331 unsigned cWindowsAfter;
332 /** An array of Window IDs for the visible and unmapped windows after
333 * the event */
334 Window *pahWindowsAfter;
335 /** The window attributes matching the windows in @a paWindowsAfter */
336 XWindowAttributes *paAttribsAfter;
337 /** The window names matching the windows in @a paWindowsAfter */
338 const char **papszNamesAfter;
339 /** The shaped window after the event - we allow at most one of these.
340 * Zero for none. */
341 Window hShapeWindowAfter;
342 /** The number of rectangles in the shaped window after the event. */
343 int cShapeRectsAfter;
344 /** The rectangles in the shaped window after the event */
345 XRectangle *paShapeRectsAfter;
346 /** The event to delivered */
347 int x11EventType;
348 /** The windows for which the event in @enmEvent is delivered */
349 Window hEventWindow;
350 /** The number of windows expected to be reported at the end of the
351 * fixture */
352 unsigned cReportedRects;
353 /** The onscreen positions of those windows. */
354 RTRECT *paReportedRects;
355};
356
357/*** Test fixture to test the code against X11 configure (move) events ***/
358
359static Window g_ahWin1[] = { 20 };
360static XWindowAttributes g_aAttrib1Before[] =
361{ { 100, 200, 200, 300, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
362 IsViewable }
363};
364static XRectangle g_aRectangle1[] =
365{
366 { 0, 0, 50, 50 },
367 { 50, 50, 150, 250 }
368};
369static XWindowAttributes g_aAttrib1After[] =
370{ { 200, 300, 200, 300, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
371 IsViewable }
372};
373static const char *g_apszNames1[] = { "Test Window" };
374
375AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib1Before));
376AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib1After));
377AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_apszNames1));
378
379static RTRECT g_aRects1[] =
380{
381 { 200, 300, 250, 350 },
382 { 250, 350, 400, 600 }
383};
384
385static SMLSFIXTURE g_testMove =
386{
387 RT_ELEMENTS(g_ahWin1),
388 g_ahWin1,
389 g_aAttrib1Before,
390 g_apszNames1,
391 20,
392 RT_ELEMENTS(g_aRectangle1),
393 g_aRectangle1,
394 RT_ELEMENTS(g_ahWin1),
395 g_ahWin1,
396 g_aAttrib1After,
397 g_apszNames1,
398 20,
399 RT_ELEMENTS(g_aRectangle1),
400 g_aRectangle1,
401 ConfigureNotify,
402 20,
403 RT_ELEMENTS(g_aRects1),
404 g_aRects1
405};
406
407/*** Test fixture to test the code against X11 configure (resize) events ***/
408
409static XWindowAttributes g_aAttrib2Before[] =
410{ { 100, 200, 200, 300, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
411 IsViewable }
412};
413static XRectangle g_aRectangle2Before[] =
414{
415 { 0, 0, 50, 50 },
416 { 50, 50, 100, 100 }
417};
418
419AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib2Before));
420
421static SMLSFIXTURE g_testResize =
422{
423 RT_ELEMENTS(g_ahWin1),
424 g_ahWin1,
425 g_aAttrib2Before,
426 g_apszNames1,
427 20,
428 RT_ELEMENTS(g_aRectangle2Before),
429 g_aRectangle2Before,
430 RT_ELEMENTS(g_ahWin1),
431 g_ahWin1,
432 g_aAttrib1After,
433 g_apszNames1,
434 20,
435 RT_ELEMENTS(g_aRectangle1),
436 g_aRectangle1,
437 ConfigureNotify,
438 20,
439 RT_ELEMENTS(g_aRects1),
440 g_aRects1
441};
442
443/*** Test fixture to test the code against X11 map events ***/
444
445static XWindowAttributes g_aAttrib3Before[] =
446{ { 200, 300, 200, 300, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
447 IsUnmapped }
448};
449
450AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib3Before));
451
452static SMLSFIXTURE g_testMap =
453{
454 RT_ELEMENTS(g_ahWin1),
455 g_ahWin1,
456 g_aAttrib3Before,
457 g_apszNames1,
458 20,
459 RT_ELEMENTS(g_aRectangle1),
460 g_aRectangle1,
461 RT_ELEMENTS(g_ahWin1),
462 g_ahWin1,
463 g_aAttrib1After,
464 g_apszNames1,
465 20,
466 RT_ELEMENTS(g_aRectangle1),
467 g_aRectangle1,
468 MapNotify,
469 20,
470 RT_ELEMENTS(g_aRects1),
471 g_aRects1
472};
473
474/*** Test fixture to test the code against X11 unmap events ***/
475
476static XWindowAttributes g_aAttrib4After[] =
477{ { 100, 200, 300, 400, 0, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
478 IsUnmapped }
479};
480
481AssertCompile(RT_ELEMENTS(g_ahWin1) == RT_ELEMENTS(g_aAttrib4After));
482
483static SMLSFIXTURE g_testUnmap =
484{
485 RT_ELEMENTS(g_ahWin1),
486 g_ahWin1,
487 g_aAttrib1Before,
488 g_apszNames1,
489 20,
490 RT_ELEMENTS(g_aRectangle1),
491 g_aRectangle1,
492 RT_ELEMENTS(g_ahWin1),
493 g_ahWin1,
494 g_aAttrib4After,
495 g_apszNames1,
496 20,
497 RT_ELEMENTS(g_aRectangle1),
498 g_aRectangle1,
499 UnmapNotify,
500 20,
501 0,
502 NULL
503};
504
505/*** Test fixture to test the code against X11 shape events ***/
506
507static XRectangle g_aRectangle5Before[] =
508{
509 { 0, 0, 200, 200 }
510};
511
512static SMLSFIXTURE g_testShape =
513{
514 RT_ELEMENTS(g_ahWin1),
515 g_ahWin1,
516 g_aAttrib1After,
517 g_apszNames1,
518 20,
519 RT_ELEMENTS(g_aRectangle5Before),
520 g_aRectangle5Before,
521 RT_ELEMENTS(g_ahWin1),
522 g_ahWin1,
523 g_aAttrib1After,
524 g_apszNames1,
525 20,
526 RT_ELEMENTS(g_aRectangle1),
527 g_aRectangle1,
528 VBoxShapeNotify,
529 20,
530 RT_ELEMENTS(g_aRects1),
531 g_aRects1
532};
533
534/*** And the test code proper ***/
535
536/** Compare two RTRECT structures */
537static bool smlsCompRect(RTRECT *pFirst, RTRECT *pSecond)
538{
539 return ( (pFirst->xLeft == pSecond->xLeft)
540 && (pFirst->yTop == pSecond->yTop)
541 && (pFirst->xRight == pSecond->xRight)
542 && (pFirst->yBottom == pSecond->yBottom));
543}
544
545static void smlsPrintDiffRects(RTRECT *pExp, RTRECT *pGot)
546{
547 RTPrintf(" Expected: %d, %d, %d, %d. Got: %d, %d, %d, %d\n",
548 pExp->xLeft, pExp->yTop, pExp->xRight, pExp->yBottom,
549 pGot->xLeft, pGot->yTop, pGot->xRight, pGot->yBottom);
550}
551
552/** Run through a test fixture */
553static unsigned smlsDoFixture(SMLSFIXTURE *pFixture, const char *pszDesc)
554{
555 VBoxGuestSeamlessX11 subject;
556 unsigned cErrs = 0;
557
558 subject.init(NULL);
559 smlsSetWindowAttributes(pFixture->paAttribsBefore,
560 pFixture->pahWindowsBefore,
561 pFixture->cWindowsBefore,
562 pFixture->papszNamesBefore);
563 smlsSetShapeRectangles(pFixture->hShapeWindowBefore,
564 pFixture->cShapeRectsBefore,
565 pFixture->paShapeRectsBefore);
566 subject.start();
567 smlsSetWindowAttributes(pFixture->paAttribsAfter,
568 pFixture->pahWindowsAfter,
569 pFixture->cWindowsAfter,
570 pFixture->papszNamesAfter);
571 smlsSetShapeRectangles(pFixture->hShapeWindowAfter,
572 pFixture->cShapeRectsAfter,
573 pFixture->paShapeRectsAfter);
574 switch(pFixture->x11EventType)
575 {
576 case ConfigureNotify:
577 subject.doConfigureEvent(pFixture->hEventWindow);
578 break;
579 case MapNotify:
580 subject.doMapEvent(pFixture->hEventWindow);
581 break;
582 case UnmapNotify:
583 subject.doUnmapEvent(pFixture->hEventWindow);
584 break;
585 case VBoxShapeNotify:
586 subject.doShapeEvent(pFixture->hEventWindow);
587 break;
588 default:
589 break;
590 }
591 std::auto_ptr<std::vector<RTRECT> > rects = subject.getRects();
592 if (rects->size() != pFixture->cReportedRects)
593 {
594 RTPrintf("%s: fixture: %s. Wrong number of rectangles reported after processing event (expected %u, got %u).\n",
595 g_pszTestName, pszDesc, pFixture->cReportedRects,
596 (*rects).size());
597 ++cErrs;
598 }
599 else
600 for (unsigned i = 0; i < rects->size(); ++i)
601 if (!smlsCompRect(&(*rects)[i], &pFixture->paReportedRects[i]))
602 {
603 RTPrintf("%s: fixture: %s. Rectangle %u wrong after processing event.\n",
604 g_pszTestName, pszDesc, i);
605 smlsPrintDiffRects(&pFixture->paReportedRects[i],
606 &(*rects)[i]);
607 ++cErrs;
608 break;
609 }
610 subject.stop();
611 subject.start();
612 if (rects->size() != pFixture->cReportedRects)
613 {
614 RTPrintf("%s: fixture: %s. Wrong number of rectangles reported without processing event (expected %u, got %u).\n",
615 g_pszTestName, pszDesc, pFixture->cReportedRects,
616 (*rects).size());
617 ++cErrs;
618 }
619 else
620 for (unsigned i = 0; i < rects->size(); ++i)
621 if (!smlsCompRect(&(*rects)[i], &pFixture->paReportedRects[i]))
622 {
623 RTPrintf("%s: fixture: %s. Rectangle %u wrong without processing event.\n",
624 g_pszTestName, pszDesc, i);
625 smlsPrintDiffRects(&pFixture->paReportedRects[i],
626 &(*rects)[i]);
627 ++cErrs;
628 break;
629 }
630 return cErrs;
631}
632
633int main( int argc, char **argv)
634{
635 RTR3Init();
636 unsigned cErrs = 0;
637 g_pszTestName = RTPathFilename(argv[0]);
638
639 RTPrintf("%s: TESTING\n", g_pszTestName);
640 cErrs += smlsDoFixture(&g_testMove,
641 "ConfigureNotify event (window moved)");
642 // Currently not working
643 cErrs += smlsDoFixture(&g_testResize,
644 "ConfigureNotify event (window resized)");
645 cErrs += smlsDoFixture(&g_testMap, "MapNotify event");
646 cErrs += smlsDoFixture(&g_testUnmap, "UnmapNotify event");
647 cErrs += smlsDoFixture(&g_testShape, "ShapeNotify event");
648 if (cErrs > 0)
649 RTPrintf("%u errors\n", cErrs);
650 return cErrs == 0 ? 0 : 1;
651}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette