OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/services/public/cpp/view_manager/view_manager.h" | 5 #include "mojo/services/public/cpp/view_manager/view_manager.h" |
6 | 6 |
7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "mojo/public/cpp/application/application_connection.h" | 10 #include "mojo/public/cpp/application/application_connection.h" |
(...skipping 23 matching lines...) Expand all Loading... |
34 base::RunLoop run_loop; | 34 base::RunLoop run_loop; |
35 current_run_loop = &run_loop; | 35 current_run_loop = &run_loop; |
36 current_run_loop->Run(); | 36 current_run_loop->Run(); |
37 current_run_loop = NULL; | 37 current_run_loop = NULL; |
38 } | 38 } |
39 | 39 |
40 void QuitRunLoop() { | 40 void QuitRunLoop() { |
41 current_run_loop->Quit(); | 41 current_run_loop->Quit(); |
42 } | 42 } |
43 | 43 |
44 void WaitForChangeToBeAcked(ViewManagerClientImpl* client) { | |
45 client->set_change_acked_callback(base::Bind(&QuitRunLoop)); | |
46 DoRunLoop(); | |
47 client->ClearChangeAckedCallback(); | |
48 } | |
49 | |
50 class ConnectServiceLoader : public ServiceLoader, | 44 class ConnectServiceLoader : public ServiceLoader, |
51 public ApplicationDelegate, | 45 public ApplicationDelegate, |
52 public ViewManagerDelegate { | 46 public ViewManagerDelegate { |
53 public: | 47 public: |
54 typedef base::Callback<void(ViewManager*, Node*)> LoadedCallback; | 48 typedef base::Callback<void(ViewManager*, Node*)> LoadedCallback; |
55 | 49 |
56 explicit ConnectServiceLoader(const LoadedCallback& callback) | 50 explicit ConnectServiceLoader(const LoadedCallback& callback) |
57 : callback_(callback), view_manager_client_factory_(this) {} | 51 : callback_(callback), view_manager_client_factory_(this) {} |
58 virtual ~ConnectServiceLoader() {} | 52 virtual ~ConnectServiceLoader() {} |
59 | 53 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 count += CountNodes(*it); | 167 count += CountNodes(*it); |
174 return count; | 168 return count; |
175 } | 169 } |
176 | 170 |
177 Node* tree_; | 171 Node* tree_; |
178 size_t tree_size_; | 172 size_t tree_size_; |
179 | 173 |
180 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); | 174 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); |
181 }; | 175 }; |
182 | 176 |
183 void WaitForTreeSizeToMatch(Node* node, size_t tree_size) { | |
184 TreeSizeMatchesObserver observer(node, tree_size); | |
185 if (observer.IsTreeCorrectSize()) | |
186 return; | |
187 node->AddObserver(&observer); | |
188 DoRunLoop(); | |
189 node->RemoveObserver(&observer); | |
190 } | |
191 | |
192 | |
193 // Utility class that waits for the destruction of some number of nodes and | 177 // Utility class that waits for the destruction of some number of nodes and |
194 // views. | 178 // views. |
195 class DestructionObserver : public NodeObserver, public ViewObserver { | 179 class DestructionObserver : public NodeObserver, public ViewObserver { |
196 public: | 180 public: |
197 // |nodes| or |views| can be NULL. | 181 // |nodes| or |views| can be NULL. |
198 DestructionObserver(std::set<Id>* nodes, std::set<Id>* views) | 182 DestructionObserver(std::set<Id>* nodes, std::set<Id>* views) |
199 : nodes_(nodes), | 183 : nodes_(nodes), |
200 views_(views) {} | 184 views_(views) {} |
201 | 185 |
202 private: | 186 private: |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 Node* node = Node::Create(window_manager()); | 401 Node* node = Node::Create(window_manager()); |
418 window_manager()->GetRoots().front()->AddChild(node); | 402 window_manager()->GetRoots().front()->AddChild(node); |
419 ViewManager* embedded = Embed(window_manager(), node); | 403 ViewManager* embedded = Embed(window_manager(), node); |
420 EXPECT_TRUE(NULL != embedded); | 404 EXPECT_TRUE(NULL != embedded); |
421 | 405 |
422 Node* node_in_embedded = embedded->GetRoots().front(); | 406 Node* node_in_embedded = embedded->GetRoots().front(); |
423 EXPECT_EQ(node->parent(), window_manager()->GetRoots().front()); | 407 EXPECT_EQ(node->parent(), window_manager()->GetRoots().front()); |
424 EXPECT_EQ(NULL, node_in_embedded->parent()); | 408 EXPECT_EQ(NULL, node_in_embedded->parent()); |
425 } | 409 } |
426 | 410 |
427 // When Window Manager embeds A @ N, then creates N2 and parents to N, N becomes | 411 // Window manager has two nodes, N1 and N11. Embeds A at N1. A should not see |
428 // visible to A. | 412 // N11. |
429 // TODO(beng): verify whether or not this is a policy we like. | 413 // TODO(sky): Update client lib to match server. |
430 TEST_F(ViewManagerTest, HierarchyChanged_NodeAdded) { | 414 TEST_F(ViewManagerTest, DISABLED_EmbeddedDoesntSeeChild) { |
431 Node* node = Node::Create(window_manager()); | |
432 window_manager()->GetRoots().front()->AddChild(node); | |
433 ViewManager* embedded = Embed(window_manager(), node); | |
434 Node* nested = Node::Create(window_manager()); | |
435 node->AddChild(nested); | |
436 WaitForTreeSizeToMatch(embedded->GetRoots().front(), 2); | |
437 EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(), | |
438 nested->id()); | |
439 } | |
440 | |
441 // Window manager has two nodes, N1 & N2. Embeds A at N1. Creates node N21, | |
442 // a child of N2. Reparents N2 to N1. N1 should become visible to A. | |
443 // TODO(beng): verify whether or not this is a policy we like. | |
444 TEST_F(ViewManagerTest, HierarchyChanged_NodeMoved) { | |
445 Node* node1 = Node::Create(window_manager()); | |
446 window_manager()->GetRoots().front()->AddChild(node1); | |
447 ViewManager* embedded = Embed(window_manager(), node1); | |
448 WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1); | |
449 | |
450 Node* node2 = Node::Create(window_manager()); | |
451 window_manager()->GetRoots().front()->AddChild(node2); | |
452 WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1); | |
453 EXPECT_TRUE(embedded->GetRoots().front()->children().empty()); | |
454 | |
455 Node* node21 = Node::Create(window_manager()); | |
456 node2->AddChild(node21); | |
457 WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1); | |
458 EXPECT_TRUE(embedded->GetRoots().front()->children().empty()); | |
459 | |
460 // Makes node21 visible to |embedded|. | |
461 node1->AddChild(node21); | |
462 WaitForTreeSizeToMatch(embedded->GetRoots().front(), 2); | |
463 EXPECT_FALSE(embedded->GetRoots().front()->children().empty()); | |
464 EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(), | |
465 node21->id()); | |
466 } | |
467 | |
468 // Window manager has two nodes, N1 and N11. Embeds A at N1. Removes N11 from | |
469 // N1. N11 should disappear from A. | |
470 // TODO(beng): verify whether or not this is a policy we like. | |
471 TEST_F(ViewManagerTest, HierarchyChanged_NodeRemoved) { | |
472 Node* node = Node::Create(window_manager()); | 415 Node* node = Node::Create(window_manager()); |
473 window_manager()->GetRoots().front()->AddChild(node); | 416 window_manager()->GetRoots().front()->AddChild(node); |
474 Node* nested = Node::Create(window_manager()); | 417 Node* nested = Node::Create(window_manager()); |
475 node->AddChild(nested); | 418 node->AddChild(nested); |
476 | 419 |
477 ViewManager* embedded = Embed(window_manager(), node); | 420 ViewManager* embedded = Embed(window_manager(), node); |
478 EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(), | 421 EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(), |
479 nested->id()); | 422 nested->id()); |
480 | |
481 node->RemoveChild(nested); | |
482 WaitForTreeSizeToMatch(embedded->GetRoots().front(), 1); | |
483 EXPECT_TRUE(embedded->GetRoots().front()->children().empty()); | 423 EXPECT_TRUE(embedded->GetRoots().front()->children().empty()); |
484 } | 424 EXPECT_TRUE(nested->parent() == NULL); |
485 | |
486 // Window manager has two nodes, N1 and N11. Embeds A at N1. Destroys N11. | |
487 // N11 should disappear from A. | |
488 // TODO(beng): verify whether or not this is a policy we like. | |
489 TEST_F(ViewManagerTest, NodeDestroyed) { | |
490 Node* node = Node::Create(window_manager()); | |
491 window_manager()->GetRoots().front()->AddChild(node); | |
492 Node* nested = Node::Create(window_manager()); | |
493 node->AddChild(nested); | |
494 | |
495 ViewManager* embedded = Embed(window_manager(), node); | |
496 EXPECT_EQ(embedded->GetRoots().front()->children().front()->id(), | |
497 nested->id()); | |
498 | |
499 // |nested| will be deleted after calling Destroy() below. | |
500 Id id = nested->id(); | |
501 nested->Destroy(); | |
502 | |
503 std::set<Id> nodes; | |
504 nodes.insert(id); | |
505 WaitForDestruction(embedded, &nodes, NULL); | |
506 | |
507 EXPECT_TRUE(embedded->GetRoots().front()->children().empty()); | |
508 EXPECT_EQ(NULL, embedded->GetNodeById(id)); | |
509 } | 425 } |
510 | 426 |
511 // http://crbug.com/396300 | 427 // http://crbug.com/396300 |
512 TEST_F(ViewManagerTest, DISABLED_ViewManagerDestroyed_CleanupNode) { | 428 TEST_F(ViewManagerTest, DISABLED_ViewManagerDestroyed_CleanupNode) { |
513 Node* node = Node::Create(window_manager()); | 429 Node* node = Node::Create(window_manager()); |
514 window_manager()->GetRoots().front()->AddChild(node); | 430 window_manager()->GetRoots().front()->AddChild(node); |
515 ViewManager* embedded = Embed(window_manager(), node); | 431 ViewManager* embedded = Embed(window_manager(), node); |
516 | 432 |
517 Id node_id = node->id(); | 433 Id node_id = node->id(); |
518 | 434 |
(...skipping 13 matching lines...) Expand all Loading... |
532 | 448 |
533 View* view = View::Create(window_manager()); | 449 View* view = View::Create(window_manager()); |
534 node->SetActiveView(view); | 450 node->SetActiveView(view); |
535 | 451 |
536 Node* node_in_embedded = embedded->GetNodeById(node->id()); | 452 Node* node_in_embedded = embedded->GetNodeById(node->id()); |
537 WaitForActiveViewToChange(node_in_embedded); | 453 WaitForActiveViewToChange(node_in_embedded); |
538 | 454 |
539 EXPECT_EQ(node_in_embedded->active_view()->id(), view->id()); | 455 EXPECT_EQ(node_in_embedded->active_view()->id(), view->id()); |
540 } | 456 } |
541 | 457 |
542 TEST_F(ViewManagerTest, DestroyView) { | 458 // TODO(sky): rethink this and who should be notified when views are |
| 459 // detached/destroyed. |
| 460 TEST_F(ViewManagerTest, DISABLED_DestroyView) { |
543 Node* node = Node::Create(window_manager()); | 461 Node* node = Node::Create(window_manager()); |
544 window_manager()->GetRoots().front()->AddChild(node); | 462 window_manager()->GetRoots().front()->AddChild(node); |
545 ViewManager* embedded = Embed(window_manager(), node); | 463 ViewManager* embedded = Embed(window_manager(), node); |
546 | 464 |
547 View* view = View::Create(window_manager()); | 465 View* view = View::Create(window_manager()); |
548 node->SetActiveView(view); | 466 node->SetActiveView(view); |
549 | 467 |
550 Node* node_in_embedded = embedded->GetNodeById(node->id()); | 468 Node* node_in_embedded = embedded->GetNodeById(node->id()); |
551 WaitForActiveViewToChange(node_in_embedded); | 469 WaitForActiveViewToChange(node_in_embedded); |
552 | 470 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 // Contains(). | 548 // Contains(). |
631 TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { | 549 TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { |
632 Node* node = Node::Create(window_manager()); | 550 Node* node = Node::Create(window_manager()); |
633 window_manager()->GetRoots().front()->AddChild(node); | 551 window_manager()->GetRoots().front()->AddChild(node); |
634 ViewManager* embedded = Embed(window_manager(), node); | 552 ViewManager* embedded = Embed(window_manager(), node); |
635 | 553 |
636 View* view_in_embedded = View::Create(embedded); | 554 View* view_in_embedded = View::Create(embedded); |
637 EXPECT_DEATH_IF_SUPPORTED(node->SetActiveView(view_in_embedded), ""); | 555 EXPECT_DEATH_IF_SUPPORTED(node->SetActiveView(view_in_embedded), ""); |
638 } | 556 } |
639 | 557 |
640 // This test verifies that a node hierarchy constructed in one connection | |
641 // becomes entirely visible to the second connection when the hierarchy is | |
642 // attached. | |
643 TEST_F(ViewManagerTest, MapSubtreeOnAttach) { | |
644 Node* node = Node::Create(window_manager()); | |
645 window_manager()->GetRoots().front()->AddChild(node); | |
646 ViewManager* embedded = Embed(window_manager(), node); | |
647 | |
648 // Create a subtree private to the window manager and make some changes to it. | |
649 Node* child1 = Node::Create(window_manager()); | |
650 Node* child11 = Node::Create(window_manager()); | |
651 child1->AddChild(child11); | |
652 WaitForChangeToBeAcked( | |
653 static_cast<ViewManagerClientImpl*>(window_manager())); | |
654 gfx::Rect child11_bounds(800, 600); | |
655 child11->SetBounds(child11_bounds); | |
656 WaitForChangeToBeAcked( | |
657 static_cast<ViewManagerClientImpl*>(window_manager())); | |
658 View* view11 = View::Create(window_manager()); | |
659 child11->SetActiveView(view11); | |
660 WaitForChangeToBeAcked( | |
661 static_cast<ViewManagerClientImpl*>(window_manager())); | |
662 | |
663 // When added to the shared node, the entire hierarchy and all property | |
664 // changes should become visible to the embedded app. | |
665 node->AddChild(child1); | |
666 WaitForTreeSizeToMatch(embedded->GetRoots().front(), 3); | |
667 | |
668 Node* child11_in_embedded = embedded->GetNodeById(child11->id()); | |
669 View* view11_in_embedded = embedded->GetViewById(view11->id()); | |
670 EXPECT_TRUE(child11_in_embedded != NULL); | |
671 EXPECT_EQ(view11_in_embedded, child11_in_embedded->active_view()); | |
672 EXPECT_EQ(child11_bounds, child11_in_embedded->bounds()); | |
673 } | |
674 | |
675 // Verifies that bounds changes applied to a node hierarchy in one connection | 558 // Verifies that bounds changes applied to a node hierarchy in one connection |
676 // are reflected to another. | 559 // are reflected to another. |
677 TEST_F(ViewManagerTest, SetBounds) { | 560 TEST_F(ViewManagerTest, SetBounds) { |
678 Node* node = Node::Create(window_manager()); | 561 Node* node = Node::Create(window_manager()); |
679 window_manager()->GetRoots().front()->AddChild(node); | 562 window_manager()->GetRoots().front()->AddChild(node); |
680 ViewManager* embedded = Embed(window_manager(), node); | 563 ViewManager* embedded = Embed(window_manager(), node); |
681 | 564 |
682 Node* node_in_embedded = embedded->GetNodeById(node->id()); | 565 Node* node_in_embedded = embedded->GetNodeById(node->id()); |
683 EXPECT_EQ(node->bounds(), node_in_embedded->bounds()); | 566 EXPECT_EQ(node->bounds(), node_in_embedded->bounds()); |
684 | 567 |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 | 658 |
776 // TODO(beng): tests for view event dispatcher. | 659 // TODO(beng): tests for view event dispatcher. |
777 // - verify that we see events for all views. | 660 // - verify that we see events for all views. |
778 | 661 |
779 // TODO(beng): tests for focus: | 662 // TODO(beng): tests for focus: |
780 // - focus between two nodes known to a connection | 663 // - focus between two nodes known to a connection |
781 // - focus between nodes unknown to one of the connections. | 664 // - focus between nodes unknown to one of the connections. |
782 // - focus between nodes unknown to either connection. | 665 // - focus between nodes unknown to either connection. |
783 | 666 |
784 } // namespace mojo | 667 } // namespace mojo |
OLD | NEW |