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

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

Powered by Google App Engine
This is Rietveld 408576698