~3v1n0/compiz/gtk-decorator-finalize-menu-0.9.10

« back to all changes in this revision

Viewing changes to tests/system/xorg-gtest/tests/compiz_xorg_gtest_test_window_stacking.cpp

  • Committer: Tarmac
  • Author(s): Sam Spilsbury
  • Date: 2013-07-18 13:06:24 UTC
  • mfrom: (3745.2.3 compiz.fix_1171314)
  • Revision ID: tarmac-20130718130624-wdwqqxwkrphvu4kv
Don't add the frame to the toplevel stack if it hasn't been created yet.

In the event that a window is unreparented or destroyed, we usually need
to add its frame window to the toplevel window stack until the time at
which we recieve a DestroyNotify for it, as there may be incoming
ConfigureNotify events puporting to stack other windows relative to
that frame.

However, this does not apply in the case where we have not yet received
a CreateNotify for the frame window. In that case, it is not possible
for any stacking requests to be made relative to this window, so it
does not need to be added immediately. Instead, we can add it at the
time that we recieve a CreateNotify for it as a regular override
redirect window until the time that it is later destroyed.

(LP: #1171314). Fixes: https://bugs.launchpad.net/bugs/1171314.

Approved by PS Jenkins bot, MC Return.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <stdexcept>
26
26
#include <gtest/gtest.h>
27
27
#include <gmock/gmock.h>
 
28
 
 
29
#include <boost/shared_array.hpp>
 
30
#include <boost/bind.hpp>
 
31
 
28
32
#include <xorg/gtest/xorg-gtest.h>
29
33
#include <compiz-xorg-gtest.h>
 
34
#include <compiz_xorg_gtest_communicator.h>
30
35
 
31
36
#include <X11/Xlib.h>
32
37
#include <X11/Xatom.h>
36
41
using ::testing::Matcher;
37
42
 
38
43
namespace ct = compiz::testing;
 
44
namespace ctm = compiz::testing::messages;
39
45
 
40
46
class CompizXorgSystemStackingTest :
41
47
    public ct::AutostartCompizXorgSystemTest
429
435
    EXPECT_EQ (dock, (*it++));
430
436
    EXPECT_EQ (w1, (*it++));
431
437
}
 
438
 
 
439
class StackingSync :
 
440
    public ct::AutostartCompizXorgSystemTestWithTestHelper
 
441
{
 
442
    public:
 
443
 
 
444
        void SetUp ();
 
445
};
 
446
 
 
447
void
 
448
StackingSync::SetUp ()
 
449
{
 
450
    ct::AutostartCompizXorgSystemTestWithTestHelper::SetUp ();
 
451
 
 
452
    XSelectInput (Display (), DefaultRootWindow (Display ()), StructureNotifyMask |
 
453
                                                              SubstructureNotifyMask);
 
454
}
 
455
 
 
456
namespace
 
