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 "view_manager/public/cpp/lib/view_manager_client_impl.h" | |
6 | |
7 #include "mojo/public/cpp/application/application_impl.h" | |
8 #include "mojo/public/cpp/application/connect.h" | |
9 #include "mojo/public/cpp/application/service_provider_impl.h" | |
10 #include "mojo/public/interfaces/application/service_provider.mojom.h" | |
11 #include "mojo/public/interfaces/application/shell.mojom.h" | |
12 #include "view_manager/public/cpp/lib/view_private.h" | |
13 #include "view_manager/public/cpp/util.h" | |
14 #include "view_manager/public/cpp/view_manager_delegate.h" | |
15 #include "view_manager/public/cpp/view_observer.h" | |
16 | |
17 namespace mojo { | |
18 | |
19 Id MakeTransportId(ConnectionSpecificId connection_id, | |
20 ConnectionSpecificId local_id) { | |
21 return (connection_id << 16) | local_id; | |
22 } | |
23 | |
24 // Helper called to construct a local view object from transport data. | |
25 View* AddViewToViewManager(ViewManagerClientImpl* client, | |
26 View* parent, | |
27 const ViewDataPtr& view_data) { | |
28 // We don't use the ctor that takes a ViewManager here, since it will call | |
29 // back to the service and attempt to create a new view. | |
30 View* view = ViewPrivate::LocalCreate(); | |
31 ViewPrivate private_view(view); | |
32 private_view.set_view_manager(client); | |
33 private_view.set_id(view_data->view_id); | |
34 private_view.set_visible(view_data->visible); | |
35 private_view.set_drawn(view_data->drawn); | |
36 private_view.LocalSetViewportMetrics(ViewportMetrics(), | |
37 *view_data->viewport_metrics); | |
38 private_view.set_properties( | |
39 view_data->properties.To<std::map<std::string, std::vector<uint8_t>>>()); | |
40 client->AddView(view); | |
41 private_view.LocalSetBounds(Rect(), *view_data->bounds); | |
42 if (parent) | |
43 ViewPrivate(parent).LocalAddChild(view); | |
44 return view; | |
45 } | |
46 | |
47 View* BuildViewTree(ViewManagerClientImpl* client, | |
48 const Array<ViewDataPtr>& views, | |
49 View* initial_parent) { | |
50 std::vector<View*> parents; | |
51 View* root = NULL; | |
52 View* last_view = NULL; | |
53 if (initial_parent) | |
54 parents.push_back(initial_parent); | |
55 for (size_t i = 0; i < views.size(); ++i) { | |
56 if (last_view && views[i]->parent_id == last_view->id()) { | |
57 parents.push_back(last_view); | |
58 } else if (!parents.empty()) { | |
59 while (parents.back()->id() != views[i]->parent_id) | |
60 parents.pop_back(); | |
61 } | |
62 View* view = AddViewToViewManager( | |
63 client, !parents.empty() ? parents.back() : NULL, views[i]); | |
64 if (!last_view) | |
65 root = view; | |
66 last_view = view; | |
67 } | |
68 return root; | |
69 } | |
70 | |
71 // Responsible for removing a root from the ViewManager when that view is | |
72 // destroyed. | |
73 class RootObserver : public ViewObserver { | |
74 public: | |
75 explicit RootObserver(View* root) : root_(root) {} | |
76 ~RootObserver() override {} | |
77 | |
78 private: | |
79 // Overridden from ViewObserver: | |
80 void OnViewDestroyed(View* view) override { | |
81 DCHECK_EQ(view, root_); | |
82 static_cast<ViewManagerClientImpl*>(root_->view_manager()) | |
83 ->RootDestroyed(root_); | |
84 view->RemoveObserver(this); | |
85 delete this; | |
86 } | |
87 | |
88 View* root_; | |
89 | |
90 MOJO_DISALLOW_COPY_AND_ASSIGN(RootObserver); | |
91 }; | |
92 | |
93 ViewManagerClientImpl::ViewManagerClientImpl( | |
94 ViewManagerDelegate* delegate, | |
95 Shell* shell, | |
96 InterfaceRequest<ViewManagerClient> request, | |
97 bool delete_on_error) | |
98 : connection_id_(0), | |
99 next_id_(1), | |
100 delegate_(delegate), | |
101 root_(nullptr), | |
102 capture_view_(nullptr), | |
103 focused_view_(nullptr), | |
104 activated_view_(nullptr), | |
105 wm_observer_binding_(this), | |
106 binding_(this, request.Pass()) { | |
107 if (delete_on_error) | |
108 binding_.set_connection_error_handler([this]() { delete this; }); | |
109 } | |
110 | |
111 ViewManagerClientImpl::~ViewManagerClientImpl() { | |
112 std::vector<View*> non_owned; | |
113 while (!views_.empty()) { | |
114 IdToViewMap::iterator it = views_.begin(); | |
115 if (OwnsView(it->second->id())) { | |
116 it->second->Destroy(); | |
117 } else { | |
118 non_owned.push_back(it->second); | |
119 views_.erase(it); | |
120 } | |
121 } | |
122 // Delete the non-owned views last. In the typical case these are roots. The | |
123 // exception is the window manager, which may know aboutother random views | |
124 // that it doesn't own. | |
125 // NOTE: we manually delete as we're a friend. | |
126 for (size_t i = 0; i < non_owned.size(); ++i) | |
127 delete non_owned[i]; | |
128 | |
129 delegate_->OnViewManagerDisconnected(this); | |
130 } | |
131 | |
132 void ViewManagerClientImpl::DestroyView(Id view_id) { | |
133 DCHECK(service_); | |
134 service_->DeleteView(view_id, ActionCompletedCallback()); | |
135 } | |
136 | |
137 void ViewManagerClientImpl::AddChild(Id child_id, Id parent_id) { | |
138 DCHECK(service_); | |
139 service_->AddView(parent_id, child_id, ActionCompletedCallback()); | |
140 } | |
141 | |
142 void ViewManagerClientImpl::RemoveChild(Id child_id, Id parent_id) { | |
143 DCHECK(service_); | |
144 service_->RemoveViewFromParent(child_id, ActionCompletedCallback()); | |
145 } | |
146 | |
147 void ViewManagerClientImpl::Reorder( | |
148 Id view_id, | |
149 Id relative_view_id, | |
150 OrderDirection direction) { | |
151 DCHECK(service_); | |
152 service_->ReorderView(view_id, relative_view_id, direction, | |
153 ActionCompletedCallback()); | |
154 } | |
155 | |
156 bool ViewManagerClientImpl::OwnsView(Id id) const { | |
157 return HiWord(id) == connection_id_; | |
158 } | |
159 | |
160 void ViewManagerClientImpl::SetBounds(Id view_id, const Rect& bounds) { | |
161 DCHECK(service_); | |
162 service_->SetViewBounds(view_id, bounds.Clone(), ActionCompletedCallback()); | |
163 } | |
164 | |
165 void ViewManagerClientImpl::SetSurfaceId(Id view_id, SurfaceIdPtr surface_id) { | |
166 DCHECK(service_); | |
167 if (surface_id.is_null()) | |
168 return; | |
169 service_->SetViewSurfaceId( | |
170 view_id, surface_id.Pass(), ActionCompletedCallback()); | |
171 } | |
172 | |
173 void ViewManagerClientImpl::SetFocus(Id view_id) { | |
174 // In order for us to get here we had to have exposed a view, which implies we | |
175 // got a connection. | |
176 DCHECK(service_); | |
177 service_->PerformAction(view_id, "focus", ActionCompletedCallback()); | |
178 } | |
179 | |
180 void ViewManagerClientImpl::SetVisible(Id view_id, bool visible) { | |
181 DCHECK(service_); | |
182 service_->SetViewVisibility(view_id, visible, ActionCompletedCallback()); | |
183 } | |
184 | |
185 void ViewManagerClientImpl::SetProperty( | |
186 Id view_id, | |
187 const std::string& name, | |
188 const std::vector<uint8_t>& data) { | |
189 DCHECK(service_); | |
190 service_->SetViewProperty(view_id, | |
191 String(name), | |
192 Array<uint8_t>::From(data), | |
193 ActionCompletedCallback()); | |
194 } | |
195 | |
196 void ViewManagerClientImpl::Embed(const String& url, Id view_id) { | |
197 Embed(url, view_id, nullptr, nullptr); | |
198 } | |
199 | |
200 void ViewManagerClientImpl::Embed(const String& url, | |
201 Id view_id, | |
202 InterfaceRequest<ServiceProvider> services, | |
203 ServiceProviderPtr exposed_services) { | |
204 DCHECK(service_); | |
205 service_->EmbedUrl(url, view_id, services.Pass(), exposed_services.Pass(), | |
206 ActionCompletedCallback()); | |
207 } | |
208 | |
209 void ViewManagerClientImpl::Embed(Id view_id, ViewManagerClientPtr client) { | |
210 DCHECK(service_); | |
211 service_->Embed(view_id, client.Pass(), ActionCompletedCallback()); | |
212 } | |
213 | |
214 void ViewManagerClientImpl::AddView(View* view) { | |
215 DCHECK(views_.find(view->id()) == views_.end()); | |
216 views_[view->id()] = view; | |
217 } | |
218 | |
219 void ViewManagerClientImpl::RemoveView(Id view_id) { | |
220 if (focused_view_ && focused_view_->id() == view_id) | |
221 OnFocusChanged(0); | |
222 if (capture_view_ && capture_view_->id() == view_id) | |
223 OnCaptureChanged(0); | |
224 if (activated_view_ && activated_view_->id() == view_id) | |
225 OnActiveWindowChanged(0); | |
226 | |
227 IdToViewMap::iterator it = views_.find(view_id); | |
228 if (it != views_.end()) | |
229 views_.erase(it); | |
230 } | |
231 | |
232 void ViewManagerClientImpl::SetViewManagerService( | |
233 ViewManagerServicePtr service) { | |
234 DCHECK(!service_); | |
235 DCHECK(service); | |
236 service_ = service.Pass(); | |
237 } | |
238 //////////////////////////////////////////////////////////////////////////////// | |
239 // ViewManagerClientImpl, ViewManager implementation: | |
240 | |
241 Id ViewManagerClientImpl::CreateViewOnServer() { | |
242 DCHECK(service_); | |
243 const Id view_id = MakeTransportId(connection_id_, ++next_id_); | |
244 service_->CreateView(view_id, [this](ErrorCode code) { | |
245 OnActionCompleted(code == ErrorCode::NONE); | |
246 }); | |
247 return view_id; | |
248 } | |
249 | |
250 const std::string& ViewManagerClientImpl::GetEmbedderURL() const { | |
251 return creator_url_; | |
252 } | |
253 | |
254 View* ViewManagerClientImpl::GetRoot() { | |
255 return root_; | |
256 } | |
257 | |
258 View* ViewManagerClientImpl::GetViewById(Id id) { | |
259 IdToViewMap::const_iterator it = views_.find(id); | |
260 return it != views_.end() ? it->second : NULL; | |
261 } | |
262 | |
263 View* ViewManagerClientImpl::GetFocusedView() { | |
264 return focused_view_; | |
265 } | |
266 | |
267 View* ViewManagerClientImpl::CreateView() { | |
268 View* view = new View(this, CreateViewOnServer()); | |
269 AddView(view); | |
270 return view; | |
271 } | |
272 | |
273 //////////////////////////////////////////////////////////////////////////////// | |
274 // ViewManagerClientImpl, ViewManagerClient implementation: | |
275 | |
276 void ViewManagerClientImpl::OnEmbed( | |
277 ConnectionSpecificId connection_id, | |
278 const String& creator_url, | |
279 ViewDataPtr root_data, | |
280 ViewManagerServicePtr view_manager_service, | |
281 InterfaceRequest<ServiceProvider> services, | |
282 ServiceProviderPtr exposed_services, | |
283 ScopedMessagePipeHandle window_manager_pipe) { | |
284 if (view_manager_service) { | |
285 DCHECK(!service_); | |
286 service_ = view_manager_service.Pass(); | |
287 } | |
288 connection_id_ = connection_id; | |
289 creator_url_ = String::From(creator_url); | |
290 | |
291 DCHECK(!root_); | |
292 root_ = AddViewToViewManager(this, nullptr, root_data); | |
293 root_->AddObserver(new RootObserver(root_)); | |
294 | |
295 window_manager_.Bind( | |
296 InterfacePtrInfo<WindowManager>(window_manager_pipe.Pass(), 0u)); | |
297 WindowManagerObserverPtr observer; | |
298 wm_observer_binding_.Bind(GetProxy(&observer)); | |
299 // binding to |this| is safe here as |window_manager_| is bound to our | |
300 // lifetime. | |
301 window_manager_->GetFocusedAndActiveViews( | |
302 observer.Pass(), | |
303 [this](uint32_t capture_view_id, uint32_t focused_view_id, | |
304 uint32_t active_view_id) { | |
305 if (GetViewById(capture_view_id) != capture_view_) | |
306 OnCaptureChanged(capture_view_id); | |
307 if (GetViewById(focused_view_id) != focused_view_) | |
308 OnFocusChanged(focused_view_id); | |
309 if (GetViewById(active_view_id) != activated_view_) | |
310 OnActiveWindowChanged(active_view_id); | |
311 }); | |
312 | |
313 delegate_->OnEmbed(root_, services.Pass(), exposed_services.Pass()); | |
314 } | |
315 | |
316 void ViewManagerClientImpl::OnEmbeddedAppDisconnected(Id view_id) { | |
317 View* view = GetViewById(view_id); | |
318 if (view) { | |
319 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(), | |
320 OnViewEmbeddedAppDisconnected(view)); | |
321 } | |
322 } | |
323 | |
324 void ViewManagerClientImpl::OnViewBoundsChanged(Id view_id, | |
325 RectPtr old_bounds, | |
326 RectPtr new_bounds) { | |
327 View* view = GetViewById(view_id); | |
328 ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds); | |
329 } | |
330 | |
331 namespace { | |
332 | |
333 void SetViewportMetricsOnDecendants(View* root, | |
334 const ViewportMetrics& old_metrics, | |
335 const ViewportMetrics& new_metrics) { | |
336 ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics); | |
337 const View::Children& children = root->children(); | |
338 for (size_t i = 0; i < children.size(); ++i) | |
339 SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics); | |
340 } | |
341 } | |
342 | |
343 void ViewManagerClientImpl::OnViewViewportMetricsChanged( | |
344 ViewportMetricsPtr old_metrics, | |
345 ViewportMetricsPtr new_metrics) { | |
346 View* view = GetRoot(); | |
347 if (view) | |
348 SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics); | |
349 } | |
350 | |
351 void ViewManagerClientImpl::OnViewHierarchyChanged( | |
352 Id view_id, | |
353 Id new_parent_id, | |
354 Id old_parent_id, | |
355 mojo::Array<ViewDataPtr> views) { | |
356 View* initial_parent = views.size() ? | |
357 GetViewById(views[0]->parent_id) : NULL; | |
358 | |
359 BuildViewTree(this, views, initial_parent); | |
360 | |
361 View* new_parent = GetViewById(new_parent_id); | |
362 View* old_parent = GetViewById(old_parent_id); | |
363 View* view = GetViewById(view_id); | |
364 if (new_parent) | |
365 ViewPrivate(new_parent).LocalAddChild(view); | |
366 else | |
367 ViewPrivate(old_parent).LocalRemoveChild(view); | |
368 } | |
369 | |
370 void ViewManagerClientImpl::OnViewReordered(Id view_id, | |
371 Id relative_view_id, | |
372 OrderDirection direction) { | |
373 View* view = GetViewById(view_id); | |
374 View* relative_view = GetViewById(relative_view_id); | |
375 if (view && relative_view) | |
376 ViewPrivate(view).LocalReorder(relative_view, direction); | |
377 } | |
378 | |
379 void ViewManagerClientImpl::OnViewDeleted(Id view_id) { | |
380 View* view = GetViewById(view_id); | |
381 if (view) | |
382 ViewPrivate(view).LocalDestroy(); | |
383 } | |
384 | |
385 void ViewManagerClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) { | |
386 // TODO(sky): there is a race condition here. If this client and another | |
387 // client change the visibility at the same time the wrong value may be set. | |
388 // Deal with this some how. | |
389 View* view = GetViewById(view_id); | |
390 if (view) | |
391 ViewPrivate(view).LocalSetVisible(visible); | |
392 } | |
393 | |
394 void ViewManagerClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) { | |
395 View* view = GetViewById(view_id); | |
396 if (view) | |
397 ViewPrivate(view).LocalSetDrawn(drawn); | |
398 } | |
399 | |
400 void ViewManagerClientImpl::OnViewSharedPropertyChanged( | |
401 Id view_id, | |
402 const String& name, | |
403 Array<uint8_t> new_data) { | |
404 View* view = GetViewById(view_id); | |
405 if (view) { | |
406 std::vector<uint8_t> data; | |
407 std::vector<uint8_t>* data_ptr = NULL; | |
408 if (!new_data.is_null()) { | |
409 data = new_data.To<std::vector<uint8_t>>(); | |
410 data_ptr = &data; | |
411 } | |
412 | |
413 view->SetSharedProperty(name, data_ptr); | |
414 } | |
415 } | |
416 | |
417 void ViewManagerClientImpl::OnViewInputEvent( | |
418 Id view_id, | |
419 EventPtr event, | |
420 const Callback<void()>& ack_callback) { | |
421 View* view = GetViewById(view_id); | |
422 if (view) { | |
423 FOR_EACH_OBSERVER(ViewObserver, | |
424 *ViewPrivate(view).observers(), | |
425 OnViewInputEvent(view, event)); | |
426 } | |
427 ack_callback.Run(); | |
428 } | |
429 | |
430 void ViewManagerClientImpl::OnPerformAction( | |
431 Id view_id, | |
432 const String& name, | |
433 const Callback<void(bool)>& callback) { | |
434 View* view = GetViewById(view_id); | |
435 callback.Run(delegate_->OnPerformAction(view, name)); | |
436 } | |
437 | |
438 //////////////////////////////////////////////////////////////////////////////// | |
439 // ViewManagerClientImpl, WindowManagerObserver implementation: | |
440 | |
441 void ViewManagerClientImpl::OnCaptureChanged(Id capture_view_id) { | |
442 View* gained_capture = GetViewById(capture_view_id); | |
443 View* lost_capture = capture_view_; | |
444 if (lost_capture) { | |
445 FOR_EACH_OBSERVER(ViewObserver, | |
446 *ViewPrivate(lost_capture).observers(), | |
447 OnViewFocusChanged(gained_capture, lost_capture)); | |
448 } | |
449 capture_view_ = gained_capture; | |
450 if (gained_capture) { | |
451 FOR_EACH_OBSERVER(ViewObserver, | |
452 *ViewPrivate(gained_capture).observers(), | |
453 OnViewFocusChanged(gained_capture, lost_capture)); | |
454 } | |
455 } | |
456 | |
457 void ViewManagerClientImpl::OnFocusChanged(Id focused_view_id) { | |
458 View* focused = GetViewById(focused_view_id); | |
459 View* blurred = focused_view_; | |
460 if (blurred) { | |
461 FOR_EACH_OBSERVER(ViewObserver, | |
462 *ViewPrivate(blurred).observers(), | |
463 OnViewFocusChanged(focused, blurred)); | |
464 } | |
465 focused_view_ = focused; | |
466 if (focused) { | |
467 FOR_EACH_OBSERVER(ViewObserver, | |
468 *ViewPrivate(focused).observers(), | |
469 OnViewFocusChanged(focused, blurred)); | |
470 } | |
471 } | |
472 | |
473 void ViewManagerClientImpl::OnActiveWindowChanged(Id active_view_id) { | |
474 View* activated = GetViewById(active_view_id); | |
475 View* deactivated = activated_view_; | |
476 if (deactivated) { | |
477 FOR_EACH_OBSERVER(ViewObserver, | |
478 *ViewPrivate(deactivated).observers(), | |
479 OnViewActivationChanged(activated, deactivated)); | |
480 } | |
481 activated_view_ = activated; | |
482 if (activated) { | |
483 FOR_EACH_OBSERVER(ViewObserver, | |
484 *ViewPrivate(activated).observers(), | |
485 OnViewActivationChanged(activated, deactivated)); | |
486 } | |
487 } | |
488 | |
489 //////////////////////////////////////////////////////////////////////////////// | |
490 // ViewManagerClientImpl, private: | |
491 | |
492 void ViewManagerClientImpl::RootDestroyed(View* root) { | |
493 DCHECK_EQ(root, root_); | |
494 root_ = nullptr; | |
495 } | |
496 | |
497 void ViewManagerClientImpl::OnActionCompleted(bool success) { | |
498 if (!change_acked_callback_.is_null()) | |
499 change_acked_callback_.Run(); | |
500 } | |
501 | |
502 Callback<void(bool)> ViewManagerClientImpl::ActionCompletedCallback() { | |
503 return [this](bool success) { OnActionCompleted(success); }; | |
504 } | |
505 | |
506 } // namespace mojo | |
OLD | NEW |