| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stddef.h> | 5 #include <stddef.h> |
| 6 #include <stdint.h> | 6 #include <stdint.h> |
| 7 | 7 |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| 11 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
| 12 #include "services/ui/common/util.h" | 12 #include "services/ui/common/util.h" |
| 13 #include "services/ui/public/cpp/tests/window_server_test_base.h" | 13 #include "services/ui/ws/window_server_test_base.h" |
| 14 #include "services/ui/public/cpp/window_observer.h" | 14 #include "ui/aura/env.h" |
| 15 #include "services/ui/public/cpp/window_private.h" | 15 #include "ui/aura/mus/window_port_mus.h" |
| 16 #include "services/ui/public/cpp/window_tree_client.h" | 16 #include "ui/aura/mus/window_tree_client.h" |
| 17 #include "services/ui/public/cpp/window_tree_client_delegate.h" | 17 #include "ui/aura/mus/window_tree_client_delegate.h" |
| 18 #include "services/ui/public/cpp/window_tree_client_observer.h" | 18 #include "ui/aura/mus/window_tree_host_mus.h" |
| 19 #include "ui/aura/test/mus/window_tree_client_private.h" |
| 20 #include "ui/aura/window.h" |
| 21 #include "ui/aura/window_observer.h" |
| 22 #include "ui/aura/window_tracker.h" |
| 19 #include "ui/gfx/geometry/rect.h" | 23 #include "ui/gfx/geometry/rect.h" |
| 20 | 24 |
| 21 namespace ui { | 25 namespace ui { |
| 22 namespace ws { | 26 namespace ws { |
| 23 | 27 |
| 24 namespace { | 28 namespace { |
| 25 | 29 |
| 26 Id server_id(ui::Window* window) { | 30 Id server_id(aura::Window* window) { |
| 27 return WindowPrivate(window).server_id(); | 31 return aura::WindowMus::Get(window)->server_id(); |
| 28 } | 32 } |
| 29 | 33 |
| 30 ui::Window* GetChildWindowByServerId(WindowTreeClient* client, uint32_t id) { | 34 aura::Window* GetChildWindowByServerId(aura::WindowTreeClient* client, |
| 31 return client->GetWindowByServerId(id); | 35 aura::Id id) { |
| 36 return aura::WindowTreeClientPrivate(client).GetWindowByServerId(id); |
| 32 } | 37 } |
| 33 | 38 |
| 34 int ValidIndexOf(const Window::Children& windows, Window* window) { | 39 class TestWindowManagerDelegate : public aura::WindowManagerDelegate { |
| 35 Window::Children::const_iterator it = | |
| 36 std::find(windows.begin(), windows.end(), window); | |
| 37 return (it != windows.end()) ? (it - windows.begin()) : -1; | |
| 38 } | |
| 39 | |
| 40 class TestWindowManagerDelegate : public WindowManagerDelegate { | |
| 41 public: | 40 public: |
| 42 TestWindowManagerDelegate() {} | 41 TestWindowManagerDelegate() {} |
| 43 ~TestWindowManagerDelegate() override {} | 42 ~TestWindowManagerDelegate() override {} |
| 44 | 43 |
| 45 // WindowManagerDelegate: | 44 // WindowManagerDelegate: |
| 46 void SetWindowManagerClient(WindowManagerClient* client) override {} | 45 void SetWindowManagerClient(aura::WindowManagerClient* client) override {} |
| 47 bool OnWmSetBounds(Window* window, gfx::Rect* bounds) override { | 46 bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) override { |
| 48 return false; | 47 return false; |
| 49 } | 48 } |
| 50 bool OnWmSetProperty( | 49 bool OnWmSetProperty( |
| 51 Window* window, | 50 aura::Window* window, |
| 52 const std::string& name, | 51 const std::string& name, |
| 53 std::unique_ptr<std::vector<uint8_t>>* new_data) override { | 52 std::unique_ptr<std::vector<uint8_t>>* new_data) override { |
| 54 return true; | 53 return false; |
| 55 } | 54 } |
| 56 Window* OnWmCreateTopLevelWindow( | 55 aura::Window* OnWmCreateTopLevelWindow( |
| 56 ui::mojom::WindowType window_type, |
| 57 std::map<std::string, std::vector<uint8_t>>* properties) override { | 57 std::map<std::string, std::vector<uint8_t>>* properties) override { |
| 58 return nullptr; | 58 return nullptr; |
| 59 } | 59 } |
| 60 void OnWmDisplayRemoved(ui::Window* window) override {} | 60 void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows, |
| 61 void OnWmClientJankinessChanged(const std::set<Window*>& client_windows, | 61 bool not_responding) override {} |
| 62 bool janky) override {} | 62 void OnWmWillCreateDisplay(const display::Display& display) override {} |
| 63 void OnWmNewDisplay(Window* window, | 63 void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host, |
| 64 const display::Display& display) override {} | 64 const display::Display& display) override {} |
| 65 void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) override {} |
| 65 void OnWmDisplayModified(const display::Display& display) override {} | 66 void OnWmDisplayModified(const display::Display& display) override {} |
| 66 void OnWmPerformMoveLoop(Window* window, | 67 mojom::EventResult OnAccelerator(uint32_t accelerator_id, |
| 68 const ui::Event& event) override { |
| 69 return ui::mojom::EventResult::UNHANDLED; |
| 70 } |
| 71 void OnWmPerformMoveLoop(aura::Window* window, |
| 67 mojom::MoveLoopSource source, | 72 mojom::MoveLoopSource source, |
| 68 const gfx::Point& cursor_location, | 73 const gfx::Point& cursor_location, |
| 69 const base::Callback<void(bool)>& on_done) override { | 74 const base::Callback<void(bool)>& on_done) override { |
| 70 } | 75 } |
| 71 void OnWmCancelMoveLoop(Window* window) override {} | 76 void OnWmCancelMoveLoop(aura::Window* window) override {} |
| 77 void OnWmSetClientArea( |
| 78 aura::Window* window, |
| 79 const gfx::Insets& insets, |
| 80 const std::vector<gfx::Rect>& additional_client_areas) override {} |
| 72 | 81 |
| 73 private: | 82 private: |
| 74 DISALLOW_COPY_AND_ASSIGN(TestWindowManagerDelegate); | 83 DISALLOW_COPY_AND_ASSIGN(TestWindowManagerDelegate); |
| 75 }; | 84 }; |
| 76 | 85 |
| 77 class BoundsChangeObserver : public WindowObserver { | 86 class BoundsChangeObserver : public aura::WindowObserver { |
| 78 public: | 87 public: |
| 79 explicit BoundsChangeObserver(Window* window) : window_(window) { | 88 explicit BoundsChangeObserver(aura::Window* window) : window_(window) { |
| 80 window_->AddObserver(this); | 89 window_->AddObserver(this); |
| 81 } | 90 } |
| 82 ~BoundsChangeObserver() override { window_->RemoveObserver(this); } | 91 ~BoundsChangeObserver() override { window_->RemoveObserver(this); } |
| 83 | 92 |
| 84 private: | 93 private: |
| 85 // Overridden from WindowObserver: | 94 // Overridden from WindowObserver: |
| 86 void OnWindowBoundsChanged(Window* window, | 95 void OnWindowBoundsChanged(aura::Window* window, |
| 87 const gfx::Rect& old_bounds, | 96 const gfx::Rect& old_bounds, |
| 88 const gfx::Rect& new_bounds) override { | 97 const gfx::Rect& new_bounds) override { |
| 89 DCHECK_EQ(window, window_); | 98 DCHECK_EQ(window, window_); |
| 90 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | 99 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 91 } | 100 } |
| 92 | 101 |
| 93 Window* window_; | 102 aura::Window* window_; |
| 94 | 103 |
| 95 DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); | 104 DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); |
| 96 }; | 105 }; |
| 97 | 106 |
| 98 // Wait until the bounds of the supplied window change; returns false on | 107 // Wait until the bounds of the supplied window change; returns false on |
| 99 // timeout. | 108 // timeout. |
| 100 bool WaitForBoundsToChange(Window* window) { | 109 bool WaitForBoundsToChange(aura::Window* window) { |
| 101 BoundsChangeObserver observer(window); | 110 BoundsChangeObserver observer(window); |
| 102 return WindowServerTestBase::DoRunLoopWithTimeout(); | 111 return WindowServerTestBase::DoRunLoopWithTimeout(); |
| 103 } | 112 } |
| 104 | 113 |
| 105 class ClientAreaChangeObserver : public WindowObserver { | |
| 106 public: | |
| 107 explicit ClientAreaChangeObserver(Window* window) : window_(window) { | |
| 108 window_->AddObserver(this); | |
| 109 } | |
| 110 ~ClientAreaChangeObserver() override { window_->RemoveObserver(this); } | |
| 111 | |
| 112 private: | |
| 113 // Overridden from WindowObserver: | |
| 114 void OnWindowClientAreaChanged( | |
| 115 Window* window, | |
| 116 const gfx::Insets& old_client_area, | |
| 117 const std::vector<gfx::Rect>& old_additional_client_areas) override { | |
| 118 DCHECK_EQ(window, window_); | |
| 119 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | |
| 120 } | |
| 121 | |
| 122 Window* window_; | |
| 123 | |
| 124 DISALLOW_COPY_AND_ASSIGN(ClientAreaChangeObserver); | |
| 125 }; | |
| 126 | |
| 127 // Wait until the bounds of the supplied window change; returns false on | |
| 128 // timeout. | |
| 129 bool WaitForClientAreaToChange(Window* window) { | |
| 130 ClientAreaChangeObserver observer(window); | |
| 131 return WindowServerTestBase::DoRunLoopWithTimeout(); | |
| 132 } | |
| 133 | 114 |
| 134 // Spins a run loop until the tree beginning at |root| has |tree_size| windows | 115 // Spins a run loop until the tree beginning at |root| has |tree_size| windows |
| 135 // (including |root|). | 116 // (including |root|). |
| 136 class TreeSizeMatchesObserver : public WindowObserver { | 117 class TreeSizeMatchesObserver : public aura::WindowObserver { |
| 137 public: | 118 public: |
| 138 TreeSizeMatchesObserver(Window* tree, size_t tree_size) | 119 TreeSizeMatchesObserver(aura::Window* tree, size_t tree_size) |
| 139 : tree_(tree), tree_size_(tree_size) { | 120 : tree_(tree), tree_size_(tree_size) { |
| 140 tree_->AddObserver(this); | 121 tree_->AddObserver(this); |
| 141 } | 122 } |
| 142 ~TreeSizeMatchesObserver() override { tree_->RemoveObserver(this); } | 123 ~TreeSizeMatchesObserver() override { tree_->RemoveObserver(this); } |
| 143 | 124 |
| 144 bool IsTreeCorrectSize() { return CountWindows(tree_) == tree_size_; } | 125 bool IsTreeCorrectSize() { return CountWindows(tree_) == tree_size_; } |
| 145 | 126 |
| 146 private: | 127 private: |
| 147 // Overridden from WindowObserver: | 128 // Overridden from WindowObserver: |
| 148 void OnTreeChanged(const TreeChangeParams& params) override { | 129 void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override { |
| 149 if (IsTreeCorrectSize()) | 130 if (IsTreeCorrectSize()) |
| 150 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | 131 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 151 } | 132 } |
| 152 | 133 |
| 153 size_t CountWindows(const Window* window) const { | 134 size_t CountWindows(const aura::Window* window) const { |
| 154 size_t count = 1; | 135 size_t count = 1; |
| 155 Window::Children::const_iterator it = window->children().begin(); | 136 for (const aura::Window* child : window->children()) |
| 156 for (; it != window->children().end(); ++it) | 137 count += CountWindows(child); |
| 157 count += CountWindows(*it); | |
| 158 return count; | 138 return count; |
| 159 } | 139 } |
| 160 | 140 |
| 161 Window* tree_; | 141 aura::Window* tree_; |
| 162 size_t tree_size_; | 142 size_t tree_size_; |
| 163 | 143 |
| 164 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); | 144 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); |
| 165 }; | 145 }; |
| 166 | 146 |
| 167 // Wait until |window| has |tree_size| descendants; returns false on timeout. | 147 // Wait until |window| has |tree_size| descendants; returns false on timeout. |
| 168 // The count includes |window|. For example, if you want to wait for |window| to | 148 // The count includes |window|. For example, if you want to wait for |window| to |
| 169 // have a single child, use a |tree_size| of 2. | 149 // have a single child, use a |tree_size| of 2. |
| 170 bool WaitForTreeSizeToMatch(Window* window, size_t tree_size) { | 150 bool WaitForTreeSizeToMatch(aura::Window* window, size_t tree_size) { |
| 171 TreeSizeMatchesObserver observer(window, tree_size); | 151 TreeSizeMatchesObserver observer(window, tree_size); |
| 172 return observer.IsTreeCorrectSize() || | 152 return observer.IsTreeCorrectSize() || |
| 173 WindowServerTestBase::DoRunLoopWithTimeout(); | 153 WindowServerTestBase::DoRunLoopWithTimeout(); |
| 174 } | 154 } |
| 175 | 155 |
| 176 class OrderChangeObserver : public WindowObserver { | 156 class StackingOrderChangeObserver : public aura::WindowObserver { |
| 177 public: | 157 public: |
| 178 OrderChangeObserver(Window* window) : window_(window) { | 158 StackingOrderChangeObserver(aura::Window* window) : window_(window) { |
| 179 window_->AddObserver(this); | 159 window_->AddObserver(this); |
| 180 } | 160 } |
| 181 ~OrderChangeObserver() override { window_->RemoveObserver(this); } | 161 ~StackingOrderChangeObserver() override { window_->RemoveObserver(this); } |
| 182 | 162 |
| 183 private: | 163 private: |
| 184 // Overridden from WindowObserver: | 164 // Overridden from aura::WindowObserver: |
| 185 void OnWindowReordered(Window* window, | 165 void OnWindowStackingChanged(aura::Window* window) override { |
| 186 Window* relative_window, | |
| 187 mojom::OrderDirection direction) override { | |
| 188 DCHECK_EQ(window, window_); | 166 DCHECK_EQ(window, window_); |
| 189 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | 167 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 190 } | 168 } |
| 191 | 169 |
| 192 Window* window_; | 170 aura::Window* window_; |
| 193 | 171 |
| 194 DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); | 172 DISALLOW_COPY_AND_ASSIGN(StackingOrderChangeObserver); |
| 195 }; | 173 }; |
| 196 | 174 |
| 197 // Wait until |window|'s tree size matches |tree_size|; returns false on | 175 // Wait until |window|'s tree size matches |tree_size|; returns false on |
| 198 // timeout. | 176 // timeout. |
| 199 bool WaitForOrderChange(WindowTreeClient* client, Window* window) { | 177 bool WaitForStackingOrderChange(aura::Window* window) { |
| 200 OrderChangeObserver observer(window); | 178 StackingOrderChangeObserver observer(window); |
| 201 return WindowServerTestBase::DoRunLoopWithTimeout(); | 179 return WindowServerTestBase::DoRunLoopWithTimeout(); |
| 202 } | 180 } |
| 203 | 181 |
| 204 // Tracks a window's destruction. Query is_valid() for current state. | 182 // Tracks a window's destruction. Query is_valid() for current state. |
| 205 class WindowTracker : public WindowObserver { | 183 class WindowTracker : public aura::WindowObserver { |
| 206 public: | 184 public: |
| 207 explicit WindowTracker(Window* window) : window_(window) { | 185 explicit WindowTracker(aura::Window* window) : window_(window) { |
| 208 window_->AddObserver(this); | 186 window_->AddObserver(this); |
| 209 } | 187 } |
| 210 ~WindowTracker() override { | 188 ~WindowTracker() override { |
| 211 if (window_) | 189 if (window_) |
| 212 window_->RemoveObserver(this); | 190 window_->RemoveObserver(this); |
| 213 } | 191 } |
| 214 | 192 |
| 215 bool is_valid() const { return !!window_; } | 193 bool is_valid() const { return !!window_; } |
| 216 | 194 |
| 217 private: | 195 private: |
| 218 // Overridden from WindowObserver: | 196 // Overridden from WindowObserver: |
| 219 void OnWindowDestroyed(Window* window) override { | 197 void OnWindowDestroyed(aura::Window* window) override { |
| 220 DCHECK_EQ(window, window_); | 198 DCHECK_EQ(window, window_); |
| 221 window_ = nullptr; | 199 window_ = nullptr; |
| 222 } | 200 } |
| 223 | 201 |
| 224 Window* window_; | 202 aura::Window* window_; |
| 225 | 203 |
| 226 DISALLOW_COPY_AND_ASSIGN(WindowTracker); | 204 DISALLOW_COPY_AND_ASSIGN(WindowTracker); |
| 227 }; | 205 }; |
| 228 | 206 |
| 207 // Creates a new Window parented to |parent| that is made visible. |
| 208 aura::Window* NewVisibleWindow(aura::Window* parent, |
| 209 aura::WindowTreeClient* client) { |
| 210 std::unique_ptr<aura::WindowPortMus> window_port_mus = |
| 211 base::MakeUnique<aura::WindowPortMus>(client, aura::WindowMusType::LOCAL); |
| 212 aura::Window* window = new aura::Window(nullptr, std::move(window_port_mus)); |
| 213 window->Init(ui::LAYER_NOT_DRAWN); |
| 214 window->Show(); |
| 215 parent->AddChild(window); |
| 216 return window; |
| 217 } |
| 218 |
| 229 } // namespace | 219 } // namespace |
| 230 | 220 |
| 231 // WindowServer | 221 // WindowServer |
| 232 // ----------------------------------------------------------------- | 222 // ----------------------------------------------------------------- |
| 233 | 223 |
| 234 struct EmbedResult { | 224 struct EmbedResult { |
| 235 EmbedResult(WindowTreeClient* client, ClientSpecificId id) | 225 bool IsValid() const { |
| 236 : client(client), client_id(id) {} | 226 return window_tree_client.get() != nullptr && |
| 237 EmbedResult() : client(nullptr), client_id(0) {} | 227 window_tree_host.get() != nullptr; |
| 228 } |
| 238 | 229 |
| 239 WindowTreeClient* client; | 230 std::unique_ptr<aura::WindowTreeClient> window_tree_client; |
| 240 | 231 std::unique_ptr<aura::WindowTreeHostMus> window_tree_host; |
| 241 // The id supplied to the callback from OnEmbed(). Depending upon the | |
| 242 // access policy this may or may not match the client id of | |
| 243 // |client|. | |
| 244 ClientSpecificId client_id; | |
| 245 }; | 232 }; |
| 246 | 233 |
| 247 Window* GetFirstRoot(WindowTreeClient* client) { | 234 aura::Window* GetFirstRoot(aura::WindowTreeClient* client) { |
| 248 return client->GetRoots().empty() ? nullptr : *client->GetRoots().begin(); | 235 return client->GetRoots().empty() ? nullptr : *client->GetRoots().begin(); |
| 249 } | 236 } |
| 250 | 237 |
| 251 // These tests model synchronization of two peer clients of the window server, | 238 // These tests model synchronization of two peer clients of the window server, |
| 252 // that are given access to some root window. | 239 // that are given access to some root window. |
| 253 | 240 |
| 254 class WindowServerTest : public WindowServerTestBase { | 241 class WindowServerTest : public WindowServerTestBase { |
| 255 public: | 242 public: |
| 243 struct ClientAreaChange { |
| 244 aura::Window* window = nullptr; |
| 245 gfx::Insets insets; |
| 246 }; |
| 247 |
| 256 WindowServerTest() {} | 248 WindowServerTest() {} |
| 257 | 249 |
| 258 Window* GetFirstWMRoot() { return GetFirstRoot(window_manager()); } | 250 aura::Window* GetFirstWMRoot() { return GetFirstRoot(window_manager()); } |
| 259 | |
| 260 Window* NewVisibleWindow(Window* parent, WindowTreeClient* client) { | |
| 261 Window* window = client->NewWindow(); | |
| 262 window->SetVisible(true); | |
| 263 parent->AddChild(window); | |
| 264 return window; | |
| 265 } | |
| 266 | 251 |
| 267 // Embeds another version of the test app @ window. This runs a run loop until | 252 // Embeds another version of the test app @ window. This runs a run loop until |
| 268 // a response is received, or a timeout. On success the new WindowServer is | 253 // a response is received, or a timeout. The return value is always non-null, |
| 269 // returned. | 254 // but if there is an error there is no WindowTreeClient. Always use |
| 270 EmbedResult Embed(Window* window) { | 255 // ASSERT_EQ(result->IsValid()) on the return value. |
| 256 std::unique_ptr<EmbedResult> Embed(aura::WindowTreeClient* window_tree_client, |
| 257 aura::Window* window) { |
| 271 DCHECK(!embed_details_); | 258 DCHECK(!embed_details_); |
| 272 embed_details_ = base::MakeUnique<EmbedDetails>(); | 259 embed_details_ = base::MakeUnique<EmbedDetails>(); |
| 273 window->Embed(ConnectAndGetWindowServerClient(), | 260 window_tree_client->Embed(window, ConnectAndGetWindowServerClient(), 0, |
| 274 base::Bind(&WindowServerTest::EmbedCallbackImpl, | 261 base::Bind(&WindowServerTest::EmbedCallbackImpl, |
| 275 base::Unretained(this))); | 262 base::Unretained(this))); |
| 263 if (embed_details_->callback_run) { |
| 264 // The callback was run immediately, this indicates an immediate failure, |
| 265 // such as |window| has children. |
| 266 EXPECT_FALSE(embed_details_->embed_result); |
| 267 embed_details_.reset(); |
| 268 return base::MakeUnique<EmbedResult>(); |
| 269 } |
| 270 // Wait for EmbedCallbackImpl() to be called with the result. |
| 276 embed_details_->waiting = true; | 271 embed_details_->waiting = true; |
| 277 if (!WindowServerTestBase::DoRunLoopWithTimeout()) | 272 if (!WindowServerTestBase::DoRunLoopWithTimeout()) { |
| 278 return EmbedResult(); | 273 embed_details_.reset(); |
| 279 const EmbedResult result(embed_details_->client, | 274 return base::MakeUnique<EmbedResult>(); |
| 280 embed_details_->client_id); | 275 } |
| 276 std::unique_ptr<EmbedResult> result = std::move(embed_details_->result); |
| 281 embed_details_.reset(); | 277 embed_details_.reset(); |
| 282 return result; | 278 return result; |
| 283 } | 279 } |
| 284 | 280 |
| 285 // Establishes a connection to this application and asks for a | 281 // Establishes a connection to this application and asks for a |
| 286 // WindowTreeClient. | 282 // WindowTreeClient. |
| 287 ui::mojom::WindowTreeClientPtr ConnectAndGetWindowServerClient() { | 283 ui::mojom::WindowTreeClientPtr ConnectAndGetWindowServerClient() { |
| 288 ui::mojom::WindowTreeClientPtr client; | 284 ui::mojom::WindowTreeClientPtr client; |
| 289 connector()->ConnectToInterface(test_name(), &client); | 285 connector()->ConnectToInterface(test_name(), &client); |
| 290 return client; | 286 return client; |
| 291 } | 287 } |
| 292 | 288 |
| 289 std::unique_ptr<ClientAreaChange> WaitForClientAreaToChange() { |
| 290 client_area_change_ = base::MakeUnique<ClientAreaChange>(); |
| 291 // The nested message loop is quit in OnWmSetClientArea(). Client area |
| 292 // changes don't route through the window, only the WindowManagerDelegate. |
| 293 if (!WindowServerTestBase::DoRunLoopWithTimeout()) { |
| 294 client_area_change_.reset(); |
| 295 return nullptr; |
| 296 } |
| 297 return std::move(client_area_change_); |
| 298 } |
| 299 |
| 293 // WindowServerTestBase: | 300 // WindowServerTestBase: |
| 294 void OnEmbed(Window* root) override { | 301 void OnEmbed( |
| 302 std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) override { |
| 295 if (!embed_details_) { | 303 if (!embed_details_) { |
| 296 WindowServerTestBase::OnEmbed(root); | 304 WindowServerTestBase::OnEmbed(std::move(window_tree_host)); |
| 297 return; | 305 return; |
| 298 } | 306 } |
| 299 | 307 |
| 300 embed_details_->client = root->window_tree(); | 308 embed_details_->result->window_tree_host = std::move(window_tree_host); |
| 309 embed_details_->result->window_tree_client = ReleaseMostRecentClient(); |
| 301 if (embed_details_->callback_run) | 310 if (embed_details_->callback_run) |
| 302 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | 311 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 303 } | 312 } |
| 313 void OnWmSetClientArea( |
| 314 aura::Window* window, |
| 315 const gfx::Insets& insets, |
| 316 const std::vector<gfx::Rect>& additional_client_areas) override { |
| 317 if (!client_area_change_.get()) |
| 318 return; |
| 319 |
| 320 client_area_change_->window = window; |
| 321 client_area_change_->insets = insets; |
| 322 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 323 } |
| 304 | 324 |
| 305 private: | 325 private: |
| 306 // Used to track the state of a call to window->Embed(). | 326 // Used to track the state of a call to window->Embed(). |
| 307 struct EmbedDetails { | 327 struct EmbedDetails { |
| 308 EmbedDetails() | 328 EmbedDetails() : result(base::MakeUnique<EmbedResult>()) {} |
| 309 : callback_run(false), | |
| 310 result(false), | |
| 311 waiting(false), | |
| 312 client(nullptr) {} | |
| 313 | 329 |
| 314 // The callback supplied to Embed() was received. | 330 // The callback function supplied to Embed() was called. |
| 315 bool callback_run; | 331 bool callback_run = false; |
| 316 | 332 |
| 317 // The boolean supplied to the Embed() callback. | 333 // The boolean supplied to the Embed() callback. |
| 318 bool result; | 334 bool embed_result = false; |
| 319 | 335 |
| 320 // Whether a MessageLoop is running. | 336 // Whether a MessageLoop is running. |
| 321 bool waiting; | 337 bool waiting = false; |
| 322 | 338 |
| 323 // Client id supplied to the Embed() callback. | 339 std::unique_ptr<EmbedResult> result; |
| 324 ClientSpecificId client_id; | |
| 325 | |
| 326 // The WindowTreeClient that resulted from the Embed(). null if |result| is | |
| 327 // false. | |
| 328 WindowTreeClient* client; | |
| 329 }; | 340 }; |
| 330 | 341 |
| 331 void EmbedCallbackImpl(bool result) { | 342 void EmbedCallbackImpl(bool result) { |
| 332 embed_details_->callback_run = true; | 343 embed_details_->callback_run = true; |
| 333 embed_details_->result = result; | 344 embed_details_->embed_result = result; |
| 334 if (embed_details_->waiting && (!result || embed_details_->client)) | 345 if (embed_details_->waiting && |
| 346 (!result || embed_details_->result->window_tree_client)) |
| 335 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | 347 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 336 } | 348 } |
| 337 | 349 |
| 338 std::unique_ptr<EmbedDetails> embed_details_; | 350 std::unique_ptr<EmbedDetails> embed_details_; |
| 339 | 351 |
| 352 std::unique_ptr<ClientAreaChange> client_area_change_; |
| 353 |
| 340 DISALLOW_COPY_AND_ASSIGN(WindowServerTest); | 354 DISALLOW_COPY_AND_ASSIGN(WindowServerTest); |
| 341 }; | 355 }; |
| 342 | 356 |
| 343 TEST_F(WindowServerTest, RootWindow) { | 357 TEST_F(WindowServerTest, RootWindow) { |
| 344 ASSERT_NE(nullptr, window_manager()); | 358 ASSERT_NE(nullptr, window_manager()); |
| 345 EXPECT_EQ(1u, window_manager()->GetRoots().size()); | 359 EXPECT_EQ(1u, window_manager()->GetRoots().size()); |
| 346 } | 360 } |
| 347 | 361 |
| 348 TEST_F(WindowServerTest, Embed) { | 362 TEST_F(WindowServerTest, Embed) { |
| 349 Window* window = window_manager()->NewWindow(); | 363 aura::Window* window = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 350 ASSERT_NE(nullptr, window); | 364 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window); |
| 351 window->SetVisible(true); | 365 ASSERT_TRUE(embed_result->IsValid()); |
| 352 GetFirstWMRoot()->AddChild(window); | |
| 353 WindowTreeClient* embedded = Embed(window).client; | |
| 354 ASSERT_NE(nullptr, embedded); | |
| 355 | 366 |
| 356 Window* window_in_embedded = GetFirstRoot(embedded); | 367 aura::Window* embed_root = embed_result->window_tree_host->window(); |
| 357 ASSERT_NE(nullptr, window_in_embedded); | 368 // WindowTreeHost::window() is the single root of the embed. |
| 358 EXPECT_EQ(server_id(window), server_id(window_in_embedded)); | 369 EXPECT_EQ(1u, embed_result->window_tree_client->GetRoots().size()); |
| 359 EXPECT_EQ(nullptr, window_in_embedded->parent()); | 370 EXPECT_EQ(embed_root, GetFirstRoot(embed_result->window_tree_client.get())); |
| 360 EXPECT_TRUE(window_in_embedded->children().empty()); | 371 EXPECT_EQ(server_id(window), server_id(embed_root)); |
| 372 EXPECT_EQ(nullptr, embed_root->parent()); |
| 373 EXPECT_TRUE(embed_root->children().empty()); |
| 361 } | 374 } |
| 362 | 375 |
| 363 // Window manager has two windows, N1 and N11. Embeds A at N1. A should not see | 376 // Window manager has two windows, N1 and N11. Embeds A at N1. A should not see |
| 364 // N11. | 377 // N11. |
| 365 TEST_F(WindowServerTest, EmbeddedDoesntSeeChild) { | 378 TEST_F(WindowServerTest, EmbeddedDoesntSeeChild) { |
| 366 Window* window = window_manager()->NewWindow(); | 379 aura::Window* window = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 367 ASSERT_NE(nullptr, window); | 380 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window); |
| 368 window->SetVisible(true); | 381 ASSERT_TRUE(embed_result->IsValid()); |
| 369 GetFirstWMRoot()->AddChild(window); | 382 aura::Window* embed_root = embed_result->window_tree_host->window(); |
| 370 Window* nested = window_manager()->NewWindow(); | 383 EXPECT_EQ(server_id(window), server_id(embed_root)); |
| 371 ASSERT_NE(nullptr, nested); | 384 EXPECT_EQ(nullptr, embed_root->parent()); |
| 372 nested->SetVisible(true); | 385 EXPECT_TRUE(embed_root->children().empty()); |
| 373 window->AddChild(nested); | |
| 374 | |
| 375 WindowTreeClient* embedded = Embed(window).client; | |
| 376 ASSERT_NE(nullptr, embedded); | |
| 377 Window* window_in_embedded = GetFirstRoot(embedded); | |
| 378 EXPECT_EQ(server_id(window), server_id(window_in_embedded)); | |
| 379 EXPECT_EQ(nullptr, window_in_embedded->parent()); | |
| 380 EXPECT_TRUE(window_in_embedded->children().empty()); | |
| 381 } | 386 } |
| 382 | 387 |
| 383 // TODO(beng): write a replacement test for the one that once existed here: | 388 // TODO(beng): write a replacement test for the one that once existed here: |
| 384 // This test validates the following scenario: | 389 // This test validates the following scenario: |
| 385 // - a window originating from one client | 390 // - a window originating from one client |
| 386 // - a window originating from a second client | 391 // - a window originating from a second client |
| 387 // + the client originating the window is destroyed | 392 // + the client originating the window is destroyed |
| 388 // -> the window should still exist (since the second client is live) but | 393 // -> the window should still exist (since the second client is live) but |
| 389 // should be disconnected from any windows. | 394 // should be disconnected from any windows. |
| 390 // http://crbug.com/396300 | 395 // http://crbug.com/396300 |
| 391 // | 396 // |
| 392 // TODO(beng): The new test should validate the scenario as described above | 397 // TODO(beng): The new test should validate the scenario as described above |
| 393 // except that the second client still has a valid tree. | 398 // except that the second client still has a valid tree. |
| 394 | 399 |
| 395 // Verifies that bounds changes applied to a window hierarchy in one client | 400 // Verifies that bounds changes applied to a window hierarchy in one client |
| 396 // are reflected to another. | 401 // are reflected to another. |
| 397 TEST_F(WindowServerTest, SetBounds) { | 402 TEST_F(WindowServerTest, SetBounds) { |
| 398 Window* window = window_manager()->NewWindow(); | 403 aura::Window* window = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 399 window->SetVisible(true); | |
| 400 GetFirstWMRoot()->AddChild(window); | |
| 401 WindowTreeClient* embedded = Embed(window).client; | |
| 402 ASSERT_NE(nullptr, embedded); | |
| 403 | 404 |
| 404 Window* window_in_embedded = | 405 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window); |
| 405 GetChildWindowByServerId(embedded, server_id(window)); | 406 ASSERT_TRUE(embed_result->IsValid()); |
| 406 EXPECT_EQ(window->bounds(), window_in_embedded->bounds()); | 407 aura::Window* embed_root = embed_result->window_tree_host->window(); |
| 408 EXPECT_EQ(window->bounds(), embed_root->bounds()); |
| 407 | 409 |
| 408 window->SetBounds(gfx::Rect(0, 0, 100, 100)); | 410 window->SetBounds(gfx::Rect(0, 0, 100, 100)); |
| 409 ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded)); | 411 ASSERT_TRUE(WaitForBoundsToChange(embed_root)); |
| 410 EXPECT_TRUE(window->bounds() == window_in_embedded->bounds()); | 412 EXPECT_EQ(window->bounds(), embed_root->bounds()); |
| 411 } | 413 } |
| 412 | 414 |
| 413 // Verifies that bounds changes applied to a window owned by a different | 415 // Verifies that bounds changes applied to a window owned by a different |
| 414 // client can be refused. | 416 // client can be refused. |
| 415 TEST_F(WindowServerTest, SetBoundsSecurity) { | 417 TEST_F(WindowServerTest, SetBoundsSecurity) { |
| 416 TestWindowManagerDelegate wm_delegate; | 418 TestWindowManagerDelegate wm_delegate; |
| 417 set_window_manager_delegate(&wm_delegate); | 419 set_window_manager_delegate(&wm_delegate); |
| 418 | 420 |
| 419 Window* window = window_manager()->NewWindow(); | 421 aura::Window* window = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 420 window->SetVisible(true); | |
| 421 GetFirstWMRoot()->AddChild(window); | |
| 422 WindowTreeClient* embedded = Embed(window).client; | |
| 423 ASSERT_NE(nullptr, embedded); | |
| 424 | 422 |
| 425 Window* window_in_embedded = | 423 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window); |
| 426 GetChildWindowByServerId(embedded, server_id(window)); | 424 ASSERT_TRUE(embed_result->IsValid()); |
| 425 aura::Window* embed_root = embed_result->window_tree_host->window(); |
| 427 window->SetBounds(gfx::Rect(0, 0, 800, 600)); | 426 window->SetBounds(gfx::Rect(0, 0, 800, 600)); |
| 428 ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded)); | 427 ASSERT_TRUE(WaitForBoundsToChange(embed_root)); |
| 429 | 428 |
| 430 window_in_embedded->SetBounds(gfx::Rect(0, 0, 1024, 768)); | 429 embed_result->window_tree_host->SetBoundsInPixels(gfx::Rect(0, 0, 1024, 768)); |
| 431 // Bounds change is initially accepted, but the server declines the request. | 430 // Bounds change is initially accepted, but the server declines the request. |
| 432 EXPECT_FALSE(window->bounds() == window_in_embedded->bounds()); | 431 EXPECT_NE(window->bounds(), embed_root->bounds()); |
| 433 | 432 |
| 434 // The client is notified when the requested is declined, and updates the | 433 // The client is notified when the requested is declined, and updates the |
| 435 // local bounds accordingly. | 434 // local bounds accordingly. |
| 436 ASSERT_TRUE(WaitForBoundsToChange(window_in_embedded)); | 435 ASSERT_TRUE(WaitForBoundsToChange(embed_root)); |
| 437 EXPECT_TRUE(window->bounds() == window_in_embedded->bounds()); | 436 EXPECT_EQ(window->bounds(), embed_root->bounds()); |
| 438 set_window_manager_delegate(nullptr); | 437 set_window_manager_delegate(nullptr); |
| 439 } | 438 } |
| 440 | 439 |
| 441 // Verifies that a root window can always be destroyed. | 440 // Verifies that a root window can always be destroyed. |
| 442 TEST_F(WindowServerTest, DestroySecurity) { | 441 TEST_F(WindowServerTest, DestroySecurity) { |
| 443 Window* window = window_manager()->NewWindow(); | 442 aura::Window* window = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 444 window->SetVisible(true); | |
| 445 GetFirstWMRoot()->AddChild(window); | |
| 446 | 443 |
| 447 WindowTreeClient* embedded = Embed(window).client; | 444 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window); |
| 448 ASSERT_NE(nullptr, embedded); | 445 ASSERT_TRUE(embed_result->IsValid()); |
| 446 aura::Window* embed_root = embed_result->window_tree_host->window(); |
| 449 | 447 |
| 450 // The root can be destroyed, even though it was not created by the client. | 448 // The root can be destroyed, even though it was not created by the client. |
| 451 Window* embed_root = GetChildWindowByServerId(embedded, server_id(window)); | 449 aura::WindowTracker tracker; |
| 452 WindowTracker tracker1(window); | 450 tracker.Add(window); |
| 453 WindowTracker tracker2(embed_root); | 451 tracker.Add(embed_root); |
| 454 embed_root->Destroy(); | 452 embed_result->window_tree_host.reset(); |
| 455 EXPECT_FALSE(tracker2.is_valid()); | 453 EXPECT_FALSE(tracker.Contains(embed_root)); |
| 456 EXPECT_TRUE(tracker1.is_valid()); | 454 EXPECT_TRUE(tracker.Contains(window)); |
| 457 | 455 |
| 458 window->Destroy(); | 456 delete window; |
| 459 EXPECT_FALSE(tracker1.is_valid()); | 457 EXPECT_FALSE(tracker.Contains(window)); |
| 460 } | 458 } |
| 461 | 459 |
| 462 TEST_F(WindowServerTest, MultiRoots) { | 460 TEST_F(WindowServerTest, MultiRoots) { |
| 463 Window* window1 = window_manager()->NewWindow(); | 461 aura::Window* window1 = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 464 window1->SetVisible(true); | 462 aura::Window* window2 = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 465 GetFirstWMRoot()->AddChild(window1); | 463 std::unique_ptr<EmbedResult> embed_result1 = Embed(window_manager(), window1); |
| 466 Window* window2 = window_manager()->NewWindow(); | 464 ASSERT_TRUE(embed_result1->IsValid()); |
| 467 window2->SetVisible(true); | 465 std::unique_ptr<EmbedResult> embed_result2 = Embed(window_manager(), window2); |
| 468 GetFirstWMRoot()->AddChild(window2); | 466 ASSERT_TRUE(embed_result2->IsValid()); |
| 469 WindowTreeClient* embedded1 = Embed(window1).client; | |
| 470 ASSERT_NE(nullptr, embedded1); | |
| 471 WindowTreeClient* embedded2 = Embed(window2).client; | |
| 472 ASSERT_NE(nullptr, embedded2); | |
| 473 EXPECT_NE(embedded1, embedded2); | |
| 474 } | 467 } |
| 475 | 468 |
| 476 TEST_F(WindowServerTest, Reorder) { | 469 TEST_F(WindowServerTest, Reorder) { |
| 477 Window* window1 = window_manager()->NewWindow(); | 470 aura::Window* window1 = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 478 window1->SetVisible(true); | |
| 479 GetFirstWMRoot()->AddChild(window1); | |
| 480 | 471 |
| 481 WindowTreeClient* embedded = Embed(window1).client; | 472 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window1); |
| 482 ASSERT_NE(nullptr, embedded); | 473 ASSERT_TRUE(embed_result->IsValid()); |
| 474 aura::WindowTreeClient* embedded = embed_result->window_tree_client.get(); |
| 475 aura::Window* embed_root = embed_result->window_tree_host->window(); |
| 483 | 476 |
| 484 Window* window11 = embedded->NewWindow(); | 477 aura::Window* window11 = NewVisibleWindow(embed_root, embedded); |
| 485 window11->SetVisible(true); | 478 aura::Window* window12 = NewVisibleWindow(embed_root, embedded); |
| 486 GetFirstRoot(embedded)->AddChild(window11); | |
| 487 Window* window12 = embedded->NewWindow(); | |
| 488 window12->SetVisible(true); | |
| 489 GetFirstRoot(embedded)->AddChild(window12); | |
| 490 ASSERT_TRUE(WaitForTreeSizeToMatch(window1, 3u)); | 479 ASSERT_TRUE(WaitForTreeSizeToMatch(window1, 3u)); |
| 491 | 480 |
| 492 Window* root_in_embedded = GetFirstRoot(embedded); | |
| 493 | 481 |
| 494 { | 482 { |
| 495 window11->MoveToFront(); | 483 window11->parent()->StackChildAtTop(window11); |
| 496 // The |embedded| tree should be updated immediately. | 484 // The |embedded| tree should be updated immediately. |
| 497 EXPECT_EQ(root_in_embedded->children().front(), | 485 EXPECT_EQ(embed_root->children().front(), |
| 498 GetChildWindowByServerId(embedded, server_id(window12))); | 486 GetChildWindowByServerId(embedded, server_id(window12))); |
| 499 EXPECT_EQ(root_in_embedded->children().back(), | 487 EXPECT_EQ(embed_root->children().back(), |
| 500 GetChildWindowByServerId(embedded, server_id(window11))); | 488 GetChildWindowByServerId(embedded, server_id(window11))); |
| 501 | 489 |
| 502 // The |window_manager()| tree is still not updated. | 490 // The window_manager() tree is still not updated. |
| 503 EXPECT_EQ(window1->children().back(), | 491 EXPECT_EQ(window1->children().back(), |
| 504 GetChildWindowByServerId(window_manager(), server_id(window12))); | 492 GetChildWindowByServerId(window_manager(), server_id(window12))); |
| 505 | 493 |
| 506 // Wait until |window_manager()| tree is updated. | 494 // Wait until window_manager() tree is updated. |
| 507 ASSERT_TRUE(WaitForOrderChange( | 495 ASSERT_TRUE(WaitForStackingOrderChange( |
| 508 window_manager(), | |
| 509 GetChildWindowByServerId(window_manager(), server_id(window11)))); | 496 GetChildWindowByServerId(window_manager(), server_id(window11)))); |
| 510 EXPECT_EQ(window1->children().front(), | 497 EXPECT_EQ(window1->children().front(), |
| 511 GetChildWindowByServerId(window_manager(), server_id(window12))); | 498 GetChildWindowByServerId(window_manager(), server_id(window12))); |
| 512 EXPECT_EQ(window1->children().back(), | 499 EXPECT_EQ(window1->children().back(), |
| 513 GetChildWindowByServerId(window_manager(), server_id(window11))); | 500 GetChildWindowByServerId(window_manager(), server_id(window11))); |
| 514 } | 501 } |
| 515 | 502 |
| 516 { | 503 { |
| 517 window11->MoveToBack(); | 504 window11->parent()->StackChildAtBottom(window11); |
| 518 // |embedded| should be updated immediately. | 505 // |embedded| should be updated immediately. |
| 519 EXPECT_EQ(root_in_embedded->children().front(), | 506 EXPECT_EQ(embed_root->children().front(), |
| 520 GetChildWindowByServerId(embedded, server_id(window11))); | 507 GetChildWindowByServerId(embedded, server_id(window11))); |
| 521 EXPECT_EQ(root_in_embedded->children().back(), | 508 EXPECT_EQ(embed_root->children().back(), |
| 522 GetChildWindowByServerId(embedded, server_id(window12))); | 509 GetChildWindowByServerId(embedded, server_id(window12))); |
| 523 | 510 |
| 524 // |window_manager()| is also eventually updated. | 511 // |window_manager()| is also eventually updated. |
| 525 EXPECT_EQ(window1->children().back(), | 512 EXPECT_EQ(window1->children().back(), |
| 526 GetChildWindowByServerId(window_manager(), server_id(window11))); | 513 GetChildWindowByServerId(window_manager(), server_id(window11))); |
| 527 ASSERT_TRUE(WaitForOrderChange( | 514 ASSERT_TRUE(WaitForStackingOrderChange( |
| 528 window_manager(), | |
| 529 GetChildWindowByServerId(window_manager(), server_id(window11)))); | 515 GetChildWindowByServerId(window_manager(), server_id(window11)))); |
| 530 EXPECT_EQ(window1->children().front(), | 516 EXPECT_EQ(window1->children().front(), |
| 531 GetChildWindowByServerId(window_manager(), server_id(window11))); | 517 GetChildWindowByServerId(window_manager(), server_id(window11))); |
| 532 EXPECT_EQ(window1->children().back(), | 518 EXPECT_EQ(window1->children().back(), |
| 533 GetChildWindowByServerId(window_manager(), server_id(window12))); | 519 GetChildWindowByServerId(window_manager(), server_id(window12))); |
| 534 } | 520 } |
| 535 } | 521 } |
| 536 | 522 |
| 537 namespace { | 523 namespace { |
| 538 | 524 |
| 539 class VisibilityChangeObserver : public WindowObserver { | 525 class VisibilityChangeObserver : public aura::WindowObserver { |
| 540 public: | 526 public: |
| 541 explicit VisibilityChangeObserver(Window* window) : window_(window) { | 527 explicit VisibilityChangeObserver(aura::Window* window) : window_(window) { |
| 542 window_->AddObserver(this); | 528 window_->AddObserver(this); |
| 543 } | 529 } |
| 544 ~VisibilityChangeObserver() override { window_->RemoveObserver(this); } | 530 ~VisibilityChangeObserver() override { window_->RemoveObserver(this); } |
| 545 | 531 |
| 546 private: | 532 private: |
| 547 // Overridden from WindowObserver: | 533 // Overridden from WindowObserver: |
| 548 void OnWindowVisibilityChanged(Window* window, bool visible) override { | 534 void OnWindowVisibilityChanged(aura::Window* window, bool visible) override { |
| 549 EXPECT_EQ(window, window_); | 535 EXPECT_EQ(window, window_); |
| 550 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | 536 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 551 } | 537 } |
| 552 | 538 |
| 553 Window* window_; | 539 aura::Window* window_; |
| 554 | 540 |
| 555 DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); | 541 DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); |
| 556 }; | 542 }; |
| 557 | 543 |
| 558 } // namespace | 544 } // namespace |
| 559 | 545 |
| 560 TEST_F(WindowServerTest, Visible) { | 546 TEST_F(WindowServerTest, Visible) { |
| 561 Window* window1 = window_manager()->NewWindow(); | 547 aura::Window* window1 = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 562 window1->SetVisible(true); | |
| 563 GetFirstWMRoot()->AddChild(window1); | |
| 564 | 548 |
| 565 // Embed another app and verify initial state. | 549 // Embed another app and verify initial state. |
| 566 WindowTreeClient* embedded = Embed(window1).client; | 550 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window1); |
| 567 ASSERT_NE(nullptr, embedded); | 551 ASSERT_TRUE(embed_result->IsValid()); |
| 568 ASSERT_NE(nullptr, GetFirstRoot(embedded)); | 552 aura::Window* embed_root = embed_result->window_tree_host->window(); |
| 569 Window* embedded_root = GetFirstRoot(embedded); | 553 EXPECT_TRUE(embed_root->TargetVisibility()); |
| 570 EXPECT_TRUE(embedded_root->visible()); | 554 EXPECT_TRUE(embed_root->IsVisible()); |
| 571 EXPECT_TRUE(embedded_root->IsDrawn()); | |
| 572 | 555 |
| 573 // Change the visible state from the first client and verify its mirrored | 556 // Change the visible state from the first client and verify its mirrored |
| 574 // correctly to the embedded app. | 557 // correctly to the embedded app. |
| 575 { | 558 { |
| 576 VisibilityChangeObserver observer(embedded_root); | 559 VisibilityChangeObserver observer(embed_root); |
| 577 window1->SetVisible(false); | 560 window1->Hide(); |
| 578 ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout()); | 561 ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout()); |
| 579 } | 562 } |
| 580 | 563 |
| 581 EXPECT_FALSE(window1->visible()); | 564 EXPECT_FALSE(window1->TargetVisibility()); |
| 582 EXPECT_FALSE(window1->IsDrawn()); | 565 EXPECT_FALSE(window1->IsVisible()); |
| 583 | 566 |
| 584 EXPECT_FALSE(embedded_root->visible()); | 567 EXPECT_FALSE(embed_root->TargetVisibility()); |
| 585 EXPECT_FALSE(embedded_root->IsDrawn()); | 568 EXPECT_FALSE(embed_root->IsVisible()); |
| 586 | 569 |
| 587 // Make the node visible again. | 570 // Make the node visible again. |
| 588 { | 571 { |
| 589 VisibilityChangeObserver observer(embedded_root); | 572 VisibilityChangeObserver observer(embed_root); |
| 590 window1->SetVisible(true); | 573 window1->Show(); |
| 591 ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout()); | 574 ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout()); |
| 592 } | 575 } |
| 593 | 576 |
| 594 EXPECT_TRUE(window1->visible()); | 577 EXPECT_TRUE(window1->TargetVisibility()); |
| 595 EXPECT_TRUE(window1->IsDrawn()); | 578 EXPECT_TRUE(window1->IsVisible()); |
| 596 | 579 |
| 597 EXPECT_TRUE(embedded_root->visible()); | 580 EXPECT_TRUE(embed_root->TargetVisibility()); |
| 598 EXPECT_TRUE(embedded_root->IsDrawn()); | 581 EXPECT_TRUE(embed_root->IsVisible()); |
| 599 } | |
| 600 | |
| 601 namespace { | |
| 602 | |
| 603 class DrawnChangeObserver : public WindowObserver { | |
| 604 public: | |
| 605 explicit DrawnChangeObserver(Window* window) : window_(window) { | |
| 606 window_->AddObserver(this); | |
| 607 } | |
| 608 ~DrawnChangeObserver() override { window_->RemoveObserver(this); } | |
| 609 | |
| 610 private: | |
| 611 // Overridden from WindowObserver: | |
| 612 void OnWindowDrawnChanged(Window* window) override { | |
| 613 EXPECT_EQ(window, window_); | |
| 614 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | |
| 615 } | |
| 616 | |
| 617 Window* window_; | |
| 618 | |
| 619 DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver); | |
| 620 }; | |
| 621 | |
| 622 } // namespace | |
| 623 | |
| 624 TEST_F(WindowServerTest, Drawn) { | |
| 625 Window* window1 = window_manager()->NewWindow(); | |
| 626 window1->SetVisible(true); | |
| 627 GetFirstWMRoot()->AddChild(window1); | |
| 628 | |
| 629 // Embed another app and verify initial state. | |
| 630 WindowTreeClient* embedded = Embed(window1).client; | |
| 631 ASSERT_NE(nullptr, embedded); | |
| 632 ASSERT_NE(nullptr, GetFirstRoot(embedded)); | |
| 633 Window* embedded_root = GetFirstRoot(embedded); | |
| 634 EXPECT_TRUE(embedded_root->visible()); | |
| 635 EXPECT_TRUE(embedded_root->IsDrawn()); | |
| 636 | |
| 637 // Change the visibility of the root, this should propagate a drawn state | |
| 638 // change to |embedded|. | |
| 639 { | |
| 640 DrawnChangeObserver observer(embedded_root); | |
| 641 GetFirstWMRoot()->SetVisible(false); | |
| 642 ASSERT_TRUE(DoRunLoopWithTimeout()); | |
| 643 } | |
| 644 | |
| 645 EXPECT_TRUE(window1->visible()); | |
| 646 EXPECT_FALSE(window1->IsDrawn()); | |
| 647 | |
| 648 EXPECT_TRUE(embedded_root->visible()); | |
| 649 EXPECT_FALSE(embedded_root->IsDrawn()); | |
| 650 } | 582 } |
| 651 | 583 |
| 652 // TODO(beng): tests for window event dispatcher. | 584 // TODO(beng): tests for window event dispatcher. |
| 653 // - verify that we see events for all windows. | 585 // - verify that we see events for all windows. |
| 654 | 586 |
| 655 namespace { | 587 TEST_F(WindowServerTest, EmbedFailsWithChildren) { |
| 656 | 588 aura::Window* window1 = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 657 class FocusChangeObserver : public WindowObserver { | 589 ASSERT_TRUE(NewVisibleWindow(window1, window_manager())); |
| 658 public: | 590 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window1); |
| 659 explicit FocusChangeObserver(Window* window) | 591 // Embed() should fail as |window1| has a child. |
| 660 : window_(window), | 592 EXPECT_FALSE(embed_result->IsValid()); |
| 661 last_gained_focus_(nullptr), | |
| 662 last_lost_focus_(nullptr), | |
| 663 quit_on_change_(true) { | |
| 664 window_->AddObserver(this); | |
| 665 } | |
| 666 ~FocusChangeObserver() override { window_->RemoveObserver(this); } | |
| 667 | |
| 668 void set_quit_on_change(bool value) { quit_on_change_ = value; } | |
| 669 | |
| 670 Window* last_gained_focus() { return last_gained_focus_; } | |
| 671 | |
| 672 Window* last_lost_focus() { return last_lost_focus_; } | |
| 673 | |
| 674 private: | |
| 675 // Overridden from WindowObserver. | |
| 676 void OnWindowFocusChanged(Window* gained_focus, Window* lost_focus) override { | |
| 677 EXPECT_TRUE(!gained_focus || gained_focus->HasFocus()); | |
| 678 EXPECT_FALSE(lost_focus && lost_focus->HasFocus()); | |
| 679 last_gained_focus_ = gained_focus; | |
| 680 last_lost_focus_ = lost_focus; | |
| 681 if (quit_on_change_) | |
| 682 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | |
| 683 } | |
| 684 | |
| 685 Window* window_; | |
| 686 Window* last_gained_focus_; | |
| 687 Window* last_lost_focus_; | |
| 688 bool quit_on_change_; | |
| 689 | |
| 690 DISALLOW_COPY_AND_ASSIGN(FocusChangeObserver); | |
| 691 }; | |
| 692 | |
| 693 class NullFocusChangeObserver : public WindowTreeClientObserver { | |
| 694 public: | |
| 695 explicit NullFocusChangeObserver(WindowTreeClient* client) | |
| 696 : client_(client) { | |
| 697 client_->AddObserver(this); | |
| 698 } | |
| 699 ~NullFocusChangeObserver() override { client_->RemoveObserver(this); } | |
| 700 | |
| 701 private: | |
| 702 // Overridden from WindowTreeClientObserver. | |
| 703 void OnWindowTreeFocusChanged(Window* gained_focus, | |
| 704 Window* lost_focus) override { | |
| 705 if (!gained_focus) | |
| 706 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | |
| 707 } | |
| 708 | |
| 709 WindowTreeClient* client_; | |
| 710 | |
| 711 DISALLOW_COPY_AND_ASSIGN(NullFocusChangeObserver); | |
| 712 }; | |
| 713 | |
| 714 bool WaitForWindowToHaveFocus(Window* window) { | |
| 715 if (window->HasFocus()) | |
| 716 return true; | |
| 717 FocusChangeObserver observer(window); | |
| 718 return WindowServerTestBase::DoRunLoopWithTimeout(); | |
| 719 } | |
| 720 | |
| 721 bool WaitForNoWindowToHaveFocus(WindowTreeClient* client) { | |
| 722 if (!client->GetFocusedWindow()) | |
| 723 return true; | |
| 724 NullFocusChangeObserver observer(client); | |
| 725 return WindowServerTestBase::DoRunLoopWithTimeout(); | |
| 726 } | |
| 727 | |
| 728 } // namespace | |
| 729 | |
| 730 TEST_F(WindowServerTest, Focus) { | |
| 731 Window* window1 = window_manager()->NewWindow(); | |
| 732 window1->SetVisible(true); | |
| 733 GetFirstWMRoot()->AddChild(window1); | |
| 734 | |
| 735 WindowTreeClient* embedded = Embed(window1).client; | |
| 736 ASSERT_NE(nullptr, embedded); | |
| 737 Window* window11 = embedded->NewWindow(); | |
| 738 window11->SetVisible(true); | |
| 739 GetFirstRoot(embedded)->AddChild(window11); | |
| 740 | |
| 741 { | |
| 742 // Focus the embed root in |embedded|. | |
| 743 Window* embedded_root = GetFirstRoot(embedded); | |
| 744 FocusChangeObserver observer(embedded_root); | |
| 745 observer.set_quit_on_change(false); | |
| 746 embedded_root->SetFocus(); | |
| 747 ASSERT_TRUE(embedded_root->HasFocus()); | |
| 748 ASSERT_NE(nullptr, observer.last_gained_focus()); | |
| 749 EXPECT_EQ(server_id(embedded_root), | |
| 750 server_id(observer.last_gained_focus())); | |
| 751 | |
| 752 // |embedded_root| is the same as |window1|, make sure |window1| got | |
| 753 // focus too. | |
| 754 ASSERT_TRUE(WaitForWindowToHaveFocus(window1)); | |
| 755 } | |
| 756 | |
| 757 // Focus a child of GetFirstRoot(embedded). | |
| 758 { | |
| 759 FocusChangeObserver observer(window11); | |
| 760 observer.set_quit_on_change(false); | |
| 761 window11->SetFocus(); | |
| 762 ASSERT_TRUE(window11->HasFocus()); | |
| 763 ASSERT_NE(nullptr, observer.last_gained_focus()); | |
| 764 ASSERT_NE(nullptr, observer.last_lost_focus()); | |
| 765 EXPECT_EQ(server_id(window11), server_id(observer.last_gained_focus())); | |
| 766 EXPECT_EQ(server_id(GetFirstRoot(embedded)), | |
| 767 server_id(observer.last_lost_focus())); | |
| 768 } | |
| 769 | |
| 770 { | |
| 771 // Add an observer on the Window that loses focus, and make sure the | |
| 772 // observer sees the right values. | |
| 773 FocusChangeObserver observer(window11); | |
| 774 observer.set_quit_on_change(false); | |
| 775 GetFirstRoot(embedded)->SetFocus(); | |
| 776 ASSERT_NE(nullptr, observer.last_gained_focus()); | |
| 777 ASSERT_NE(nullptr, observer.last_lost_focus()); | |
| 778 EXPECT_EQ(server_id(window11), server_id(observer.last_lost_focus())); | |
| 779 EXPECT_EQ(server_id(GetFirstRoot(embedded)), | |
| 780 server_id(observer.last_gained_focus())); | |
| 781 } | |
| 782 } | |
| 783 | |
| 784 TEST_F(WindowServerTest, ClearFocus) { | |
| 785 Window* window1 = window_manager()->NewWindow(); | |
| 786 window1->SetVisible(true); | |
| 787 GetFirstWMRoot()->AddChild(window1); | |
| 788 | |
| 789 WindowTreeClient* embedded = Embed(window1).client; | |
| 790 ASSERT_NE(nullptr, embedded); | |
| 791 Window* window11 = embedded->NewWindow(); | |
| 792 window11->SetVisible(true); | |
| 793 GetFirstRoot(embedded)->AddChild(window11); | |
| 794 | |
| 795 // Focus the embed root in |embedded|. | |
| 796 Window* embedded_root = GetFirstRoot(embedded); | |
| 797 { | |
| 798 FocusChangeObserver observer(embedded_root); | |
| 799 observer.set_quit_on_change(false); | |
| 800 embedded_root->SetFocus(); | |
| 801 ASSERT_TRUE(embedded_root->HasFocus()); | |
| 802 ASSERT_NE(nullptr, observer.last_gained_focus()); | |
| 803 EXPECT_EQ(server_id(embedded_root), | |
| 804 server_id(observer.last_gained_focus())); | |
| 805 | |
| 806 // |embedded_root| is the same as |window1|, make sure |window1| got | |
| 807 // focus too. | |
| 808 ASSERT_TRUE(WaitForWindowToHaveFocus(window1)); | |
| 809 } | |
| 810 | |
| 811 { | |
| 812 FocusChangeObserver observer(window1); | |
| 813 embedded->ClearFocus(); | |
| 814 ASSERT_FALSE(embedded_root->HasFocus()); | |
| 815 EXPECT_FALSE(embedded->GetFocusedWindow()); | |
| 816 | |
| 817 ASSERT_TRUE(WindowServerTestBase::DoRunLoopWithTimeout()); | |
| 818 EXPECT_FALSE(window1->HasFocus()); | |
| 819 EXPECT_FALSE(window_manager()->GetFocusedWindow()); | |
| 820 } | |
| 821 } | |
| 822 | |
| 823 TEST_F(WindowServerTest, FocusNonFocusableWindow) { | |
| 824 Window* window = window_manager()->NewWindow(); | |
| 825 window->SetVisible(true); | |
| 826 GetFirstWMRoot()->AddChild(window); | |
| 827 | |
| 828 WindowTreeClient* client = Embed(window).client; | |
| 829 ASSERT_NE(nullptr, client); | |
| 830 ASSERT_FALSE(client->GetRoots().empty()); | |
| 831 Window* client_window = *client->GetRoots().begin(); | |
| 832 client_window->SetCanFocus(false); | |
| 833 | |
| 834 client_window->SetFocus(); | |
| 835 ASSERT_TRUE(client_window->HasFocus()); | |
| 836 | |
| 837 WaitForNoWindowToHaveFocus(client); | |
| 838 ASSERT_FALSE(client_window->HasFocus()); | |
| 839 } | |
| 840 | |
| 841 TEST_F(WindowServerTest, Activation) { | |
| 842 Window* parent = NewVisibleWindow(GetFirstWMRoot(), window_manager()); | |
| 843 | |
| 844 // Allow the child windows to be activated. Do this before we wait, that way | |
| 845 // we're guaranteed that when we request focus from a separate client the | |
| 846 // requests are processed in order. | |
| 847 window_manager_client()->AddActivationParent(parent); | |
| 848 | |
| 849 Window* child1 = NewVisibleWindow(parent, window_manager()); | |
| 850 Window* child2 = NewVisibleWindow(parent, window_manager()); | |
| 851 Window* child3 = NewVisibleWindow(parent, window_manager()); | |
| 852 | |
| 853 child1->AddTransientWindow(child3); | |
| 854 | |
| 855 WindowTreeClient* embedded1 = Embed(child1).client; | |
| 856 ASSERT_NE(nullptr, embedded1); | |
| 857 WindowTreeClient* embedded2 = Embed(child2).client; | |
| 858 ASSERT_NE(nullptr, embedded2); | |
| 859 | |
| 860 Window* child11 = NewVisibleWindow(GetFirstRoot(embedded1), embedded1); | |
| 861 Window* child21 = NewVisibleWindow(GetFirstRoot(embedded2), embedded2); | |
| 862 | |
| 863 WaitForTreeSizeToMatch(parent, 6); | |
| 864 | |
| 865 EXPECT_EQ(0, ValidIndexOf(parent->children(), child1)); | |
| 866 // NOTE: |child3| is after |child1| as |child3| is a transient child of | |
| 867 // |child1|. | |
| 868 EXPECT_EQ(1, ValidIndexOf(parent->children(), child3)); | |
| 869 EXPECT_EQ(2, ValidIndexOf(parent->children(), child2)); | |
| 870 | |
| 871 // Set focus on |child11|, order of windows should not change. | |
| 872 child11->SetFocus(); | |
| 873 ASSERT_TRUE(WaitForWindowToHaveFocus(child11)); | |
| 874 ASSERT_TRUE(WaitForWindowToHaveFocus( | |
| 875 GetChildWindowByServerId(window_manager(), server_id(child11)))); | |
| 876 EXPECT_EQ(server_id(child11), | |
| 877 server_id(window_manager()->GetFocusedWindow())); | |
| 878 EXPECT_EQ(server_id(child11), server_id(embedded1->GetFocusedWindow())); | |
| 879 EXPECT_EQ(nullptr, embedded2->GetFocusedWindow()); | |
| 880 EXPECT_EQ(0, ValidIndexOf(parent->children(), child1)); | |
| 881 EXPECT_EQ(1, ValidIndexOf(parent->children(), child3)); | |
| 882 EXPECT_EQ(2, ValidIndexOf(parent->children(), child2)); | |
| 883 | |
| 884 // Set focus on |child21|. This should activate |child2|. Again, order should | |
| 885 // not change. | |
| 886 child21->SetFocus(); | |
| 887 ASSERT_TRUE(WaitForWindowToHaveFocus(child21)); | |
| 888 ASSERT_TRUE(WaitForWindowToHaveFocus( | |
| 889 GetChildWindowByServerId(window_manager(), server_id(child21)))); | |
| 890 EXPECT_EQ(server_id(child21), | |
| 891 server_id(window_manager()->GetFocusedWindow())); | |
| 892 EXPECT_EQ(server_id(child21), server_id(embedded2->GetFocusedWindow())); | |
| 893 EXPECT_TRUE(WaitForNoWindowToHaveFocus(embedded1)); | |
| 894 EXPECT_EQ(nullptr, embedded1->GetFocusedWindow()); | |
| 895 EXPECT_EQ(0, ValidIndexOf(parent->children(), child1)); | |
| 896 EXPECT_EQ(1, ValidIndexOf(parent->children(), child3)); | |
| 897 EXPECT_EQ(2, ValidIndexOf(parent->children(), child2)); | |
| 898 } | |
| 899 | |
| 900 TEST_F(WindowServerTest, ActivationNext) { | |
| 901 Window* parent = GetFirstWMRoot(); | |
| 902 Window* child1 = NewVisibleWindow(parent, window_manager()); | |
| 903 Window* child2 = NewVisibleWindow(parent, window_manager()); | |
| 904 Window* child3 = NewVisibleWindow(parent, window_manager()); | |
| 905 | |
| 906 WindowTreeClient* embedded1 = Embed(child1).client; | |
| 907 ASSERT_NE(nullptr, embedded1); | |
| 908 WindowTreeClient* embedded2 = Embed(child2).client; | |
| 909 ASSERT_NE(nullptr, embedded2); | |
| 910 WindowTreeClient* embedded3 = Embed(child3).client; | |
| 911 ASSERT_NE(nullptr, embedded3); | |
| 912 | |
| 913 Window* child11 = NewVisibleWindow(GetFirstRoot(embedded1), embedded1); | |
| 914 Window* child21 = NewVisibleWindow(GetFirstRoot(embedded2), embedded2); | |
| 915 Window* child31 = NewVisibleWindow(GetFirstRoot(embedded3), embedded3); | |
| 916 WaitForTreeSizeToMatch(parent, 7); | |
| 917 | |
| 918 Window* focused[] = { child31, child21, child11, child31, nullptr }; | |
| 919 for (size_t index = 0; focused[index]; ++index) { | |
| 920 window_manager_client()->ActivateNextWindow(); | |
| 921 WaitForWindowToHaveFocus(focused[index]); | |
| 922 EXPECT_TRUE(focused[index]->HasFocus()); | |
| 923 } | |
| 924 } | 593 } |
| 925 | 594 |
| 926 namespace { | 595 namespace { |
| 927 | 596 |
| 928 class DestroyedChangedObserver : public WindowObserver { | 597 class DestroyObserver : public aura::WindowObserver { |
| 929 public: | 598 public: |
| 930 DestroyedChangedObserver(Window* window, bool* got_destroy) | 599 DestroyObserver(aura::WindowTreeClient* client, bool* got_destroy) |
| 931 : window_(window), got_destroy_(got_destroy) { | |
| 932 window_->AddObserver(this); | |
| 933 } | |
| 934 ~DestroyedChangedObserver() override { | |
| 935 if (window_) | |
| 936 window_->RemoveObserver(this); | |
| 937 } | |
| 938 | |
| 939 private: | |
| 940 // Overridden from WindowObserver: | |
| 941 void OnWindowDestroyed(Window* window) override { | |
| 942 EXPECT_EQ(window, window_); | |
| 943 window_->RemoveObserver(this); | |
| 944 *got_destroy_ = true; | |
| 945 window_ = nullptr; | |
| 946 } | |
| 947 | |
| 948 Window* window_; | |
| 949 bool* got_destroy_; | |
| 950 | |
| 951 DISALLOW_COPY_AND_ASSIGN(DestroyedChangedObserver); | |
| 952 }; | |
| 953 | |
| 954 } // namespace | |
| 955 | |
| 956 // Verifies deleting a WindowServer sends the right notifications. | |
| 957 TEST_F(WindowServerTest, DeleteWindowServer) { | |
| 958 Window* window = window_manager()->NewWindow(); | |
| 959 ASSERT_NE(nullptr, window); | |
| 960 window->SetVisible(true); | |
| 961 GetFirstWMRoot()->AddChild(window); | |
| 962 WindowTreeClient* client = Embed(window).client; | |
| 963 ASSERT_TRUE(client); | |
| 964 bool got_destroy = false; | |
| 965 DestroyedChangedObserver observer(GetFirstRoot(client), &got_destroy); | |
| 966 DeleteWindowTreeClient(client); | |
| 967 EXPECT_TRUE(got_destroy); | |
| 968 } | |
| 969 | |
| 970 class WindowRemovedFromParentObserver : public WindowObserver { | |
| 971 public: | |
| 972 explicit WindowRemovedFromParentObserver(Window* window) | |
| 973 : window_(window), was_removed_(false) { | |
| 974 window_->AddObserver(this); | |
| 975 } | |
| 976 ~WindowRemovedFromParentObserver() override { window_->RemoveObserver(this); } | |
| 977 | |
| 978 bool was_removed() const { return was_removed_; } | |
| 979 | |
| 980 private: | |
| 981 // Overridden from WindowObserver: | |
| 982 void OnTreeChanged(const TreeChangeParams& params) override { | |
| 983 if (params.target == window_ && !params.new_parent) | |
| 984 was_removed_ = true; | |
| 985 } | |
| 986 | |
| 987 Window* window_; | |
| 988 bool was_removed_; | |
| 989 | |
| 990 DISALLOW_COPY_AND_ASSIGN(WindowRemovedFromParentObserver); | |
| 991 }; | |
| 992 | |
| 993 TEST_F(WindowServerTest, EmbedRemovesChildren) { | |
| 994 Window* window1 = window_manager()->NewWindow(); | |
| 995 Window* window2 = window_manager()->NewWindow(); | |
| 996 GetFirstWMRoot()->AddChild(window1); | |
| 997 window1->AddChild(window2); | |
| 998 | |
| 999 WindowRemovedFromParentObserver observer(window2); | |
| 1000 window1->Embed(ConnectAndGetWindowServerClient()); | |
| 1001 EXPECT_TRUE(observer.was_removed()); | |
| 1002 EXPECT_EQ(nullptr, window2->parent()); | |
| 1003 EXPECT_TRUE(window1->children().empty()); | |
| 1004 | |
| 1005 // Run the message loop so the Embed() call above completes. Without this | |
| 1006 // we may end up reconnecting to the test and rerunning the test, which is | |
| 1007 // problematic since the other services don't shut down. | |
| 1008 ASSERT_TRUE(DoRunLoopWithTimeout()); | |
| 1009 } | |
| 1010 | |
| 1011 namespace { | |
| 1012 | |
| 1013 class DestroyObserver : public WindowObserver { | |
| 1014 public: | |
| 1015 DestroyObserver(WindowTreeClient* client, bool* got_destroy) | |
| 1016 : got_destroy_(got_destroy) { | 600 : got_destroy_(got_destroy) { |
| 1017 GetFirstRoot(client)->AddObserver(this); | 601 GetFirstRoot(client)->AddObserver(this); |
| 1018 } | 602 } |
| 1019 ~DestroyObserver() override {} | 603 ~DestroyObserver() override {} |
| 1020 | 604 |
| 1021 private: | 605 private: |
| 1022 // Overridden from WindowObserver: | 606 // Overridden from aura::WindowObserver: |
| 1023 void OnWindowDestroyed(Window* window) override { | 607 void OnWindowDestroyed(aura::Window* window) override { |
| 1024 *got_destroy_ = true; | 608 *got_destroy_ = true; |
| 1025 window->RemoveObserver(this); | 609 window->RemoveObserver(this); |
| 1026 | 610 |
| 1027 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); | 611 EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); |
| 1028 } | 612 } |
| 1029 | 613 |
| 1030 bool* got_destroy_; | 614 bool* got_destroy_; |
| 1031 | 615 |
| 1032 DISALLOW_COPY_AND_ASSIGN(DestroyObserver); | 616 DISALLOW_COPY_AND_ASSIGN(DestroyObserver); |
| 1033 }; | 617 }; |
| 1034 | 618 |
| 1035 } // namespace | 619 } // namespace |
| 1036 | 620 |
| 1037 // Verifies deleting a Window that is the root of another client notifies | 621 // Verifies deleting a Window that is the root of another client notifies |
| 1038 // observers in the right order (OnWindowDestroyed() before | 622 // observers in the right order (OnWindowDestroyed() before |
| 1039 // OnWindowManagerDestroyed()). | 623 // OnWindowManagerDestroyed()). |
| 1040 TEST_F(WindowServerTest, WindowServerDestroyedAfterRootObserver) { | 624 TEST_F(WindowServerTest, WindowServerDestroyedAfterRootObserver) { |
| 1041 Window* embed_window = window_manager()->NewWindow(); | 625 aura::Window* window = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 1042 GetFirstWMRoot()->AddChild(embed_window); | |
| 1043 | 626 |
| 1044 WindowTreeClient* embedded_client = Embed(embed_window).client; | 627 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window); |
| 628 ASSERT_TRUE(embed_result->IsValid()); |
| 629 aura::WindowTreeClient* embedded_client = |
| 630 embed_result->window_tree_client.get(); |
| 1045 | 631 |
| 1046 bool got_destroy = false; | 632 bool got_destroy = false; |
| 1047 DestroyObserver observer(embedded_client, &got_destroy); | 633 DestroyObserver observer(embedded_client, &got_destroy); |
| 1048 // Delete the window |embedded_client| is embedded in. This is async, | 634 // Delete the window |embedded_client| is embedded in. |embedded_client| is |
| 1049 // but will eventually trigger deleting |embedded_client|. | 635 // asynchronously notified and cleans up. |
| 1050 embed_window->Destroy(); | 636 delete window; |
| 1051 EXPECT_TRUE(DoRunLoopWithTimeout()); | 637 EXPECT_TRUE(DoRunLoopWithTimeout()); |
| 1052 EXPECT_TRUE(got_destroy); | 638 ASSERT_TRUE(got_destroy); |
| 639 // The WindowTreeHost was destroyed as well (by |
| 640 // WindowServerTestBase::OnEmbedRootDestroyed()). |
| 641 embed_result->window_tree_host.release(); |
| 642 EXPECT_EQ(0u, embed_result->window_tree_client->GetRoots().size()); |
| 1053 } | 643 } |
| 1054 | 644 |
| 1055 TEST_F(WindowServerTest, ClientAreaChanged) { | 645 TEST_F(WindowServerTest, ClientAreaChanged) { |
| 1056 Window* embed_window = window_manager()->NewWindow(); | 646 aura::Window* window = NewVisibleWindow(GetFirstWMRoot(), window_manager()); |
| 1057 GetFirstWMRoot()->AddChild(embed_window); | |
| 1058 | 647 |
| 1059 WindowTreeClient* embedded_client = Embed(embed_window).client; | 648 std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window); |
| 649 ASSERT_TRUE(embed_result->IsValid()); |
| 1060 | 650 |
| 1061 // Verify change from embedded makes it to parent. | 651 // Verify change from embedded makes it to parent. |
| 1062 GetFirstRoot(embedded_client)->SetClientArea(gfx::Insets(1, 2, 3, 4)); | 652 const gfx::Insets insets(1, 2, 3, 4); |
| 1063 ASSERT_TRUE(WaitForClientAreaToChange(embed_window)); | 653 embed_result->window_tree_host->SetClientArea(insets); |
| 1064 EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == embed_window->client_area()); | 654 std::unique_ptr<ClientAreaChange> client_area_change = |
| 1065 | 655 WaitForClientAreaToChange(); |
| 1066 // Changing bounds shouldn't effect client area. | 656 ASSERT_TRUE(client_area_change); |
| 1067 embed_window->SetBounds(gfx::Rect(21, 22, 23, 24)); | 657 EXPECT_EQ(window, client_area_change->window); |
| 1068 WaitForBoundsToChange(GetFirstRoot(embedded_client)); | 658 EXPECT_EQ(insets, client_area_change->insets); |
| 1069 EXPECT_TRUE(gfx::Rect(21, 22, 23, 24) == | |
| 1070 GetFirstRoot(embedded_client)->bounds()); | |
| 1071 EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == | |
| 1072 GetFirstRoot(embedded_client)->client_area()); | |
| 1073 } | 659 } |
| 1074 | 660 |
| 1075 class EstablishConnectionViaFactoryDelegate : public TestWindowManagerDelegate { | 661 class EstablishConnectionViaFactoryDelegate : public TestWindowManagerDelegate { |
| 1076 public: | 662 public: |
| 1077 explicit EstablishConnectionViaFactoryDelegate( | 663 explicit EstablishConnectionViaFactoryDelegate(aura::WindowTreeClient* client) |
| 1078 WindowTreeClient* client) | |
| 1079 : client_(client), run_loop_(nullptr), created_window_(nullptr) {} | 664 : client_(client), run_loop_(nullptr), created_window_(nullptr) {} |
| 1080 ~EstablishConnectionViaFactoryDelegate() override {} | 665 ~EstablishConnectionViaFactoryDelegate() override {} |
| 1081 | 666 |
| 1082 bool QuitOnCreate() { | 667 bool QuitOnCreate() { |
| 1083 if (run_loop_) | 668 if (run_loop_) |
| 1084 return false; | 669 return false; |
| 1085 | 670 |
| 1086 created_window_ = nullptr; | 671 created_window_ = nullptr; |
| 1087 run_loop_ = base::MakeUnique<base::RunLoop>(); | 672 run_loop_ = base::MakeUnique<base::RunLoop>(); |
| 1088 run_loop_->Run(); | 673 run_loop_->Run(); |
| 1089 run_loop_.reset(); | 674 run_loop_.reset(); |
| 1090 return created_window_ != nullptr; | 675 return created_window_ != nullptr; |
| 1091 } | 676 } |
| 1092 | 677 |
| 1093 Window* created_window() { return created_window_; } | 678 aura::Window* created_window() { return created_window_; } |
| 1094 | 679 |
| 1095 // WindowManagerDelegate: | 680 // WindowManagerDelegate: |
| 1096 Window* OnWmCreateTopLevelWindow( | 681 aura::Window* OnWmCreateTopLevelWindow( |
| 682 ui::mojom::WindowType window_type, |
| 1097 std::map<std::string, std::vector<uint8_t>>* properties) override { | 683 std::map<std::string, std::vector<uint8_t>>* properties) override { |
| 1098 created_window_ = client_->NewWindow(properties); | 684 created_window_ = NewVisibleWindow((*client_->GetRoots().begin()), client_); |
| 1099 (*client_->GetRoots().begin())->AddChild(created_window_); | |
| 1100 if (run_loop_) | 685 if (run_loop_) |
| 1101 run_loop_->Quit(); | 686 run_loop_->Quit(); |
| 1102 return created_window_; | 687 return created_window_; |
| 1103 } | 688 } |
| 1104 | 689 |
| 1105 private: | 690 private: |
| 1106 WindowTreeClient* client_; | 691 aura::WindowTreeClient* client_; |
| 1107 std::unique_ptr<base::RunLoop> run_loop_; | 692 std::unique_ptr<base::RunLoop> run_loop_; |
| 1108 Window* created_window_; | 693 aura::Window* created_window_; |
| 1109 | 694 |
| 1110 DISALLOW_COPY_AND_ASSIGN(EstablishConnectionViaFactoryDelegate); | 695 DISALLOW_COPY_AND_ASSIGN(EstablishConnectionViaFactoryDelegate); |
| 1111 }; | 696 }; |
| 1112 | 697 |
| 1113 TEST_F(WindowServerTest, EstablishConnectionViaFactory) { | 698 TEST_F(WindowServerTest, EstablishConnectionViaFactory) { |
| 1114 EstablishConnectionViaFactoryDelegate delegate(window_manager()); | 699 EstablishConnectionViaFactoryDelegate delegate(window_manager()); |
| 1115 set_window_manager_delegate(&delegate); | 700 set_window_manager_delegate(&delegate); |
| 1116 WindowTreeClient second_client(this, nullptr, nullptr); | 701 aura::WindowTreeClient second_client(connector(), this); |
| 1117 second_client.ConnectViaWindowTreeFactory(connector()); | 702 second_client.ConnectViaWindowTreeFactory(); |
| 1118 Window* window_in_second_client = second_client.NewTopLevelWindow(nullptr); | 703 aura::WindowTreeHostMus window_tree_host_in_second_client(&second_client); |
| 1119 ASSERT_TRUE(window_in_second_client); | 704 ASSERT_TRUE(second_client.GetRoots().count( |
| 1120 ASSERT_TRUE(second_client.GetRoots().count(window_in_second_client) > 0); | 705 window_tree_host_in_second_client.window()) > 0); |
| 1121 // Wait for the window to appear in the wm. | 706 // Wait for the window to appear in the wm. |
| 1122 ASSERT_TRUE(delegate.QuitOnCreate()); | 707 ASSERT_TRUE(delegate.QuitOnCreate()); |
| 1123 | 708 |
| 1124 Window* window_in_wm = delegate.created_window(); | 709 aura::Window* window_in_wm = delegate.created_window(); |
| 1125 ASSERT_TRUE(window_in_wm); | 710 ASSERT_TRUE(window_in_wm); |
| 1126 | 711 |
| 1127 // Change the bounds in the wm, and make sure the child sees it. | 712 // Change the bounds in the wm, and make sure the child sees it. |
| 1128 window_in_wm->SetBounds(gfx::Rect(1, 11, 12, 101)); | 713 const gfx::Rect window_bounds(1, 11, 12, 101); |
| 1129 ASSERT_TRUE(WaitForBoundsToChange(window_in_second_client)); | 714 window_in_wm->SetBounds(window_bounds); |
| 1130 EXPECT_EQ(gfx::Rect(1, 11, 12, 101), window_in_second_client->bounds()); | 715 ASSERT_TRUE( |
| 716 WaitForBoundsToChange(window_tree_host_in_second_client.window())); |
| 717 EXPECT_EQ(window_bounds, |
| 718 window_tree_host_in_second_client.GetBoundsInPixels()); |
| 1131 } | 719 } |
| 1132 | 720 |
| 1133 } // namespace ws | 721 } // namespace ws |
| 1134 } // namespace ui | 722 } // namespace ui |
| OLD | NEW |