VirtualBox

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

Last change on this file since 21216 was 21216, checked in by vboxsync, 16 years ago

Additions/x11/VBoxClient: fix resizing of shaped windows

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