diff options
Diffstat (limited to 'mojo/services')
-rw-r--r-- | mojo/services/public/interfaces/view_manager/view_manager.mojom | 30 | ||||
-rw-r--r-- | mojo/services/view_manager/root_view_manager.cc | 49 | ||||
-rw-r--r-- | mojo/services/view_manager/root_view_manager.h | 57 | ||||
-rw-r--r-- | mojo/services/view_manager/view.cc | 30 | ||||
-rw-r--r-- | mojo/services/view_manager/view.h | 20 | ||||
-rw-r--r-- | mojo/services/view_manager/view_delegate.h | 35 | ||||
-rw-r--r-- | mojo/services/view_manager/view_manager_connection.cc | 39 | ||||
-rw-r--r-- | mojo/services/view_manager/view_manager_connection.h | 33 | ||||
-rw-r--r-- | mojo/services/view_manager/view_manager_connection_unittest.cc | 309 | ||||
-rw-r--r-- | mojo/services/view_manager/view_manager_export.h | 26 |
10 files changed, 599 insertions, 29 deletions
diff --git a/mojo/services/public/interfaces/view_manager/view_manager.mojom b/mojo/services/public/interfaces/view_manager/view_manager.mojom index 45a7e69..456b221 100644 --- a/mojo/services/public/interfaces/view_manager/view_manager.mojom +++ b/mojo/services/public/interfaces/view_manager/view_manager.mojom @@ -6,25 +6,33 @@ module mojo.services.view_manager { // Each View is identified by the following pair. The |manager_id| is assigned // by the server and uniquely identifies the ViewManager. A value of 0 can be -// used to indicate 'this' manager. The |view_id| is assigned by the client. -// Non-negative values may be used. Server uses negative to identify special -// values. For example, -1 is the root. +// used to indicate 'this' manager. For received notifications a value of 0 for +// |manager_id| indicates the view is owned by the ViewManager. The |view_id| +// is assigned by the client. Non-negative values may be used. Server uses +// negative to identify special values. For example, -1 is the root. struct ViewId { int32 manager_id; int32 view_id; }; + +// Functions that mutate the hierarchy take a |change_id|. |change_id| is an +// arbitrary value assigned by the client originating the change. It may be +// used by the client originating the change to later identify the change in +// an OnViewHierarchyChanged callback. |change_id| is only passed to the client +// that originated the change. All other clients get a value of 0. [Peer=ViewManagerClient] interface ViewManager { // Creates a new view with the specified id. It is up to the client to ensure // the id is unique to the connection (the id need not be globally unique). CreateView(int32 view_id) => (bool success); - // Reparents a view. - AddView(ViewId parent, ViewId child) => (bool success); + // Reparents a view. See description above class for details of |change_id|. + AddView(ViewId parent, ViewId child, int32 change_id) => (bool success); - // Removes a view from its current parent. - RemoveFromParent(ViewId view) => (bool success); + // Removes a view from its current parent. See description above class for + // details of |change_id|. + RemoveViewFromParent(ViewId view, int32 change_id) => (bool success); }; [Peer=ViewManager] @@ -32,6 +40,14 @@ interface ViewManagerClient { // Invoked once the connection has been established. |manager_id| is the id // used to uniquely identify the ViewManager. OnConnectionEstablished(int32 manager_id); + + // Invoked when a change is done to the hierarchy. |new_parent| and/or + // |old_parent| may be NULL. See description above ViewManager for details on + // |change_id|. + OnViewHierarchyChanged(ViewId view, + ViewId new_parent, + ViewId old_parent, + int32 change_id); }; } diff --git a/mojo/services/view_manager/root_view_manager.cc b/mojo/services/view_manager/root_view_manager.cc index d791cb3..e691314 100644 --- a/mojo/services/view_manager/root_view_manager.cc +++ b/mojo/services/view_manager/root_view_manager.cc @@ -17,9 +17,20 @@ const int32_t kRootId = -1; } // namespace +RootViewManager::ScopedChange::ScopedChange(ViewManagerConnection* connection, + RootViewManager* root, + int32_t change_id) + : root_(root) { + root_->PrepareForChange(connection, change_id); +} + +RootViewManager::ScopedChange::~ScopedChange() { + root_->FinishChange(); +} + RootViewManager::RootViewManager() : next_connection_id_(1), - root_(kRootId) { + root_(this, kRootId) { } RootViewManager::~RootViewManager() { @@ -45,6 +56,29 @@ View* RootViewManager::GetView(int32_t manager_id, int32_t view_id) { return i == connection_map_.end() ? NULL : i->second->GetView(view_id); } +void RootViewManager::NotifyViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent) { + for (ConnectionMap::iterator i = connection_map_.begin(); + i != connection_map_.end(); ++i) { + const int32_t change_id = (change_ && i->first == change_->connection_id) ? + change_->change_id : 0; + i->second->NotifyViewHierarchyChanged( + view, new_parent, old_parent, change_id); + } +} + +void RootViewManager::PrepareForChange(ViewManagerConnection* connection, + int32_t change_id) { + DCHECK(!change_.get()); // Should only ever have one change in flight. + change_.reset(new Change(connection->id(), change_id)); +} + +void RootViewManager::FinishChange() { + DCHECK(change_.get()); // PrepareForChange/FinishChange should be balanced. + change_.reset(); +} + void RootViewManager::OnCreated() { } @@ -59,6 +93,19 @@ void RootViewManager::OnEvent(const Event& event, callback.Run(); } +ViewId RootViewManager::GetViewId(const View* view) const { + ViewId::Builder builder; + builder.set_manager_id(0); + builder.set_view_id(view->id()); + return builder.Finish(); +} + +void RootViewManager::OnViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent) { + NotifyViewHierarchyChanged(view, new_parent, old_parent); +} + } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/view_manager/root_view_manager.h b/mojo/services/view_manager/root_view_manager.h index 65376ce..dfb7541 100644 --- a/mojo/services/view_manager/root_view_manager.h +++ b/mojo/services/view_manager/root_view_manager.h @@ -10,6 +10,8 @@ #include "base/basictypes.h" #include "mojo/services/native_viewport/native_viewport.mojom.h" #include "mojo/services/view_manager/view.h" +#include "mojo/services/view_manager/view_delegate.h" +#include "mojo/services/view_manager/view_manager_export.h" namespace mojo { namespace services { @@ -21,8 +23,25 @@ class ViewManagerConnection; // RootViewManager is responsible for managing the set of ViewManagerConnections // as well as providing the root of the View hierarchy. -class RootViewManager : public NativeViewportClient { +class MOJO_VIEW_MANAGER_EXPORT RootViewManager + : public NativeViewportClient, + public ViewDelegate { public: + // Create when a ViewManagerConnection is about to make a change. Ensures + // clients are notified of the correct change id. + class ScopedChange { + public: + ScopedChange(ViewManagerConnection* connection, + RootViewManager* root, + int32_t change_id); + ~ScopedChange(); + + private: + RootViewManager* root_; + + DISALLOW_COPY_AND_ASSIGN(ScopedChange); + }; + RootViewManager(); virtual ~RootViewManager(); @@ -36,9 +55,36 @@ class RootViewManager : public NativeViewportClient { // one. View* GetView(int32_t manager_id, int32_t view_id); + // Notifies all ViewManagerConnections of a hierarchy change. + void NotifyViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent); + private: + // Tracks a change. + struct Change { + Change(int32_t connection_id, int32_t change_id) + : connection_id(connection_id), + change_id(change_id) { + } + + int32_t connection_id; + int32_t change_id; + }; + typedef std::map<int32_t, ViewManagerConnection*> ConnectionMap; + // Invoked when a particular connection is about to make a change. Records + // the |change_id| so that it can be supplied to the clients by way of + // OnViewHierarchyChanged(). + // Changes should never nest, meaning each PrepareForChange() must be + // balanced with a call to FinishChange() with no PrepareForChange() + // in between. + void PrepareForChange(ViewManagerConnection* connection, int32_t change_id); + + // Balances a call to PrepareForChange(). + void FinishChange(); + // Overridden from NativeViewportClient: virtual void OnCreated() OVERRIDE; virtual void OnDestroyed() OVERRIDE; @@ -46,6 +92,12 @@ class RootViewManager : public NativeViewportClient { virtual void OnEvent(const Event& event, const mojo::Callback<void()>& callback) OVERRIDE; + // Overriden from ViewDelegate: + virtual ViewId GetViewId(const View* view) const OVERRIDE; + virtual void OnViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent) OVERRIDE; + // ID to use for next ViewManagerConnection. int32_t next_connection_id_; @@ -55,6 +107,9 @@ class RootViewManager : public NativeViewportClient { // Root of Views that are displayed. View root_; + // If non-null we're processing a change. + scoped_ptr<Change> change_; + DISALLOW_COPY_AND_ASSIGN(RootViewManager); }; diff --git a/mojo/services/view_manager/view.cc b/mojo/services/view_manager/view.cc index 6215854..903e628 100644 --- a/mojo/services/view_manager/view.cc +++ b/mojo/services/view_manager/view.cc @@ -4,6 +4,8 @@ #include "mojo/services/view_manager/view.h" +#include "mojo/public/cpp/bindings/allocation_scope.h" +#include "mojo/services/view_manager/view_delegate.h" #include "ui/aura/window_property.h" DECLARE_WINDOW_PROPERTY_TYPE(mojo::services::view_manager::View*); @@ -14,9 +16,14 @@ namespace view_manager { DEFINE_WINDOW_PROPERTY_KEY(View*, kViewKey, NULL); -// TODO(sky): figure out window delegate. -View::View(int32_t id) : id_(id), window_(NULL) { +View::View(ViewDelegate* delegate, const int32_t id) + : delegate_(delegate), + id_(id), + window_(NULL) { + DCHECK(delegate); // Must provide a delegate. window_.set_owned_by_parent(false); + window_.AddObserver(this); + window_.SetProperty(kViewKey, this); } View::~View() { @@ -36,6 +43,25 @@ void View::Remove(View* child) { window_.RemoveChild(&child->window_); } +ViewId View::GetViewId() const { + return delegate_->GetViewId(this); +} + +void View::OnWindowHierarchyChanged( + const aura::WindowObserver::HierarchyChangeParams& params) { + if (params.target != &window_ || params.receiver != &window_) + return; + AllocationScope scope; + ViewId new_parent_id; + if (params.new_parent) + new_parent_id = params.new_parent->GetProperty(kViewKey)->GetViewId(); + ViewId old_parent_id; + if (params.old_parent) + old_parent_id = params.old_parent->GetProperty(kViewKey)->GetViewId(); + delegate_->OnViewHierarchyChanged(delegate_->GetViewId(this), new_parent_id, + old_parent_id); +} + } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/view_manager/view.h b/mojo/services/view_manager/view.h index 1815f7f..8b954ab 100644 --- a/mojo/services/view_manager/view.h +++ b/mojo/services/view_manager/view.h @@ -6,16 +6,23 @@ #define MOJO_SERVICES_VIEW_MANAGER_VIEW_H_ #include "base/logging.h" +#include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h" +#include "mojo/services/view_manager/view_manager_export.h" #include "ui/aura/window.h" +#include "ui/aura/window_observer.h" namespace mojo { namespace services { namespace view_manager { -class View { +class RootViewManager; +class ViewDelegate; +class ViewId; + +class MOJO_VIEW_MANAGER_EXPORT View : public aura::WindowObserver { public: - View(int32_t view_id); - ~View(); + View(ViewDelegate* delegate, const int32_t id); + virtual ~View(); int32 id() const { return id_; } @@ -25,6 +32,13 @@ class View { View* GetParent(); private: + ViewId GetViewId() const; + + // WindowObserver overrides: + virtual void OnWindowHierarchyChanged( + const aura::WindowObserver::HierarchyChangeParams& params) OVERRIDE; + + ViewDelegate* delegate_; const int32_t id_; aura::Window window_; diff --git a/mojo/services/view_manager/view_delegate.h b/mojo/services/view_manager/view_delegate.h new file mode 100644 index 0000000..efd6fa8 --- /dev/null +++ b/mojo/services/view_manager/view_delegate.h @@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_SERVICES_VIEW_MANAGER_VIEW_DELEGATE_H_ +#define MOJO_SERVICES_VIEW_MANAGER_VIEW_DELEGATE_H_ + +#include "mojo/services/view_manager/view_manager_export.h" + +namespace mojo { +namespace services { +namespace view_manager { + +class View; +class ViewId; + +class MOJO_VIEW_MANAGER_EXPORT ViewDelegate { + public: + // Returns the ViewId for the view. + virtual ViewId GetViewId(const View* view) const = 0; + + // Invoked when the hierarchy has changed. + virtual void OnViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent) = 0; + + protected: + virtual ~ViewDelegate() {} +}; + +} // namespace view_manager +} // namespace services +} // namespace mojo + +#endif // MOJO_SERVICES_VIEW_MANAGER_VIEW_DELEGATE_H_ diff --git a/mojo/services/view_manager/view_manager_connection.cc b/mojo/services/view_manager/view_manager_connection.cc index 5b85d98..12179b8 100644 --- a/mojo/services/view_manager/view_manager_connection.cc +++ b/mojo/services/view_manager/view_manager_connection.cc @@ -26,8 +26,8 @@ void ViewManagerConnection::Initialize( DCHECK_EQ(0, id_); // Should only get Initialize() once. ServiceConnection<ViewManager, ViewManagerConnection, RootViewManager>:: Initialize(service_factory, client_handle.Pass()); - context()->AddConnection(this); id_ = context()->GetAndAdvanceNextConnectionId(); + context()->AddConnection(this); client()->OnConnectionEstablished(id_); } @@ -44,42 +44,67 @@ View* ViewManagerConnection::GetViewById(const ViewId& view_id) { void ViewManagerConnection::CreateView( int32_t view_id, - const mojo::Callback<void(bool)>& callback) { + const Callback<void(bool)>& callback) { // Negative values are reserved. if (view_map_.find(view_id) != view_map_.end() || view_id < 0) { callback.Run(false); return; } - view_map_[view_id] = new View(view_id); + view_map_[view_id] = new View(this, view_id); callback.Run(true); } void ViewManagerConnection::AddView( const ViewId& parent_id, const ViewId& child_id, - const mojo::Callback<void(bool)>& callback) { + int32_t change_id, + const Callback<void(bool)>& callback) { View* parent_view = GetViewById(parent_id); View* child_view = GetViewById(child_id); bool success = false; if (parent_view && child_view && parent_view != child_view) { + RootViewManager::ScopedChange change(this, context(), change_id); parent_view->Add(child_view); success = true; } callback.Run(success); } -void ViewManagerConnection::RemoveFromParent( +void ViewManagerConnection::RemoveViewFromParent( const ViewId& view_id, - const mojo::Callback<void(bool)>& callback) { + int32_t change_id, + const Callback<void(bool)>& callback) { View* view = GetViewById(view_id); bool success = false; if (view && view->GetParent()) { - view->GetParent()->Add(view); + RootViewManager::ScopedChange change(this, context(), change_id); + view->GetParent()->Remove(view); success = true; } callback.Run(success); } +void ViewManagerConnection::NotifyViewHierarchyChanged( + const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent, + int32_t change_id) { + client()->OnViewHierarchyChanged(view, new_parent, old_parent, change_id); +} + +ViewId ViewManagerConnection::GetViewId(const View* view) const { + ViewId::Builder builder; + builder.set_manager_id(id_); + builder.set_view_id(view->id()); + return builder.Finish(); +} + +void ViewManagerConnection::OnViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent) { + context()->NotifyViewHierarchyChanged(view, new_parent, old_parent); +} + } // namespace view_manager } // namespace services } // namespace mojo diff --git a/mojo/services/view_manager/view_manager_connection.h b/mojo/services/view_manager/view_manager_connection.h index 2b0d4c1..2f75cc3 100644 --- a/mojo/services/view_manager/view_manager_connection.h +++ b/mojo/services/view_manager/view_manager_connection.h @@ -10,6 +10,8 @@ #include "base/basictypes.h" #include "mojo/public/cpp/shell/service.h" #include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h" +#include "mojo/services/view_manager/view_delegate.h" +#include "mojo/services/view_manager/view_manager_export.h" namespace mojo { namespace services { @@ -19,9 +21,10 @@ class RootViewManager; class View; // Manages a connection from the client. -class ViewManagerConnection : public ServiceConnection<ViewManager, - ViewManagerConnection, - RootViewManager> { +class MOJO_VIEW_MANAGER_EXPORT ViewManagerConnection + : public ServiceConnection<ViewManager, ViewManagerConnection, + RootViewManager>, + public ViewDelegate { public: ViewManagerConnection(); virtual ~ViewManagerConnection(); @@ -36,6 +39,12 @@ class ViewManagerConnection : public ServiceConnection<ViewManager, // Returns the View by id. View* GetView(int32_t id); + // Notifies the client of a hierarchy change. + void NotifyViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent, + int32_t change_id); + private: typedef std::map<int32_t, View*> ViewMap; @@ -44,13 +53,21 @@ class ViewManagerConnection : public ServiceConnection<ViewManager, // Overridden from ViewManager: virtual void CreateView(int32_t view_id, - const mojo::Callback<void(bool)>& callback) OVERRIDE; + const Callback<void(bool)>& callback) OVERRIDE; virtual void AddView(const ViewId& parent_id, const ViewId& child_id, - const mojo::Callback<void(bool)>& callback) OVERRIDE; - virtual void RemoveFromParent( - const ViewId& view_id, - const mojo::Callback<void(bool)>& callback) OVERRIDE; + int32_t change_id, + const Callback<void(bool)>& callback) OVERRIDE; + virtual void RemoveViewFromParent( + const ViewId& view, + int32_t change_id, + const Callback<void(bool)>& callback) OVERRIDE; + + // Overriden from ViewDelegate: + virtual ViewId GetViewId(const View* view) const OVERRIDE; + virtual void OnViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent) OVERRIDE; // Id of this connection as assigned by RootViewManager. Assigned in // Initialize(). diff --git a/mojo/services/view_manager/view_manager_connection_unittest.cc b/mojo/services/view_manager/view_manager_connection_unittest.cc new file mode 100644 index 0000000..611c125 --- /dev/null +++ b/mojo/services/view_manager/view_manager_connection_unittest.cc @@ -0,0 +1,309 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/services/view_manager/view_manager_connection.h" + +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "mojo/public/cpp/bindings/allocation_scope.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/services/view_manager/root_view_manager.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace services { +namespace view_manager { + +namespace { + +base::RunLoop* current_run_loop = NULL; + +// Sets |current_run_loop| and runs it. It is expected that someone else quits +// the loop. +void DoRunLoop() { + base::RunLoop run_loop; + current_run_loop = &run_loop; + current_run_loop->Run(); + current_run_loop = NULL; +} + +// Converts |id| into a string. +std::string ViewIdToString(const ViewId& id) { + return id.is_null() ? "null" : + base::StringPrintf("%d,%d", id.manager_id(), id.view_id()); +} + +// Boolean callback. Sets |result_cache| to the value of |result| and quits +// the run loop. +void BooleanCallback(bool* result_cache, bool result) { + *result_cache = result; + current_run_loop->Quit(); +} + +// Creates a ViewId from the specified parameters. +ViewId CreateViewId(int32_t manager_id, int32_t view_id) { + ViewId::Builder builder; + builder.set_manager_id(manager_id); + builder.set_view_id(view_id); + return builder.Finish(); +} + +// Creates a view with the specified id. Returns true on success. Blocks until +// we get back result from server. +bool CreateView(ViewManager* view_manager, int32_t id) { + bool result = false; + view_manager->CreateView(id, base::Bind(&BooleanCallback, &result)); + DoRunLoop(); + return result; +} + +// Adds a view, blocking until done. +bool AddView(ViewManager* view_manager, + const ViewId& parent, + const ViewId& child, + int32_t change_id) { + bool result = false; + view_manager->AddView(parent, child, change_id, + base::Bind(&BooleanCallback, &result)); + DoRunLoop(); + return result; +} + +// Removes a view, blocking until done. +bool RemoveViewFromParent(ViewManager* view_manager, + const ViewId& view, + int32_t change_id) { + bool result = false; + view_manager->RemoveViewFromParent(view, change_id, + base::Bind(&BooleanCallback, &result)); + DoRunLoop(); + return result; +} + +} // namespace + +typedef std::vector<std::string> Changes; + +class ViewManagerClientImpl : public ViewManagerClient { + public: + ViewManagerClientImpl() : id_(0), quit_count_(0) {} + + void set_quit_count(int count) { quit_count_ = count; } + + int32_t id() const { return id_; } + + Changes GetAndClearChanges() { + Changes changes; + changes.swap(changes_); + return changes; + } + + private: + // View overrides: + virtual void OnConnectionEstablished(int32_t manager_id) OVERRIDE { + id_ = manager_id; + current_run_loop->Quit(); + } + virtual void OnViewHierarchyChanged(const ViewId& view, + const ViewId& new_parent, + const ViewId& old_parent, + int32_t change_id) OVERRIDE { + changes_.push_back( + base::StringPrintf( + "change_id=%d view=%s new_parent=%s old_parent=%s", + change_id, ViewIdToString(view).c_str(), + ViewIdToString(new_parent).c_str(), + ViewIdToString(old_parent).c_str())); + if (quit_count_ > 0) { + if (--quit_count_ == 0) + current_run_loop->Quit(); + } + } + + int32_t id_; + + // Used to determine when/if to quit the run loop. + int quit_count_; + + Changes changes_; + + DISALLOW_COPY_AND_ASSIGN(ViewManagerClientImpl); +}; + +class ViewManagerConnectionTest : public testing::Test { + public: + ViewManagerConnectionTest() : service_factory_(&root_view_manager_) {} + + virtual void SetUp() OVERRIDE { + InterfacePipe<ViewManagerClient, ViewManager> pipe; + view_manager_.reset(pipe.handle_to_peer.Pass(), &client_); + connection_.Initialize( + &service_factory_, + ScopedMessagePipeHandle::From(pipe.handle_to_self.Pass())); + // Wait for the id. + DoRunLoop(); + } + + protected: + // Creates a second connection to the viewmanager. + void EstablishSecondConnection() { + connection2_.reset(new ViewManagerConnection); + InterfacePipe<ViewManagerClient, ViewManager> pipe; + view_manager2_.reset(pipe.handle_to_peer.Pass(), &client2_); + connection2_->Initialize( + &service_factory_, + ScopedMessagePipeHandle::From(pipe.handle_to_self.Pass())); + // Wait for the id. + DoRunLoop(); + } + + Environment env_; + base::MessageLoop loop_; + RootViewManager root_view_manager_; + ServiceConnector<ViewManagerConnection, RootViewManager> service_factory_; + ViewManagerConnection connection_; + ViewManagerClientImpl client_; + RemotePtr<ViewManager> view_manager_; + + ViewManagerClientImpl client2_; + RemotePtr<ViewManager> view_manager2_; + scoped_ptr<ViewManagerConnection> connection2_; + + DISALLOW_COPY_AND_ASSIGN(ViewManagerConnectionTest); +}; + +// Verifies client gets a valid id. +TEST_F(ViewManagerConnectionTest, ValidId) { + EXPECT_NE(0, client_.id()); +} + +// Verifies two clients/connections get different ids. +TEST_F(ViewManagerConnectionTest, TwoClientsGetDifferentConnectionIds) { + EstablishSecondConnection(); + EXPECT_NE(0, client2_.id()); + EXPECT_NE(client_.id(), client2_.id()); +} + +// Verifies client gets a valid id. +TEST_F(ViewManagerConnectionTest, CreateView) { + ASSERT_TRUE(CreateView(view_manager_.get(), 1)); + + // Can't create a view with the same id. + ASSERT_FALSE(CreateView(view_manager_.get(), 1)); +} + +// Verifies hierarchy changes. +TEST_F(ViewManagerConnectionTest, AddRemoveNotify) { + ASSERT_TRUE(CreateView(view_manager_.get(), 1)); + ASSERT_TRUE(CreateView(view_manager_.get(), 2)); + + EXPECT_TRUE(client_.GetAndClearChanges().empty()); + + // Make 2 a child of 1. + { + AllocationScope scope; + ASSERT_TRUE(AddView(view_manager_.get(), + CreateViewId(client_.id(), 1), + CreateViewId(client_.id(), 2), + 11)); + Changes changes(client_.GetAndClearChanges()); + ASSERT_EQ(1u, changes.size()); + EXPECT_EQ("change_id=11 view=1,2 new_parent=1,1 old_parent=null", + changes[0]); + } + + // Remove 2 from its parent. + { + AllocationScope scope; + ASSERT_TRUE(RemoveViewFromParent(view_manager_.get(), + CreateViewId(client_.id(), 2), + 101)); + Changes changes(client_.GetAndClearChanges()); + ASSERT_EQ(1u, changes.size()); + EXPECT_EQ("change_id=101 view=1,2 new_parent=null old_parent=1,1", + changes[0]); + } +} + +// Verifies hierarchy changes are sent to multiple clients. +TEST_F(ViewManagerConnectionTest, AddRemoveNotifyMultipleConnections) { + EstablishSecondConnection(); + + // Create two views in first connection. + ASSERT_TRUE(CreateView(view_manager_.get(), 1)); + ASSERT_TRUE(CreateView(view_manager_.get(), 2)); + + EXPECT_TRUE(client_.GetAndClearChanges().empty()); + EXPECT_TRUE(client2_.GetAndClearChanges().empty()); + + // Make 2 a child of 1. + { + AllocationScope scope; + ASSERT_TRUE(AddView(view_manager_.get(), + CreateViewId(client_.id(), 1), + CreateViewId(client_.id(), 2), + 11)); + Changes changes(client_.GetAndClearChanges()); + ASSERT_EQ(1u, changes.size()); + EXPECT_EQ("change_id=11 view=1,2 new_parent=1,1 old_parent=null", + changes[0]); + } + + // Second client should also have received the change. + { + Changes changes(client2_.GetAndClearChanges()); + if (changes.empty()) { + client2_.set_quit_count(1); + DoRunLoop(); + changes = client2_.GetAndClearChanges(); + } + ASSERT_EQ(1u, changes.size()); + EXPECT_EQ("change_id=0 view=1,2 new_parent=1,1 old_parent=null", + changes[0]); + } +} + +// Verifies adding to root sends right notifications. +TEST_F(ViewManagerConnectionTest, AddToRoot) { + ASSERT_TRUE(CreateView(view_manager_.get(), 21)); + ASSERT_TRUE(CreateView(view_manager_.get(), 3)); + + EXPECT_TRUE(client_.GetAndClearChanges().empty()); + + // Make 3 a child of 21. + { + AllocationScope scope; + ASSERT_TRUE(AddView(view_manager_.get(), + CreateViewId(client_.id(), 21), + CreateViewId(client_.id(), 3), + 11)); + Changes changes(client_.GetAndClearChanges()); + ASSERT_EQ(1u, changes.size()); + EXPECT_EQ("change_id=11 view=1,3 new_parent=1,21 old_parent=null", + changes[0]); + } + + // Make 21 a child of the root. + { + AllocationScope scope; + ASSERT_TRUE(AddView(view_manager_.get(), + CreateViewId(0, -1), + CreateViewId(client_.id(), 21), + 44)); + Changes changes(client_.GetAndClearChanges()); + ASSERT_EQ(1u, changes.size()); + EXPECT_EQ("change_id=44 view=1,21 new_parent=0,-1 old_parent=null", + changes[0]); + } +} + +} // namespace view_manager +} // namespace services +} // namespace mojo diff --git a/mojo/services/view_manager/view_manager_export.h b/mojo/services/view_manager/view_manager_export.h new file mode 100644 index 0000000..f48f94e --- /dev/null +++ b/mojo/services/view_manager/view_manager_export.h @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_SERVICES_VIEW_MANAGER_VIEW_MANAGER_EXPORT_H_ +#define MOJO_SERVICES_VIEW_MANAGER_VIEW_MANAGER_EXPORT_H_ + +#if defined(WIN32) + +#if defined(MOJO_VIEW_MANAGER_IMPLEMENTATION) +#define MOJO_VIEW_MANAGER_EXPORT __declspec(dllexport) +#else +#define MOJO_VIEW_MANAGER_EXPORT __declspec(dllimport) +#endif + +#else // !defined(WIN32) + +#if defined(MOJO_VIEW_MANAGER_IMPLEMENTATION) +#define MOJO_VIEW_MANAGER_EXPORT __attribute__((visibility("default"))) +#else +#define MOJO_VIEW_MANAGER_EXPORT +#endif + +#endif // defined(WIN32) + +#endif // MOJO_SERVICES_VIEW_MANAGER_VIEW_MANAGER_EXPORT_H_ |