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.
5 #include "components/view_manager/connection_manager.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "components/view_manager/client_connection.h"
10 #include "components/view_manager/connection_manager_delegate.h"
11 #include "components/view_manager/display_manager.h"
12 #include "components/view_manager/focus_controller.h"
13 #include "components/view_manager/server_view.h"
14 #include "components/view_manager/view_coordinate_conversions.h"
15 #include "components/view_manager/view_manager_service_impl.h"
16 #include "mojo/application/public/interfaces/service_provider.mojom.h"
17 #include "mojo/converters/geometry/geometry_type_converters.h"
18 #include "mojo/converters/input_events/input_events_type_converters.h"
20 using mojo::ConnectionSpecificId
;
22 namespace view_manager
{
25 // Creates a copy of |view|. The copied view has |delegate| as its delegate.
26 // This does not recurse.
27 ServerView
* CloneView(const ServerView
* view
, ServerViewDelegate
* delegate
) {
28 ServerView
* clone
= new ServerView(delegate
, ClonedViewId());
29 clone
->SetBounds(view
->bounds());
30 clone
->SetSurfaceId(view
->surface_id());
31 clone
->SetOpacity(view
->opacity());
35 // Creates copies of all the visible children of |parent|. Newly cloned views
36 // are added to |cloned_parent| and have |delegate| as their delegate. The
37 // stacking order of the cloned views is preseved.
38 void CloneViewTree(const ServerView
* parent
,
39 ServerView
* cloned_parent
,
40 ServerViewDelegate
* delegate
) {
41 DCHECK(parent
->visible());
42 for (const ServerView
* to_clone
: parent
->GetChildren()) {
43 if (to_clone
->visible()) {
44 ServerView
* cloned
= CloneView(to_clone
, delegate
);
45 cloned_parent
->Add(cloned
);
46 CloneViewTree(to_clone
, cloned
, delegate
);
51 // Recurses through all the children of |view| moving any cloned views to
52 // |new_parent| stacked above |stack_above|. |stack_above| is updated as views
54 void ReparentClonedViews(ServerView
* new_parent
,
55 ServerView
** stack_above
,
57 if (view
->id() == ClonedViewId()) {
58 const gfx::Rect
new_bounds(ConvertRectBetweenViews(
59 view
, new_parent
, gfx::Rect(view
->bounds().size())));
60 new_parent
->Add(view
);
61 new_parent
->Reorder(view
, *stack_above
, mojo::ORDER_DIRECTION_ABOVE
);
62 view
->SetBounds(new_bounds
);
67 for (ServerView
* child
: view
->GetChildren())
68 ReparentClonedViews(new_parent
, stack_above
, child
);
71 // Deletes |view| and all its descendants.
72 void DeleteViewTree(ServerView
* view
) {
73 for (ServerView
* child
: view
->GetChildren())
74 DeleteViewTree(child
);
79 // TODO(sky): nuke, proof of concept.
80 bool DecrementAnimatingViewsOpacity(ServerView
* view
) {
81 if (view
->id() == ClonedViewId()) {
82 const float new_opacity
= view
->opacity() - .05f
;
86 view
->SetOpacity(new_opacity
);
89 bool ret_value
= false;
90 for (ServerView
* child
: view
->GetChildren()) {
91 if (DecrementAnimatingViewsOpacity(child
))
99 ConnectionManager::ScopedChange::ScopedChange(
100 ViewManagerServiceImpl
* connection
,
101 ConnectionManager
* connection_manager
,
103 : connection_manager_(connection_manager
),
104 connection_id_(connection
->id()),
105 is_delete_view_(is_delete_view
) {
106 connection_manager_
->PrepareForChange(this);
109 ConnectionManager::ScopedChange::~ScopedChange() {
110 connection_manager_
->FinishChange();
113 ConnectionManager::ConnectionManager(
114 ConnectionManagerDelegate
* delegate
,
116 mojo::ApplicationImpl
* app_impl
,
117 const scoped_refptr
<gles2::GpuState
>& gpu_state
)
118 : delegate_(delegate
),
119 window_manager_client_connection_(nullptr),
120 next_connection_id_(1),
122 event_dispatcher_(this),
123 current_change_(nullptr),
124 in_destructor_(false),
125 animation_runner_(base::TimeTicks::Now()),
126 focus_controller_(new FocusController(this)) {
127 view_manager_root_
.reset(new ViewManagerRootImpl(
128 RootViewId(next_root_id_
++), this, is_headless
, app_impl
, gpu_state
));
129 view_manager_root_
->Init();
132 ConnectionManager::~ConnectionManager() {
133 in_destructor_
= true;
135 // Deleting views will attempt to advance focus. When we're being destroyed
136 // that is not necessary. Additionally |focus_controller_| needs to be
137 // destroyed before |root_|.
138 focus_controller_
.reset();
140 view_manager_root_
.reset();
141 STLDeleteValues(&connection_map_
);
142 // All the connections should have been destroyed.
143 DCHECK(connection_map_
.empty());
146 ServerView
* ConnectionManager::CreateServerView(const ViewId
& id
) {
147 ServerView
* view
= new ServerView(this, id
);
148 view
->AddObserver(this);
152 ConnectionSpecificId
ConnectionManager::GetAndAdvanceNextConnectionId() {
153 const ConnectionSpecificId id
= next_connection_id_
++;
154 DCHECK_LT(id
, next_connection_id_
);
158 void ConnectionManager::OnConnectionError(ClientConnection
* connection
) {
159 if (connection
== window_manager_client_connection_
) {
160 window_manager_client_connection_
= nullptr;
161 delegate_
->OnLostConnectionToWindowManager();
162 // Assume we've been destroyed.
166 scoped_ptr
<ClientConnection
> connection_owner(connection
);
168 connection_map_
.erase(connection
->service()->id());
170 // TODO(sky): I may want to advance focus differently if focus is in
173 // Notify remaining connections so that they can cleanup.
174 for (auto& pair
: connection_map_
) {
175 pair
.second
->service()->OnWillDestroyViewManagerServiceImpl(
176 connection
->service());
180 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id
,
181 const ViewId
& view_id
,
182 mojo::URLRequestPtr request
) {
183 mojo::ViewManagerServicePtr service_ptr
;
184 ClientConnection
* client_connection
=
185 delegate_
->CreateClientConnectionForEmbedAtView(
186 this, GetProxy(&service_ptr
), creator_id
, request
.Pass(), view_id
);
187 AddConnection(client_connection
);
188 client_connection
->service()->Init(client_connection
->client(),
190 OnConnectionMessagedClient(client_connection
->service()->id());
193 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id
,
194 const ViewId
& view_id
,
195 mojo::ViewManagerClientPtr client
) {
196 mojo::ViewManagerServicePtr service_ptr
;
197 ClientConnection
* client_connection
=
198 delegate_
->CreateClientConnectionForEmbedAtView(
199 this, GetProxy(&service_ptr
), creator_id
, view_id
, client
.Pass());
200 AddConnection(client_connection
);
201 client_connection
->service()->Init(client_connection
->client(),
203 OnConnectionMessagedClient(client_connection
->service()->id());
206 void ConnectionManager::OnAccelerator(ServerView
* root
, mojo::EventPtr event
) {
207 // TODO(fsamuel): Support multiple roots.
208 view_manager_root_
->client()->OnAccelerator(event
.Pass());
211 ViewManagerServiceImpl
* ConnectionManager::GetConnection(
212 ConnectionSpecificId connection_id
) {
213 ConnectionMap::iterator i
= connection_map_
.find(connection_id
);
214 return i
== connection_map_
.end() ? nullptr : i
->second
->service();
217 ServerView
* ConnectionManager::GetView(const ViewId
& id
) {
218 // TODO(fsamuel): Support multiple roots.
219 if (view_manager_root_
->root_view()->id() == id
)
220 return view_manager_root_
->root_view();
221 ViewManagerServiceImpl
* service
= GetConnection(id
.connection_id
);
222 return service
? service
->GetView(id
) : nullptr;
225 void ConnectionManager::SetFocusedView(ServerView
* view
) {
226 ServerView
* old_focused
= GetFocusedView();
227 if (old_focused
== view
)
229 focus_controller_
->SetFocusedView(view
);
230 OnFocusChanged(old_focused
, view
);
233 ServerView
* ConnectionManager::GetFocusedView() {
234 return focus_controller_
->GetFocusedView();
237 bool ConnectionManager::IsViewAttachedToRoot(const ServerView
* view
) const {
238 // TODO(fsamuel): Support multiple roots.
239 return view_manager_root_
->IsViewAttachedToRoot(view
);
242 void ConnectionManager::SchedulePaint(const ServerView
* view
,
243 const gfx::Rect
& bounds
) {
244 // TODO(fsamuel): Support multiple roots.
245 view_manager_root_
->SchedulePaintIfInViewport(view
, bounds
);
248 void ConnectionManager::OnDisplayClosed() {
249 // TODO(fsamuel): Only report we lost the connection to the window manager
250 // if there are no more roots.
251 delegate_
->OnLostConnectionToWindowManager();
254 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id
) {
256 current_change_
->MarkConnectionAsMessaged(id
);
259 bool ConnectionManager::DidConnectionMessageClient(
260 ConnectionSpecificId id
) const {
261 return current_change_
&& current_change_
->DidMessageConnection(id
);
264 mojo::ViewportMetricsPtr
ConnectionManager::GetViewportMetricsForView(
265 const ServerView
* view
) {
266 // TODO(fsamuel): Support multiple roots. We should pull the metrics from
267 // the viewport where this |view| belong.
268 return view_manager_root_
->GetViewportMetrics().Clone();
271 const ViewManagerServiceImpl
* ConnectionManager::GetConnectionWithRoot(
272 const ViewId
& id
) const {
273 for (auto& pair
: connection_map_
) {
274 if (pair
.second
->service()->IsRoot(id
))
275 return pair
.second
->service();
280 ViewManagerServiceImpl
* ConnectionManager::GetEmbedRoot(
281 ViewManagerServiceImpl
* service
) {
283 const ViewId
* root_id
= service
->root();
284 if (!root_id
|| root_id
->connection_id
== service
->id())
287 ViewManagerServiceImpl
* parent_service
=
288 GetConnection(root_id
->connection_id
);
289 service
= parent_service
;
290 if (service
&& service
->is_embed_root())
296 void ConnectionManager::SetWindowManagerClientConnection(
297 scoped_ptr
<ClientConnection
> connection
) {
298 CHECK(!window_manager_client_connection_
);
299 window_manager_client_connection_
= connection
.release();
300 AddConnection(window_manager_client_connection_
);
301 window_manager_client_connection_
->service()->Init(
302 window_manager_client_connection_
->client(), nullptr);
305 mojo::ViewManagerClient
*
306 ConnectionManager::GetWindowManagerViewManagerClient() {
307 CHECK(window_manager_client_connection_
);
308 return window_manager_client_connection_
->client();
311 bool ConnectionManager::CloneAndAnimate(const ViewId
& view_id
) {
312 ServerView
* view
= GetView(view_id
);
313 if (!view
|| !view
->IsDrawn() || (view
->GetRoot() == view
))
315 if (!animation_timer_
.IsRunning()) {
316 animation_timer_
.Start(FROM_HERE
, base::TimeDelta::FromMilliseconds(100),
317 this, &ConnectionManager::DoAnimation
);
319 ServerView
* clone
= CloneView(view
, this);
320 CloneViewTree(view
, clone
, this);
321 view
->parent()->Add(clone
);
322 view
->parent()->Reorder(clone
, view
, mojo::ORDER_DIRECTION_ABOVE
);
326 void ConnectionManager::DispatchInputEventToView(const ServerView
* view
,
327 mojo::EventPtr event
) {
328 // It's possible for events to flow through here from the platform_window
329 // before any connections are established with the view_manager.
330 if (!has_window_manager_client_connection())
333 // If the view is an embed root, forward to the embedded view, not the owner.
334 ViewManagerServiceImpl
* connection
= GetConnectionWithRoot(view
->id());
336 connection
= GetConnection(view
->id().connection_id
);
338 connection
->client()->OnViewInputEvent(ViewIdToTransportId(view
->id()),
340 base::Bind(&base::DoNothing
));
343 void ConnectionManager::OnEvent(ViewManagerRootImpl
* root
,
344 mojo::EventPtr event
) {
345 event_dispatcher_
.OnEvent(root
->root_view(), event
.Pass());
348 void ConnectionManager::AddAccelerator(ViewManagerRootImpl
* root
,
349 mojo::KeyboardCode keyboard_code
,
350 mojo::EventFlags flags
) {
351 event_dispatcher_
.AddAccelerator(keyboard_code
, flags
);
354 void ConnectionManager::RemoveAccelerator(ViewManagerRootImpl
* root
,
355 mojo::KeyboardCode keyboard_code
,
356 mojo::EventFlags flags
) {
357 event_dispatcher_
.RemoveAccelerator(keyboard_code
, flags
);
360 void ConnectionManager::ProcessViewBoundsChanged(const ServerView
* view
,
361 const gfx::Rect
& old_bounds
,
362 const gfx::Rect
& new_bounds
) {
363 for (auto& pair
: connection_map_
) {
364 pair
.second
->service()->ProcessViewBoundsChanged(
365 view
, old_bounds
, new_bounds
, IsChangeSource(pair
.first
));
369 void ConnectionManager::ProcessWillChangeViewHierarchy(
370 const ServerView
* view
,
371 const ServerView
* new_parent
,
372 const ServerView
* old_parent
) {
373 for (auto& pair
: connection_map_
) {
374 pair
.second
->service()->ProcessWillChangeViewHierarchy(
375 view
, new_parent
, old_parent
, IsChangeSource(pair
.first
));
379 void ConnectionManager::ProcessViewHierarchyChanged(
380 const ServerView
* view
,
381 const ServerView
* new_parent
,
382 const ServerView
* old_parent
) {
383 for (auto& pair
: connection_map_
) {
384 pair
.second
->service()->ProcessViewHierarchyChanged(
385 view
, new_parent
, old_parent
, IsChangeSource(pair
.first
));
389 void ConnectionManager::ProcessViewReorder(
390 const ServerView
* view
,
391 const ServerView
* relative_view
,
392 const mojo::OrderDirection direction
) {
393 for (auto& pair
: connection_map_
) {
394 pair
.second
->service()->ProcessViewReorder(view
, relative_view
, direction
,
395 IsChangeSource(pair
.first
));
399 void ConnectionManager::ProcessViewDeleted(const ViewId
& view
) {
400 for (auto& pair
: connection_map_
) {
401 pair
.second
->service()->ProcessViewDeleted(view
,
402 IsChangeSource(pair
.first
));
406 void ConnectionManager::ProcessViewportMetricsChanged(
407 const mojo::ViewportMetrics
& old_metrics
,
408 const mojo::ViewportMetrics
& new_metrics
) {
409 for (auto& pair
: connection_map_
) {
410 pair
.second
->service()->ProcessViewportMetricsChanged(
411 old_metrics
, new_metrics
, IsChangeSource(pair
.first
));
415 void ConnectionManager::PrepareForChange(ScopedChange
* change
) {
416 // Should only ever have one change in flight.
417 CHECK(!current_change_
);
418 current_change_
= change
;
421 void ConnectionManager::FinishChange() {
422 // PrepareForChange/FinishChange should be balanced.
423 CHECK(current_change_
);
424 current_change_
= NULL
;
427 void ConnectionManager::DoAnimation() {
428 // TODO(fsamuel): Support multiple roots.
429 if (!DecrementAnimatingViewsOpacity(view_manager_root_
->root_view()))
430 animation_timer_
.Stop();
433 void ConnectionManager::AddConnection(ClientConnection
* connection
) {
434 DCHECK_EQ(0u, connection_map_
.count(connection
->service()->id()));
435 connection_map_
[connection
->service()->id()] = connection
;
438 void ConnectionManager::PrepareToDestroyView(ServerView
* view
) {
439 if (!in_destructor_
&& IsViewAttachedToRoot(view
) &&
440 view
->id() != ClonedViewId()) {
441 // We're about to destroy a view. Any cloned views need to be reparented
442 // else the animation would no longer be visible. By moving to a visible
443 // view, view->parent(), we ensure the animation is still visible.
444 ServerView
* parent_above
= view
;
445 ReparentClonedViews(view
->parent(), &parent_above
, view
);
448 animation_runner_
.CancelAnimationForView(view
);
451 void ConnectionManager::PrepareToChangeViewHierarchy(ServerView
* view
,
452 ServerView
* new_parent
,
453 ServerView
* old_parent
) {
454 if (view
->id() == ClonedViewId() || in_destructor_
)
457 if (IsViewAttachedToRoot(view
)) {
458 // We're about to reparent a view. Any cloned views need to be reparented
459 // else the animation may be effected in unusual ways. For example, the view
460 // could move to a new location such that the animation is entirely clipped.
461 // By moving to view->parent() we ensure the animation is still visible.
462 ServerView
* parent_above
= view
;
463 ReparentClonedViews(view
->parent(), &parent_above
, view
);
466 animation_runner_
.CancelAnimationForView(view
);
469 void ConnectionManager::PrepareToChangeViewVisibility(ServerView
* view
) {
473 if (IsViewAttachedToRoot(view
) && view
->id() != ClonedViewId() &&
475 // We're about to hide |view|, this would implicitly make any cloned views
476 // hide too. Reparent so that animations are still visible.
477 ServerView
* parent_above
= view
;
478 ReparentClonedViews(view
->parent(), &parent_above
, view
);
481 const bool is_parent_drawn
= view
->parent() && view
->parent()->IsDrawn();
482 if (!is_parent_drawn
|| !view
->visible())
483 animation_runner_
.CancelAnimationForView(view
);
486 void ConnectionManager::OnScheduleViewPaint(const ServerView
* view
) {
488 SchedulePaint(view
, gfx::Rect(view
->bounds().size()));
491 const ServerView
* ConnectionManager::GetRootView(const ServerView
* view
) const {
492 while (view
&& view
->parent())
493 view
= view
->parent();
494 if (view_manager_root_
->root_view() == view
)
499 void ConnectionManager::OnViewDestroyed(ServerView
* view
) {
501 ProcessViewDeleted(view
->id());
504 void ConnectionManager::OnWillChangeViewHierarchy(ServerView
* view
,
505 ServerView
* new_parent
,
506 ServerView
* old_parent
) {
507 if (view
->id() == ClonedViewId() || in_destructor_
)
510 ProcessWillChangeViewHierarchy(view
, new_parent
, old_parent
);
513 void ConnectionManager::OnViewHierarchyChanged(ServerView
* view
,
514 ServerView
* new_parent
,
515 ServerView
* old_parent
) {
519 ProcessViewHierarchyChanged(view
, new_parent
, old_parent
);
521 // TODO(beng): optimize.
523 SchedulePaint(old_parent
, gfx::Rect(old_parent
->bounds().size()));
525 SchedulePaint(new_parent
, gfx::Rect(new_parent
->bounds().size()));
528 void ConnectionManager::OnViewBoundsChanged(ServerView
* view
,
529 const gfx::Rect
& old_bounds
,
530 const gfx::Rect
& new_bounds
) {
534 ProcessViewBoundsChanged(view
, old_bounds
, new_bounds
);
538 // TODO(sky): optimize this.
539 SchedulePaint(view
->parent(), old_bounds
);
540 SchedulePaint(view
->parent(), new_bounds
);
543 void ConnectionManager::OnViewReordered(ServerView
* view
,
544 ServerView
* relative
,
545 mojo::OrderDirection direction
) {
547 SchedulePaint(view
, gfx::Rect(view
->bounds().size()));
550 void ConnectionManager::OnWillChangeViewVisibility(ServerView
* view
) {
554 // Need to repaint if the view was drawn (which means it's in the process of
555 // hiding) or the view is transitioning to drawn.
556 if (view
->parent() && (view
->IsDrawn() ||
557 (!view
->visible() && view
->parent()->IsDrawn()))) {
558 SchedulePaint(view
->parent(), view
->bounds());
561 for (auto& pair
: connection_map_
) {
562 pair
.second
->service()->ProcessWillChangeViewVisibility(
563 view
, IsChangeSource(pair
.first
));
567 void ConnectionManager::OnViewSharedPropertyChanged(
569 const std::string
& name
,
570 const std::vector
<uint8_t>* new_data
) {
571 for (auto& pair
: connection_map_
) {
572 pair
.second
->service()->ProcessViewPropertyChanged(
573 view
, name
, new_data
, IsChangeSource(pair
.first
));
577 void ConnectionManager::CloneAndAnimate(mojo::Id transport_view_id
) {
578 CloneAndAnimate(ViewIdFromTransportId(transport_view_id
));
581 void ConnectionManager::OnFocusChanged(ServerView
* old_focused_view
,
582 ServerView
* new_focused_view
) {
583 // There are up to four connections that need to be notified:
584 // . the connection containing |old_focused_view|.
585 // . the connection with |old_focused_view| as its root.
586 // . the connection containing |new_focused_view|.
587 // . the connection with |new_focused_view| as its root.
588 // Some of these connections may be the same. The following takes care to
589 // notify each only once.
590 ViewManagerServiceImpl
* owning_connection_old
= nullptr;
591 ViewManagerServiceImpl
* embedded_connection_old
= nullptr;
593 if (old_focused_view
) {
594 owning_connection_old
= GetConnection(old_focused_view
->id().connection_id
);
595 if (owning_connection_old
) {
596 owning_connection_old
->ProcessFocusChanged(old_focused_view
,
599 embedded_connection_old
= GetConnectionWithRoot(old_focused_view
->id());
600 if (embedded_connection_old
) {
601 DCHECK_NE(owning_connection_old
, embedded_connection_old
);
602 embedded_connection_old
->ProcessFocusChanged(old_focused_view
,
606 ViewManagerServiceImpl
* owning_connection_new
= nullptr;
607 ViewManagerServiceImpl
* embedded_connection_new
= nullptr;
608 if (new_focused_view
) {
609 owning_connection_new
= GetConnection(new_focused_view
->id().connection_id
);
610 if (owning_connection_new
&&
611 owning_connection_new
!= owning_connection_old
&&
612 owning_connection_new
!= embedded_connection_old
) {
613 owning_connection_new
->ProcessFocusChanged(old_focused_view
,
616 embedded_connection_new
= GetConnectionWithRoot(new_focused_view
->id());
617 if (embedded_connection_new
&&
618 embedded_connection_new
!= owning_connection_old
&&
619 embedded_connection_new
!= embedded_connection_old
) {
620 DCHECK_NE(owning_connection_new
, embedded_connection_new
);
621 embedded_connection_new
->ProcessFocusChanged(old_focused_view
,
626 if (has_window_manager_client_connection()) {
627 // Window manager should always be notified of focus change.
628 ViewManagerServiceImpl
* wm_connection
=
629 window_manager_client_connection_
->service();
630 if (wm_connection
!= owning_connection_old
&&
631 wm_connection
!= embedded_connection_old
&&
632 wm_connection
!= owning_connection_new
&&
633 wm_connection
!= embedded_connection_new
) {
634 wm_connection
->ProcessFocusChanged(old_focused_view
, new_focused_view
);
639 } // namespace view_manager