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/converters/geometry/geometry_type_converters.h"
17 #include "mojo/converters/input_events/input_events_type_converters.h"
18 #include "third_party/mojo/src/mojo/public/interfaces/application/service_provider.mojom.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(ConnectionManagerDelegate
* delegate
,
114 scoped_ptr
<DisplayManager
> display_manager
,
115 mojo::WindowManagerInternal
* wm_internal
)
116 : delegate_(delegate
),
117 window_manager_client_connection_(nullptr),
118 next_connection_id_(1),
119 display_manager_(display_manager
.Pass()),
120 root_(CreateServerView(RootViewId())),
121 wm_internal_(wm_internal
),
122 current_change_(nullptr),
123 in_destructor_(false),
124 animation_runner_(base::TimeTicks::Now()),
125 event_dispatcher_(this),
126 event_dispatcher_binding_(&event_dispatcher_
),
127 focus_controller_(new FocusController(this, root_
.get())) {
128 root_
->SetBounds(gfx::Rect(800, 600));
129 root_
->SetVisible(true);
131 mojo::NativeViewportEventDispatcherPtr event_dispatcher_ptr
;
132 event_dispatcher_binding_
.Bind(GetProxy(&event_dispatcher_ptr
));
133 display_manager_
->Init(this, event_dispatcher_ptr
.Pass());
136 ConnectionManager::~ConnectionManager() {
137 in_destructor_
= true;
139 // Deleting views will attempt to advance focus. When we're being destroyed
140 // that is not necessary. Additionally |focus_controller_| needs to be
141 // destroyed before |root_|.
142 focus_controller_
.reset();
144 STLDeleteValues(&connection_map_
);
145 // All the connections should have been destroyed.
146 DCHECK(connection_map_
.empty());
150 ServerView
* ConnectionManager::CreateServerView(const ViewId
& id
) {
151 ServerView
* view
= new ServerView(this, id
);
152 view
->AddObserver(this);
156 ConnectionSpecificId
ConnectionManager::GetAndAdvanceNextConnectionId() {
157 const ConnectionSpecificId id
= next_connection_id_
++;
158 DCHECK_LT(id
, next_connection_id_
);
162 void ConnectionManager::OnConnectionError(ClientConnection
* connection
) {
163 if (connection
== window_manager_client_connection_
) {
164 window_manager_client_connection_
= nullptr;
165 delegate_
->OnLostConnectionToWindowManager();
166 // Assume we've been destroyed.
170 scoped_ptr
<ClientConnection
> connection_owner(connection
);
172 connection_map_
.erase(connection
->service()->id());
174 // TODO(sky): I may want to advance focus differently if focus is in
177 // Notify remaining connections so that they can cleanup.
178 for (auto& pair
: connection_map_
) {
179 pair
.second
->service()->OnWillDestroyViewManagerServiceImpl(
180 connection
->service());
184 void ConnectionManager::EmbedAtView(
185 ConnectionSpecificId creator_id
,
186 const std::string
& url
,
187 const ViewId
& view_id
,
188 mojo::InterfaceRequest
<mojo::ServiceProvider
> services
,
189 mojo::ServiceProviderPtr exposed_services
) {
190 std::string creator_url
;
191 ConnectionMap::const_iterator it
= connection_map_
.find(creator_id
);
192 if (it
!= connection_map_
.end())
193 creator_url
= it
->second
->service()->url();
195 mojo::ViewManagerServicePtr service_ptr
;
196 ClientConnection
* client_connection
=
197 delegate_
->CreateClientConnectionForEmbedAtView(
198 this, GetProxy(&service_ptr
), creator_id
, creator_url
, url
, view_id
);
199 AddConnection(client_connection
);
200 client_connection
->service()->Init(client_connection
->client(),
201 service_ptr
.Pass(), services
.Pass(),
202 exposed_services
.Pass());
203 OnConnectionMessagedClient(client_connection
->service()->id());
206 void ConnectionManager::EmbedAtView(mojo::ConnectionSpecificId creator_id
,
207 const ViewId
& view_id
,
208 mojo::ViewManagerClientPtr client
) {
209 std::string creator_url
;
210 ConnectionMap::const_iterator it
= connection_map_
.find(creator_id
);
211 if (it
!= connection_map_
.end())
212 creator_url
= it
->second
->service()->url();
214 mojo::ViewManagerServicePtr service_ptr
;
215 ClientConnection
* client_connection
=
216 delegate_
->CreateClientConnectionForEmbedAtView(
217 this, GetProxy(&service_ptr
), creator_id
, creator_url
, view_id
,
219 AddConnection(client_connection
);
220 client_connection
->service()->Init(client_connection
->client(),
221 service_ptr
.Pass(), nullptr, nullptr);
222 OnConnectionMessagedClient(client_connection
->service()->id());
225 ViewManagerServiceImpl
* ConnectionManager::GetConnection(
226 ConnectionSpecificId connection_id
) {
227 ConnectionMap::iterator i
= connection_map_
.find(connection_id
);
228 return i
== connection_map_
.end() ? nullptr : i
->second
->service();
231 ServerView
* ConnectionManager::GetView(const ViewId
& id
) {
232 if (id
== root_
->id())
234 ViewManagerServiceImpl
* service
= GetConnection(id
.connection_id
);
235 return service
? service
->GetView(id
) : nullptr;
238 void ConnectionManager::SetFocusedView(ServerView
* view
) {
239 ServerView
* old_focused
= GetFocusedView();
240 if (old_focused
== view
)
242 focus_controller_
->SetFocusedView(view
);
243 OnFocusChanged(old_focused
, view
);
246 ServerView
* ConnectionManager::GetFocusedView() {
247 return focus_controller_
->GetFocusedView();
250 void ConnectionManager::OnConnectionMessagedClient(ConnectionSpecificId id
) {
252 current_change_
->MarkConnectionAsMessaged(id
);
255 bool ConnectionManager::DidConnectionMessageClient(
256 ConnectionSpecificId id
) const {
257 return current_change_
&& current_change_
->DidMessageConnection(id
);
260 const ViewManagerServiceImpl
* ConnectionManager::GetConnectionWithRoot(
261 const ViewId
& id
) const {
262 for (auto& pair
: connection_map_
) {
263 if (pair
.second
->service()->IsRoot(id
))
264 return pair
.second
->service();
269 void ConnectionManager::SetWindowManagerClientConnection(
270 scoped_ptr
<ClientConnection
> connection
) {
271 CHECK(!window_manager_client_connection_
);
272 window_manager_client_connection_
= connection
.release();
273 AddConnection(window_manager_client_connection_
);
274 window_manager_client_connection_
->service()->Init(
275 window_manager_client_connection_
->client(), nullptr, nullptr, nullptr);
278 mojo::ViewManagerClient
*
279 ConnectionManager::GetWindowManagerViewManagerClient() {
280 CHECK(window_manager_client_connection_
);
281 return window_manager_client_connection_
->client();
284 bool ConnectionManager::CloneAndAnimate(const ViewId
& view_id
) {
285 ServerView
* view
= GetView(view_id
);
286 if (!view
|| !view
->IsDrawn(root_
.get()) || view
== root_
.get())
288 if (!animation_timer_
.IsRunning()) {
289 animation_timer_
.Start(FROM_HERE
, base::TimeDelta::FromMilliseconds(100),
290 this, &ConnectionManager::DoAnimation
);
292 ServerView
* clone
= CloneView(view
, this);
293 CloneViewTree(view
, clone
, this);
294 view
->parent()->Add(clone
);
295 view
->parent()->Reorder(clone
, view
, mojo::ORDER_DIRECTION_ABOVE
);
299 void ConnectionManager::ProcessEvent(mojo::EventPtr event
) {
300 event_dispatcher_
.OnEvent(event
.Pass(), EventDispatcher::OnEventCallback());
303 void ConnectionManager::DispatchInputEventToView(const ServerView
* view
,
304 mojo::EventPtr event
) {
305 // If the view is an embed root, forward to the embedded view, not the owner.
306 ViewManagerServiceImpl
* connection
= GetConnectionWithRoot(view
->id());
308 connection
= GetConnection(view
->id().connection_id
);
310 connection
->client()->OnViewInputEvent(ViewIdToTransportId(view
->id()),
312 base::Bind(&base::DoNothing
));
315 void ConnectionManager::ProcessViewBoundsChanged(const ServerView
* view
,
316 const gfx::Rect
& old_bounds
,
317 const gfx::Rect
& new_bounds
) {
318 for (auto& pair
: connection_map_
) {
319 pair
.second
->service()->ProcessViewBoundsChanged(
320 view
, old_bounds
, new_bounds
, IsChangeSource(pair
.first
));
324 void ConnectionManager::ProcessViewportMetricsChanged(
325 const mojo::ViewportMetrics
& old_metrics
,
326 const mojo::ViewportMetrics
& new_metrics
) {
327 for (auto& pair
: connection_map_
) {
328 pair
.second
->service()->ProcessViewportMetricsChanged(
329 old_metrics
, new_metrics
, IsChangeSource(pair
.first
));
333 void ConnectionManager::ProcessWillChangeViewHierarchy(
334 const ServerView
* view
,
335 const ServerView
* new_parent
,
336 const ServerView
* old_parent
) {
337 for (auto& pair
: connection_map_
) {
338 pair
.second
->service()->ProcessWillChangeViewHierarchy(
339 view
, new_parent
, old_parent
, IsChangeSource(pair
.first
));
343 void ConnectionManager::ProcessViewHierarchyChanged(
344 const ServerView
* view
,
345 const ServerView
* new_parent
,
346 const ServerView
* old_parent
) {
347 for (auto& pair
: connection_map_
) {
348 pair
.second
->service()->ProcessViewHierarchyChanged(
349 view
, new_parent
, old_parent
, IsChangeSource(pair
.first
));
353 void ConnectionManager::ProcessViewReorder(
354 const ServerView
* view
,
355 const ServerView
* relative_view
,
356 const mojo::OrderDirection direction
) {
357 for (auto& pair
: connection_map_
) {
358 pair
.second
->service()->ProcessViewReorder(view
, relative_view
, direction
,
359 IsChangeSource(pair
.first
));
363 void ConnectionManager::ProcessViewDeleted(const ViewId
& view
) {
364 for (auto& pair
: connection_map_
) {
365 pair
.second
->service()->ProcessViewDeleted(view
,
366 IsChangeSource(pair
.first
));
370 void ConnectionManager::PrepareForChange(ScopedChange
* change
) {
371 // Should only ever have one change in flight.
372 CHECK(!current_change_
);
373 current_change_
= change
;
376 void ConnectionManager::FinishChange() {
377 // PrepareForChange/FinishChange should be balanced.
378 CHECK(current_change_
);
379 current_change_
= NULL
;
382 void ConnectionManager::DoAnimation() {
383 if (!DecrementAnimatingViewsOpacity(root()))
384 animation_timer_
.Stop();
387 void ConnectionManager::AddConnection(ClientConnection
* connection
) {
388 DCHECK_EQ(0u, connection_map_
.count(connection
->service()->id()));
389 connection_map_
[connection
->service()->id()] = connection
;
392 void ConnectionManager::PrepareToDestroyView(ServerView
* view
) {
393 if (!in_destructor_
&& root_
->Contains(view
) && view
!= root_
.get() &&
394 view
->id() != ClonedViewId()) {
395 // We're about to destroy a view. Any cloned views need to be reparented
396 // else the animation would no longer be visible. By moving to a visible
397 // view, view->parent(), we ensure the animation is still visible.
398 ServerView
* parent_above
= view
;
399 ReparentClonedViews(view
->parent(), &parent_above
, view
);
402 animation_runner_
.CancelAnimationForView(view
);
405 void ConnectionManager::PrepareToChangeViewHierarchy(ServerView
* view
,
406 ServerView
* new_parent
,
407 ServerView
* old_parent
) {
408 if (view
->id() == ClonedViewId() || in_destructor_
)
411 if (root_
->Contains(view
) && view
!= root_
.get()) {
412 // We're about to reparent a view. Any cloned views need to be reparented
413 // else the animation may be effected in unusual ways. For example, the view
414 // could move to a new location such that the animation is entirely clipped.
415 // By moving to view->parent() we ensure the animation is still visible.
416 ServerView
* parent_above
= view
;
417 ReparentClonedViews(view
->parent(), &parent_above
, view
);
420 animation_runner_
.CancelAnimationForView(view
);
423 void ConnectionManager::PrepareToChangeViewVisibility(ServerView
* view
) {
427 if (view
!= root_
.get() && view
->id() != ClonedViewId() &&
428 root_
->Contains(view
) && view
->IsDrawn(root_
.get())) {
429 // We're about to hide |view|, this would implicitly make any cloned views
430 // hide too. Reparent so that animations are still visible.
431 ServerView
* parent_above
= view
;
432 ReparentClonedViews(view
->parent(), &parent_above
, view
);
435 const bool is_parent_drawn
=
436 view
->parent() && view
->parent()->IsDrawn(root_
.get());
437 if (!is_parent_drawn
|| !view
->visible())
438 animation_runner_
.CancelAnimationForView(view
);
441 void ConnectionManager::OnScheduleViewPaint(const ServerView
* view
) {
443 display_manager_
->SchedulePaint(view
, gfx::Rect(view
->bounds().size()));
446 void ConnectionManager::OnViewDestroyed(ServerView
* view
) {
448 ProcessViewDeleted(view
->id());
451 void ConnectionManager::OnWillChangeViewHierarchy(ServerView
* view
,
452 ServerView
* new_parent
,
453 ServerView
* old_parent
) {
454 if (view
->id() == ClonedViewId() || in_destructor_
)
457 ProcessWillChangeViewHierarchy(view
, new_parent
, old_parent
);
460 void ConnectionManager::OnViewHierarchyChanged(ServerView
* view
,
461 ServerView
* new_parent
,
462 ServerView
* old_parent
) {
466 ProcessViewHierarchyChanged(view
, new_parent
, old_parent
);
468 // TODO(beng): optimize.
470 display_manager_
->SchedulePaint(old_parent
,
471 gfx::Rect(old_parent
->bounds().size()));
474 display_manager_
->SchedulePaint(new_parent
,
475 gfx::Rect(new_parent
->bounds().size()));
479 void ConnectionManager::OnViewBoundsChanged(ServerView
* view
,
480 const gfx::Rect
& old_bounds
,
481 const gfx::Rect
& new_bounds
) {
485 ProcessViewBoundsChanged(view
, old_bounds
, new_bounds
);
489 // TODO(sky): optimize this.
490 display_manager_
->SchedulePaint(view
->parent(), old_bounds
);
491 display_manager_
->SchedulePaint(view
->parent(), new_bounds
);
494 void ConnectionManager::OnViewReordered(ServerView
* view
,
495 ServerView
* relative
,
496 mojo::OrderDirection direction
) {
498 display_manager_
->SchedulePaint(view
, gfx::Rect(view
->bounds().size()));
501 void ConnectionManager::OnWillChangeViewVisibility(ServerView
* view
) {
505 // Need to repaint if the view was drawn (which means it's in the process of
506 // hiding) or the view is transitioning to drawn.
507 if (view
->IsDrawn(root_
.get()) || (!view
->visible() && view
->parent() &&
508 view
->parent()->IsDrawn(root_
.get()))) {
509 display_manager_
->SchedulePaint(view
->parent(), view
->bounds());
512 for (auto& pair
: connection_map_
) {
513 pair
.second
->service()->ProcessWillChangeViewVisibility(
514 view
, IsChangeSource(pair
.first
));
518 void ConnectionManager::OnViewSharedPropertyChanged(
520 const std::string
& name
,
521 const std::vector
<uint8_t>* new_data
) {
522 for (auto& pair
: connection_map_
) {
523 pair
.second
->service()->ProcessViewPropertyChanged(
524 view
, name
, new_data
, IsChangeSource(pair
.first
));
528 void ConnectionManager::SetViewportSize(mojo::SizePtr size
) {
529 display_manager_
->SetViewportSize(size
.To
<gfx::Size
>());
532 void ConnectionManager::DispatchInputEventToViewDEPRECATED(
533 mojo::Id transport_view_id
,
534 mojo::EventPtr event
) {
535 const ViewId
view_id(ViewIdFromTransportId(transport_view_id
));
537 ViewManagerServiceImpl
* connection
= GetConnectionWithRoot(view_id
);
539 connection
= GetConnection(view_id
.connection_id
);
541 connection
->client()->OnViewInputEvent(
542 transport_view_id
, event
.Pass(), base::Bind(&base::DoNothing
));
546 void ConnectionManager::CloneAndAnimate(mojo::Id transport_view_id
) {
547 CloneAndAnimate(ViewIdFromTransportId(transport_view_id
));
550 void ConnectionManager::AddAccelerator(mojo::KeyboardCode keyboard_code
,
551 mojo::EventFlags flags
) {
552 event_dispatcher_
.AddAccelerator(keyboard_code
, flags
);
555 void ConnectionManager::RemoveAccelerator(mojo::KeyboardCode keyboard_code
,
556 mojo::EventFlags flags
) {
557 event_dispatcher_
.RemoveAccelerator(keyboard_code
, flags
);
560 void ConnectionManager::OnFocusChanged(ServerView
* old_focused_view
,
561 ServerView
* new_focused_view
) {
562 // There are up to four connections that need to be notified:
563 // . the connection containing |old_focused_view|.
564 // . the connection with |old_focused_view| as its root.
565 // . the connection containing |new_focused_view|.
566 // . the connection with |new_focused_view| as its root.
567 // Some of these connections may be the same. The following takes care to
568 // notify each only once.
569 ViewManagerServiceImpl
* owning_connection_old
= nullptr;
570 ViewManagerServiceImpl
* embedded_connection_old
= nullptr;
572 if (old_focused_view
) {
573 owning_connection_old
= GetConnection(old_focused_view
->id().connection_id
);
574 if (owning_connection_old
) {
575 owning_connection_old
->ProcessFocusChanged(old_focused_view
,
578 embedded_connection_old
= GetConnectionWithRoot(old_focused_view
->id());
579 if (embedded_connection_old
) {
580 DCHECK_NE(owning_connection_old
, embedded_connection_old
);
581 embedded_connection_old
->ProcessFocusChanged(old_focused_view
,
585 ViewManagerServiceImpl
* owning_connection_new
= nullptr;
586 ViewManagerServiceImpl
* embedded_connection_new
= nullptr;
587 if (new_focused_view
) {
588 owning_connection_new
= GetConnection(new_focused_view
->id().connection_id
);
589 if (owning_connection_new
&&
590 owning_connection_new
!= owning_connection_old
&&
591 owning_connection_new
!= embedded_connection_old
) {
592 owning_connection_new
->ProcessFocusChanged(old_focused_view
,
595 embedded_connection_new
= GetConnectionWithRoot(new_focused_view
->id());
596 if (embedded_connection_new
&&
597 embedded_connection_new
!= owning_connection_old
&&
598 embedded_connection_new
!= embedded_connection_old
) {
599 DCHECK_NE(owning_connection_new
, embedded_connection_new
);
600 embedded_connection_new
->ProcessFocusChanged(old_focused_view
,
605 if (has_window_manager_client_connection()) {
606 // Window manager should always be notified of focus change.
607 ViewManagerServiceImpl
* wm_connection
=
608 window_manager_client_connection_
->service();
609 if (wm_connection
!= owning_connection_old
&&
610 wm_connection
!= embedded_connection_old
&&
611 wm_connection
!= owning_connection_new
&&
612 wm_connection
!= embedded_connection_new
) {
613 wm_connection
->ProcessFocusChanged(old_focused_view
, new_focused_view
);
618 } // namespace view_manager