Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(467)

Side by Side Diff: components/mus/ws/window_tree_client_unittest.cc

Issue 2119963002: Move mus to //services/ui (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/mus/ws/window_tree_binding.cc ('k') | components/mus/ws/window_tree_factory.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « components/mus/ws/window_tree_binding.cc ('k') | components/mus/ws/window_tree_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698