457
{
 
458
    Window CreateAndWaitForCreation (Display *dpy)
 
459
    {
 
460
        Window w = ct::CreateNormalWindow (dpy);
 
461
        Advance (dpy,
 
462
                 ct::WaitForEventOfTypeOnWindow (dpy,
 
463
                                                 DefaultRootWindow (dpy),
 
464
                                                 CreateNotify,
 
465
                                                 -1,
 
466
                                                 -1));
 
467
        return w;
 
468
    }
 
469
 
 
470
    Window CreateOverrideRedirectWindow (Display *dpy)
 
471
    {
 
472
        XSetWindowAttributes attrib;
 
473
 
 
474
        attrib.override_redirect = true;
 
475
 
 
476
        Window w =
 
477
            XCreateWindow (dpy, DefaultRootWindow (dpy),
 
478
                           ct::WINDOW_X,
 
479
                           ct::WINDOW_Y,
 
480
                           ct::WINDOW_WIDTH,
 
481
                           ct::WINDOW_HEIGHT,
 
482
                           0,
 
483
                           DefaultDepth (dpy, 0),
 
484
                           InputOutput,
 
485
                           DefaultVisual (dpy, DefaultScreen (dpy)),
 
486
                           CWOverrideRedirect,
 
487
                           &attrib);
 
488
 
 
489
        XSelectInput (dpy, w, StructureNotifyMask);
 
490
        return w;
 
491
    }
 
492
 
 
493
    Window MapAndWaitForParent (Display *dpy, Window w)
 
494
    {
 
495
        XMapRaised (dpy, w);
 
496
 
 
497
        Advance (dpy,
 
498
                 ct::WaitForEventOfTypeOnWindow (dpy,
 
499
                                                 w,
 
500
                                                 ReparentNotify,
 
501
                                                 -1,
 
502
                                                 -1));
 
503
 
 
504
        return ct::GetTopmostNonRootParent (dpy, w);
 
505
    }
 
506
 
 
507
    void DestroyOnReparent (Display          *dpy,
 
508
                            ct::MessageAtoms &atoms,
 
509
                            Window           w)
 
510
    {
 
511
        Window root = DefaultRootWindow (dpy);
 
512
        Atom   atom =
 
513
            atoms.FetchForString (ctm::TEST_HELPER_DESTROY_ON_REPARENT);
 
514
 
 
515
        std::vector <long> data (4);
 
516
 
 
517
        ct::SendClientMessage (dpy, atom, root, w, data);
 
518
    }
 
519
 
 
520
    Window WaitForNextCreatedWindow (Display *dpy)
 
521
    {
 
522
        XEvent ev;
 
523
        while (true)
 
524
        {
 
525
            XNextEvent (dpy, &ev);
 
526
            if (ev.type == CreateNotify)
 
527
                return ev.xcreatewindow.window;
 
528
        }
 
529
 
 
530
        return 0;
 
531
    }
 
532
 
 
533
    void WaitForManage (Display          *dpy,
 
534
                        ct::MessageAtoms &atoms)
 
535
    {
 
536
        Atom   atom =
 
537
            atoms.FetchForString (ctm::TEST_HELPER_WINDOW_READY);
 
538
        XEvent ev;
 
539
 
 
540
        ct::ReceiveMessage (dpy, atom, ev);
 
541
    }
 
542
 
 
543
    void RestackAbove (Display *dpy,
 
544
                       Window  w,
 
545
                       Window  above)
 
546
    {
 
547
        XWindowChanges xwc;
 
548
 
 
549
        xwc.stack_mode = Above;
 
550
        xwc.sibling = above;
 
551
 
 
552
        XConfigureWindow (dpy, w, CWStackMode | CWSibling, &xwc);
 
553
    }
 
554
 
 
555
    void RestackAtLeastAbove (Display          *dpy,
 
556
                              ct::MessageAtoms &atoms,
 
557
                              Window           w,
 
558
                              Window           above)
 
559
    {
 
560
        Window root = DefaultRootWindow (dpy);
 
561
        Atom   atom =
 
562
            atoms.FetchForString (ctm::TEST_HELPER_RESTACK_ATLEAST_ABOVE);
 
563
 
 
564
        std::vector <long> data (4);
 
565
 
 
566
        data[0] = above;
 
567
        ct::SendClientMessage (dpy, atom, root, w, data);
 
568
    }
 
569
 
 
570
    void FreeWindowArray (Window *array)
 
571
    {
 
572
        XFree (array);
 
573
    }
 
574
 
 
575
    typedef boost::shared_array <Window> WindowArray;
 
576
 
 
577
    WindowArray GetChildren (Display      *dpy,
 
578
                             Window       w,
 
579
                             unsigned int &n)
 
580
    {
 
581
        Window unused;
 
582
        Window *children;
 
583
 
 
584
        if (!XQueryTree (dpy, w, &unused, &unused, &children, &n))
 
585
            throw std::logic_error ("XQueryTree failed");
 
586
 
 
587
        return WindowArray (children, boost::bind (FreeWindowArray, _1));
 
588
    }
 
589
 
 
590
    class StackPositionMatcher :
 
591
        public MatcherInterface <Window>
 
592
    {
 
593
        public:
 
594
 
 
595
            StackPositionMatcher (const WindowArray &array,
 
596
                                  Window            cmp,
 
597
                                  unsigned int      n);
 
598
 
 
599
        protected:
 
600
 
 
601
            bool MatchAndExplain (Window              window,
 
602
                                  MatchResultListener *listener) const;
 
603
            void DescribeTo (std::ostream *os) const;
 
604
 
 
605
        private:
 
606
 
 
607
            virtual bool Compare (int lhsPos,
 
608
                                  int rhsPos) const = 0;
 
609
            virtual void ExplainCompare (std::ostream *os) const = 0;
 
610
 
 
611
            WindowArray  array;
 
612
            unsigned int arrayNum;
 
613
            Window       cmp;
 
614
 
 
615
    };
 
616
 
 
617
    StackPositionMatcher::StackPositionMatcher (const WindowArray &array,
 
618
                                                Window            cmp,
 
619
                                                unsigned int      n) :
 
620
        array (array),
 
621
        arrayNum (n),
 
622
        cmp (cmp)
 
623
    {
 
624
    }
 
625
 
 
626
    bool
 
627
    StackPositionMatcher::MatchAndExplain (Window window,
 
628
                                           MatchResultListener *listener) const
 
629
    {
 
630
        int lhsPos = -1, rhsPos = -1;
 
631
 
 
632
        for (unsigned int i = 0; i < arrayNum; ++i)
 
633
        {
 
634
            if (array[i] == window)
 
635
                lhsPos = i;
 
636
            if (array[i] == cmp)
 
637
                rhsPos = i;
 
638
        }
 
639
 
 
640
        if (lhsPos > -1 &&
 
641
            rhsPos > -1)
 
642
        {
 
643
            if (Compare (lhsPos, rhsPos))
 
644
                return true;
 
645
        }
 
646
 
 
647
        /* Match failed, add stack to MatchResultListener */
 
648
        if (listener->IsInterested ())
 
649
        {
 
650
            std::stringstream windowStack;
 
651
 
 
652
            windowStack << "Window Stack (bottom to top ["
 
653
                        << arrayNum
 
654
                        << "]): \n";
 
655
            *listener << windowStack.str ();
 
656
            for (unsigned int i = 0; i < arrayNum; ++i)
 
657
            {
 
658
                std::stringstream ss;
 
659
                ss << " - 0x"
 
660
                   << std::hex
 
661
                   << array[i]
 
662
                   << std::dec
 
663
                   << std::endl;
 
664
                *listener << ss.str ();
 
665
            }
 
666
 
 
667
            std::stringstream lhsPosMsg, rhsPosMsg;
 
668
 
 
669
            lhsPosMsg << "Position of 0x"
 
670
                      << std::hex
 
671
                      << window
 
672
                      << std::dec
 
673
                      << " : "
 
674
                      << lhsPos;
 
675
 
 
676
            rhsPosMsg << "Position of 0x"
 
677
                      << std::hex
 
678
                      << cmp
 
679
                      << std::dec
 
680
                      << " : "
 
681
                      << rhsPos;
 
682
 
 
683
            *listener << lhsPosMsg.str () << "\n";
 
684
            *listener << rhsPosMsg.str () << "\n";
 
685
        }
 
686
 
 
687
        return false;
 
688
    }
 
689
 
 
690
    void
 
691
    StackPositionMatcher::DescribeTo (std::ostream *os) const
 
692
    {
 
693
        *os << "Window is ";
 
694
        ExplainCompare (os);
 
695
        *os << " in relation to 0x" << std::hex << cmp << std::dec;
 
696
    }
 
697
 
 
698
    class GreaterThanInStackMatcher :
 
699
        public StackPositionMatcher
 
700
    {
 
701
        public:
 
702
 
 
703
            GreaterThanInStackMatcher (const WindowArray &array,
 
704
                                       Window            cmp,
 
705
                                       unsigned int      n);
 
706
 
 
707
        private:
 
708
 
 
709
            bool Compare (int lhsPos, int rhsPos) const;
 
710
            void ExplainCompare (std::ostream *os) const;
 
711
    };
 
712
 
 
713
    GreaterThanInStackMatcher::GreaterThanInStackMatcher (const WindowArray &array,
 
714
                                                          Window            cmp,
 
715
                                                          unsigned int      n) :
 
716
        StackPositionMatcher (array, cmp, n)
 
717
    {
 
718
    }
 
719
 
 
720
    bool GreaterThanInStackMatcher::Compare (int lhsPos, int rhsPos) const
 
721
    {
 
722
        return lhsPos > rhsPos;
 
723
    }
 
724
 
 
725
    void GreaterThanInStackMatcher::ExplainCompare (std::ostream *os) const
 
726
    {
 
727
        *os << "greater than";
 
728
    }
 
729
 
 
730
    class LessThanInStackMatcher :
 
731
        public StackPositionMatcher
 
732
    {
 
733
        public:
 
734
 
 
735
            LessThanInStackMatcher (const WindowArray &array,
 
736
                                    Window            cmp,
 
737
                                    unsigned int      n);
 
738
 
 
739
        private:
 
740
 
 
741
            bool Compare (int lhsPos, int rhsPos) const;
 
742
            void ExplainCompare (std::ostream *os) const;
 
743
    };
 
744
 
 
745
    LessThanInStackMatcher::LessThanInStackMatcher (const WindowArray &array,
 
746
                                                    Window            cmp,
 
747
                                                    unsigned int      n) :
 
748
        StackPositionMatcher (array, cmp, n)
 
749
    {
 
750
    }
 
751
 
 
752
    bool LessThanInStackMatcher::Compare (int lhsPos, int rhsPos) const
 
753
    {
 
754
        return lhsPos < rhsPos;
 
755
    }
 
756
 
 
757
    void LessThanInStackMatcher::ExplainCompare (std::ostream *os) const
 
758
    {
 
759
        *os << "less than";
 
760
    }
 
761
 
 
762
    inline Matcher <Window> GreaterThanInStack (const WindowArray &array,
 
763
                                                unsigned int      n,
 
764
                                                Window            cmp)
 
765
    {
 
766
        return MakeMatcher (new GreaterThanInStackMatcher (array, cmp, n));
 
767
    }
 
768
 
 
769
    inline Matcher <Window> LessThanInStack (const WindowArray &array,
 
770
                                             unsigned int      n,
 
771
                                             Window            cmp)
 
772
    {
 
773
        return MakeMatcher (new LessThanInStackMatcher (array, cmp, n));
 
774
    }
 
775
}
 
