| 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 |