OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <stddef.h> | |
6 #include <stdint.h> | |
7 | |
8 #include "base/bind.h" | |
9 #include "base/macros.h" | |
10 #include "base/message_loop/message_loop.h" | |
11 #include "base/run_loop.h" | |
12 #include "base/strings/stringprintf.h" | |
13 #include "components/mus/public/cpp/tests/window_server_shelltest_base.h" | |
14 #include "components/mus/public/interfaces/window_tree.mojom.h" | |
15 #include "components/mus/public/interfaces/window_tree_host.mojom.h" | |
16 #include "components/mus/ws/ids.h" | |
17 #include "components/mus/ws/test_change_tracker.h" | |
18 #include "mojo/public/cpp/bindings/associated_binding.h" | |
19 #include "services/shell/public/cpp/shell_test.h" | |
20 | |
21 using mojo::Array; | |
22 using shell::Connection; | |
23 using mojo::InterfaceRequest; | |
24 using shell::ShellClient; | |
25 using mojo::String; | |
26 using mus::mojom::WindowDataPtr; | |
27 using mus::mojom::WindowTree; | |
28 using mus::mojom::WindowTreeClient; | |
29 | |
30 namespace mus { | |
31 namespace ws { | |
32 namespace test { | |
33 | |
34 namespace { | |
35 | |
36 // Creates an id used for transport from the specified parameters. | |
37 Id BuildWindowId(ClientSpecificId client_id, | |
38 ClientSpecificId window_id) { | |
39 return (client_id << 16) | window_id; | |
40 } | |
41 | |
42 // Callback function from WindowTree functions. | |
43 // ---------------------------------- | |
44 | |
45 void WindowTreeResultCallback(base::RunLoop* run_loop, | |
46 std::vector<TestWindow>* windows, | |
47 Array<WindowDataPtr> results) { | |
48 WindowDatasToTestWindows(results, windows); | |
49 run_loop->Quit(); | |
50 } | |
51 | |
52 void EmbedCallbackImpl(base::RunLoop* run_loop, | |
53 bool* result_cache, | |
54 bool result) { | |
55 *result_cache = result; | |
56 run_loop->Quit(); | |
57 } | |
58 | |
59 // ----------------------------------------------------------------------------- | |
60 | |
61 bool EmbedUrl(shell::Connector* connector, | |
62 WindowTree* tree, | |
63 const String& url, | |
64 Id root_id) { | |
65 bool result = false; | |
66 base::RunLoop run_loop; | |
67 { | |
68 mojom::WindowTreeClientPtr client; | |
69 connector->ConnectToInterface(url.get(), &client); | |
70 const uint32_t embed_flags = 0; | |
71 tree->Embed(root_id, std::move(client), embed_flags, | |
72 base::Bind(&EmbedCallbackImpl, &run_loop, &result)); | |
73 } | |
74 run_loop.Run(); | |
75 return result; | |
76 } | |
77 | |
78 bool Embed(WindowTree* tree, Id root_id, mojom::WindowTreeClientPtr client) { | |
79 bool result = false; | |
80 base::RunLoop run_loop; | |
81 { | |
82 const uint32_t embed_flags = 0; | |
83 tree->Embed(root_id, std::move(client), embed_flags, | |
84 base::Bind(&EmbedCallbackImpl, &run_loop, &result)); | |
85 } | |
86 run_loop.Run(); | |
87 return result; | |
88 } | |
89 | |
90 void GetWindowTree(WindowTree* tree, | |
91 Id window_id, | |
92 std::vector<TestWindow>* windows) { | |
93 base::RunLoop run_loop; | |
94 tree->GetWindowTree( | |
95 window_id, base::Bind(&WindowTreeResultCallback, &run_loop, windows)); | |
96 run_loop.Run(); | |
97 } | |
98 | |
99 // Utility functions ----------------------------------------------------------- | |
100 | |
101 const Id kNullParentId = 0; | |
102 std::string IdToString(Id id) { | |
103 return (id == kNullParentId) ? "null" : base::StringPrintf( | |
104 "%d,%d", HiWord(id), LoWord(id)); | |
105 } | |
106 | |
107 std::string WindowParentToString(Id window, Id parent) { | |
108 return base::StringPrintf("window=%s parent=%s", IdToString(window).c_str(), | |
109 IdToString(parent).c_str()); | |
110 } | |
111 | |
112 // ----------------------------------------------------------------------------- | |
113 | |
114 // A WindowTreeClient implementation that logs all changes to a tracker. | |
115 class TestWindowTreeClient : public mojom::WindowTreeClient, | |
116 public TestChangeTracker::Delegate, | |
117 public mojom::WindowManager { | |
118 public: | |
119 TestWindowTreeClient() | |
120 : binding_(this), | |
121 client_id_(0), | |
122 root_window_id_(0), | |
123 // Start with a random large number so tests can use lower ids if they | |
124 // want. | |
125 next_change_id_(10000), | |
126 waiting_change_id_(0), | |
127 on_change_completed_result_(false), | |
128 track_root_bounds_changes_(false) { | |
129 tracker_.set_delegate(this); | |
130 } | |
131 | |
132 void Bind(mojo::InterfaceRequest<mojom::WindowTreeClient> request) { | |
133 binding_.Bind(std::move(request)); | |
134 } | |
135 | |
136 mojom::WindowTree* tree() { return tree_.get(); } | |
137 TestChangeTracker* tracker() { return &tracker_; } | |
138 Id root_window_id() const { return root_window_id_; } | |
139 | |
140 // Sets whether changes to the bounds of the root should be tracked. Normally | |
141 // they are ignored (as during startup we often times get random size | |
142 // changes). | |
143 void set_track_root_bounds_changes(bool value) { | |
144 track_root_bounds_changes_ = value; | |
145 } | |
146 | |
147 // Runs a nested MessageLoop until |count| changes (calls to | |
148 // WindowTreeClient functions) have been received. | |
149 void WaitForChangeCount(size_t count) { | |
150 if (tracker_.changes()->size() >= count) | |
151 return; | |
152 | |
153 ASSERT_TRUE(wait_state_.get() == nullptr); | |
154 wait_state_.reset(new WaitState); | |
155 wait_state_->change_count = count; | |
156 wait_state_->run_loop.Run(); | |
157 wait_state_.reset(); | |
158 } | |
159 | |
160 uint32_t GetAndAdvanceChangeId() { return next_change_id_++; } | |
161 | |
162 // Runs a nested MessageLoop until OnEmbed() has been encountered. | |
163 void WaitForOnEmbed() { | |
164 if (tree_) | |
165 return; | |
166 embed_run_loop_.reset(new base::RunLoop); | |
167 embed_run_loop_->Run(); | |
168 embed_run_loop_.reset(); | |
169 } | |
170 | |
171 bool WaitForChangeCompleted(uint32_t id) { | |
172 waiting_change_id_ = id; | |
173 change_completed_run_loop_.reset(new base::RunLoop); | |
174 change_completed_run_loop_->Run(); | |
175 return on_change_completed_result_; | |
176 } | |
177 | |
178 bool DeleteWindow(Id id) { | |
179 const uint32_t change_id = GetAndAdvanceChangeId(); | |
180 tree()->DeleteWindow(change_id, id); | |
181 return WaitForChangeCompleted(change_id); | |
182 } | |
183 | |
184 bool AddWindow(Id parent, Id child) { | |
185 const uint32_t change_id = GetAndAdvanceChangeId(); | |
186 tree()->AddWindow(change_id, parent, child); | |
187 return WaitForChangeCompleted(change_id); | |
188 } | |
189 | |
190 bool RemoveWindowFromParent(Id window_id) { | |
191 const uint32_t change_id = GetAndAdvanceChangeId(); | |
192 tree()->RemoveWindowFromParent(change_id, window_id); | |
193 return WaitForChangeCompleted(change_id); | |
194 } | |
195 | |
196 bool ReorderWindow(Id window_id, | |
197 Id relative_window_id, | |
198 mojom::OrderDirection direction) { | |
199 const uint32_t change_id = GetAndAdvanceChangeId(); | |
200 tree()->ReorderWindow(change_id, window_id, relative_window_id, direction); | |
201 return WaitForChangeCompleted(change_id); | |
202 } | |
203 | |
204 // Waits for all messages to be received by |ws|. This is done by attempting | |
205 // to create a bogus window. When we get the response we know all messages | |
206 // have been processed. | |
207 bool WaitForAllMessages() { | |
208 return NewWindowWithCompleteId(WindowIdToTransportId(InvalidWindowId())) == | |
209 0; | |
210 } | |
211 | |
212 Id NewWindow(ClientSpecificId window_id) { | |
213 return NewWindowWithCompleteId(BuildWindowId(client_id_, window_id)); | |
214 } | |
215 | |
216 // Generally you want NewWindow(), but use this if you need to test given | |
217 // a complete window id (NewWindow() ors with the client id). | |
218 Id NewWindowWithCompleteId(Id id) { | |
219 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties; | |
220 const uint32_t change_id = GetAndAdvanceChangeId(); | |
221 tree()->NewWindow(change_id, id, std::move(properties)); | |
222 return WaitForChangeCompleted(change_id) ? id : 0; | |
223 } | |
224 | |
225 bool SetWindowProperty(Id window_id, | |
226 const std::string& name, | |
227 const std::vector<uint8_t>* data) { | |
228 Array<uint8_t> mojo_data(nullptr); | |
229 if (data) | |
230 mojo_data = Array<uint8_t>::From(*data); | |
231 const uint32_t change_id = GetAndAdvanceChangeId(); | |
232 tree()->SetWindowProperty(change_id, window_id, name, std::move(mojo_data)); | |
233 return WaitForChangeCompleted(change_id); | |
234 } | |
235 | |
236 bool SetPredefinedCursor(Id window_id, mojom::Cursor cursor) { | |
237 const uint32_t change_id = GetAndAdvanceChangeId(); | |
238 tree()->SetPredefinedCursor(change_id, window_id, cursor); | |
239 return WaitForChangeCompleted(change_id); | |
240 } | |
241 | |
242 bool SetWindowVisibility(Id window_id, bool visible) { | |
243 const uint32_t change_id = GetAndAdvanceChangeId(); | |
244 tree()->SetWindowVisibility(change_id, window_id, visible); | |
245 return WaitForChangeCompleted(change_id); | |
246 } | |
247 | |
248 bool SetWindowOpacity(Id window_id, float opacity) { | |
249 const uint32_t change_id = GetAndAdvanceChangeId(); | |
250 tree()->SetWindowOpacity(change_id, window_id, opacity); | |
251 return WaitForChangeCompleted(change_id); | |
252 } | |
253 | |
254 private: | |
255 // Used when running a nested MessageLoop. | |
256 struct WaitState { | |
257 WaitState() : change_count(0) {} | |
258 | |
259 // Number of changes waiting for. | |
260 size_t change_count; | |
261 base::RunLoop run_loop; | |
262 }; | |
263 | |
264 // TestChangeTracker::Delegate: | |
265 void OnChangeAdded() override { | |
266 if (wait_state_.get() && | |
267 tracker_.changes()->size() >= wait_state_->change_count) { | |
268 wait_state_->run_loop.Quit(); | |
269 } | |
270 } | |
271 | |
272 // WindowTreeClient: | |
273 void OnEmbed(ClientSpecificId client_id, | |
274 WindowDataPtr root, | |
275 mojom::WindowTreePtr tree, | |
276 int64_t display_id, | |
277 Id focused_window_id, | |
278 bool drawn) override { | |
279 // TODO(sky): add coverage of |focused_window_id|. | |
280 ASSERT_TRUE(root); | |
281 root_window_id_ = root->window_id; | |
282 tree_ = std::move(tree); | |
283 client_id_ = client_id; | |
284 tracker()->OnEmbed(client_id, std::move(root), drawn); | |
285 if (embed_run_loop_) | |
286 embed_run_loop_->Quit(); | |
287 } | |
288 void OnEmbeddedAppDisconnected(Id window_id) override { | |
289 tracker()->OnEmbeddedAppDisconnected(window_id); | |
290 } | |
291 void OnUnembed(Id window_id) override { tracker()->OnUnembed(window_id); } | |
292 void OnLostCapture(Id window_id) override { | |
293 tracker()->OnLostCapture(window_id); | |
294 } | |
295 void OnTopLevelCreated(uint32_t change_id, | |
296 mojom::WindowDataPtr data, | |
297 int64_t display_id, | |
298 bool drawn) override { | |
299 tracker()->OnTopLevelCreated(change_id, std::move(data), drawn); | |
300 } | |
301 void OnWindowBoundsChanged(Id window_id, | |
302 const gfx::Rect& old_bounds, | |
303 const gfx::Rect& new_bounds) override { | |
304 // The bounds of the root may change during startup on Android at random | |
305 // times. As this doesn't matter, and shouldn't impact test exepctations, | |
306 // it is ignored. | |
307 if (window_id == root_window_id_ && !track_root_bounds_changes_) | |
308 return; | |
309 tracker()->OnWindowBoundsChanged(window_id, old_bounds, new_bounds); | |
310 } | |
311 void OnClientAreaChanged( | |
312 uint32_t window_id, | |
313 const gfx::Insets& new_client_area, | |
314 mojo::Array<gfx::Rect> new_additional_client_areas) override {} | |
315 void OnTransientWindowAdded(uint32_t window_id, | |
316 uint32_t transient_window_id) override { | |
317 tracker()->OnTransientWindowAdded(window_id, transient_window_id); | |
318 } | |
319 void OnTransientWindowRemoved(uint32_t window_id, | |
320 uint32_t transient_window_id) override { | |
321 tracker()->OnTransientWindowRemoved(window_id, transient_window_id); | |
322 } | |
323 void OnWindowHierarchyChanged(Id window, | |
324 Id old_parent, | |
325 Id new_parent, | |
326 Array<WindowDataPtr> windows) override { | |
327 tracker()->OnWindowHierarchyChanged(window, old_parent, new_parent, | |
328 std::move(windows)); | |
329 } | |
330 void OnWindowReordered(Id window_id, | |
331 Id relative_window_id, | |
332 mojom::OrderDirection direction) override { | |
333 tracker()->OnWindowReordered(window_id, relative_window_id, direction); | |
334 } | |
335 void OnWindowDeleted(Id window) override { | |
336 tracker()->OnWindowDeleted(window); | |
337 } | |
338 void OnWindowVisibilityChanged(uint32_t window, bool visible) override { | |
339 tracker()->OnWindowVisibilityChanged(window, visible); | |
340 } | |
341 void OnWindowOpacityChanged(uint32_t window, | |
342 float old_opacity, | |
343 float new_opacity) override { | |
344 tracker()->OnWindowOpacityChanged(window, new_opacity); | |
345 } | |
346 void OnWindowParentDrawnStateChanged(uint32_t window, bool drawn) override { | |
347 tracker()->OnWindowParentDrawnStateChanged(window, drawn); | |
348 } | |
349 void OnWindowInputEvent(uint32_t event_id, | |
350 Id window_id, | |
351 std::unique_ptr<ui::Event> event, | |
352 uint32_t event_observer_id) override { | |
353 // Ack input events to clear the state on the server. These can be received | |
354 // during test startup. X11Window::DispatchEvent sends a synthetic move | |
355 // event to notify of entry. | |
356 tree()->OnWindowInputEventAck(event_id, mojom::EventResult::HANDLED); | |
357 // Don't log input events as none of the tests care about them and they | |
358 // may come in at random points. | |
359 } | |
360 void OnEventObserved(std::unique_ptr<ui::Event>, | |
361 uint32_t event_observer_id) override {} | |
362 void OnWindowSharedPropertyChanged(uint32_t window, | |
363 const String& name, | |
364 Array<uint8_t> new_data) override { | |
365 tracker_.OnWindowSharedPropertyChanged(window, name, std::move(new_data)); | |
366 } | |
367 // TODO(sky): add testing coverage. | |
368 void OnWindowFocused(uint32_t focused_window_id) override {} | |
369 void OnWindowPredefinedCursorChanged(uint32_t window_id, | |
370 mojom::Cursor cursor_id) override { | |
371 tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id); | |
372 } | |
373 void OnChangeCompleted(uint32_t change_id, bool success) override { | |
374 if (waiting_change_id_ == change_id && change_completed_run_loop_) { | |
375 on_change_completed_result_ = success; | |
376 change_completed_run_loop_->Quit(); | |
377 } | |
378 } | |
379 void RequestClose(uint32_t window_id) override {} | |
380 void GetWindowManager(mojo::AssociatedInterfaceRequest<mojom::WindowManager> | |
381 internal) override { | |
382 window_manager_binding_.reset( | |
383 new mojo::AssociatedBinding<mojom::WindowManager>(this, | |
384 std::move(internal))); | |
385 tree_->GetWindowManagerClient( | |
386 GetProxy(&window_manager_client_, tree_.associated_group())); | |
387 } | |
388 | |
389 // mojom::WindowManager: | |
390 void OnConnect(uint16_t client_id) override {} | |
391 void WmNewDisplayAdded(mojom::DisplayPtr display, | |
392 mojom::WindowDataPtr root_data, | |
393 bool drawn) override { | |
394 NOTIMPLEMENTED(); | |
395 } | |
396 void WmSetBounds(uint32_t change_id, | |
397 uint32_t window_id, | |
398 const gfx::Rect& bounds) override { | |
399 window_manager_client_->WmResponse(change_id, false); | |
400 } | |
401 void WmSetProperty(uint32_t change_id, | |
402 uint32_t window_id, | |
403 const mojo::String& name, | |
404 mojo::Array<uint8_t> value) override { | |
405 window_manager_client_->WmResponse(change_id, false); | |
406 } | |
407 void WmCreateTopLevelWindow( | |
408 uint32_t change_id, | |
409 ClientSpecificId requesting_client_id, | |
410 mojo::Map<mojo::String, mojo::Array<uint8_t>> properties) override { | |
411 NOTIMPLEMENTED(); | |
412 } | |
413 void WmClientJankinessChanged(ClientSpecificId client_id, | |
414 bool janky) override { | |
415 NOTIMPLEMENTED(); | |
416 } | |
417 void OnAccelerator(uint32_t id, std::unique_ptr<ui::Event> event) override { | |
418 NOTIMPLEMENTED(); | |
419 } | |
420 | |
421 TestChangeTracker tracker_; | |
422 | |
423 mojom::WindowTreePtr tree_; | |
424 | |
425 // If non-null we're waiting for OnEmbed() using this RunLoop. | |
426 std::unique_ptr<base::RunLoop> embed_run_loop_; | |
427 | |
428 // If non-null we're waiting for a certain number of change notifications to | |
429 // be encountered. | |
430 std::unique_ptr<WaitState> wait_state_; | |
431 | |
432 mojo::Binding<WindowTreeClient> binding_; | |
433 Id client_id_; | |
434 Id root_window_id_; | |
435 uint32_t next_change_id_; | |
436 uint32_t waiting_change_id_; | |
437 bool on_change_completed_result_; | |
438 bool track_root_bounds_changes_; | |
439 std::unique_ptr<base::RunLoop> change_completed_run_loop_; | |
440 | |
441 std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManager>> | |
442 window_manager_binding_; | |
443 mojom::WindowManagerClientAssociatedPtr window_manager_client_; | |
444 | |
445 DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient); | |
446 }; | |
447 | |
448 // ----------------------------------------------------------------------------- | |
449 | |
450 // InterfaceFactory for vending TestWindowTreeClients. | |
451 class WindowTreeClientFactory | |
452 : public shell::InterfaceFactory<WindowTreeClient> { | |
453 public: | |
454 WindowTreeClientFactory() {} | |
455 ~WindowTreeClientFactory() override {} | |
456 | |
457 // Runs a nested MessageLoop until a new instance has been created. | |
458 std::unique_ptr<TestWindowTreeClient> WaitForInstance() { | |
459 if (!client_impl_.get()) { | |
460 DCHECK(!run_loop_); | |
461 run_loop_.reset(new base::RunLoop); | |
462 run_loop_->Run(); | |
463 run_loop_.reset(); | |
464 } | |
465 return std::move(client_impl_); | |
466 } | |
467 | |
468 private: | |
469 // InterfaceFactory<WindowTreeClient>: | |
470 void Create(Connection* connection, | |
471 InterfaceRequest<WindowTreeClient> request) override { | |
472 client_impl_.reset(new TestWindowTreeClient()); | |
473 client_impl_->Bind(std::move(request)); | |
474 if (run_loop_.get()) | |
475 run_loop_->Quit(); | |
476 } | |
477 | |
478 std::unique_ptr<TestWindowTreeClient> client_impl_; | |
479 std::unique_ptr<base::RunLoop> run_loop_; | |
480 | |
481 DISALLOW_COPY_AND_ASSIGN(WindowTreeClientFactory); | |
482 }; | |
483 | |
484 } // namespace | |
485 | |
486 class WindowTreeClientTest : public WindowServerShellTestBase { | |
487 public: | |
488 WindowTreeClientTest() | |
489 : client_id_1_(0), client_id_2_(0), root_window_id_(0) {} | |
490 | |
491 ~WindowTreeClientTest() override {} | |
492 | |
493 protected: | |
494 // Returns the changes from the various clients. | |
495 std::vector<Change>* changes1() { return wt_client1_->tracker()->changes(); } | |
496 std::vector<Change>* changes2() { return wt_client2_->tracker()->changes(); } | |
497 std::vector<Change>* changes3() { return wt_client3_->tracker()->changes(); } | |
498 | |
499 // Various clients. |wt1()|, being the first client, has special permissions | |
500 // (it's treated as the window manager). | |
501 WindowTree* wt1() { return wt_client1_->tree(); } | |
502 WindowTree* wt2() { return wt_client2_->tree(); } | |
503 WindowTree* wt3() { return wt_client3_->tree(); } | |
504 | |
505 TestWindowTreeClient* wt_client1() { return wt_client1_.get(); } | |
506 TestWindowTreeClient* wt_client2() { return wt_client2_.get(); } | |
507 TestWindowTreeClient* wt_client3() { return wt_client3_.get(); } | |
508 | |
509 Id root_window_id() const { return root_window_id_; } | |
510 | |
511 int client_id_1() const { return client_id_1_; } | |
512 int client_id_2() const { return client_id_2_; } | |
513 | |
514 void EstablishSecondClientWithRoot(Id root_id) { | |
515 ASSERT_TRUE(wt_client2_.get() == nullptr); | |
516 wt_client2_ = | |
517 EstablishClientViaEmbed(wt1(), root_id, &client_id_2_); | |
518 ASSERT_GT(client_id_2_, 0); | |
519 ASSERT_TRUE(wt_client2_.get() != nullptr); | |
520 } | |
521 | |
522 void EstablishSecondClient(bool create_initial_window) { | |
523 Id window_1_1 = 0; | |
524 if (create_initial_window) { | |
525 window_1_1 = wt_client1()->NewWindow(1); | |
526 ASSERT_TRUE(window_1_1); | |
527 } | |
528 ASSERT_NO_FATAL_FAILURE( | |
529 EstablishSecondClientWithRoot(BuildWindowId(client_id_1(), 1))); | |
530 | |
531 if (create_initial_window) { | |
532 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]", | |
533 ChangeWindowDescription(*changes2())); | |
534 } | |
535 } | |
536 | |
537 void EstablishThirdClient(WindowTree* owner, Id root_id) { | |
538 ASSERT_TRUE(wt_client3_.get() == nullptr); | |
539 wt_client3_ = EstablishClientViaEmbed(owner, root_id, nullptr); | |
540 ASSERT_TRUE(wt_client3_.get() != nullptr); | |
541 } | |
542 | |
543 std::unique_ptr<TestWindowTreeClient> WaitForWindowTreeClient() { | |
544 return client_factory_->WaitForInstance(); | |
545 } | |
546 | |
547 // Establishes a new client by way of Embed() on the specified WindowTree. | |
548 std::unique_ptr<TestWindowTreeClient> EstablishClientViaEmbed( | |
549 WindowTree* owner, | |
550 Id root_id, | |
551 int* client_id) { | |
552 return EstablishClientViaEmbedWithPolicyBitmask(owner, root_id, client_id); | |
553 } | |
554 | |
555 std::unique_ptr<TestWindowTreeClient> | |
556 EstablishClientViaEmbedWithPolicyBitmask(WindowTree* owner, | |
557 Id root_id, | |
558 int* client_id) { | |
559 if (!EmbedUrl(connector(), owner, test_name(), root_id)) { | |
560 ADD_FAILURE() << "Embed() failed"; | |
561 return nullptr; | |
562 } | |
563 std::unique_ptr<TestWindowTreeClient> client = | |
564 client_factory_->WaitForInstance(); | |
565 if (!client.get()) { | |
566 ADD_FAILURE() << "WaitForInstance failed"; | |
567 return nullptr; | |
568 } | |
569 client->WaitForOnEmbed(); | |
570 | |
571 EXPECT_EQ("OnEmbed", | |
572 SingleChangeToDescription(*client->tracker()->changes())); | |
573 if (client_id) | |
574 *client_id = (*client->tracker()->changes())[0].client_id; | |
575 return client; | |
576 } | |
577 | |
578 // WindowServerShellTestBase: | |
579 bool AcceptConnection(shell::Connection* connection) override { | |
580 connection->AddInterface(client_factory_.get()); | |
581 return true; | |
582 } | |
583 | |
584 void SetUp() override { | |
585 client_factory_.reset(new WindowTreeClientFactory()); | |
586 | |
587 WindowServerShellTestBase::SetUp(); | |
588 | |
589 mojom::WindowTreeHostFactoryPtr factory; | |
590 connector()->ConnectToInterface("mojo:mus", &factory); | |
591 | |
592 mojom::WindowTreeClientPtr tree_client_ptr; | |
593 wt_client1_.reset(new TestWindowTreeClient()); | |
594 wt_client1_->Bind(GetProxy(&tree_client_ptr)); | |
595 | |
596 factory->CreateWindowTreeHost(GetProxy(&host_), | |
597 std::move(tree_client_ptr)); | |
598 | |
599 // Next we should get an embed call on the "window manager" client. | |
600 wt_client1_->WaitForOnEmbed(); | |
601 | |
602 ASSERT_EQ(1u, changes1()->size()); | |
603 EXPECT_EQ(CHANGE_TYPE_EMBED, (*changes1())[0].type); | |
604 // All these tests assume 1 for the client id. The only real assertion here | |
605 // is the client id is not zero, but adding this as rest of code here | |
606 // assumes 1. | |
607 ASSERT_GT((*changes1())[0].client_id, 0); | |
608 client_id_1_ = (*changes1())[0].client_id; | |
609 ASSERT_FALSE((*changes1())[0].windows.empty()); | |
610 root_window_id_ = (*changes1())[0].windows[0].window_id; | |
611 ASSERT_EQ(root_window_id_, wt_client1_->root_window_id()); | |
612 changes1()->clear(); | |
613 } | |
614 | |
615 void TearDown() override { | |
616 // Destroy these before the message loop is destroyed (happens in | |
617 // WindowServerShellTestBase::TearDown). | |
618 wt_client1_.reset(); | |
619 wt_client2_.reset(); | |
620 wt_client3_.reset(); | |
621 client_factory_.reset(); | |
622 WindowServerShellTestBase::TearDown(); | |
623 } | |
624 | |
625 std::unique_ptr<TestWindowTreeClient> wt_client1_; | |
626 std::unique_ptr<TestWindowTreeClient> wt_client2_; | |
627 std::unique_ptr<TestWindowTreeClient> wt_client3_; | |
628 | |
629 mojom::WindowTreeHostPtr host_; | |
630 | |
631 private: | |
632 std::unique_ptr<WindowTreeClientFactory> client_factory_; | |
633 int client_id_1_; | |
634 int client_id_2_; | |
635 Id root_window_id_; | |
636 | |
637 DISALLOW_COPY_AND_ASSIGN(WindowTreeClientTest); | |
638 }; | |
639 | |
640 // Verifies two clients get different ids. | |
641 TEST_F(WindowTreeClientTest, TwoClientsGetDifferentClientIds) { | |
642 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
643 | |
644 ASSERT_EQ(1u, changes2()->size()); | |
645 ASSERT_NE(client_id_1(), client_id_2()); | |
646 } | |
647 | |
648 // Verifies when Embed() is invoked any child windows are removed. | |
649 TEST_F(WindowTreeClientTest, WindowsRemovedWhenEmbedding) { | |
650 // Two windows 1 and 2. 2 is parented to 1. | |
651 Id window_1_1 = wt_client1()->NewWindow(1); | |
652 ASSERT_TRUE(window_1_1); | |
653 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
654 | |
655 Id window_1_2 = wt_client1()->NewWindow(2); | |
656 ASSERT_TRUE(window_1_2); | |
657 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2)); | |
658 | |
659 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
660 ASSERT_EQ(1u, changes2()->size()); | |
661 ASSERT_EQ(1u, (*changes2())[0].windows.size()); | |
662 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]", | |
663 ChangeWindowDescription(*changes2())); | |
664 | |
665 // Embed() removed window 2. | |
666 { | |
667 std::vector<TestWindow> windows; | |
668 GetWindowTree(wt1(), window_1_2, &windows); | |
669 EXPECT_EQ(WindowParentToString(window_1_2, kNullParentId), | |
670 SingleWindowDescription(windows)); | |
671 } | |
672 | |
673 // ws2 should not see window 2. | |
674 { | |
675 std::vector<TestWindow> windows; | |
676 GetWindowTree(wt2(), window_1_1, &windows); | |
677 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId), | |
678 SingleWindowDescription(windows)); | |
679 } | |
680 { | |
681 std::vector<TestWindow> windows; | |
682 GetWindowTree(wt2(), window_1_2, &windows); | |
683 EXPECT_TRUE(windows.empty()); | |
684 } | |
685 | |
686 // Windows 3 and 4 in client 2. | |
687 Id window_2_3 = wt_client2()->NewWindow(3); | |
688 Id window_2_4 = wt_client2()->NewWindow(4); | |
689 ASSERT_TRUE(window_2_3); | |
690 ASSERT_TRUE(window_2_4); | |
691 ASSERT_TRUE(wt_client2()->AddWindow(window_2_3, window_2_4)); | |
692 | |
693 // Client 3 rooted at 2. | |
694 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_3)); | |
695 | |
696 // Window 4 should no longer have a parent. | |
697 { | |
698 std::vector<TestWindow> windows; | |
699 GetWindowTree(wt2(), window_2_3, &windows); | |
700 EXPECT_EQ(WindowParentToString(window_2_3, kNullParentId), | |
701 SingleWindowDescription(windows)); | |
702 | |
703 windows.clear(); | |
704 GetWindowTree(wt2(), window_2_4, &windows); | |
705 EXPECT_EQ(WindowParentToString(window_2_4, kNullParentId), | |
706 SingleWindowDescription(windows)); | |
707 } | |
708 | |
709 // And window 4 should not be visible to client 3. | |
710 { | |
711 std::vector<TestWindow> windows; | |
712 GetWindowTree(wt3(), window_2_3, &windows); | |
713 EXPECT_EQ("no windows", SingleWindowDescription(windows)); | |
714 } | |
715 } | |
716 | |
717 // Verifies once Embed() has been invoked the parent client can't see any | |
718 // children. | |
719 TEST_F(WindowTreeClientTest, CantAccessChildrenOfEmbeddedWindow) { | |
720 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
721 | |
722 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
723 Id window_2_2 = wt_client2()->NewWindow(2); | |
724 ASSERT_TRUE(window_2_2); | |
725 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2)); | |
726 | |
727 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_2)); | |
728 | |
729 Id window_3_3 = wt_client3()->NewWindow(3); | |
730 ASSERT_TRUE(window_3_3); | |
731 ASSERT_TRUE( | |
732 wt_client3()->AddWindow(wt_client3()->root_window_id(), window_3_3)); | |
733 | |
734 // Even though 3 is a child of 2 client 2 can't see 3 as it's from a | |
735 // different client. | |
736 { | |
737 std::vector<TestWindow> windows; | |
738 GetWindowTree(wt2(), window_2_2, &windows); | |
739 EXPECT_EQ(WindowParentToString(window_2_2, window_1_1), | |
740 SingleWindowDescription(windows)); | |
741 } | |
742 | |
743 // Client 2 shouldn't be able to get window 3 at all. | |
744 { | |
745 std::vector<TestWindow> windows; | |
746 GetWindowTree(wt2(), window_3_3, &windows); | |
747 EXPECT_TRUE(windows.empty()); | |
748 } | |
749 | |
750 // Client 1 should be able to see it all (its the root). | |
751 { | |
752 std::vector<TestWindow> windows; | |
753 GetWindowTree(wt1(), window_1_1, &windows); | |
754 ASSERT_EQ(3u, windows.size()); | |
755 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId), | |
756 windows[0].ToString()); | |
757 // NOTE: we expect a match of WindowParentToString(window_2_2, window_1_1), | |
758 // but the ids are in the id space of client2, which is not the same as | |
759 // the id space of wt1(). | |
760 EXPECT_EQ("window=2,1 parent=1,1", windows[1].ToString()); | |
761 // Same thing here, we really want to test for | |
762 // WindowParentToString(window_3_3, window_2_2). | |
763 EXPECT_EQ("window=3,1 parent=2,1", windows[2].ToString()); | |
764 } | |
765 } | |
766 | |
767 // Verifies once Embed() has been invoked the parent can't mutate the children. | |
768 TEST_F(WindowTreeClientTest, CantModifyChildrenOfEmbeddedWindow) { | |
769 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
770 | |
771 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
772 Id window_2_1 = wt_client2()->NewWindow(1); | |
773 ASSERT_TRUE(window_2_1); | |
774 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
775 | |
776 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1)); | |
777 | |
778 Id window_2_2 = wt_client2()->NewWindow(2); | |
779 ASSERT_TRUE(window_2_2); | |
780 // Client 2 shouldn't be able to add anything to the window anymore. | |
781 ASSERT_FALSE(wt_client2()->AddWindow(window_2_1, window_2_2)); | |
782 | |
783 // Create window 3 in client 3 and add it to window 3. | |
784 Id window_3_1 = wt_client3()->NewWindow(1); | |
785 ASSERT_TRUE(window_3_1); | |
786 ASSERT_TRUE(wt_client3()->AddWindow(window_2_1, window_3_1)); | |
787 | |
788 // Client 2 shouldn't be able to remove window 3. | |
789 ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_3_1)); | |
790 } | |
791 | |
792 // Verifies client gets a valid id. | |
793 TEST_F(WindowTreeClientTest, NewWindow) { | |
794 Id window_1_1 = wt_client1()->NewWindow(1); | |
795 ASSERT_TRUE(window_1_1); | |
796 EXPECT_TRUE(changes1()->empty()); | |
797 | |
798 // Can't create a window with the same id. | |
799 ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId(window_1_1)); | |
800 EXPECT_TRUE(changes1()->empty()); | |
801 | |
802 // Can't create a window with a bogus client id. | |
803 ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId( | |
804 BuildWindowId(client_id_1() + 1, 1))); | |
805 EXPECT_TRUE(changes1()->empty()); | |
806 } | |
807 | |
808 // Verifies AddWindow fails when window is already in position. | |
809 TEST_F(WindowTreeClientTest, AddWindowWithNoChange) { | |
810 // Create the embed point now so that the ids line up. | |
811 ASSERT_TRUE(wt_client1()->NewWindow(1)); | |
812 Id window_1_2 = wt_client1()->NewWindow(2); | |
813 Id window_1_3 = wt_client1()->NewWindow(3); | |
814 ASSERT_TRUE(window_1_2); | |
815 ASSERT_TRUE(window_1_3); | |
816 | |
817 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
818 | |
819 // Make 3 a child of 2. | |
820 ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_3)); | |
821 | |
822 // Try again, this should fail. | |
823 EXPECT_FALSE(wt_client1()->AddWindow(window_1_2, window_1_3)); | |
824 } | |
825 | |
826 // Verifies AddWindow fails when window is already in position. | |
827 TEST_F(WindowTreeClientTest, AddAncestorFails) { | |
828 // Create the embed point now so that the ids line up. | |
829 ASSERT_TRUE(wt_client1()->NewWindow(1)); | |
830 Id window_1_2 = wt_client1()->NewWindow(2); | |
831 Id window_1_3 = wt_client1()->NewWindow(3); | |
832 ASSERT_TRUE(window_1_2); | |
833 ASSERT_TRUE(window_1_3); | |
834 | |
835 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
836 | |
837 // Make 3 a child of 2. | |
838 ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_3)); | |
839 | |
840 // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3. | |
841 EXPECT_FALSE(wt_client1()->AddWindow(window_1_3, window_1_2)); | |
842 } | |
843 | |
844 // Verifies adding to root sends right notifications. | |
845 TEST_F(WindowTreeClientTest, AddToRoot) { | |
846 // Create the embed point now so that the ids line up. | |
847 Id window_1_1 = wt_client1()->NewWindow(1); | |
848 ASSERT_TRUE(window_1_1); | |
849 Id window_1_21 = wt_client1()->NewWindow(21); | |
850 Id window_1_3 = wt_client1()->NewWindow(3); | |
851 ASSERT_TRUE(window_1_21); | |
852 ASSERT_TRUE(window_1_3); | |
853 | |
854 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
855 changes2()->clear(); | |
856 | |
857 // Make 3 a child of 21. | |
858 ASSERT_TRUE(wt_client1()->AddWindow(window_1_21, window_1_3)); | |
859 | |
860 // Make 21 a child of 1. | |
861 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_21)); | |
862 | |
863 // Client 2 should not be told anything (because the window is from a | |
864 // different client). Create a window to ensure we got a response from | |
865 // the server. | |
866 ASSERT_TRUE(wt_client2()->NewWindow(100)); | |
867 EXPECT_TRUE(changes2()->empty()); | |
868 } | |
869 | |
870 // Verifies HierarchyChanged is correctly sent for various adds/removes. | |
871 TEST_F(WindowTreeClientTest, WindowHierarchyChangedWindows) { | |
872 // Create the embed point now so that the ids line up. | |
873 Id window_1_1 = wt_client1()->NewWindow(1); | |
874 // 1,2->1,11. | |
875 Id window_1_2 = wt_client1()->NewWindow(2); | |
876 ASSERT_TRUE(window_1_2); | |
877 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true)); | |
878 Id window_1_11 = wt_client1()->NewWindow(11); | |
879 ASSERT_TRUE(window_1_11); | |
880 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_11, true)); | |
881 ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_11)); | |
882 | |
883 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
884 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
885 | |
886 ASSERT_TRUE(wt_client2()->WaitForAllMessages()); | |
887 changes2()->clear(); | |
888 | |
889 // 1,1->1,2->1,11 | |
890 { | |
891 // Client 2 should not get anything (1,2 is from another client). | |
892 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2)); | |
893 ASSERT_TRUE(wt_client2()->WaitForAllMessages()); | |
894 EXPECT_TRUE(changes2()->empty()); | |
895 } | |
896 | |
897 // 0,1->1,1->1,2->1,11. | |
898 { | |
899 // Client 2 is now connected to the root, so it should have gotten a drawn | |
900 // notification. | |
901 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
902 wt_client2_->WaitForChangeCount(1u); | |
903 EXPECT_EQ( | |
904 "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true", | |
905 SingleChangeToDescription(*changes2())); | |
906 } | |
907 | |
908 // 1,1->1,2->1,11. | |
909 { | |
910 // Client 2 is no longer connected to the root, should get drawn state | |
911 // changed. | |
912 changes2()->clear(); | |
913 ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1)); | |
914 wt_client2_->WaitForChangeCount(1); | |
915 EXPECT_EQ( | |
916 "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=false", | |
917 SingleChangeToDescription(*changes2())); | |
918 } | |
919 | |
920 // 1,1->1,2->1,11->1,111. | |
921 Id window_1_111 = wt_client1()->NewWindow(111); | |
922 ASSERT_TRUE(window_1_111); | |
923 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_111, true)); | |
924 { | |
925 changes2()->clear(); | |
926 ASSERT_TRUE(wt_client1()->AddWindow(window_1_11, window_1_111)); | |
927 ASSERT_TRUE(wt_client2()->WaitForAllMessages()); | |
928 EXPECT_TRUE(changes2()->empty()); | |
929 } | |
930 | |
931 // 0,1->1,1->1,2->1,11->1,111 | |
932 { | |
933 changes2()->clear(); | |
934 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
935 wt_client2_->WaitForChangeCount(1); | |
936 EXPECT_EQ( | |
937 "DrawnStateChanged window=" + IdToString(window_1_1) + " drawn=true", | |
938 SingleChangeToDescription(*changes2())); | |
939 } | |
940 } | |
941 | |
942 TEST_F(WindowTreeClientTest, WindowHierarchyChangedAddingKnownToUnknown) { | |
943 // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no | |
944 // parent). | |
945 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
946 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
947 | |
948 Id window_2_11 = wt_client2()->NewWindow(11); | |
949 Id window_2_2 = wt_client2()->NewWindow(2); | |
950 Id window_2_21 = wt_client2()->NewWindow(21); | |
951 ASSERT_TRUE(window_2_11); | |
952 ASSERT_TRUE(window_2_2); | |
953 ASSERT_TRUE(window_2_21); | |
954 | |
955 // Set up the hierarchy. | |
956 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
957 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_11)); | |
958 ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_21)); | |
959 | |
960 // Remove 11, should result in a hierarchy change for the root. | |
961 { | |
962 changes1()->clear(); | |
963 ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11)); | |
964 | |
965 wt_client1_->WaitForChangeCount(1); | |
966 // 2,1 should be IdToString(window_2_11), but window_2_11 is in the id | |
967 // space of client2, not client1. | |
968 EXPECT_EQ("HierarchyChanged window=2,1 old_parent=" + | |
969 IdToString(window_1_1) + " new_parent=null", | |
970 SingleChangeToDescription(*changes1())); | |
971 } | |
972 | |
973 // Add 2 to 1. | |
974 { | |
975 changes1()->clear(); | |
976 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2)); | |
977 wt_client1_->WaitForChangeCount(1); | |
978 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2) + | |
979 " old_parent=null new_parent=" + IdToString(window_1_1), | |
980 SingleChangeToDescription(*changes1())); | |
981 // "window=2,3 parent=2,2]" should be, | |
982 // WindowParentToString(window_2_21, window_2_2), but isn't because of | |
983 // differing id spaces. | |
984 EXPECT_EQ("[" + WindowParentToString(window_2_2, window_1_1) + | |
985 "],[window=2,3 parent=2,2]", | |
986 ChangeWindowDescription(*changes1())); | |
987 } | |
988 } | |
989 | |
990 TEST_F(WindowTreeClientTest, ReorderWindow) { | |
991 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
992 | |
993 Id window_2_1 = wt_client2()->NewWindow(1); | |
994 Id window_2_2 = wt_client2()->NewWindow(2); | |
995 Id window_2_3 = wt_client2()->NewWindow(3); | |
996 Id window_1_4 = wt_client1()->NewWindow(4); // Peer to 1,1 | |
997 Id window_1_5 = wt_client1()->NewWindow(5); // Peer to 1,1 | |
998 Id window_2_6 = wt_client2()->NewWindow(6); // Child of 1,2. | |
999 Id window_2_7 = wt_client2()->NewWindow(7); // Unparented. | |
1000 Id window_2_8 = wt_client2()->NewWindow(8); // Unparented. | |
1001 ASSERT_TRUE(window_2_1); | |
1002 ASSERT_TRUE(window_2_2); | |
1003 ASSERT_TRUE(window_2_3); | |
1004 ASSERT_TRUE(window_1_4); | |
1005 ASSERT_TRUE(window_1_5); | |
1006 ASSERT_TRUE(window_2_6); | |
1007 ASSERT_TRUE(window_2_7); | |
1008 ASSERT_TRUE(window_2_8); | |
1009 | |
1010 ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2)); | |
1011 ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_6)); | |
1012 ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_3)); | |
1013 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_4)); | |
1014 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_5)); | |
1015 ASSERT_TRUE( | |
1016 wt_client2()->AddWindow(BuildWindowId(client_id_1(), 1), window_2_1)); | |
1017 | |
1018 { | |
1019 changes1()->clear(); | |
1020 ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3, | |
1021 mojom::OrderDirection::ABOVE)); | |
1022 | |
1023 wt_client1_->WaitForChangeCount(1); | |
1024 EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" + | |
1025 IdToString(window_2_3) + " direction=above", | |
1026 SingleChangeToDescription(*changes1())); | |
1027 } | |
1028 | |
1029 { | |
1030 changes1()->clear(); | |
1031 ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3, | |
1032 mojom::OrderDirection::BELOW)); | |
1033 | |
1034 wt_client1_->WaitForChangeCount(1); | |
1035 EXPECT_EQ("Reordered window=" + IdToString(window_2_2) + " relative=" + | |
1036 IdToString(window_2_3) + " direction=below", | |
1037 SingleChangeToDescription(*changes1())); | |
1038 } | |
1039 | |
1040 // view2 is already below view3. | |
1041 EXPECT_FALSE(wt_client2()->ReorderWindow(window_2_2, window_2_3, | |
1042 mojom::OrderDirection::BELOW)); | |
1043 | |
1044 // view4 & 5 are unknown to client 2. | |
1045 EXPECT_FALSE(wt_client2()->ReorderWindow(window_1_4, window_1_5, | |
1046 mojom::OrderDirection::ABOVE)); | |
1047 | |
1048 // view6 & view3 have different parents. | |
1049 EXPECT_FALSE(wt_client1()->ReorderWindow(window_2_3, window_2_6, | |
1050 mojom::OrderDirection::ABOVE)); | |
1051 | |
1052 // Non-existent window-ids | |
1053 EXPECT_FALSE(wt_client1()->ReorderWindow(BuildWindowId(client_id_1(), 27), | |
1054 BuildWindowId(client_id_1(), 28), | |
1055 mojom::OrderDirection::ABOVE)); | |
1056 | |
1057 // view7 & view8 are un-parented. | |
1058 EXPECT_FALSE(wt_client1()->ReorderWindow(window_2_7, window_2_8, | |
1059 mojom::OrderDirection::ABOVE)); | |
1060 } | |
1061 | |
1062 // Verifies DeleteWindow works. | |
1063 TEST_F(WindowTreeClientTest, DeleteWindow) { | |
1064 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1065 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1066 Id window_2_1 = wt_client2()->NewWindow(1); | |
1067 ASSERT_TRUE(window_2_1); | |
1068 | |
1069 // Make 2 a child of 1. | |
1070 { | |
1071 changes1()->clear(); | |
1072 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1073 wt_client1_->WaitForChangeCount(1); | |
1074 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) + | |
1075 " old_parent=null new_parent=" + IdToString(window_1_1), | |
1076 SingleChangeToDescription(*changes1())); | |
1077 } | |
1078 | |
1079 // Delete 2. | |
1080 { | |
1081 changes1()->clear(); | |
1082 changes2()->clear(); | |
1083 ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1)); | |
1084 EXPECT_TRUE(changes2()->empty()); | |
1085 | |
1086 wt_client1_->WaitForChangeCount(1); | |
1087 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1), | |
1088 SingleChangeToDescription(*changes1())); | |
1089 } | |
1090 } | |
1091 | |
1092 // Verifies DeleteWindow isn't allowed from a separate client. | |
1093 TEST_F(WindowTreeClientTest, DeleteWindowFromAnotherClientDisallowed) { | |
1094 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1095 EXPECT_FALSE(wt_client2()->DeleteWindow(BuildWindowId(client_id_1(), 1))); | |
1096 } | |
1097 | |
1098 // Verifies if a window was deleted and then reused that other clients are | |
1099 // properly notified. | |
1100 TEST_F(WindowTreeClientTest, ReuseDeletedWindowId) { | |
1101 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1102 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1103 Id window_2_1 = wt_client2()->NewWindow(1); | |
1104 ASSERT_TRUE(window_2_1); | |
1105 | |
1106 // Add 2 to 1. | |
1107 { | |
1108 changes1()->clear(); | |
1109 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1110 wt_client1_->WaitForChangeCount(1); | |
1111 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) + | |
1112 " old_parent=null new_parent=" + IdToString(window_1_1), | |
1113 SingleChangeToDescription(*changes1())); | |
1114 EXPECT_EQ("[" + WindowParentToString(window_2_1, window_1_1) + "]", | |
1115 ChangeWindowDescription(*changes1())); | |
1116 } | |
1117 | |
1118 // Delete 2. | |
1119 { | |
1120 changes1()->clear(); | |
1121 ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1)); | |
1122 | |
1123 wt_client1_->WaitForChangeCount(1); | |
1124 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1), | |
1125 SingleChangeToDescription(*changes1())); | |
1126 } | |
1127 | |
1128 // Create 2 again, and add it back to 1. Should get the same notification. | |
1129 window_2_1 = wt_client2()->NewWindow(2); | |
1130 ASSERT_TRUE(window_2_1); | |
1131 { | |
1132 changes1()->clear(); | |
1133 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1134 | |
1135 wt_client1_->WaitForChangeCount(1); | |
1136 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_1) + | |
1137 " old_parent=null new_parent=" + IdToString(window_1_1), | |
1138 SingleChangeToDescription(*changes1())); | |
1139 EXPECT_EQ("[" + WindowParentToString(window_2_1, window_1_1) + "]", | |
1140 ChangeWindowDescription(*changes1())); | |
1141 } | |
1142 } | |
1143 | |
1144 // Assertions for GetWindowTree. | |
1145 TEST_F(WindowTreeClientTest, GetWindowTree) { | |
1146 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1147 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1148 | |
1149 // Create 11 in first client and make it a child of 1. | |
1150 Id window_1_11 = wt_client1()->NewWindow(11); | |
1151 ASSERT_TRUE(window_1_11); | |
1152 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1153 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_11)); | |
1154 | |
1155 // Create two windows in second client, 2 and 3, both children of 1. | |
1156 Id window_2_1 = wt_client2()->NewWindow(1); | |
1157 Id window_2_2 = wt_client2()->NewWindow(2); | |
1158 ASSERT_TRUE(window_2_1); | |
1159 ASSERT_TRUE(window_2_2); | |
1160 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1161 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2)); | |
1162 | |
1163 // Verifies GetWindowTree() on the root. The root client sees all. | |
1164 { | |
1165 std::vector<TestWindow> windows; | |
1166 GetWindowTree(wt1(), root_window_id(), &windows); | |
1167 ASSERT_EQ(5u, windows.size()); | |
1168 EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId), | |
1169 windows[0].ToString()); | |
1170 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()), | |
1171 windows[1].ToString()); | |
1172 EXPECT_EQ(WindowParentToString(window_1_11, window_1_1), | |
1173 windows[2].ToString()); | |
1174 EXPECT_EQ(WindowParentToString(window_2_1, window_1_1), | |
1175 windows[3].ToString()); | |
1176 EXPECT_EQ(WindowParentToString(window_2_2, window_1_1), | |
1177 windows[4].ToString()); | |
1178 } | |
1179 | |
1180 // Verifies GetWindowTree() on the window 1,1 from wt2(). wt2() sees 1,1 as | |
1181 // 1,1 | |
1182 // is wt2()'s root and wt2() sees all the windows it created. | |
1183 { | |
1184 std::vector<TestWindow> windows; | |
1185 GetWindowTree(wt2(), window_1_1, &windows); | |
1186 ASSERT_EQ(3u, windows.size()); | |
1187 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId), | |
1188 windows[0].ToString()); | |
1189 EXPECT_EQ(WindowParentToString(window_2_1, window_1_1), | |
1190 windows[1].ToString()); | |
1191 EXPECT_EQ(WindowParentToString(window_2_2, window_1_1), | |
1192 windows[2].ToString()); | |
1193 } | |
1194 | |
1195 // Client 2 shouldn't be able to get the root tree. | |
1196 { | |
1197 std::vector<TestWindow> windows; | |
1198 GetWindowTree(wt2(), root_window_id(), &windows); | |
1199 ASSERT_EQ(0u, windows.size()); | |
1200 } | |
1201 } | |
1202 | |
1203 TEST_F(WindowTreeClientTest, SetWindowBounds) { | |
1204 Id window_1_1 = wt_client1()->NewWindow(1); | |
1205 ASSERT_TRUE(window_1_1); | |
1206 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1207 | |
1208 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
1209 | |
1210 changes2()->clear(); | |
1211 | |
1212 wt_client2_->set_track_root_bounds_changes(true); | |
1213 | |
1214 wt1()->SetWindowBounds(10, window_1_1, gfx::Rect(0, 0, 100, 100)); | |
1215 ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(10)); | |
1216 | |
1217 wt_client2_->WaitForChangeCount(1); | |
1218 EXPECT_EQ("BoundsChanged window=" + IdToString(window_1_1) + | |
1219 " old_bounds=0,0 0x0 new_bounds=0,0 100x100", | |
1220 SingleChangeToDescription(*changes2())); | |
1221 | |
1222 // Should not be possible to change the bounds of a window created by another | |
1223 // client. | |
1224 wt2()->SetWindowBounds(11, window_1_1, gfx::Rect(0, 0, 0, 0)); | |
1225 ASSERT_FALSE(wt_client2()->WaitForChangeCompleted(11)); | |
1226 } | |
1227 | |
1228 // Verify AddWindow fails when trying to manipulate windows in other roots. | |
1229 TEST_F(WindowTreeClientTest, CantMoveWindowsFromOtherRoot) { | |
1230 // Create 1 and 2 in the first client. | |
1231 Id window_1_1 = wt_client1()->NewWindow(1); | |
1232 Id window_1_2 = wt_client1()->NewWindow(2); | |
1233 ASSERT_TRUE(window_1_1); | |
1234 ASSERT_TRUE(window_1_2); | |
1235 | |
1236 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
1237 | |
1238 // Try to move 2 to be a child of 1 from client 2. This should fail as 2 | |
1239 // should not be able to access 1. | |
1240 ASSERT_FALSE(wt_client2()->AddWindow(window_1_1, window_1_2)); | |
1241 | |
1242 // Try to reparent 1 to the root. A client is not allowed to reparent its | |
1243 // roots. | |
1244 ASSERT_FALSE(wt_client2()->AddWindow(root_window_id(), window_1_1)); | |
1245 } | |
1246 | |
1247 // Verify RemoveWindowFromParent fails for windows that are descendants of the | |
1248 // roots. | |
1249 TEST_F(WindowTreeClientTest, CantRemoveWindowsInOtherRoots) { | |
1250 // Create 1 and 2 in the first client and parent both to the root. | |
1251 Id window_1_1 = wt_client1()->NewWindow(1); | |
1252 Id window_1_2 = wt_client1()->NewWindow(2); | |
1253 ASSERT_TRUE(window_1_1); | |
1254 ASSERT_TRUE(window_1_2); | |
1255 | |
1256 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1257 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2)); | |
1258 | |
1259 // Establish the second client and give it the root 1. | |
1260 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
1261 | |
1262 // Client 2 should not be able to remove window 2 or 1 from its parent. | |
1263 ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_2)); | |
1264 ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_1)); | |
1265 | |
1266 // Create windows 10 and 11 in 2. | |
1267 Id window_2_10 = wt_client2()->NewWindow(10); | |
1268 Id window_2_11 = wt_client2()->NewWindow(11); | |
1269 ASSERT_TRUE(window_2_10); | |
1270 ASSERT_TRUE(window_2_11); | |
1271 | |
1272 // Parent 11 to 10. | |
1273 ASSERT_TRUE(wt_client2()->AddWindow(window_2_10, window_2_11)); | |
1274 // Remove 11 from 10. | |
1275 ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11)); | |
1276 | |
1277 // Verify nothing was actually removed. | |
1278 { | |
1279 std::vector<TestWindow> windows; | |
1280 GetWindowTree(wt1(), root_window_id(), &windows); | |
1281 ASSERT_EQ(3u, windows.size()); | |
1282 EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId), | |
1283 windows[0].ToString()); | |
1284 EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()), | |
1285 windows[1].ToString()); | |
1286 EXPECT_EQ(WindowParentToString(window_1_2, root_window_id()), | |
1287 windows[2].ToString()); | |
1288 } | |
1289 } | |
1290 | |
1291 // Verify GetWindowTree fails for windows that are not descendants of the roots. | |
1292 TEST_F(WindowTreeClientTest, CantGetWindowTreeOfOtherRoots) { | |
1293 // Create 1 and 2 in the first client and parent both to the root. | |
1294 Id window_1_1 = wt_client1()->NewWindow(1); | |
1295 Id window_1_2 = wt_client1()->NewWindow(2); | |
1296 ASSERT_TRUE(window_1_1); | |
1297 ASSERT_TRUE(window_1_2); | |
1298 | |
1299 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1300 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2)); | |
1301 | |
1302 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
1303 | |
1304 std::vector<TestWindow> windows; | |
1305 | |
1306 // Should get nothing for the root. | |
1307 GetWindowTree(wt2(), root_window_id(), &windows); | |
1308 ASSERT_TRUE(windows.empty()); | |
1309 | |
1310 // Should get nothing for window 2. | |
1311 GetWindowTree(wt2(), window_1_2, &windows); | |
1312 ASSERT_TRUE(windows.empty()); | |
1313 | |
1314 // Should get window 1 if asked for. | |
1315 GetWindowTree(wt2(), window_1_1, &windows); | |
1316 ASSERT_EQ(1u, windows.size()); | |
1317 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId), | |
1318 windows[0].ToString()); | |
1319 } | |
1320 | |
1321 TEST_F(WindowTreeClientTest, EmbedWithSameWindowId) { | |
1322 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1323 changes2()->clear(); | |
1324 | |
1325 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1326 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_1_1)); | |
1327 | |
1328 // Client 2 should have been told of the unembed and delete. | |
1329 { | |
1330 wt_client2_->WaitForChangeCount(2); | |
1331 EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1), | |
1332 ChangesToDescription1(*changes2())[0]); | |
1333 EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1), | |
1334 ChangesToDescription1(*changes2())[1]); | |
1335 } | |
1336 | |
1337 // Client 2 has no root. Verify it can't see window 1,1 anymore. | |
1338 { | |
1339 std::vector<TestWindow> windows; | |
1340 GetWindowTree(wt2(), window_1_1, &windows); | |
1341 EXPECT_TRUE(windows.empty()); | |
1342 } | |
1343 } | |
1344 | |
1345 TEST_F(WindowTreeClientTest, EmbedWithSameWindowId2) { | |
1346 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1347 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1348 changes2()->clear(); | |
1349 | |
1350 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_1_1)); | |
1351 | |
1352 // Client 2 should have been told about the unembed and delete. | |
1353 wt_client2_->WaitForChangeCount(2); | |
1354 changes2()->clear(); | |
1355 | |
1356 // Create a window in the third client and parent it to the root. | |
1357 Id window_3_1 = wt_client3()->NewWindow(1); | |
1358 ASSERT_TRUE(window_3_1); | |
1359 ASSERT_TRUE(wt_client3()->AddWindow(window_1_1, window_3_1)); | |
1360 | |
1361 // Client 1 should have been told about the add (it owns the window). | |
1362 { | |
1363 wt_client1_->WaitForChangeCount(1); | |
1364 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_3_1) + | |
1365 " old_parent=null new_parent=" + IdToString(window_1_1), | |
1366 SingleChangeToDescription(*changes1())); | |
1367 } | |
1368 | |
1369 // Embed 1,1 again. | |
1370 { | |
1371 changes3()->clear(); | |
1372 | |
1373 // We should get a new client for the new embedding. | |
1374 std::unique_ptr<TestWindowTreeClient> client4( | |
1375 EstablishClientViaEmbed(wt1(), window_1_1, nullptr)); | |
1376 ASSERT_TRUE(client4.get()); | |
1377 EXPECT_EQ("[" + WindowParentToString(window_1_1, kNullParentId) + "]", | |
1378 ChangeWindowDescription(*client4->tracker()->changes())); | |
1379 | |
1380 // And 3 should get an unembed and delete. | |
1381 wt_client3_->WaitForChangeCount(2); | |
1382 EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1), | |
1383 ChangesToDescription1(*changes3())[0]); | |
1384 EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1), | |
1385 ChangesToDescription1(*changes3())[1]); | |
1386 } | |
1387 | |
1388 // wt3() has no root. Verify it can't see window 1,1 anymore. | |
1389 { | |
1390 std::vector<TestWindow> windows; | |
1391 GetWindowTree(wt3(), window_1_1, &windows); | |
1392 EXPECT_TRUE(windows.empty()); | |
1393 } | |
1394 | |
1395 // Verify 3,1 is no longer parented to 1,1. We have to do this from 1,1 as | |
1396 // wt3() can no longer see 1,1. | |
1397 { | |
1398 std::vector<TestWindow> windows; | |
1399 GetWindowTree(wt1(), window_1_1, &windows); | |
1400 ASSERT_EQ(1u, windows.size()); | |
1401 EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId), | |
1402 windows[0].ToString()); | |
1403 } | |
1404 | |
1405 // Verify wt3() can still see the window it created 3,1. | |
1406 { | |
1407 std::vector<TestWindow> windows; | |
1408 GetWindowTree(wt3(), window_3_1, &windows); | |
1409 ASSERT_EQ(1u, windows.size()); | |
1410 EXPECT_EQ(WindowParentToString(window_3_1, kNullParentId), | |
1411 windows[0].ToString()); | |
1412 } | |
1413 } | |
1414 | |
1415 // Assertions for SetWindowVisibility. | |
1416 TEST_F(WindowTreeClientTest, SetWindowVisibility) { | |
1417 // Create 1 and 2 in the first client and parent both to the root. | |
1418 Id window_1_1 = wt_client1()->NewWindow(1); | |
1419 Id window_1_2 = wt_client1()->NewWindow(2); | |
1420 ASSERT_TRUE(window_1_1); | |
1421 ASSERT_TRUE(window_1_2); | |
1422 | |
1423 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1424 { | |
1425 std::vector<TestWindow> windows; | |
1426 GetWindowTree(wt1(), root_window_id(), &windows); | |
1427 ASSERT_EQ(2u, windows.size()); | |
1428 EXPECT_EQ( | |
1429 WindowParentToString(root_window_id(), kNullParentId) + " visible=true", | |
1430 windows[0].ToString2()); | |
1431 EXPECT_EQ( | |
1432 WindowParentToString(window_1_1, root_window_id()) + " visible=false", | |
1433 windows[1].ToString2()); | |
1434 } | |
1435 | |
1436 // Show all the windows. | |
1437 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
1438 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true)); | |
1439 { | |
1440 std::vector<TestWindow> windows; | |
1441 GetWindowTree(wt1(), root_window_id(), &windows); | |
1442 ASSERT_EQ(2u, windows.size()); | |
1443 EXPECT_EQ( | |
1444 WindowParentToString(root_window_id(), kNullParentId) + " visible=true", | |
1445 windows[0].ToString2()); | |
1446 EXPECT_EQ( | |
1447 WindowParentToString(window_1_1, root_window_id()) + " visible=true", | |
1448 windows[1].ToString2()); | |
1449 } | |
1450 | |
1451 // Hide 1. | |
1452 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false)); | |
1453 { | |
1454 std::vector<TestWindow> windows; | |
1455 GetWindowTree(wt1(), window_1_1, &windows); | |
1456 ASSERT_EQ(1u, windows.size()); | |
1457 EXPECT_EQ( | |
1458 WindowParentToString(window_1_1, root_window_id()) + " visible=false", | |
1459 windows[0].ToString2()); | |
1460 } | |
1461 | |
1462 // Attach 2 to 1. | |
1463 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2)); | |
1464 { | |
1465 std::vector<TestWindow> windows; | |
1466 GetWindowTree(wt1(), window_1_1, &windows); | |
1467 ASSERT_EQ(2u, windows.size()); | |
1468 EXPECT_EQ( | |
1469 WindowParentToString(window_1_1, root_window_id()) + " visible=false", | |
1470 windows[0].ToString2()); | |
1471 EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) + " visible=true", | |
1472 windows[1].ToString2()); | |
1473 } | |
1474 | |
1475 // Show 1. | |
1476 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
1477 { | |
1478 std::vector<TestWindow> windows; | |
1479 GetWindowTree(wt1(), window_1_1, &windows); | |
1480 ASSERT_EQ(2u, windows.size()); | |
1481 EXPECT_EQ( | |
1482 WindowParentToString(window_1_1, root_window_id()) + " visible=true", | |
1483 windows[0].ToString2()); | |
1484 EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) + " visible=true", | |
1485 windows[1].ToString2()); | |
1486 } | |
1487 } | |
1488 | |
1489 // Test that we hear the cursor change in other clients. | |
1490 TEST_F(WindowTreeClientTest, SetCursor) { | |
1491 // Get a second client to listen in. | |
1492 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1493 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1494 changes2()->clear(); | |
1495 | |
1496 ASSERT_TRUE( | |
1497 wt_client1()->SetPredefinedCursor(window_1_1, mojom::Cursor::IBEAM)); | |
1498 wt_client2_->WaitForChangeCount(1u); | |
1499 | |
1500 EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_id=4", | |
1501 SingleChangeToDescription(*changes2())); | |
1502 } | |
1503 | |
1504 // Assertions for SetWindowVisibility sending notifications. | |
1505 TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications) { | |
1506 // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root. | |
1507 Id window_1_1 = wt_client1()->NewWindow(1); | |
1508 ASSERT_TRUE(window_1_1); | |
1509 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
1510 // Setting to the same value should return true. | |
1511 EXPECT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
1512 | |
1513 Id window_1_2 = wt_client1()->NewWindow(2); | |
1514 ASSERT_TRUE(window_1_2); | |
1515 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true)); | |
1516 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1517 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2)); | |
1518 | |
1519 // Establish the second client at 1,2. | |
1520 ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2)); | |
1521 | |
1522 // Add 2,3 as a child of 1,2. | |
1523 Id window_2_1 = wt_client2()->NewWindow(1); | |
1524 ASSERT_TRUE(window_2_1); | |
1525 ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, true)); | |
1526 ASSERT_TRUE(wt_client2()->AddWindow(window_1_2, window_2_1)); | |
1527 ASSERT_TRUE(wt_client1()->WaitForAllMessages()); | |
1528 | |
1529 changes2()->clear(); | |
1530 // Hide 1,2 from client 1. Client 2 should see this. | |
1531 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, false)); | |
1532 { | |
1533 wt_client2_->WaitForChangeCount(1); | |
1534 EXPECT_EQ( | |
1535 "VisibilityChanged window=" + IdToString(window_1_2) + " visible=false", | |
1536 SingleChangeToDescription(*changes2())); | |
1537 } | |
1538 | |
1539 changes1()->clear(); | |
1540 // Show 1,2 from client 2, client 1 should be notified. | |
1541 ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_1_2, true)); | |
1542 { | |
1543 wt_client1_->WaitForChangeCount(1); | |
1544 EXPECT_EQ( | |
1545 "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true", | |
1546 SingleChangeToDescription(*changes1())); | |
1547 } | |
1548 | |
1549 changes2()->clear(); | |
1550 // Hide 1,1, client 2 should be told the draw state changed. | |
1551 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false)); | |
1552 { | |
1553 wt_client2_->WaitForChangeCount(1); | |
1554 EXPECT_EQ( | |
1555 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=false", | |
1556 SingleChangeToDescription(*changes2())); | |
1557 } | |
1558 | |
1559 changes2()->clear(); | |
1560 // Show 1,1 from client 1. Client 2 should see this. | |
1561 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
1562 { | |
1563 wt_client2_->WaitForChangeCount(1); | |
1564 EXPECT_EQ( | |
1565 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true", | |
1566 SingleChangeToDescription(*changes2())); | |
1567 } | |
1568 | |
1569 // Change visibility of 2,3, client 1 should see this. | |
1570 changes1()->clear(); | |
1571 ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, false)); | |
1572 { | |
1573 wt_client1_->WaitForChangeCount(1); | |
1574 EXPECT_EQ( | |
1575 "VisibilityChanged window=" + IdToString(window_2_1) + " visible=false", | |
1576 SingleChangeToDescription(*changes1())); | |
1577 } | |
1578 | |
1579 changes2()->clear(); | |
1580 // Remove 1,1 from the root, client 2 should see drawn state changed. | |
1581 ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1)); | |
1582 { | |
1583 wt_client2_->WaitForChangeCount(1); | |
1584 EXPECT_EQ( | |
1585 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=false", | |
1586 SingleChangeToDescription(*changes2())); | |
1587 } | |
1588 | |
1589 changes2()->clear(); | |
1590 // Add 1,1 back to the root, client 2 should see drawn state changed. | |
1591 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1592 { | |
1593 wt_client2_->WaitForChangeCount(1); | |
1594 EXPECT_EQ( | |
1595 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true", | |
1596 SingleChangeToDescription(*changes2())); | |
1597 } | |
1598 } | |
1599 | |
1600 // Assertions for SetWindowVisibility sending notifications. | |
1601 TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications2) { | |
1602 // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root. | |
1603 Id window_1_1 = wt_client1()->NewWindow(1); | |
1604 ASSERT_TRUE(window_1_1); | |
1605 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
1606 Id window_1_2 = wt_client1()->NewWindow(2); | |
1607 ASSERT_TRUE(window_1_2); | |
1608 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1609 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2)); | |
1610 | |
1611 // Establish the second client at 1,2. | |
1612 ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2)); | |
1613 EXPECT_EQ("OnEmbed drawn=true", SingleChangeToDescription2(*changes2())); | |
1614 changes2()->clear(); | |
1615 | |
1616 // Show 1,2 from client 1. Client 2 should see this. | |
1617 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true)); | |
1618 { | |
1619 wt_client2_->WaitForChangeCount(1); | |
1620 EXPECT_EQ( | |
1621 "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true", | |
1622 SingleChangeToDescription(*changes2())); | |
1623 } | |
1624 } | |
1625 | |
1626 // Assertions for SetWindowVisibility sending notifications. | |
1627 TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications3) { | |
1628 // Create 1,1 and 1,2. 1,2 is made a child of 1,1 and 1,1 a child of the root. | |
1629 Id window_1_1 = wt_client1()->NewWindow(1); | |
1630 ASSERT_TRUE(window_1_1); | |
1631 Id window_1_2 = wt_client1()->NewWindow(2); | |
1632 ASSERT_TRUE(window_1_2); | |
1633 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1634 ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2)); | |
1635 | |
1636 // Establish the second client at 1,2. | |
1637 ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2)); | |
1638 EXPECT_EQ("OnEmbed drawn=false", SingleChangeToDescription2(*changes2())); | |
1639 changes2()->clear(); | |
1640 | |
1641 // Show 1,1, drawn should be true for 1,2 (as that is all the child sees). | |
1642 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true)); | |
1643 { | |
1644 wt_client2_->WaitForChangeCount(1); | |
1645 EXPECT_EQ( | |
1646 "DrawnStateChanged window=" + IdToString(window_1_2) + " drawn=true", | |
1647 SingleChangeToDescription(*changes2())); | |
1648 } | |
1649 changes2()->clear(); | |
1650 | |
1651 // Show 1,2, visible should be true. | |
1652 ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true)); | |
1653 { | |
1654 wt_client2_->WaitForChangeCount(1); | |
1655 EXPECT_EQ( | |
1656 "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true", | |
1657 SingleChangeToDescription(*changes2())); | |
1658 } | |
1659 } | |
1660 | |
1661 // Tests that when opacity is set on a window, that the calling client is not | |
1662 // notified, however children are. Also that setting the same opacity is | |
1663 // rejected and no on eis notifiyed. | |
1664 TEST_F(WindowTreeClientTest, SetOpacityNotifications) { | |
1665 Id window_1_1 = wt_client1()->NewWindow(1); | |
1666 ASSERT_TRUE(window_1_1); | |
1667 | |
1668 ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_1)); | |
1669 Id window_2_1 = wt_client2()->NewWindow(1); | |
1670 ASSERT_TRUE(window_2_1); | |
1671 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1672 ASSERT_TRUE(wt_client1()->WaitForAllMessages()); | |
1673 | |
1674 changes1()->clear(); | |
1675 changes2()->clear(); | |
1676 // Change opacity, no notification for calling client. | |
1677 ASSERT_TRUE(wt_client1()->SetWindowOpacity(window_1_1, 0.5f)); | |
1678 EXPECT_TRUE(changes1()->empty()); | |
1679 wt_client2()->WaitForChangeCount(1); | |
1680 EXPECT_EQ( | |
1681 "OpacityChanged window_id=" + IdToString(window_1_1) + " opacity=0.50", | |
1682 SingleChangeToDescription(*changes2())); | |
1683 | |
1684 changes2()->clear(); | |
1685 // Attempting to set the same opacity should succeed, but no notification as | |
1686 // there was no actual change. | |
1687 ASSERT_TRUE(wt_client1()->SetWindowOpacity(window_1_1, 0.5f)); | |
1688 EXPECT_TRUE(changes1()->empty()); | |
1689 wt_client2()->WaitForAllMessages(); | |
1690 EXPECT_TRUE(changes2()->empty()); | |
1691 } | |
1692 | |
1693 TEST_F(WindowTreeClientTest, SetWindowProperty) { | |
1694 Id window_1_1 = wt_client1()->NewWindow(1); | |
1695 ASSERT_TRUE(window_1_1); | |
1696 | |
1697 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false)); | |
1698 changes2()->clear(); | |
1699 | |
1700 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1701 { | |
1702 std::vector<TestWindow> windows; | |
1703 GetWindowTree(wt1(), root_window_id(), &windows); | |
1704 ASSERT_EQ(2u, windows.size()); | |
1705 EXPECT_EQ(root_window_id(), windows[0].window_id); | |
1706 EXPECT_EQ(window_1_1, windows[1].window_id); | |
1707 ASSERT_EQ(0u, windows[1].properties.size()); | |
1708 } | |
1709 | |
1710 // Set properties on 1. | |
1711 changes2()->clear(); | |
1712 std::vector<uint8_t> one(1, '1'); | |
1713 ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", &one)); | |
1714 { | |
1715 wt_client2_->WaitForChangeCount(1); | |
1716 EXPECT_EQ( | |
1717 "PropertyChanged window=" + IdToString(window_1_1) + " key=one value=1", | |
1718 SingleChangeToDescription(*changes2())); | |
1719 } | |
1720 | |
1721 // Test that our properties exist in the window tree | |
1722 { | |
1723 std::vector<TestWindow> windows; | |
1724 GetWindowTree(wt1(), window_1_1, &windows); | |
1725 ASSERT_EQ(1u, windows.size()); | |
1726 ASSERT_EQ(1u, windows[0].properties.size()); | |
1727 EXPECT_EQ(one, windows[0].properties["one"]); | |
1728 } | |
1729 | |
1730 changes2()->clear(); | |
1731 // Set back to null. | |
1732 ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", NULL)); | |
1733 { | |
1734 wt_client2_->WaitForChangeCount(1); | |
1735 EXPECT_EQ("PropertyChanged window=" + IdToString(window_1_1) + | |
1736 " key=one value=NULL", | |
1737 SingleChangeToDescription(*changes2())); | |
1738 } | |
1739 } | |
1740 | |
1741 TEST_F(WindowTreeClientTest, OnEmbeddedAppDisconnected) { | |
1742 // Create client 2 and 3. | |
1743 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1744 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1745 Id window_2_1 = wt_client2()->NewWindow(1); | |
1746 ASSERT_TRUE(window_2_1); | |
1747 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1748 changes2()->clear(); | |
1749 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1)); | |
1750 | |
1751 // Client 1 should get a hierarchy change for window_2_1. | |
1752 wt_client1_->WaitForChangeCount(1); | |
1753 changes1()->clear(); | |
1754 | |
1755 // Close client 3. Client 2 (which had previously embedded 3) should | |
1756 // be notified of this. | |
1757 wt_client3_.reset(); | |
1758 wt_client2_->WaitForChangeCount(1); | |
1759 EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_2_1), | |
1760 SingleChangeToDescription(*changes2())); | |
1761 | |
1762 // The closing is only interesting to the root that did the embedding. Other | |
1763 // clients should not be notified of this. | |
1764 wt_client1_->WaitForAllMessages(); | |
1765 EXPECT_TRUE(changes1()->empty()); | |
1766 } | |
1767 | |
1768 // Verifies when the parent of an Embed() is destroyed the embedded app gets | |
1769 // a WindowDeleted (and doesn't trigger a DCHECK). | |
1770 TEST_F(WindowTreeClientTest, OnParentOfEmbedDisconnects) { | |
1771 // Create client 2 and 3. | |
1772 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1773 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1774 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1775 Id window_2_1 = wt_client2()->NewWindow(1); | |
1776 Id window_2_2 = wt_client2()->NewWindow(2); | |
1777 ASSERT_TRUE(window_2_1); | |
1778 ASSERT_TRUE(window_2_2); | |
1779 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1780 ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2)); | |
1781 changes2()->clear(); | |
1782 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_2)); | |
1783 changes3()->clear(); | |
1784 | |
1785 // Close client 2. Client 3 should get a delete (for its root). | |
1786 wt_client2_.reset(); | |
1787 wt_client3_->WaitForChangeCount(1); | |
1788 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_2), | |
1789 SingleChangeToDescription(*changes3())); | |
1790 } | |
1791 | |
1792 // Verifies WindowTreeImpl doesn't incorrectly erase from its internal | |
1793 // map when a window from another client with the same window_id is removed. | |
1794 TEST_F(WindowTreeClientTest, DontCleanMapOnDestroy) { | |
1795 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1796 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1797 ASSERT_TRUE(wt_client2()->NewWindow(1)); | |
1798 changes1()->clear(); | |
1799 wt_client2_.reset(); | |
1800 wt_client1_->WaitForChangeCount(1); | |
1801 EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_1_1), | |
1802 SingleChangeToDescription(*changes1())); | |
1803 std::vector<TestWindow> windows; | |
1804 GetWindowTree(wt1(), window_1_1, &windows); | |
1805 EXPECT_FALSE(windows.empty()); | |
1806 } | |
1807 | |
1808 // Verifies Embed() works when supplying a WindowTreeClient. | |
1809 TEST_F(WindowTreeClientTest, EmbedSupplyingWindowTreeClient) { | |
1810 ASSERT_TRUE(wt_client1()->NewWindow(1)); | |
1811 | |
1812 TestWindowTreeClient client2; | |
1813 mojom::WindowTreeClientPtr client2_ptr; | |
1814 mojo::Binding<WindowTreeClient> client2_binding(&client2, &client2_ptr); | |
1815 ASSERT_TRUE(Embed(wt1(), BuildWindowId(client_id_1(), 1), | |
1816 std::move(client2_ptr))); | |
1817 client2.WaitForOnEmbed(); | |
1818 EXPECT_EQ("OnEmbed", | |
1819 SingleChangeToDescription(*client2.tracker()->changes())); | |
1820 } | |
1821 | |
1822 TEST_F(WindowTreeClientTest, EmbedFailsFromOtherClient) { | |
1823 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1824 | |
1825 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1826 Id window_2_1 = wt_client2()->NewWindow(1); | |
1827 ASSERT_TRUE(window_2_1); | |
1828 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1829 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1)); | |
1830 | |
1831 Id window_3_3 = wt_client3()->NewWindow(3); | |
1832 ASSERT_TRUE(window_3_3); | |
1833 ASSERT_TRUE(wt_client3()->AddWindow(window_2_1, window_3_3)); | |
1834 | |
1835 // 2 should not be able to embed in window_3_3 as window_3_3 was not created | |
1836 // by | |
1837 // 2. | |
1838 EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(), window_3_3)); | |
1839 } | |
1840 | |
1841 // Verifies Embed() from window manager on another clients window works. | |
1842 TEST_F(WindowTreeClientTest, EmbedFromOtherClient) { | |
1843 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1844 | |
1845 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1846 Id window_2_1 = wt_client2()->NewWindow(1); | |
1847 ASSERT_TRUE(window_2_1); | |
1848 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1849 | |
1850 changes2()->clear(); | |
1851 | |
1852 // Establish a third client in window_2_1. | |
1853 ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_2_1)); | |
1854 | |
1855 ASSERT_TRUE(wt_client2()->WaitForAllMessages()); | |
1856 EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2())); | |
1857 } | |
1858 | |
1859 TEST_F(WindowTreeClientTest, CantEmbedFromClientRoot) { | |
1860 // Shouldn't be able to embed into the root. | |
1861 ASSERT_FALSE(EmbedUrl(connector(), wt1(), test_name(), root_window_id())); | |
1862 | |
1863 // Even though the call above failed a WindowTreeClient was obtained. We need | |
1864 // to | |
1865 // wait for it else we throw off the next connect. | |
1866 WaitForWindowTreeClient(); | |
1867 | |
1868 // Don't allow a client to embed into its own root. | |
1869 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1870 EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(), | |
1871 BuildWindowId(client_id_1(), 1))); | |
1872 | |
1873 // Need to wait for a WindowTreeClient for same reason as above. | |
1874 WaitForWindowTreeClient(); | |
1875 | |
1876 Id window_1_2 = wt_client1()->NewWindow(2); | |
1877 ASSERT_TRUE(window_1_2); | |
1878 ASSERT_TRUE( | |
1879 wt_client1()->AddWindow(BuildWindowId(client_id_1(), 1), window_1_2)); | |
1880 ASSERT_TRUE(wt_client3_.get() == nullptr); | |
1881 wt_client3_ = | |
1882 EstablishClientViaEmbedWithPolicyBitmask(wt1(), window_1_2, nullptr); | |
1883 ASSERT_TRUE(wt_client3_.get() != nullptr); | |
1884 | |
1885 // window_1_2 is ws3's root, so even though v3 is an embed root it should not | |
1886 // be able to Embed into itself. | |
1887 ASSERT_FALSE(EmbedUrl(connector(), wt3(), test_name(), window_1_2)); | |
1888 } | |
1889 | |
1890 // Verifies that a transient window tracks its parent's lifetime. | |
1891 TEST_F(WindowTreeClientTest, TransientWindowTracksTransientParentLifetime) { | |
1892 ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true)); | |
1893 Id window_1_1 = BuildWindowId(client_id_1(), 1); | |
1894 | |
1895 Id window_2_1 = wt_client2()->NewWindow(1); | |
1896 Id window_2_2 = wt_client2()->NewWindow(2); | |
1897 Id window_2_3 = wt_client2()->NewWindow(3); | |
1898 ASSERT_TRUE(window_2_1); | |
1899 | |
1900 // root -> window_1_1 -> window_2_1 | |
1901 // root -> window_1_1 -> window_2_2 | |
1902 // root -> window_1_1 -> window_2_3 | |
1903 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1904 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1)); | |
1905 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2)); | |
1906 ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_3)); | |
1907 | |
1908 // window_2_2 and window_2_3 now track the lifetime of window_2_1. | |
1909 changes1()->clear(); | |
1910 wt2()->AddTransientWindow(10, window_2_1, window_2_2); | |
1911 wt2()->AddTransientWindow(11, window_2_1, window_2_3); | |
1912 wt_client1()->WaitForChangeCount(2); | |
1913 EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) + | |
1914 " child = " + IdToString(window_2_2), | |
1915 ChangesToDescription1(*changes1())[0]); | |
1916 EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) + | |
1917 " child = " + IdToString(window_2_3), | |
1918 ChangesToDescription1(*changes1())[1]); | |
1919 | |
1920 changes1()->clear(); | |
1921 wt2()->RemoveTransientWindowFromParent(12, window_2_3); | |
1922 wt_client1()->WaitForChangeCount(1); | |
1923 EXPECT_EQ("RemoveTransientWindowFromParent parent = " + | |
1924 IdToString(window_2_1) + " child = " + IdToString(window_2_3), | |
1925 SingleChangeToDescription(*changes1())); | |
1926 | |
1927 changes1()->clear(); | |
1928 ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1)); | |
1929 wt_client1()->WaitForChangeCount(2); | |
1930 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_2), | |
1931 ChangesToDescription1(*changes1())[0]); | |
1932 EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1), | |
1933 ChangesToDescription1(*changes1())[1]); | |
1934 } | |
1935 | |
1936 TEST_F(WindowTreeClientTest, Ids) { | |
1937 const Id window_1_100 = wt_client1()->NewWindow(100); | |
1938 ASSERT_TRUE(window_1_100); | |
1939 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_100)); | |
1940 | |
1941 // Establish the second client at 1,100. | |
1942 ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_100)); | |
1943 | |
1944 // 1,100 is the id in the wt_client1's id space. The new client should see | |
1945 // 2,1 (the server id). | |
1946 const Id window_1_100_in_ws2 = BuildWindowId(client_id_1(), 1); | |
1947 EXPECT_EQ(window_1_100_in_ws2, wt_client2()->root_window_id()); | |
1948 | |
1949 // The first window created in the second client gets a server id of 2,1 | |
1950 // regardless of the id the client uses. | |
1951 const Id window_2_101 = wt_client2()->NewWindow(101); | |
1952 ASSERT_TRUE(wt_client2()->AddWindow(window_1_100_in_ws2, window_2_101)); | |
1953 const Id window_2_101_in_ws1 = BuildWindowId(client_id_2(), 1); | |
1954 wt_client1()->WaitForChangeCount(1); | |
1955 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101_in_ws1) + | |
1956 " old_parent=null new_parent=" + IdToString(window_1_100), | |
1957 SingleChangeToDescription(*changes1())); | |
1958 changes1()->clear(); | |
1959 | |
1960 // Change the bounds of window_2_101 and make sure server gets it. | |
1961 wt2()->SetWindowBounds(11, window_2_101, gfx::Rect(1, 2, 3, 4)); | |
1962 ASSERT_TRUE(wt_client2()->WaitForChangeCompleted(11)); | |
1963 wt_client1()->WaitForChangeCount(1); | |
1964 EXPECT_EQ("BoundsChanged window=" + IdToString(window_2_101_in_ws1) + | |
1965 " old_bounds=0,0 0x0 new_bounds=1,2 3x4", | |
1966 SingleChangeToDescription(*changes1())); | |
1967 changes2()->clear(); | |
1968 | |
1969 // Remove 2_101 from wm, client1 should see the change. | |
1970 wt1()->RemoveWindowFromParent(12, window_2_101_in_ws1); | |
1971 ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(12)); | |
1972 wt_client2()->WaitForChangeCount(1); | |
1973 EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101) + | |
1974 " old_parent=" + IdToString(window_1_100_in_ws2) + | |
1975 " new_parent=null", | |
1976 SingleChangeToDescription(*changes2())); | |
1977 } | |
1978 | |
1979 // Tests that setting capture fails when no input event has occurred, and there | |
1980 // is no notification of lost capture. | |
1981 TEST_F(WindowTreeClientTest, ExplicitCaptureWithoutInput) { | |
1982 Id window_1_1 = wt_client1()->NewWindow(1); | |
1983 | |
1984 // Add the window to the root, so that they have a Display to handle input | |
1985 // capture. | |
1986 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
1987 changes1()->clear(); | |
1988 | |
1989 // Since there has been no input, capture should not succeed. No lost capture | |
1990 // message is expected. | |
1991 wt1()->SetCapture(1, window_1_1); | |
1992 wt_client1_->WaitForAllMessages(); | |
1993 EXPECT_TRUE(changes1()->empty()); | |
1994 | |
1995 // Since there is no window with capture, lost capture should not be notified. | |
1996 wt1()->ReleaseCapture(3, window_1_1); | |
1997 wt_client1_->WaitForAllMessages(); | |
1998 EXPECT_TRUE(changes1()->empty()); | |
1999 } | |
2000 | |
2001 // TODO(jonross): Enable this once apptests can send input events to the server. | |
2002 // Enabling capture requires that the client be processing events. | |
2003 TEST_F(WindowTreeClientTest, DISABLED_ExplicitCapturePropagation) { | |
2004 Id window_1_1 = wt_client1()->NewWindow(1); | |
2005 Id window_1_2 = wt_client1()->NewWindow(2); | |
2006 | |
2007 // Add the windows to the root, so that they have a Display to handle input | |
2008 // capture. | |
2009 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1)); | |
2010 ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2)); | |
2011 | |
2012 changes1()->clear(); | |
2013 // Window 1 takes capture then Window 2 takes capture. | |
2014 // Verify that window 1 has lost capture. | |
2015 wt1()->SetCapture(1, window_1_1); | |
2016 wt1()->SetCapture(2, window_1_2); | |
2017 wt_client1_->WaitForChangeCount(1); | |
2018 | |
2019 EXPECT_EQ("OnLostCapture window=" + IdToString(window_1_1), | |
2020 SingleChangeToDescription(*changes1())); | |
2021 | |
2022 changes1()->clear(); | |
2023 // Explicitly releasing capture should not notify of lost capture. | |
2024 wt1()->ReleaseCapture(3, window_1_2); | |
2025 wt_client1_->WaitForAllMessages(); | |
2026 | |
2027 EXPECT_TRUE(changes1()->empty()); | |
2028 } | |
2029 | |
2030 // TODO(sky): need to better track changes to initial client. For example, | |
2031 // that SetBounsdWindows/AddWindow and the like don't result in messages to the | |
2032 // originating client. | |
2033 | |
2034 // TODO(sky): make sure coverage of what was | |
2035 // WindowManagerTest.SecondEmbedRoot_InitService and | |
2036 // WindowManagerTest.MultipleEmbedRootsBeforeWTHReady gets added to window | |
2037 // manager | |
2038 // tests. | |
2039 | |
2040 } // namespace test | |
2041 } // namespace ws | |
2042 } // namespace mus | |
OLD | NEW |