OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "components/mus/view_tree_host_impl.h" | |
6 | |
7 #include "base/strings/utf_string_conversions.h" | |
8 #include "components/mus/connection_manager.h" | |
9 #include "components/mus/display_manager.h" | |
10 #include "components/mus/focus_controller.h" | |
11 #include "components/mus/public/cpp/types.h" | |
12 #include "components/mus/view_tree_host_delegate.h" | |
13 #include "components/mus/view_tree_impl.h" | |
14 #include "mojo/common/common_type_converters.h" | |
15 #include "mojo/converters/geometry/geometry_type_converters.h" | |
16 | |
17 namespace mus { | |
18 | |
19 ViewTreeHostImpl::ViewTreeHostImpl( | |
20 mojo::ViewTreeHostClientPtr client, | |
21 ConnectionManager* connection_manager, | |
22 mojo::ApplicationImpl* app_impl, | |
23 const scoped_refptr<GpuState>& gpu_state, | |
24 const scoped_refptr<SurfacesState>& surfaces_state) | |
25 : delegate_(nullptr), | |
26 connection_manager_(connection_manager), | |
27 client_(client.Pass()), | |
28 event_dispatcher_(this), | |
29 display_manager_(DisplayManager::Create(app_impl, | |
30 gpu_state, | |
31 surfaces_state)), | |
32 focus_controller_(new FocusController(this)) { | |
33 display_manager_->Init(this); | |
34 if (client_) { | |
35 client_.set_connection_error_handler( | |
36 base::Bind(&ViewTreeHostImpl::OnClientClosed, base::Unretained(this))); | |
37 } | |
38 } | |
39 | |
40 ViewTreeHostImpl::~ViewTreeHostImpl() {} | |
41 | |
42 void ViewTreeHostImpl::Init(ViewTreeHostDelegate* delegate) { | |
43 delegate_ = delegate; | |
44 if (delegate_ && root_) | |
45 delegate_->OnDisplayInitialized(); | |
46 } | |
47 | |
48 ViewTreeImpl* ViewTreeHostImpl::GetViewTree() { | |
49 return delegate_ ? delegate_->GetViewTree() : nullptr; | |
50 } | |
51 | |
52 bool ViewTreeHostImpl::IsViewAttachedToRoot(const ServerView* view) const { | |
53 return root_->Contains(view) && view != root_.get(); | |
54 } | |
55 | |
56 bool ViewTreeHostImpl::SchedulePaintIfInViewport(const ServerView* view, | |
57 const gfx::Rect& bounds) { | |
58 if (root_->Contains(view)) { | |
59 display_manager_->SchedulePaint(view, bounds); | |
60 return true; | |
61 } | |
62 return false; | |
63 } | |
64 | |
65 const mojo::ViewportMetrics& ViewTreeHostImpl::GetViewportMetrics() const { | |
66 return display_manager_->GetViewportMetrics(); | |
67 } | |
68 | |
69 void ViewTreeHostImpl::SetFocusedView(ServerView* new_focused_view) { | |
70 ServerView* old_focused_view = focus_controller_->GetFocusedView(); | |
71 if (old_focused_view == new_focused_view) | |
72 return; | |
73 DCHECK(root_view()->Contains(new_focused_view)); | |
74 focus_controller_->SetFocusedView(new_focused_view); | |
75 // TODO(beng): have the FocusController notify us via FocusControllerDelegate. | |
76 OnFocusChanged(old_focused_view, new_focused_view); | |
77 } | |
78 | |
79 ServerView* ViewTreeHostImpl::GetFocusedView() { | |
80 return focus_controller_->GetFocusedView(); | |
81 } | |
82 | |
83 void ViewTreeHostImpl::DestroyFocusController() { | |
84 focus_controller_.reset(); | |
85 } | |
86 | |
87 void ViewTreeHostImpl::UpdateTextInputState(ServerView* view, | |
88 const ui::TextInputState& state) { | |
89 // Do not need to update text input for unfocused views. | |
90 if (!display_manager_ || focus_controller_->GetFocusedView() != view) | |
91 return; | |
92 display_manager_->UpdateTextInputState(state); | |
93 } | |
94 | |
95 void ViewTreeHostImpl::SetImeVisibility(ServerView* view, bool visible) { | |
96 // Do not need to show or hide IME for unfocused view. | |
97 if (focus_controller_->GetFocusedView() != view) | |
98 return; | |
99 display_manager_->SetImeVisibility(visible); | |
100 } | |
101 | |
102 void ViewTreeHostImpl::OnAccelerator(uint32_t accelerator_id, | |
103 mojo::EventPtr event) { | |
104 client()->OnAccelerator(accelerator_id, event.Pass()); | |
105 } | |
106 | |
107 void ViewTreeHostImpl::DispatchInputEventToView(ServerView* target, | |
108 mojo::EventPtr event) { | |
109 // If the view is an embed root, forward to the embedded view, not the owner. | |
110 ViewTreeImpl* connection = | |
111 connection_manager_->GetConnectionWithRoot(target->id()); | |
112 if (!connection) | |
113 connection = connection_manager_->GetConnection(target->id().connection_id); | |
114 connection->client()->OnViewInputEvent(ViewIdToTransportId(target->id()), | |
115 event.Pass(), | |
116 base::Bind(&base::DoNothing)); | |
117 } | |
118 | |
119 void ViewTreeHostImpl::SetSize(mojo::SizePtr size) { | |
120 display_manager_->SetViewportSize(size.To<gfx::Size>()); | |
121 } | |
122 | |
123 void ViewTreeHostImpl::SetTitle(const mojo::String& title) { | |
124 display_manager_->SetTitle(title.To<base::string16>()); | |
125 } | |
126 | |
127 void ViewTreeHostImpl::AddAccelerator(uint32_t id, | |
128 mojo::KeyboardCode keyboard_code, | |
129 mojo::EventFlags flags) { | |
130 event_dispatcher_.AddAccelerator(id, keyboard_code, flags); | |
131 } | |
132 | |
133 void ViewTreeHostImpl::RemoveAccelerator(uint32_t id) { | |
134 event_dispatcher_.RemoveAccelerator(id); | |
135 } | |
136 | |
137 void ViewTreeHostImpl::OnClientClosed() { | |
138 // |display_manager_.reset()| destroys the display-manager first, and then | |
139 // sets |display_manager_| to nullptr. However, destroying |display_manager_| | |
140 // can destroy the corresponding ViewTreeHostConnection, and |this|. So | |
141 // setting it to nullptr afterwards in reset() ends up writing on free'd | |
142 // memory. So transfer over to a local scoped_ptr<> before destroying it. | |
143 scoped_ptr<DisplayManager> temp = display_manager_.Pass(); | |
144 } | |
145 | |
146 ServerView* ViewTreeHostImpl::GetRootView() { | |
147 return root_.get(); | |
148 } | |
149 | |
150 void ViewTreeHostImpl::OnEvent(mojo::EventPtr event) { | |
151 event_dispatcher_.OnEvent(event.Pass()); | |
152 } | |
153 | |
154 void ViewTreeHostImpl::OnDisplayClosed() { | |
155 if (delegate_) | |
156 delegate_->OnDisplayClosed(); | |
157 } | |
158 | |
159 void ViewTreeHostImpl::OnViewportMetricsChanged( | |
160 const mojo::ViewportMetrics& old_metrics, | |
161 const mojo::ViewportMetrics& new_metrics) { | |
162 if (!root_) { | |
163 root_.reset(connection_manager_->CreateServerView( | |
164 RootViewId(connection_manager_->GetAndAdvanceNextHostId()))); | |
165 root_->SetBounds(gfx::Rect(new_metrics.size_in_pixels.To<gfx::Size>())); | |
166 root_->SetVisible(true); | |
167 if (delegate_) | |
168 delegate_->OnDisplayInitialized(); | |
169 } else { | |
170 root_->SetBounds(gfx::Rect(new_metrics.size_in_pixels.To<gfx::Size>())); | |
171 } | |
172 // TODO(fsamuel): We shouldn't broadcast this to all connections but only | |
173 // those within a window root. | |
174 connection_manager_->ProcessViewportMetricsChanged(old_metrics, new_metrics); | |
175 } | |
176 | |
177 void ViewTreeHostImpl::OnTopLevelSurfaceChanged(cc::SurfaceId surface_id) { | |
178 surface_id_ = surface_id; | |
179 } | |
180 | |
181 void ViewTreeHostImpl::OnFocusChanged(ServerView* old_focused_view, | |
182 ServerView* new_focused_view) { | |
183 // There are up to four connections that need to be notified: | |
184 // . the connection containing |old_focused_view|. | |
185 // . the connection with |old_focused_view| as its root. | |
186 // . the connection containing |new_focused_view|. | |
187 // . the connection with |new_focused_view| as its root. | |
188 // Some of these connections may be the same. The following takes care to | |
189 // notify each only once. | |
190 ViewTreeImpl* owning_connection_old = nullptr; | |
191 ViewTreeImpl* embedded_connection_old = nullptr; | |
192 | |
193 if (old_focused_view) { | |
194 owning_connection_old = connection_manager_->GetConnection( | |
195 old_focused_view->id().connection_id); | |
196 if (owning_connection_old) { | |
197 owning_connection_old->ProcessFocusChanged(old_focused_view, | |
198 new_focused_view); | |
199 } | |
200 embedded_connection_old = | |
201 connection_manager_->GetConnectionWithRoot(old_focused_view->id()); | |
202 if (embedded_connection_old) { | |
203 DCHECK_NE(owning_connection_old, embedded_connection_old); | |
204 embedded_connection_old->ProcessFocusChanged(old_focused_view, | |
205 new_focused_view); | |
206 } | |
207 } | |
208 ViewTreeImpl* owning_connection_new = nullptr; | |
209 ViewTreeImpl* embedded_connection_new = nullptr; | |
210 if (new_focused_view) { | |
211 owning_connection_new = connection_manager_->GetConnection( | |
212 new_focused_view->id().connection_id); | |
213 if (owning_connection_new && | |
214 owning_connection_new != owning_connection_old && | |
215 owning_connection_new != embedded_connection_old) { | |
216 owning_connection_new->ProcessFocusChanged(old_focused_view, | |
217 new_focused_view); | |
218 } | |
219 embedded_connection_new = | |
220 connection_manager_->GetConnectionWithRoot(new_focused_view->id()); | |
221 if (embedded_connection_new && | |
222 embedded_connection_new != owning_connection_old && | |
223 embedded_connection_new != embedded_connection_old) { | |
224 DCHECK_NE(owning_connection_new, embedded_connection_new); | |
225 embedded_connection_new->ProcessFocusChanged(old_focused_view, | |
226 new_focused_view); | |
227 } | |
228 } | |
229 | |
230 // Ensure that we always notify the root connection of a focus change. | |
231 ViewTreeImpl* root_tree = GetViewTree(); | |
232 if (root_tree != owning_connection_old && | |
233 root_tree != embedded_connection_old && | |
234 root_tree != owning_connection_new && | |
235 root_tree != embedded_connection_new) { | |
236 root_tree->ProcessFocusChanged(old_focused_view, new_focused_view); | |
237 } | |
238 | |
239 UpdateTextInputState(new_focused_view, new_focused_view->text_input_state()); | |
240 } | |
241 | |
242 } // namespace mus | |
OLD | NEW |