OLD | NEW |
| (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 "mojo/services/view_manager/connection_manager.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/stl_util.h" | |
9 #include "mojo/converters/geometry/geometry_type_converters.h" | |
10 #include "mojo/converters/input_events/input_events_type_converters.h" | |
11 #include "mojo/public/interfaces/application/service_provider.mojom.h" | |
12 #include "mojo/services/view_manager/client_connection.h" | |
13 #include "mojo/services/view_manager/connection_manager_delegate.h" | |
14 #include "mojo/services/view_manager/display_manager.h" | |
15 #include "mojo/services/view_manager/server_view.h" | |
16 #include "mojo/services/view_manager/view_coordinate_conversions.h" | |
17 #include "mojo/services/view_manager/view_manager_service_impl.h" | |
18 | |
19 namespace mojo { | |
20 namespace service { | |
21 namespace { | |
22 | |
23 // Creates a copy of |view|. The copied view has |delegate| as its delegate. | |
24 // This does not recurse. | |
25 ServerView* CloneView(const ServerView* view, ServerViewDelegate* delegate) { | |
26 ServerView* clone = new ServerView(delegate, ClonedViewId()); | |
27 clone->SetBounds(view->bounds()); | |
28 clone->SetSurfaceId(view->surface_id()); | |
29 clone->SetOpacity(view->opacity()); | |
30 return clone; | |
31 } | |
32 | |
33 // Creates copies of all the visible children of |parent|. Newly cloned views | |
34 // are added to |cloned_parent| and have |delegate| as their delegate. The | |
35 // stacking order of the cloned views is preseved. | |
36 void CloneViewTree(const ServerView* parent, | |
37 ServerView* cloned_parent, | |
38 ServerViewDelegate* delegate) { | |
39 DCHECK(parent->visible()); | |
40 for (const ServerView* to_clone : parent->GetChildren()) { | |
41 if (to_clone->visible()) { | |
42 ServerView* cloned = CloneView(to_clone, delegate); | |
43 cloned_parent->Add(cloned); | |
44 CloneViewTree(to_clone, cloned, delegate); | |
45 } | |
46 } | |
47 } | |
48 | |
49 // Recurses through all the children of |view| moving any cloned views to | |
50 // |new_parent| stacked above |stack_above|. |stack_above| is updated as views | |
51 // are moved. | |
52 void ReparentClonedViews(ServerView* new_parent, | |
53 ServerView** stack_above, | |
54 ServerView* view) { | |
55 if (view->id() == ClonedViewId()) { | |
56 const gfx::Rect new_bounds(ConvertRectBetweenViews( | |
57 view, new_parent, gfx::Rect(view->bounds().size()))); | |
58 new_parent->Add(view); | |
59 new_parent->Reorder(view, *stack_above, ORDER_DIRECTION_ABOVE); | |
60 view->SetBounds(new_bounds); | |
61 *stack_above = view; | |
62 return; | |
63 } | |
64 | |
65 for (ServerView* child : view->GetChildren()) | |
66 ReparentClonedViews(new_parent, stack_above, child); | |
67 } | |
68 | |
69 // Deletes |view| and all its descendants. | |
70 void DeleteViewTree(ServerView* view) { | |
71 for (ServerView* child : view->GetChildren()) | |
72 DeleteViewTree(child); | |
73 | |
74 delete view; | |
75 } | |
76 | |
77 // TODO(sky): nuke, proof of concept. | |
78 bool DecrementAnimatingViewsOpacity(ServerView* view) { | |
79 if (view->id() == ClonedViewId()) { | |
80 const float new_opacity = view->opacity() - .05f; | |
81 if (new_opacity <= 0) | |
82 DeleteViewTree(view); | |
83 else | |
84 view->SetOpacity(new_opacity); | |
85 return true; | |
86 } | |
87 bool ret_value = false; | |
88 for (ServerView* child : view->GetChildren()) { | |
89 if (DecrementAnimatingViewsOpacity(child)) | |
90 ret_value = true; | |
91 } | |
92 return ret_value; | |
93 } | |
94 | |
95 } // namespace | |
96 | |
97 ConnectionManager::ScopedChange::ScopedChange( | |
98 ViewManagerServiceImpl* connection, | |
99 ConnectionManager* connection_manager, | |
100 bool is_delete_view) | |
101 : connection_manager_(connection_manager), | |
102 connection_id_(connection->id()), | |
103 is_delete_view_(is_delete_view) { | |
104 connection_manager_->PrepareForChange(this); | |
105 } | |
106 | |
107 ConnectionManager::ScopedChange::~ScopedChange() { | |
108 connection_manager_->FinishChange(); | |
109 } | |
110 | |
111 ConnectionManager::ConnectionManager(ConnectionManagerDelegate* delegate, | |
112 scoped_ptr<DisplayManager> display_manager, | |
113 WindowManagerInternal* wm_internal) | |
114 : delegate_(delegate), | |
115 window_manager_client_connection_(nullptr), | |
116 next_connection_id_(1), | |
117 display_manager_(display_manager.Pass()), | |
118 root_(new ServerView(this, RootViewId())), | |
119 wm_internal_(wm_internal), | |
120 current_change_(nullptr), | |
121 in_destructor_(false) { | |
122 root_->SetBounds(gfx::Rect(800, 600)); | |
123 root_->SetVisible(true); | |
124 display_manager_->Init(this); | |
125 } | |
126 | |
127 ConnectionManager::~ConnectionManager() { | |
128 in_destructor_ = true; | |
129 | |
130 STLDeleteValues(&connection_map_); | |
131 // All the connections should have been destroyed. | |
132 DCHECK(connection_map_.empty()); | |
133 root_.reset(); | |
134 } | |
135 | |
136 ConnectionSpecificId ConnectionManager::GetAndAdvanceNextConnectionId() { | |
137 const ConnectionSpecificId id = next_connection_id_++; | |
138 DCHECK_LT(id, next_connection_id_); | |
139 return id; | |
140 } | |
141 | |
142 void ConnectionManager::OnConnectionError(ClientConnection* connection) { | |
143 if (connection == window_manager_client_connection_) { | |
144 window_manager_client_connection_ = nullptr; | |
145 delegate_->OnLostConnectionToWindowManager(); | |
146 // Assume we've been destroyed. | |
147 return; | |
148 } | |
149 | |
150 scoped_ptr<ClientConnection> connection_owner(connection); | |
151 | |
152 connection_map_.erase(connection->service()->id()); | |
153 | |
154 // Notify remaining connections so that they can cleanup. | |
155 for (auto& pair : connection_map_) { | |
156 pair.second->service()->OnWillDestroyViewManagerServiceImpl( | |
157 connection->service()); | |
158 } | |
159 } | |
160 | |
161 void ConnectionManager::EmbedAtView( | |
162 ConnectionSpecificId creator_id, | |
163 const std::string& url, | |
164 const ViewId& view_id, | |
165 InterfaceRequest<ServiceProvider> service_provider) { | |
166 std::string creator_url; | |
167 ConnectionMap::const_iterator it = connection_map_.find(creator_id); | |
168 if (it != connection_map_.end()) | |
169 creator_url = it->second->service()->url(); | |
170 | |
171 ClientConnection* client_connection = | |
172 delegate_->CreateClientConnectionForEmbedAtView( | |
173 this, creator_id, creator_url, url, view_id); | |
174 AddConnection(client_connection); | |
175 client_connection->service()->Init(client_connection->client(), | |
176 service_provider.Pass()); | |
177 OnConnectionMessagedClient(client_connection->service()->id()); | |
178 } | |
179 | |
180 ViewManagerServiceImpl* ConnectionManager::GetConnection( | |
181 ConnectionSpecificId connection_id) { | |
182 ConnectionMap::iterator i = connection_map_.find(connection_id); | |
183 return i == connection_map_.end() ? nullptr : i->second->service(); | |
184 } | |
185 | |
186 ServerView* ConnectionManager::GetView(const ViewId& id) { | |
187 if (id == root_->id()) | |
188 return root_.get(); | |
189 ViewManagerServiceImpl* service = GetConnection(id.connection_id); | |
190 return service ? service->GetView(id) : nullptr; | |
191 } | |
192 | |
193 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id) { | |
194 if (current_change_) | |
195 current_change_->MarkConnectionAsMessaged(id); | |
196 } | |
197 | |
198 bool ConnectionManager::DidConnectionMessageClient( | |
199 ConnectionSpecificId id) const { | |
200 return current_change_ && current_change_->DidMessageConnection(id); | |
201 } | |
202 | |
203 const ViewManagerServiceImpl* ConnectionManager::GetConnectionWithRoot( | |
204 const ViewId& id) const { | |
205 for (auto& pair : connection_map_) { | |
206 if (pair.second->service()->IsRoot(id)) | |
207 return pair.second->service(); | |
208 } | |
209 return nullptr; | |
210 } | |
211 | |
212 void ConnectionManager::SetWindowManagerClientConnection( | |
213 scoped_ptr<ClientConnection> connection) { | |
214 CHECK(!window_manager_client_connection_); | |
215 window_manager_client_connection_ = connection.release(); | |
216 AddConnection(window_manager_client_connection_); | |
217 window_manager_client_connection_->service()->Init( | |
218 window_manager_client_connection_->client(), | |
219 InterfaceRequest<ServiceProvider>()); | |
220 } | |
221 | |
222 bool ConnectionManager::CloneAndAnimate(const ViewId& view_id) { | |
223 ServerView* view = GetView(view_id); | |
224 if (!view || !view->IsDrawn(root_.get()) || view == root_.get()) | |
225 return false; | |
226 if (!animation_timer_.IsRunning()) { | |
227 animation_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(100), | |
228 this, &ConnectionManager::DoAnimation); | |
229 } | |
230 ServerView* clone = CloneView(view, this); | |
231 CloneViewTree(view, clone, this); | |
232 view->parent()->Add(clone); | |
233 view->parent()->Reorder(clone, view, ORDER_DIRECTION_ABOVE); | |
234 return true; | |
235 } | |
236 | |
237 void ConnectionManager::ProcessViewBoundsChanged(const ServerView* view, | |
238 const gfx::Rect& old_bounds, | |
239 const gfx::Rect& new_bounds) { | |
240 for (auto& pair : connection_map_) { | |
241 pair.second->service()->ProcessViewBoundsChanged( | |
242 view, old_bounds, new_bounds, IsChangeSource(pair.first)); | |
243 } | |
244 } | |
245 | |
246 void ConnectionManager::ProcessWillChangeViewHierarchy( | |
247 const ServerView* view, | |
248 const ServerView* new_parent, | |
249 const ServerView* old_parent) { | |
250 for (auto& pair : connection_map_) { | |
251 pair.second->service()->ProcessWillChangeViewHierarchy( | |
252 view, new_parent, old_parent, IsChangeSource(pair.first)); | |
253 } | |
254 } | |
255 | |
256 void ConnectionManager::ProcessViewHierarchyChanged( | |
257 const ServerView* view, | |
258 const ServerView* new_parent, | |
259 const ServerView* old_parent) { | |
260 for (auto& pair : connection_map_) { | |
261 pair.second->service()->ProcessViewHierarchyChanged( | |
262 view, new_parent, old_parent, IsChangeSource(pair.first)); | |
263 } | |
264 } | |
265 | |
266 void ConnectionManager::ProcessViewReorder(const ServerView* view, | |
267 const ServerView* relative_view, | |
268 const OrderDirection direction) { | |
269 for (auto& pair : connection_map_) { | |
270 pair.second->service()->ProcessViewReorder(view, relative_view, direction, | |
271 IsChangeSource(pair.first)); | |
272 } | |
273 } | |
274 | |
275 void ConnectionManager::ProcessViewDeleted(const ViewId& view) { | |
276 for (auto& pair : connection_map_) { | |
277 pair.second->service()->ProcessViewDeleted(view, | |
278 IsChangeSource(pair.first)); | |
279 } | |
280 } | |
281 | |
282 void ConnectionManager::PrepareForChange(ScopedChange* change) { | |
283 // Should only ever have one change in flight. | |
284 CHECK(!current_change_); | |
285 current_change_ = change; | |
286 } | |
287 | |
288 void ConnectionManager::FinishChange() { | |
289 // PrepareForChange/FinishChange should be balanced. | |
290 CHECK(current_change_); | |
291 current_change_ = NULL; | |
292 } | |
293 | |
294 void ConnectionManager::DoAnimation() { | |
295 if (!DecrementAnimatingViewsOpacity(root())) | |
296 animation_timer_.Stop(); | |
297 } | |
298 | |
299 void ConnectionManager::AddConnection(ClientConnection* connection) { | |
300 DCHECK_EQ(0u, connection_map_.count(connection->service()->id())); | |
301 connection_map_[connection->service()->id()] = connection; | |
302 } | |
303 | |
304 void ConnectionManager::OnWillDestroyView(ServerView* view) { | |
305 if (!in_destructor_ && root_->Contains(view) && view != root_.get() && | |
306 view->id() != ClonedViewId()) { | |
307 // We're about to destroy a view. Any cloned views need to be reparented | |
308 // else the animation would no longer be visible. By moving to a visible | |
309 // view, view->parent(), we ensure the animation is still visible. | |
310 ServerView* parent_above = view; | |
311 ReparentClonedViews(view->parent(), &parent_above, view); | |
312 } | |
313 } | |
314 | |
315 void ConnectionManager::OnViewDestroyed(const ServerView* view) { | |
316 if (!in_destructor_) | |
317 ProcessViewDeleted(view->id()); | |
318 } | |
319 | |
320 void ConnectionManager::OnWillChangeViewHierarchy(ServerView* view, | |
321 ServerView* new_parent, | |
322 ServerView* old_parent) { | |
323 if (view->id() == ClonedViewId() || in_destructor_) | |
324 return; | |
325 | |
326 if (root_->Contains(view) && view != root_.get()) { | |
327 // We're about to reparent a view. Any cloned views need to be reparented | |
328 // else the animation may be effected in unusual ways. For example, the view | |
329 // could move to a new location such that the animation is entirely clipped. | |
330 // By moving to view->parent() we ensure the animation is still visible. | |
331 ServerView* parent_above = view; | |
332 ReparentClonedViews(view->parent(), &parent_above, view); | |
333 } | |
334 | |
335 ProcessWillChangeViewHierarchy(view, new_parent, old_parent); | |
336 } | |
337 | |
338 void ConnectionManager::OnViewHierarchyChanged(const ServerView* view, | |
339 const ServerView* new_parent, | |
340 const ServerView* old_parent) { | |
341 if (in_destructor_) | |
342 return; | |
343 | |
344 ProcessViewHierarchyChanged(view, new_parent, old_parent); | |
345 | |
346 // TODO(beng): optimize. | |
347 if (old_parent) { | |
348 display_manager_->SchedulePaint(old_parent, | |
349 gfx::Rect(old_parent->bounds().size())); | |
350 } | |
351 if (new_parent) { | |
352 display_manager_->SchedulePaint(new_parent, | |
353 gfx::Rect(new_parent->bounds().size())); | |
354 } | |
355 } | |
356 | |
357 void ConnectionManager::OnViewBoundsChanged(const ServerView* view, | |
358 const gfx::Rect& old_bounds, | |
359 const gfx::Rect& new_bounds) { | |
360 if (in_destructor_) | |
361 return; | |
362 | |
363 ProcessViewBoundsChanged(view, old_bounds, new_bounds); | |
364 if (!view->parent()) | |
365 return; | |
366 | |
367 // TODO(sky): optimize this. | |
368 display_manager_->SchedulePaint(view->parent(), old_bounds); | |
369 display_manager_->SchedulePaint(view->parent(), new_bounds); | |
370 } | |
371 | |
372 void ConnectionManager::OnViewSurfaceIdChanged(const ServerView* view) { | |
373 if (!in_destructor_) | |
374 display_manager_->SchedulePaint(view, gfx::Rect(view->bounds().size())); | |
375 } | |
376 | |
377 void ConnectionManager::OnViewReordered(const ServerView* view, | |
378 const ServerView* relative, | |
379 OrderDirection direction) { | |
380 if (!in_destructor_) | |
381 display_manager_->SchedulePaint(view, gfx::Rect(view->bounds().size())); | |
382 } | |
383 | |
384 void ConnectionManager::OnWillChangeViewVisibility(ServerView* view) { | |
385 if (in_destructor_) | |
386 return; | |
387 | |
388 // Need to repaint if the view was drawn (which means it'll in the process of | |
389 // hiding) or the view is transitioning to drawn. | |
390 if (view->IsDrawn(root_.get()) || (!view->visible() && view->parent() && | |
391 view->parent()->IsDrawn(root_.get()))) { | |
392 display_manager_->SchedulePaint(view->parent(), view->bounds()); | |
393 } | |
394 | |
395 if (view != root_.get() && view->id() != ClonedViewId() && | |
396 root_->Contains(view) && view->IsDrawn(root_.get())) { | |
397 // We're about to hide |view|, this would implicitly make any cloned views | |
398 // hide to. Reparent so that animations are still visible. | |
399 ServerView* parent_above = view; | |
400 ReparentClonedViews(view->parent(), &parent_above, view); | |
401 } | |
402 | |
403 for (auto& pair : connection_map_) { | |
404 pair.second->service()->ProcessWillChangeViewVisibility( | |
405 view, IsChangeSource(pair.first)); | |
406 } | |
407 } | |
408 | |
409 void ConnectionManager::OnViewSharedPropertyChanged( | |
410 const ServerView* view, | |
411 const std::string& name, | |
412 const std::vector<uint8_t>* new_data) { | |
413 for (auto& pair : connection_map_) { | |
414 pair.second->service()->ProcessViewPropertyChanged( | |
415 view, name, new_data, IsChangeSource(pair.first)); | |
416 } | |
417 } | |
418 | |
419 void ConnectionManager::OnScheduleViewPaint(const ServerView* view) { | |
420 if (!in_destructor_) | |
421 display_manager_->SchedulePaint(view, gfx::Rect(view->bounds().size())); | |
422 } | |
423 | |
424 void ConnectionManager::DispatchInputEventToView(Id transport_view_id, | |
425 EventPtr event) { | |
426 const ViewId view_id(ViewIdFromTransportId(transport_view_id)); | |
427 | |
428 ViewManagerServiceImpl* connection = GetConnectionWithRoot(view_id); | |
429 if (!connection) | |
430 connection = GetConnection(view_id.connection_id); | |
431 if (connection) { | |
432 connection->client()->OnViewInputEvent( | |
433 transport_view_id, event.Pass(), base::Bind(&base::DoNothing)); | |
434 } | |
435 } | |
436 | |
437 void ConnectionManager::SetViewportSize(SizePtr size) { | |
438 gfx::Size new_size = size.To<gfx::Size>(); | |
439 display_manager_->SetViewportSize(new_size); | |
440 } | |
441 | |
442 void ConnectionManager::CloneAndAnimate(Id transport_view_id) { | |
443 CloneAndAnimate(ViewIdFromTransportId(transport_view_id)); | |
444 } | |
445 | |
446 } // namespace service | |
447 } // namespace mojo | |
OLD | NEW |