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 "mojo/services/view_manager/connection_manager.h"
6
7 #include "base/logging.h"
8 #include "mojo/public/cpp/application/application_connection.h"
9 #include "mojo/public/interfaces/application/service_provider.mojom.h"
10 #include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
11 #include "mojo/services/view_manager/view_manager_service_impl.h"
12
13 namespace mojo {
14 namespace service {
15
ScopedChange(ViewManagerServiceImpl * connection,ConnectionManager * connection_manager,bool is_delete_view)16 ConnectionManager::ScopedChange::ScopedChange(
17 ViewManagerServiceImpl* connection,
18 ConnectionManager* connection_manager,
19 bool is_delete_view)
20 : connection_manager_(connection_manager),
21 connection_id_(connection->id()),
22 is_delete_view_(is_delete_view) {
23 connection_manager_->PrepareForChange(this);
24 }
25
~ScopedChange()26 ConnectionManager::ScopedChange::~ScopedChange() {
27 connection_manager_->FinishChange();
28 }
29
ConnectionManager(ApplicationConnection * app_connection,const Callback<void ()> & native_viewport_closed_callback)30 ConnectionManager::ConnectionManager(
31 ApplicationConnection* app_connection,
32 const Callback<void()>& native_viewport_closed_callback)
33 : app_connection_(app_connection),
34 next_connection_id_(1),
35 display_manager_(app_connection,
36 this,
37 native_viewport_closed_callback),
38 root_(new ServerView(this, RootViewId())),
39 current_change_(NULL) {
40 root_->SetBounds(gfx::Rect(800, 600));
41 }
42
~ConnectionManager()43 ConnectionManager::~ConnectionManager() {
44 while (!connections_created_by_connect_.empty())
45 delete *(connections_created_by_connect_.begin());
46 // All the connections should have been destroyed.
47 DCHECK(connection_map_.empty());
48 root_.reset();
49 }
50
GetAndAdvanceNextConnectionId()51 ConnectionSpecificId ConnectionManager::GetAndAdvanceNextConnectionId() {
52 const ConnectionSpecificId id = next_connection_id_++;
53 DCHECK_LT(id, next_connection_id_);
54 return id;
55 }
56
AddConnection(ViewManagerServiceImpl * connection)57 void ConnectionManager::AddConnection(ViewManagerServiceImpl* connection) {
58 DCHECK_EQ(0u, connection_map_.count(connection->id()));
59 connection_map_[connection->id()] = connection;
60 }
61
RemoveConnection(ViewManagerServiceImpl * connection)62 void ConnectionManager::RemoveConnection(ViewManagerServiceImpl* connection) {
63 connection_map_.erase(connection->id());
64 connections_created_by_connect_.erase(connection);
65
66 // Notify remaining connections so that they can cleanup.
67 for (ConnectionMap::const_iterator i = connection_map_.begin();
68 i != connection_map_.end();
69 ++i) {
70 i->second->OnViewManagerServiceImplDestroyed(connection->id());
71 }
72 }
73
EmbedRoot(const std::string & url,InterfaceRequest<ServiceProvider> service_provider)74 void ConnectionManager::EmbedRoot(
75 const std::string& url,
76 InterfaceRequest<ServiceProvider> service_provider) {
77 if (connection_map_.empty()) {
78 EmbedImpl(kInvalidConnectionId,
79 String::From(url),
80 RootViewId(),
81 service_provider.Pass());
82 return;
83 }
84 ViewManagerServiceImpl* connection = GetConnection(kWindowManagerConnection);
85 connection->client()->Embed(url, service_provider.Pass());
86 }
87
Embed(ConnectionSpecificId creator_id,const String & url,Id transport_view_id,InterfaceRequest<ServiceProvider> service_provider)88 void ConnectionManager::Embed(
89 ConnectionSpecificId creator_id,
90 const String& url,
91 Id transport_view_id,
92 InterfaceRequest<ServiceProvider> service_provider) {
93 EmbedImpl(creator_id,
94 url,
95 ViewIdFromTransportId(transport_view_id),
96 service_provider.Pass())->set_delete_on_connection_error();
97 }
98
GetConnection(ConnectionSpecificId connection_id)99 ViewManagerServiceImpl* ConnectionManager::GetConnection(
100 ConnectionSpecificId connection_id) {
101 ConnectionMap::iterator i = connection_map_.find(connection_id);
102 return i == connection_map_.end() ? NULL : i->second;
103 }
104
GetView(const ViewId & id)105 ServerView* ConnectionManager::GetView(const ViewId& id) {
106 if (id == root_->id())
107 return root_.get();
108 ConnectionMap::iterator i = connection_map_.find(id.connection_id);
109 return i == connection_map_.end() ? NULL : i->second->GetView(id);
110 }
111
OnConnectionMessagedClient(ConnectionSpecificId id)112 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) {
113 if (current_change_)
114 current_change_->MarkConnectionAsMessaged(id);
115 }
116
DidConnectionMessageClient(ConnectionSpecificId id) const117 bool ConnectionManager::DidConnectionMessageClient(
118 ConnectionSpecificId id) const {
119 return current_change_ && current_change_->DidMessageConnection(id);
120 }
121
GetConnectionWithRoot(const ViewId & id) const122 const ViewManagerServiceImpl* ConnectionManager::GetConnectionWithRoot(
123 const ViewId& id) const {
124 for (ConnectionMap::const_iterator i = connection_map_.begin();
125 i != connection_map_.end();
126 ++i) {
127 if (i->second->HasRoot(id))
128 return i->second;
129 }
130 return NULL;
131 }
132
DispatchViewInputEventToWindowManager(EventPtr event)133 void ConnectionManager::DispatchViewInputEventToWindowManager(EventPtr event) {
134 // Input events are forwarded to the WindowManager. The WindowManager
135 // eventually calls back to us with DispatchOnViewInputEvent().
136 ViewManagerServiceImpl* connection = GetConnection(kWindowManagerConnection);
137 if (!connection)
138 return;
139 connection->client()->DispatchOnViewInputEvent(event.Pass());
140 }
141
ProcessViewBoundsChanged(const ServerView * view,const gfx::Rect & old_bounds,const gfx::Rect & new_bounds)142 void ConnectionManager::ProcessViewBoundsChanged(const ServerView* view,
143 const gfx::Rect& old_bounds,
144 const gfx::Rect& new_bounds) {
145 for (ConnectionMap::iterator i = connection_map_.begin();
146 i != connection_map_.end();
147 ++i) {
148 i->second->ProcessViewBoundsChanged(
149 view, old_bounds, new_bounds, IsChangeSource(i->first));
150 }
151 }
152
ProcessWillChangeViewHierarchy(const ServerView * view,const ServerView * new_parent,const ServerView * old_parent)153 void ConnectionManager::ProcessWillChangeViewHierarchy(
154 const ServerView* view,
155 const ServerView* new_parent,
156 const ServerView* old_parent) {
157 for (ConnectionMap::iterator i = connection_map_.begin();
158 i != connection_map_.end();
159 ++i) {
160 i->second->ProcessWillChangeViewHierarchy(
161 view, new_parent, old_parent, IsChangeSource(i->first));
162 }
163 }
164
ProcessViewHierarchyChanged(const ServerView * view,const ServerView * new_parent,const ServerView * old_parent)165 void ConnectionManager::ProcessViewHierarchyChanged(
166 const ServerView* view,
167 const ServerView* new_parent,
168 const ServerView* old_parent) {
169 for (ConnectionMap::iterator i = connection_map_.begin();
170 i != connection_map_.end();
171 ++i) {
172 i->second->ProcessViewHierarchyChanged(
173 view, new_parent, old_parent, IsChangeSource(i->first));
174 }
175 }
176
ProcessViewReorder(const ServerView * view,const ServerView * relative_view,const OrderDirection direction)177 void ConnectionManager::ProcessViewReorder(const ServerView* view,
178 const ServerView* relative_view,
179 const OrderDirection direction) {
180 for (ConnectionMap::iterator i = connection_map_.begin();
181 i != connection_map_.end();
182 ++i) {
183 i->second->ProcessViewReorder(
184 view, relative_view, direction, IsChangeSource(i->first));
185 }
186 }
187
ProcessViewDeleted(const ViewId & view)188 void ConnectionManager::ProcessViewDeleted(const ViewId& view) {
189 for (ConnectionMap::iterator i = connection_map_.begin();
190 i != connection_map_.end();
191 ++i) {
192 i->second->ProcessViewDeleted(view, IsChangeSource(i->first));
193 }
194 }
195
PrepareForChange(ScopedChange * change)196 void ConnectionManager::PrepareForChange(ScopedChange* change) {
197 // Should only ever have one change in flight.
198 CHECK(!current_change_);
199 current_change_ = change;
200 }
201
FinishChange()202 void ConnectionManager::FinishChange() {
203 // PrepareForChange/FinishChange should be balanced.
204 CHECK(current_change_);
205 current_change_ = NULL;
206 }
207
EmbedImpl(const ConnectionSpecificId creator_id,const String & url,const ViewId & root_id,InterfaceRequest<ServiceProvider> service_provider)208 ViewManagerServiceImpl* ConnectionManager::EmbedImpl(
209 const ConnectionSpecificId creator_id,
210 const String& url,
211 const ViewId& root_id,
212 InterfaceRequest<ServiceProvider> service_provider) {
213 MessagePipe pipe;
214
215 ServiceProvider* view_manager_service_provider =
216 app_connection_->ConnectToApplication(url)->GetServiceProvider();
217 view_manager_service_provider->ConnectToService(
218 ViewManagerServiceImpl::Client::Name_, pipe.handle1.Pass());
219
220 std::string creator_url;
221 ConnectionMap::const_iterator it = connection_map_.find(creator_id);
222 if (it != connection_map_.end())
223 creator_url = it->second->url();
224
225 ViewManagerServiceImpl* connection =
226 new ViewManagerServiceImpl(this,
227 creator_id,
228 creator_url,
229 url.To<std::string>(),
230 root_id,
231 service_provider.Pass());
232 WeakBindToPipe(connection, pipe.handle0.Pass());
233 connections_created_by_connect_.insert(connection);
234 OnConnectionMessagedClient(connection->id());
235 return connection;
236 }
237
OnViewDestroyed(const ServerView * view)238 void ConnectionManager::OnViewDestroyed(const ServerView* view) {
239 ProcessViewDeleted(view->id());
240 }
241
OnWillChangeViewHierarchy(const ServerView * view,const ServerView * new_parent,const ServerView * old_parent)242 void ConnectionManager::OnWillChangeViewHierarchy(
243 const ServerView* view,
244 const ServerView* new_parent,
245 const ServerView* old_parent) {
246 if (!display_manager_.in_setup())
247 ProcessWillChangeViewHierarchy(view, new_parent, old_parent);
248 }
249
OnViewHierarchyChanged(const ServerView * view,const ServerView * new_parent,const ServerView * old_parent)250 void ConnectionManager::OnViewHierarchyChanged(const ServerView* view,
251 const ServerView* new_parent,
252 const ServerView* old_parent) {
253 if (!display_manager_.in_setup())
254 ProcessViewHierarchyChanged(view, new_parent, old_parent);
255 // TODO(beng): optimize.
256 if (old_parent) {
257 display_manager_.SchedulePaint(old_parent,
258 gfx::Rect(old_parent->bounds().size()));
259 }
260 if (new_parent) {
261 display_manager_.SchedulePaint(new_parent,
262 gfx::Rect(new_parent->bounds().size()));
263 }
264 }
265
OnViewBoundsChanged(const ServerView * view,const gfx::Rect & old_bounds,const gfx::Rect & new_bounds)266 void ConnectionManager::OnViewBoundsChanged(const ServerView* view,
267 const gfx::Rect& old_bounds,
268 const gfx::Rect& new_bounds) {
269 ProcessViewBoundsChanged(view, old_bounds, new_bounds);
270 if (!view->parent())
271 return;
272
273 // TODO(sky): optimize this.
274 display_manager_.SchedulePaint(view->parent(), old_bounds);
275 display_manager_.SchedulePaint(view->parent(), new_bounds);
276 }
277
OnViewSurfaceIdChanged(const ServerView * view)278 void ConnectionManager::OnViewSurfaceIdChanged(const ServerView* view) {
279 display_manager_.SchedulePaint(view, gfx::Rect(view->bounds().size()));
280 }
281
OnWillChangeViewVisibility(const ServerView * view)282 void ConnectionManager::OnWillChangeViewVisibility(const ServerView* view) {
283 for (ConnectionMap::iterator i = connection_map_.begin();
284 i != connection_map_.end();
285 ++i) {
286 i->second->ProcessWillChangeViewVisibility(view, IsChangeSource(i->first));
287 }
288 }
289
290 } // namespace service
291 } // namespace mojo
292