Chromium Code Reviews| 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 { |
|
Elliot Glaysher
2016/08/08 18:17:28
Does this test need to be an interactive ui test?
Tom (Use chromium acct)
2016/08/08 23:23:38
yeah, the tests do create (and map) windows. ui/b
danakj
2016/08/09 22:18:44
So do compositor_unittests.
Tom (Use chromium acct)
2016/08/15 19:57:00
Ok, just leaving as a unit test in that case.
|
| + 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 |