429
435
EXPECT_EQ (dock, (*it++));
430
436
EXPECT_EQ (w1, (*it++));
440
public ct::AutostartCompizXorgSystemTestWithTestHelper
448
StackingSync::SetUp ()
450
ct::AutostartCompizXorgSystemTestWithTestHelper::SetUp ();
452
XSelectInput (Display (), DefaultRootWindow (Display ()), StructureNotifyMask |
453
SubstructureNotifyMask);
458
Window CreateAndWaitForCreation (Display *dpy)
460
Window w = ct::CreateNormalWindow (dpy);
462
ct::WaitForEventOfTypeOnWindow (dpy,
463
DefaultRootWindow (dpy),
470
Window CreateOverrideRedirectWindow (Display *dpy)
472
XSetWindowAttributes attrib;
474
attrib.override_redirect = true;
477
XCreateWindow (dpy, DefaultRootWindow (dpy),
483
DefaultDepth (dpy, 0),
485
DefaultVisual (dpy, DefaultScreen (dpy)),
489
XSelectInput (dpy, w, StructureNotifyMask);
493
Window MapAndWaitForParent (Display *dpy, Window w)
498
ct::WaitForEventOfTypeOnWindow (dpy,
504
return ct::GetTopmostNonRootParent (dpy, w);
507
void DestroyOnReparent (Display *dpy,
508
ct::MessageAtoms &atoms,
511
Window root = DefaultRootWindow (dpy);
513
atoms.FetchForString (ctm::TEST_HELPER_DESTROY_ON_REPARENT);
515
std::vector <long> data (4);
517
ct::SendClientMessage (dpy, atom, root, w, data);
520
Window WaitForNextCreatedWindow (Display *dpy)
525
XNextEvent (dpy, &ev);
526
if (ev.type == CreateNotify)
527
return ev.xcreatewindow.window;
533
void WaitForManage (Display *dpy,
534
ct::MessageAtoms &atoms)
537
atoms.FetchForString (ctm::TEST_HELPER_WINDOW_READY);
540
ct::ReceiveMessage (dpy, atom, ev);
543
void RestackAbove (Display *dpy,
549
xwc.stack_mode = Above;
552
XConfigureWindow (dpy, w, CWStackMode | CWSibling, &xwc);
555
void RestackAtLeastAbove (Display *dpy,
556
ct::MessageAtoms &atoms,
560
Window root = DefaultRootWindow (dpy);
562
atoms.FetchForString (ctm::TEST_HELPER_RESTACK_ATLEAST_ABOVE);
564
std::vector <long> data (4);
567
ct::SendClientMessage (dpy, atom, root, w, data);
570
void FreeWindowArray (Window *array)
575
typedef boost::shared_array <Window> WindowArray;
577
WindowArray GetChildren (Display *dpy,
584
if (!XQueryTree (dpy, w, &unused, &unused, &children, &n))
585
throw std::logic_error ("XQueryTree failed");
587
return WindowArray (children, boost::bind (FreeWindowArray, _1));
590
class StackPositionMatcher :
591
public MatcherInterface <Window>
595
StackPositionMatcher (const WindowArray &array,
601
bool MatchAndExplain (Window window,
602
MatchResultListener *listener) const;
603
void DescribeTo (std::ostream *os) const;
607
virtual bool Compare (int lhsPos,
608
int rhsPos) const = 0;
609
virtual void ExplainCompare (std::ostream *os) const = 0;
612
unsigned int arrayNum;
617
StackPositionMatcher::StackPositionMatcher (const WindowArray &array,
627
StackPositionMatcher::MatchAndExplain (Window window,
628
MatchResultListener *listener) const
630
int lhsPos = -1, rhsPos = -1;
632
for (unsigned int i = 0; i < arrayNum; ++i)
634
if (array[i] == window)
643
if (Compare (lhsPos, rhsPos))
647
/* Match failed, add stack to MatchResultListener */
648
if (listener->IsInterested ())
650
std::stringstream windowStack;
652
windowStack << "Window Stack (bottom to top ["
655
*listener << windowStack.str ();
656
for (unsigned int i = 0; i < arrayNum; ++i)
658
std::stringstream ss;
664
*listener << ss.str ();
667
std::stringstream lhsPosMsg, rhsPosMsg;
669
lhsPosMsg << "Position of 0x"
676
rhsPosMsg << "Position of 0x"
683
*listener << lhsPosMsg.str () << "\n";
684
*listener << rhsPosMsg.str () << "\n";
691
StackPositionMatcher::DescribeTo (std::ostream *os) const
695
*os << " in relation to 0x" << std::hex << cmp << std::dec;
698
class GreaterThanInStackMatcher :
699
public StackPositionMatcher
703
GreaterThanInStackMatcher (const WindowArray &array,
709
bool Compare (int lhsPos, int rhsPos) const;
710
void ExplainCompare (std::ostream *os) const;
713
GreaterThanInStackMatcher::GreaterThanInStackMatcher (const WindowArray &array,
716
StackPositionMatcher (array, cmp, n)
720
bool GreaterThanInStackMatcher::Compare (int lhsPos, int rhsPos) const
722
return lhsPos > rhsPos;
725
void GreaterThanInStackMatcher::ExplainCompare (std::ostream *os) const
727
*os << "greater than";
730
class LessThanInStackMatcher :
731
public StackPositionMatcher
735
LessThanInStackMatcher (const WindowArray &array,
741
bool Compare (int lhsPos, int rhsPos) const;
742
void ExplainCompare (std::ostream *os) const;
745
LessThanInStackMatcher::LessThanInStackMatcher (const WindowArray &array,
748
StackPositionMatcher (array, cmp, n)
752
bool LessThanInStackMatcher::Compare (int lhsPos, int rhsPos) const
754
return lhsPos < rhsPos;
757
void LessThanInStackMatcher::ExplainCompare (std::ostream *os) const
762
inline Matcher <Window> GreaterThanInStack (const WindowArray &array,
766
return MakeMatcher (new GreaterThanInStackMatcher (array, cmp, n));
769
inline Matcher <Window> LessThanInStack (const WindowArray &array,
773
return MakeMatcher (new LessThanInStackMatcher (array, cmp, n));
777
TEST_F (StackingSync, DestroyClientJustBeforeReparent)
779
::Display *dpy = Display ();
781
ct::MessageAtoms atoms (dpy);
783
/* Set up three normal windows */
784
Window w1 = CreateAndWaitForCreation (dpy);
785
Window w2 = CreateAndWaitForCreation (dpy);
786
Window w3 = CreateAndWaitForCreation (dpy);
788
Window p1 = MapAndWaitForParent (dpy, w1);
789
Window p2 = MapAndWaitForParent (dpy, w2);
790
Window p3 = MapAndWaitForParent (dpy, w3);
792
/* Create another normal window, but immediately mark
793
* it destroyed within compiz as soon as it is reparented,
794
* so that we force the reparented-but-destroyed strategy
796
Window destroyed = CreateAndWaitForCreation (dpy);
798
DestroyOnReparent (dpy, atoms, destroyed);
799
XMapRaised (dpy, destroyed);
801
/* Wait for the destroyed window's parent to be created
802
* in the toplevel stack as a result of the reparent operation */
803
Window parentOfDestroyed = WaitForNextCreatedWindow (dpy);
804
WaitForManage (dpy, atoms);
806
/* Create an override redirect window and wait for it to be
808
Window override = CreateOverrideRedirectWindow (dpy);
809
WaitForManage (dpy, atoms);
811
/* Place the destroyed window's parent above
812
* p1 in the stack directly */
813
RestackAbove (dpy, parentOfDestroyed, p1);
815
/* Ask compiz to place the override redirect window
816
* at least above the destroyed window's parent
817
* in the stack. This requires compiz to locate the
818
* destroyed window's parent in the stack */
819
RestackAtLeastAbove (dpy, atoms, override, parentOfDestroyed);
821
/* Wait for the override window to be configured */
823
ct::WaitForEventOfTypeOnWindow (dpy,
830
WindowArray windows (GetChildren (dpy, DefaultRootWindow (dpy), n));
832
EXPECT_THAT (p2, LessThanInStack (windows, n, override));
833
EXPECT_THAT (p3, GreaterThanInStack (windows, n, override));