1 // Copyright 2015 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/view_tree_host_impl.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "components/view_manager/connection_manager.h"
9 #include "components/view_manager/display_manager.h"
10 #include "components/view_manager/focus_controller.h"
11 #include "components/view_manager/public/cpp/types.h"
12 #include "components/view_manager/view_tree_host_delegate.h"
13 #include "components/view_manager/view_tree_impl.h"
14 #include "mojo/common/common_type_converters.h"
15 #include "mojo/converters/geometry/geometry_type_converters.h"
17 namespace view_manager
{
19 ViewTreeHostImpl::ViewTreeHostImpl(
20 mojo::ViewTreeHostClientPtr client
,
21 ConnectionManager
* connection_manager
,
23 mojo::ApplicationImpl
* app_impl
,
24 const scoped_refptr
<gles2::GpuState
>& gpu_state
,
25 const scoped_refptr
<surfaces::SurfacesState
>& surfaces_state
)
27 connection_manager_(connection_manager
),
28 client_(client
.Pass()),
29 event_dispatcher_(this),
31 DisplayManager::Create(is_headless
,
35 focus_controller_(new FocusController(this)) {
36 display_manager_
->Init(this);
38 client_
.set_connection_error_handler(
39 base::Bind(&ViewTreeHostImpl::OnClientClosed
,
40 base::Unretained(this)));
44 ViewTreeHostImpl::~ViewTreeHostImpl() {
47 void ViewTreeHostImpl::Init(ViewTreeHostDelegate
* delegate
) {
49 if (delegate_
&& root_
)
50 delegate_
->OnDisplayInitialized();
53 ViewTreeImpl
* ViewTreeHostImpl::GetViewTree() {
54 return delegate_
? delegate_
->GetViewTree() : nullptr;
57 bool ViewTreeHostImpl::IsViewAttachedToRoot(const ServerView
* view
) const {
58 return root_
->Contains(view
) && view
!= root_
.get();
61 bool ViewTreeHostImpl::SchedulePaintIfInViewport(const ServerView
* view
,
62 const gfx::Rect
& bounds
) {
63 if (root_
->Contains(view
)) {
64 display_manager_
->SchedulePaint(view
, bounds
);
70 const mojo::ViewportMetrics
& ViewTreeHostImpl::GetViewportMetrics() const {
71 return display_manager_
->GetViewportMetrics();
74 void ViewTreeHostImpl::SetFocusedView(ServerView
* new_focused_view
) {
75 ServerView
* old_focused_view
= focus_controller_
->GetFocusedView();
76 if (old_focused_view
== new_focused_view
)
78 DCHECK(root_view()->Contains(new_focused_view
));
79 focus_controller_
->SetFocusedView(new_focused_view
);
80 // TODO(beng): have the FocusController notify us via FocusControllerDelegate.
81 OnFocusChanged(old_focused_view
, new_focused_view
);
84 ServerView
* ViewTreeHostImpl::GetFocusedView() {
85 return focus_controller_
->GetFocusedView();
88 void ViewTreeHostImpl::DestroyFocusController() {
89 focus_controller_
.reset();
92 void ViewTreeHostImpl::UpdateTextInputState(ServerView
* view
,
93 const ui::TextInputState
& state
) {
94 // Do not need to update text input for unfocused views.
95 if (!display_manager_
|| focus_controller_
->GetFocusedView() != view
)
97 display_manager_
->UpdateTextInputState(state
);
100 void ViewTreeHostImpl::SetImeVisibility(ServerView
* view
, bool visible
) {
101 // Do not need to show or hide IME for unfocused view.
102 if (focus_controller_
->GetFocusedView() != view
)
104 display_manager_
->SetImeVisibility(visible
);
107 void ViewTreeHostImpl::OnAccelerator(uint32_t accelerator_id
,
108 mojo::EventPtr event
) {
109 client()->OnAccelerator(accelerator_id
, event
.Pass());
112 void ViewTreeHostImpl::DispatchInputEventToView(const ServerView
* target
,
113 mojo::EventPtr event
) {
114 // If the view is an embed root, forward to the embedded view, not the owner.
115 ViewTreeImpl
* connection
=
116 connection_manager_
->GetConnectionWithRoot(target
->id());
118 connection
= connection_manager_
->GetConnection(target
->id().connection_id
);
119 DCHECK_EQ(this, connection
->GetHost());
120 connection
->client()->OnViewInputEvent(ViewIdToTransportId(target
->id()),
122 base::Bind(&base::DoNothing
));
125 void ViewTreeHostImpl::SetSize(mojo::SizePtr size
) {
126 display_manager_
->SetViewportSize(size
.To
<gfx::Size
>());
129 void ViewTreeHostImpl::SetTitle(const mojo::String
& title
) {
130 display_manager_
->SetTitle(title
.To
<base::string16
>());
133 void ViewTreeHostImpl::AddAccelerator(uint32_t id
,
134 mojo::KeyboardCode keyboard_code
,
135 mojo::EventFlags flags
) {
136 event_dispatcher_
.AddAccelerator(id
, keyboard_code
, flags
);
139 void ViewTreeHostImpl::RemoveAccelerator(uint32_t id
) {
140 event_dispatcher_
.RemoveAccelerator(id
);
143 void ViewTreeHostImpl::OnClientClosed() {
144 // |display_manager_.reset()| destroys the display-manager first, and then
145 // sets |display_manager_| to nullptr. However, destroying |display_manager_|
146 // can destroy the corresponding ViewTreeHostConnection, and |this|. So
147 // setting it to nullptr afterwards in reset() ends up writing on free'd
148 // memory. So transfer over to a local scoped_ptr<> before destroying it.
149 scoped_ptr
<DisplayManager
> temp
= display_manager_
.Pass();
152 ServerView
* ViewTreeHostImpl::GetRootView() {
156 void ViewTreeHostImpl::OnEvent(mojo::EventPtr event
) {
157 event_dispatcher_
.OnEvent(event
.Pass());
160 void ViewTreeHostImpl::OnDisplayClosed() {
162 delegate_
->OnDisplayClosed();
165 void ViewTreeHostImpl::OnViewportMetricsChanged(
166 const mojo::ViewportMetrics
& old_metrics
,
167 const mojo::ViewportMetrics
& new_metrics
) {
169 root_
.reset(connection_manager_
->CreateServerView(
170 RootViewId(connection_manager_
->GetAndAdvanceNextHostId())));
171 root_
->SetBounds(gfx::Rect(new_metrics
.size_in_pixels
.To
<gfx::Size
>()));
172 root_
->SetVisible(true);
174 delegate_
->OnDisplayInitialized();
176 root_
->SetBounds(gfx::Rect(new_metrics
.size_in_pixels
.To
<gfx::Size
>()));
178 // TODO(fsamuel): We shouldn't broadcast this to all connections but only
179 // those within a window root.
180 connection_manager_
->ProcessViewportMetricsChanged(old_metrics
, new_metrics
);
183 void ViewTreeHostImpl::OnFocusChanged(ServerView
* old_focused_view
,
184 ServerView
* new_focused_view
) {
185 // There are up to four connections that need to be notified:
186 // . the connection containing |old_focused_view|.
187 // . the connection with |old_focused_view| as its root.
188 // . the connection containing |new_focused_view|.
189 // . the connection with |new_focused_view| as its root.
190 // Some of these connections may be the same. The following takes care to
191 // notify each only once.
192 ViewTreeImpl
* owning_connection_old
= nullptr;
193 ViewTreeImpl
* embedded_connection_old
= nullptr;
195 if (old_focused_view
) {
196 owning_connection_old
= connection_manager_
->GetConnection(
197 old_focused_view
->id().connection_id
);
198 if (owning_connection_old
) {
199 owning_connection_old
->ProcessFocusChanged(old_focused_view
,
202 embedded_connection_old
=
203 connection_manager_
->GetConnectionWithRoot(old_focused_view
->id());
204 if (embedded_connection_old
) {
205 DCHECK_NE(owning_connection_old
, embedded_connection_old
);
206 embedded_connection_old
->ProcessFocusChanged(old_focused_view
,
210 ViewTreeImpl
* owning_connection_new
= nullptr;
211 ViewTreeImpl
* embedded_connection_new
= nullptr;
212 if (new_focused_view
) {
213 owning_connection_new
= connection_manager_
->GetConnection(
214 new_focused_view
->id().connection_id
);
215 if (owning_connection_new
&&
216 owning_connection_new
!= owning_connection_old
&&
217 owning_connection_new
!= embedded_connection_old
) {
218 owning_connection_new
->ProcessFocusChanged(old_focused_view
,
221 embedded_connection_new
=
222 connection_manager_
->GetConnectionWithRoot(new_focused_view
->id());
223 if (embedded_connection_new
&&
224 embedded_connection_new
!= owning_connection_old
&&
225 embedded_connection_new
!= embedded_connection_old
) {
226 DCHECK_NE(owning_connection_new
, embedded_connection_new
);
227 embedded_connection_new
->ProcessFocusChanged(old_focused_view
,
232 // Ensure that we always notify the root connection of a focus change.
233 ViewTreeImpl
* root_tree
= GetViewTree();
234 if (root_tree
!= owning_connection_old
&&
235 root_tree
!= embedded_connection_old
&&
236 root_tree
!= owning_connection_new
&&
237 root_tree
!= embedded_connection_new
) {
238 root_tree
->ProcessFocusChanged(old_focused_view
, new_focused_view
);
241 UpdateTextInputState(new_focused_view
, new_focused_view
->text_input_state());
244 } // namespace view_manager