776
 
 
777
TEST_F (StackingSync, DestroyClientJustBeforeReparent)
 
778
{
 
779
    ::Display *dpy = Display ();
 
780
 
 
781
    ct::MessageAtoms atoms (dpy);
 
782
 
 
783
    /* Set up three normal windows */
 
784
    Window w1 = CreateAndWaitForCreation (dpy);
 
785
    Window w2 = CreateAndWaitForCreation (dpy);
 
786
    Window w3 = CreateAndWaitForCreation (dpy);
 
787
 
 
788
    Window p1 = MapAndWaitForParent (dpy, w1);
 
789
    Window p2 = MapAndWaitForParent (dpy, w2);
 
790
    Window p3 = MapAndWaitForParent (dpy, w3);
 
791
 
 
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
 
795
     * to kick in */
 
796
    Window destroyed = CreateAndWaitForCreation (dpy);
 
797
 
 
798
    DestroyOnReparent (dpy, atoms, destroyed);
 
799
    XMapRaised (dpy, destroyed);
 
800
 
 
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);
 
805
 
 
806
    /* Create an override redirect window and wait for it to be
 
807
     * managed */
 
808
    Window override = CreateOverrideRedirectWindow (dpy);
 
809
    WaitForManage (dpy, atoms);
 
810
 
 
811
    /* Place the destroyed window's parent above
 
812
     * p1 in the stack directly */
 
813
    RestackAbove (dpy, parentOfDestroyed, p1);
 
814
 
 
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);
 
820
 
 
821
    /* Wait for the override window to be configured */
 
822
    Advance (dpy,
 
823
             ct::WaitForEventOfTypeOnWindow (dpy,
 
824
                                             override,
 
825
                                             ConfigureNotify,
 
826
                                             -1,
 
827
                                             -1));
 
828
 
 
829
    unsigned int n;
 
830
    WindowArray  windows (GetChildren (dpy, DefaultRootWindow (dpy), n));
 
831
 
 
832
    EXPECT_THAT (p2, LessThanInStack (windows, n, override));
 
833
    EXPECT_THAT (p3, GreaterThanInStack (windows, n, override));
 
834
}