| Index: ui/base/x/x11_window_cache_unittest.cc
|
| diff --git a/ui/base/x/x11_window_cache_unittest.cc b/ui/base/x/x11_window_cache_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..446302592f27889317c1e006902ad37dc96cb5e3
|
| --- /dev/null
|
| +++ b/ui/base/x/x11_window_cache_unittest.cc
|
| @@ -0,0 +1,426 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ui/base/x/x11_window_cache.h"
|
| +
|
| +#include "base/macros.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "ui/gfx/x/x11_types.h"
|
| +
|
| +#include <X11/Xlib.h>
|
| +#include <X11/Xatom.h>
|
| +
|
| +namespace ui {
|
| +
|
| +class XWindowCacheTest : public testing::Test {
|
| + public:
|
| + XWindowCacheTest()
|
| + : display_(gfx::GetXDisplay()),
|
| + root_(DefaultRootWindow(display_)),
|
| + testing_atom_(XInternAtom(display_, "CHROMIUM_TESTING_ATOM", False)) {}
|
| + ~XWindowCacheTest() override {}
|
| +
|
| + protected:
|
| + void SetUp() override { XSynchronize(display_, True); }
|
| +
|
| + void TearDown() override { XSynchronize(display_, False); }
|
| +
|
| + void EnsureMemoryReclaimed(XWindowCache* cache) {
|
| + cache->Synchronize();
|
| + EXPECT_TRUE(cache->windows_.empty());
|
| + EXPECT_TRUE(cache->requests_.empty());
|
| + }
|
| +
|
| + XID CreateWindow(XID parent) {
|
| + XSetWindowAttributes swa;
|
| + swa.override_redirect = True;
|
| + return XCreateWindow(display_, parent, 0, 0, 1, 1, 0, CopyFromParent,
|
| + InputOutput, CopyFromParent, CWOverrideRedirect, &swa);
|
| + }
|
| +
|
| + void SetProperty8(XID window, XID property, uint8_t value) {
|
| + XChangeProperty(display_, window, property, XA_CARDINAL, 8, PropModeReplace,
|
| + &value, 1);
|
| + }
|
| +
|
| + template <typename T>
|
| + void VerifyStackingOrder(const XWindowCache::Window* window,
|
| + const T& container) {
|
| + EXPECT_TRUE(window);
|
| + EXPECT_EQ(window->children.size(), container.size());
|
| + auto it = window->children.begin();
|
| + for (XID id : container)
|
| + EXPECT_EQ(id, (*it++)->id);
|
| + }
|
| +
|
| + XDisplay* display_;
|
| + XID root_;
|
| + XAtom testing_atom_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(XWindowCacheTest);
|
| +};
|
| +
|
| +TEST_F(XWindowCacheTest, BasicTest) {
|
| + XID parent_xid = CreateWindow(root_);
|
| + XID child1_xid = CreateWindow(parent_xid);
|
| + XID child2_xid = CreateWindow(parent_xid);
|
| +
|
| + XWindowCache cache(display_, parent_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| + auto parent_window = cache.GetWindow(parent_xid);
|
| + EXPECT_TRUE(parent_window);
|
| + EXPECT_EQ(parent_window->children.size(), 2U);
|
| + auto it = parent_window->children.begin();
|
| + EXPECT_EQ((*it++)->id, child2_xid);
|
| + EXPECT_EQ((*it++)->id, child1_xid);
|
| +
|
| + XDestroyWindow(display_, parent_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, NestingTest) {
|
| + XID parent_xid = CreateWindow(root_);
|
| + XID child_xid = CreateWindow(parent_xid);
|
| + XID nested_child_xid = CreateWindow(child_xid);
|
| + SetProperty8(nested_child_xid, testing_atom_, 0x42);
|
| +
|
| + XWindowCache cache(display_, parent_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + auto parent_window = cache.GetWindow(parent_xid);
|
| + EXPECT_TRUE(parent_window);
|
| + EXPECT_EQ(parent_window->children.size(), 1U);
|
| + EXPECT_EQ(parent_window->properties.size(), 0U);
|
| +
|
| + auto child_window = parent_window->children.front();
|
| + EXPECT_TRUE(child_window);
|
| + EXPECT_EQ(child_window->children.size(), 1U);
|
| + EXPECT_EQ(child_window->properties.size(), 0U);
|
| +
|
| + auto nested_child_window = child_window->children.front();
|
| + EXPECT_TRUE(nested_child_window);
|
| + EXPECT_EQ(nested_child_window->children.size(), 0U);
|
| + EXPECT_EQ(nested_child_window->properties.size(), 1U);
|
| +
|
| + auto prop = nested_child_window->GetProperty(testing_atom_);
|
| + EXPECT_TRUE(prop);
|
| + EXPECT_TRUE(prop->cached_property);
|
| + EXPECT_EQ(prop->type, XA_CARDINAL);
|
| + EXPECT_EQ(prop->data_format, 8);
|
| + EXPECT_EQ(prop->data_length, 1);
|
| + EXPECT_EQ(prop->data.bits_8[0], 0x42);
|
| +
|
| + XDestroyWindow(display_, parent_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, CreateNotifyAndDestroyNotifyTest) {
|
| + XID parent_xid = CreateWindow(root_);
|
| +
|
| + XWindowCache cache(display_, parent_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + XID child1_xid = CreateWindow(parent_xid);
|
| + XID child2_xid = CreateWindow(parent_xid);
|
| +
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + auto parent_window = cache.GetWindow(parent_xid);
|
| + EXPECT_TRUE(parent_window);
|
| + EXPECT_EQ(parent_window->children.size(), 2U);
|
| + auto it = parent_window->children.begin();
|
| + EXPECT_EQ((*it++)->id, child2_xid);
|
| + EXPECT_EQ((*it++)->id, child1_xid);
|
| +
|
| + XDestroyWindow(display_, child1_xid);
|
| + XDestroyWindow(display_, child2_xid);
|
| +
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + parent_window = cache.GetWindow(parent_xid);
|
| + EXPECT_TRUE(parent_window);
|
| + EXPECT_EQ(parent_window->children.size(), 0U);
|
| +
|
| + XDestroyWindow(display_, parent_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, PropertyNotifyTest) {
|
| + XID window_xid = CreateWindow(root_);
|
| + SetProperty8(window_xid, testing_atom_, 0x42);
|
| +
|
| + XWindowCache cache(display_, window_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + auto window = cache.GetWindow(window_xid);
|
| + EXPECT_TRUE(window);
|
| + EXPECT_EQ(window->children.size(), 0U);
|
| + EXPECT_EQ(window->properties.size(), 1U);
|
| +
|
| + auto prop = window->GetProperty(testing_atom_);
|
| + EXPECT_TRUE(prop);
|
| + EXPECT_TRUE(prop->cached_property);
|
| + EXPECT_EQ(prop->type, XA_CARDINAL);
|
| + EXPECT_EQ(prop->data_format, 8);
|
| + EXPECT_EQ(prop->data_length, 1);
|
| + EXPECT_EQ(prop->data.bits_8[0], 0x42);
|
| +
|
| + SetProperty8(window_xid, testing_atom_, 0x24);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + prop = window->GetProperty(testing_atom_);
|
| + EXPECT_TRUE(prop);
|
| + EXPECT_TRUE(prop->cached_property);
|
| + EXPECT_EQ(prop->type, XA_CARDINAL);
|
| + EXPECT_EQ(prop->data_format, 8);
|
| + EXPECT_EQ(prop->data_length, 1);
|
| + EXPECT_EQ(prop->data.bits_8[0], 0x24);
|
| +
|
| + XDestroyWindow(display_, window_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, MapNotifyUnmapNotifyTest) {
|
| + XID window_xid = CreateWindow(root_);
|
| +
|
| + XWindowCache cache(display_, window_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + auto window = cache.GetWindow(window_xid);
|
| + EXPECT_TRUE(window);
|
| + EXPECT_TRUE(window->cached_attributes);
|
| + EXPECT_FALSE(window->is_mapped);
|
| +
|
| + XMapWindow(display_, window_xid);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_TRUE(window->is_mapped);
|
| +
|
| + XUnmapWindow(display_, window_xid);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_FALSE(window->is_mapped);
|
| +
|
| + XDestroyWindow(display_, window_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, CirculateNotifyTest) {
|
| + XID parent_xid = CreateWindow(root_);
|
| +
|
| + std::list<XID> children_xids;
|
| + for (int i = 0; i < 10; i++) {
|
| + XID child = CreateWindow(parent_xid);
|
| + children_xids.push_front(child);
|
| + XMapWindow(display_, child);
|
| + }
|
| +
|
| + XWindowCache cache(display_, parent_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + XID child;
|
| + XCirculateSubwindowsUp(display_, parent_xid);
|
| + child = children_xids.back();
|
| + children_xids.pop_back();
|
| + children_xids.push_front(child);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + XCirculateSubwindowsDown(display_, parent_xid);
|
| + child = children_xids.front();
|
| + children_xids.pop_front();
|
| + children_xids.push_back(child);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + XDestroyWindow(display_, parent_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, ConfigureNotifyTest) {
|
| + XID window_xid = CreateWindow(root_);
|
| +
|
| + XWindowCache cache(display_, window_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| + auto window = cache.GetWindow(window_xid);
|
| + EXPECT_TRUE(window);
|
| + EXPECT_TRUE(window->cached_attributes);
|
| + EXPECT_TRUE(window->cached_geometry);
|
| +
|
| + EXPECT_EQ(window->x, 0);
|
| + EXPECT_EQ(window->y, 0);
|
| + XMoveWindow(display_, window_xid, 1, 1);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_EQ(window->x, 1);
|
| + EXPECT_EQ(window->y, 1);
|
| +
|
| + EXPECT_EQ(window->width, 1U);
|
| + EXPECT_EQ(window->height, 1U);
|
| + XResizeWindow(display_, window_xid, 2, 2);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_EQ(window->width, 2U);
|
| + EXPECT_EQ(window->height, 2U);
|
| +
|
| + EXPECT_EQ(window->border_width, 0U);
|
| + XSetWindowBorderWidth(display_, window_xid, 1);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + EXPECT_EQ(window->border_width, 1U);
|
| +
|
| + XDestroyWindow(display_, window_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, StackingOrderTest) {
|
| + XID parent_xid = CreateWindow(root_);
|
| +
|
| + std::vector<XID> children_xids;
|
| + for (int i = 0; i < 10; i++) {
|
| + XID child = CreateWindow(parent_xid);
|
| + children_xids.push_back(child);
|
| + XMapWindow(display_, child);
|
| + }
|
| + std::reverse(children_xids.begin(), children_xids.end());
|
| +
|
| + XWindowCache cache(display_, parent_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + // XRaiseWindow
|
| + // Raise window 5
|
| + XID child = children_xids[5];
|
| + XRaiseWindow(display_, child);
|
| + children_xids.erase(children_xids.begin() + 5);
|
| + children_xids.insert(children_xids.begin(), child);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + // XLowerWindow
|
| + // Lower window 5
|
| + child = children_xids[5];
|
| + XLowerWindow(display_, child);
|
| + children_xids.erase(children_xids.begin() + 5);
|
| + children_xids.insert(children_xids.end(), child);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + // XRestackWindows
|
| + // Stack window 2 below window 6
|
| + XID restack_windows[2] = {children_xids[6], children_xids[2]};
|
| + child = children_xids[2];
|
| + children_xids.erase(children_xids.begin() + 2);
|
| + children_xids.insert(children_xids.begin() + 6, child);
|
| + XRestackWindows(display_, restack_windows, 2);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + // XConfigureWindow
|
| + // Stack window 2 below window 6
|
| + XWindowChanges changes;
|
| + child = children_xids[2];
|
| + changes.sibling = children_xids[6];
|
| + changes.stack_mode = Below;
|
| + children_xids.erase(children_xids.begin() + 2);
|
| + children_xids.insert(children_xids.begin() + 6, child);
|
| + XConfigureWindow(display_, child, CWSibling | CWStackMode, &changes);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| + VerifyStackingOrder(cache.GetWindow(parent_xid), children_xids);
|
| +
|
| + XDestroyWindow(display_, parent_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, GravityNotifyTest) {
|
| + XID parent_xid = CreateWindow(root_);
|
| + XID child_xid = CreateWindow(parent_xid);
|
| +
|
| + XSetWindowAttributes swa;
|
| + swa.bit_gravity = ForgetGravity;
|
| + swa.win_gravity = NorthEastGravity;
|
| + XChangeWindowAttributes(display_, child_xid, CWBitGravity | CWWinGravity,
|
| + &swa);
|
| +
|
| + XResizeWindow(display_, parent_xid, 100, 100);
|
| + XResizeWindow(display_, child_xid, 25, 25);
|
| + XMoveWindow(display_, child_xid, 75, 0);
|
| +
|
| + XWindowCache cache(display_, parent_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| +
|
| + auto parent = cache.GetWindow(parent_xid);
|
| + EXPECT_TRUE(parent);
|
| + EXPECT_EQ(parent->x, 0);
|
| + EXPECT_EQ(parent->y, 0);
|
| + EXPECT_EQ(parent->width, 100U);
|
| + EXPECT_EQ(parent->height, 100U);
|
| + auto child = cache.GetWindow(child_xid);
|
| + EXPECT_TRUE(child);
|
| + EXPECT_EQ(child->x, 75);
|
| + EXPECT_EQ(child->y, 0);
|
| +
|
| + XResizeWindow(display_, parent_xid, 50, 50);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| +
|
| + EXPECT_EQ(child->x, 25);
|
| + EXPECT_EQ(child->y, 0);
|
| +
|
| + XDestroyWindow(display_, parent_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +TEST_F(XWindowCacheTest, ReparentNotifyTest) {
|
| + // Start with this tree:
|
| + //
|
| + // child1 -- grandchild
|
| + // /
|
| + // parent
|
| + // \
|
| + // child2
|
| + XID parent_xid = CreateWindow(root_);
|
| + XID child1_xid = CreateWindow(parent_xid);
|
| + XID child2_xid = CreateWindow(parent_xid);
|
| + XID grandchild_xid = CreateWindow(child1_xid);
|
| +
|
| + XWindowCache cache(display_, parent_xid);
|
| + EXPECT_TRUE(cache.BlockUntilTreeIsCached());
|
| + auto parent = cache.GetWindow(parent_xid);
|
| + auto child1 = cache.GetWindow(child1_xid);
|
| + auto child2 = cache.GetWindow(child2_xid);
|
| + auto grandchild = cache.GetWindow(grandchild_xid);
|
| +
|
| + EXPECT_TRUE(parent);
|
| + EXPECT_TRUE(child1);
|
| + EXPECT_TRUE(child2);
|
| + EXPECT_TRUE(grandchild);
|
| + EXPECT_EQ(parent->children.size(), 2U);
|
| + EXPECT_EQ(child1->children.size(), 1U);
|
| + EXPECT_EQ(child2->children.size(), 0U);
|
| + EXPECT_EQ(grandchild->children.size(), 0U);
|
| + EXPECT_EQ(child1->children.front(), grandchild);
|
| + EXPECT_EQ(grandchild->parent, child1);
|
| +
|
| + // Reparent grandchild so the tree now looks like this:
|
| + //
|
| + // child1
|
| + // /
|
| + // parent
|
| + // \
|
| + // child2 -- grandchild
|
| + XReparentWindow(display_, grandchild_xid, child2_xid, 0, 0);
|
| + EXPECT_TRUE(cache.Synchronize());
|
| +
|
| + EXPECT_EQ(parent->children.size(), 2U);
|
| + EXPECT_EQ(child1->children.size(), 0U);
|
| + EXPECT_EQ(child2->children.size(), 1U);
|
| + EXPECT_EQ(grandchild->children.size(), 0U);
|
| + EXPECT_EQ(child2->children.front(), grandchild);
|
| + EXPECT_EQ(grandchild->parent, child2);
|
| +
|
| + XDestroyWindow(display_, parent_xid);
|
| + EnsureMemoryReclaimed(&cache);
|
| +}
|
| +
|
| +} // namespace ui
|
|
|