| 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/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/cpp/lib/view_private.h" |
| 13 #include "view_manager/cpp/util.h" |
| 14 #include "view_manager/cpp/view_manager_delegate.h" |
| 15 #include "view_manager/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(Id view_id, |
| 148 Id relative_view_id, |
| 149 OrderDirection direction) { |
| 150 DCHECK(service_); |
| 151 service_->ReorderView(view_id, relative_view_id, direction, |
| 152 ActionCompletedCallback()); |
| 153 } |
| 154 |
| 155 bool ViewManagerClientImpl::OwnsView(Id id) const { |
| 156 return HiWord(id) == connection_id_; |
| 157 } |
| 158 |
| 159 void ViewManagerClientImpl::SetBounds(Id view_id, const Rect& bounds) { |
| 160 DCHECK(service_); |
| 161 service_->SetViewBounds(view_id, bounds.Clone(), ActionCompletedCallback()); |
| 162 } |
| 163 |
| 164 void ViewManagerClientImpl::SetSurfaceId(Id view_id, SurfaceIdPtr surface_id) { |
| 165 DCHECK(service_); |
| 166 if (surface_id.is_null()) |
| 167 return; |
| 168 service_->SetViewSurfaceId(view_id, surface_id.Pass(), |
| 169 ActionCompletedCallback()); |
| 170 } |
| 171 |
| 172 void ViewManagerClientImpl::SetFocus(Id view_id) { |
| 173 // In order for us to get here we had to have exposed a view, which implies we |
| 174 // got a connection. |
| 175 DCHECK(service_); |
| 176 service_->PerformAction(view_id, "focus", ActionCompletedCallback()); |
| 177 } |
| 178 |
| 179 void ViewManagerClientImpl::SetVisible(Id view_id, bool visible) { |
| 180 DCHECK(service_); |
| 181 service_->SetViewVisibility(view_id, visible, ActionCompletedCallback()); |
| 182 } |
| 183 |
| 184 void ViewManagerClientImpl::SetProperty(Id view_id, |
| 185 const std::string& name, |
| 186 const std::vector<uint8_t>& data) { |
| 187 DCHECK(service_); |
| 188 service_->SetViewProperty(view_id, String(name), Array<uint8_t>::From(data), |
| 189 ActionCompletedCallback()); |
| 190 } |
| 191 |
| 192 void ViewManagerClientImpl::Embed(const String& url, Id view_id) { |
| 193 Embed(url, view_id, nullptr, nullptr); |
| 194 } |
| 195 |
| 196 void ViewManagerClientImpl::Embed(const String& url, |
| 197 Id view_id, |
| 198 InterfaceRequest<ServiceProvider> services, |
| 199 ServiceProviderPtr exposed_services) { |
| 200 DCHECK(service_); |
| 201 service_->EmbedUrl(url, view_id, services.Pass(), exposed_services.Pass(), |
| 202 ActionCompletedCallback()); |
| 203 } |
| 204 |
| 205 void ViewManagerClientImpl::Embed(Id view_id, ViewManagerClientPtr client) { |
| 206 DCHECK(service_); |
| 207 service_->Embed(view_id, client.Pass(), ActionCompletedCallback()); |
| 208 } |
| 209 |
| 210 void ViewManagerClientImpl::AddView(View* view) { |
| 211 DCHECK(views_.find(view->id()) == views_.end()); |
| 212 views_[view->id()] = view; |
| 213 } |
| 214 |
| 215 void ViewManagerClientImpl::RemoveView(Id view_id) { |
| 216 if (focused_view_ && focused_view_->id() == view_id) |
| 217 OnFocusChanged(0); |
| 218 if (capture_view_ && capture_view_->id() == view_id) |
| 219 OnCaptureChanged(0); |
| 220 if (activated_view_ && activated_view_->id() == view_id) |
| 221 OnActiveWindowChanged(0); |
| 222 |
| 223 IdToViewMap::iterator it = views_.find(view_id); |
| 224 if (it != views_.end()) |
| 225 views_.erase(it); |
| 226 } |
| 227 |
| 228 void ViewManagerClientImpl::SetViewManagerService( |
| 229 ViewManagerServicePtr service) { |
| 230 DCHECK(!service_); |
| 231 DCHECK(service); |
| 232 service_ = service.Pass(); |
| 233 } |
| 234 //////////////////////////////////////////////////////////////////////////////// |
| 235 // ViewManagerClientImpl, ViewManager implementation: |
| 236 |
| 237 Id ViewManagerClientImpl::CreateViewOnServer() { |
| 238 DCHECK(service_); |
| 239 const Id view_id = MakeTransportId(connection_id_, ++next_id_); |
| 240 service_->CreateView(view_id, [this](ErrorCode code) { |
| 241 OnActionCompleted(code == ErrorCode::NONE); |
| 242 }); |
| 243 return view_id; |
| 244 } |
| 245 |
| 246 const std::string& ViewManagerClientImpl::GetEmbedderURL() const { |
| 247 return creator_url_; |
| 248 } |
| 249 |
| 250 View* ViewManagerClientImpl::GetRoot() { |
| 251 return root_; |
| 252 } |
| 253 |
| 254 View* ViewManagerClientImpl::GetViewById(Id id) { |
| 255 IdToViewMap::const_iterator it = views_.find(id); |
| 256 return it != views_.end() ? it->second : NULL; |
| 257 } |
| 258 |
| 259 View* ViewManagerClientImpl::GetFocusedView() { |
| 260 return focused_view_; |
| 261 } |
| 262 |
| 263 View* ViewManagerClientImpl::CreateView() { |
| 264 View* view = new View(this, CreateViewOnServer()); |
| 265 AddView(view); |
| 266 return view; |
| 267 } |
| 268 |
| 269 //////////////////////////////////////////////////////////////////////////////// |
| 270 // ViewManagerClientImpl, ViewManagerClient implementation: |
| 271 |
| 272 void ViewManagerClientImpl::OnEmbed( |
| 273 ConnectionSpecificId connection_id, |
| 274 const String& creator_url, |
| 275 ViewDataPtr root_data, |
| 276 ViewManagerServicePtr view_manager_service, |
| 277 InterfaceRequest<ServiceProvider> services, |
| 278 ServiceProviderPtr exposed_services, |
| 279 ScopedMessagePipeHandle window_manager_pipe) { |
| 280 if (view_manager_service) { |
| 281 DCHECK(!service_); |
| 282 service_ = view_manager_service.Pass(); |
| 283 } |
| 284 connection_id_ = connection_id; |
| 285 creator_url_ = String::From(creator_url); |
| 286 |
| 287 DCHECK(!root_); |
| 288 root_ = AddViewToViewManager(this, nullptr, root_data); |
| 289 root_->AddObserver(new RootObserver(root_)); |
| 290 |
| 291 window_manager_.Bind( |
| 292 InterfacePtrInfo<WindowManager>(window_manager_pipe.Pass(), 0u)); |
| 293 WindowManagerObserverPtr observer; |
| 294 wm_observer_binding_.Bind(GetProxy(&observer)); |
| 295 // binding to |this| is safe here as |window_manager_| is bound to our |
| 296 // lifetime. |
| 297 window_manager_->GetFocusedAndActiveViews( |
| 298 observer.Pass(), |
| 299 [this](uint32_t capture_view_id, uint32_t focused_view_id, |
| 300 uint32_t active_view_id) { |
| 301 if (GetViewById(capture_view_id) != capture_view_) |
| 302 OnCaptureChanged(capture_view_id); |
| 303 if (GetViewById(focused_view_id) != focused_view_) |
| 304 OnFocusChanged(focused_view_id); |
| 305 if (GetViewById(active_view_id) != activated_view_) |
| 306 OnActiveWindowChanged(active_view_id); |
| 307 }); |
| 308 |
| 309 delegate_->OnEmbed(root_, services.Pass(), exposed_services.Pass()); |
| 310 } |
| 311 |
| 312 void ViewManagerClientImpl::OnEmbeddedAppDisconnected(Id view_id) { |
| 313 View* view = GetViewById(view_id); |
| 314 if (view) { |
| 315 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(), |
| 316 OnViewEmbeddedAppDisconnected(view)); |
| 317 } |
| 318 } |
| 319 |
| 320 void ViewManagerClientImpl::OnViewBoundsChanged(Id view_id, |
| 321 RectPtr old_bounds, |
| 322 RectPtr new_bounds) { |
| 323 View* view = GetViewById(view_id); |
| 324 ViewPrivate(view).LocalSetBounds(*old_bounds, *new_bounds); |
| 325 } |
| 326 |
| 327 namespace { |
| 328 |
| 329 void SetViewportMetricsOnDecendants(View* root, |
| 330 const ViewportMetrics& old_metrics, |
| 331 const ViewportMetrics& new_metrics) { |
| 332 ViewPrivate(root).LocalSetViewportMetrics(old_metrics, new_metrics); |
| 333 const View::Children& children = root->children(); |
| 334 for (size_t i = 0; i < children.size(); ++i) |
| 335 SetViewportMetricsOnDecendants(children[i], old_metrics, new_metrics); |
| 336 } |
| 337 } |
| 338 |
| 339 void ViewManagerClientImpl::OnViewViewportMetricsChanged( |
| 340 ViewportMetricsPtr old_metrics, |
| 341 ViewportMetricsPtr new_metrics) { |
| 342 View* view = GetRoot(); |
| 343 if (view) |
| 344 SetViewportMetricsOnDecendants(view, *old_metrics, *new_metrics); |
| 345 } |
| 346 |
| 347 void ViewManagerClientImpl::OnViewHierarchyChanged( |
| 348 Id view_id, |
| 349 Id new_parent_id, |
| 350 Id old_parent_id, |
| 351 mojo::Array<ViewDataPtr> views) { |
| 352 View* initial_parent = views.size() ? GetViewById(views[0]->parent_id) : NULL; |
| 353 |
| 354 BuildViewTree(this, views, initial_parent); |
| 355 |
| 356 View* new_parent = GetViewById(new_parent_id); |
| 357 View* old_parent = GetViewById(old_parent_id); |
| 358 View* view = GetViewById(view_id); |
| 359 if (new_parent) |
| 360 ViewPrivate(new_parent).LocalAddChild(view); |
| 361 else |
| 362 ViewPrivate(old_parent).LocalRemoveChild(view); |
| 363 } |
| 364 |
| 365 void ViewManagerClientImpl::OnViewReordered(Id view_id, |
| 366 Id relative_view_id, |
| 367 OrderDirection direction) { |
| 368 View* view = GetViewById(view_id); |
| 369 View* relative_view = GetViewById(relative_view_id); |
| 370 if (view && relative_view) |
| 371 ViewPrivate(view).LocalReorder(relative_view, direction); |
| 372 } |
| 373 |
| 374 void ViewManagerClientImpl::OnViewDeleted(Id view_id) { |
| 375 View* view = GetViewById(view_id); |
| 376 if (view) |
| 377 ViewPrivate(view).LocalDestroy(); |
| 378 } |
| 379 |
| 380 void ViewManagerClientImpl::OnViewVisibilityChanged(Id view_id, bool visible) { |
| 381 // TODO(sky): there is a race condition here. If this client and another |
| 382 // client change the visibility at the same time the wrong value may be set. |
| 383 // Deal with this some how. |
| 384 View* view = GetViewById(view_id); |
| 385 if (view) |
| 386 ViewPrivate(view).LocalSetVisible(visible); |
| 387 } |
| 388 |
| 389 void ViewManagerClientImpl::OnViewDrawnStateChanged(Id view_id, bool drawn) { |
| 390 View* view = GetViewById(view_id); |
| 391 if (view) |
| 392 ViewPrivate(view).LocalSetDrawn(drawn); |
| 393 } |
| 394 |
| 395 void ViewManagerClientImpl::OnViewSharedPropertyChanged( |
| 396 Id view_id, |
| 397 const String& name, |
| 398 Array<uint8_t> new_data) { |
| 399 View* view = GetViewById(view_id); |
| 400 if (view) { |
| 401 std::vector<uint8_t> data; |
| 402 std::vector<uint8_t>* data_ptr = NULL; |
| 403 if (!new_data.is_null()) { |
| 404 data = new_data.To<std::vector<uint8_t>>(); |
| 405 data_ptr = &data; |
| 406 } |
| 407 |
| 408 view->SetSharedProperty(name, data_ptr); |
| 409 } |
| 410 } |
| 411 |
| 412 void ViewManagerClientImpl::OnViewInputEvent( |
| 413 Id view_id, |
| 414 EventPtr event, |
| 415 const Callback<void()>& ack_callback) { |
| 416 View* view = GetViewById(view_id); |
| 417 if (view) { |
| 418 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(view).observers(), |
| 419 OnViewInputEvent(view, event)); |
| 420 } |
| 421 ack_callback.Run(); |
| 422 } |
| 423 |
| 424 void ViewManagerClientImpl::OnPerformAction( |
| 425 Id view_id, |
| 426 const String& name, |
| 427 const Callback<void(bool)>& callback) { |
| 428 View* view = GetViewById(view_id); |
| 429 callback.Run(delegate_->OnPerformAction(view, name)); |
| 430 } |
| 431 |
| 432 //////////////////////////////////////////////////////////////////////////////// |
| 433 // ViewManagerClientImpl, WindowManagerObserver implementation: |
| 434 |
| 435 void ViewManagerClientImpl::OnCaptureChanged(Id capture_view_id) { |
| 436 View* gained_capture = GetViewById(capture_view_id); |
| 437 View* lost_capture = capture_view_; |
| 438 if (lost_capture) { |
| 439 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(lost_capture).observers(), |
| 440 OnViewFocusChanged(gained_capture, lost_capture)); |
| 441 } |
| 442 capture_view_ = gained_capture; |
| 443 if (gained_capture) { |
| 444 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(gained_capture).observers(), |
| 445 OnViewFocusChanged(gained_capture, lost_capture)); |
| 446 } |
| 447 } |
| 448 |
| 449 void ViewManagerClientImpl::OnFocusChanged(Id focused_view_id) { |
| 450 View* focused = GetViewById(focused_view_id); |
| 451 View* blurred = focused_view_; |
| 452 if (blurred) { |
| 453 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(blurred).observers(), |
| 454 OnViewFocusChanged(focused, blurred)); |
| 455 } |
| 456 focused_view_ = focused; |
| 457 if (focused) { |
| 458 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(focused).observers(), |
| 459 OnViewFocusChanged(focused, blurred)); |
| 460 } |
| 461 } |
| 462 |
| 463 void ViewManagerClientImpl::OnActiveWindowChanged(Id active_view_id) { |
| 464 View* activated = GetViewById(active_view_id); |
| 465 View* deactivated = activated_view_; |
| 466 if (deactivated) { |
| 467 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(deactivated).observers(), |
| 468 OnViewActivationChanged(activated, deactivated)); |
| 469 } |
| 470 activated_view_ = activated; |
| 471 if (activated) { |
| 472 FOR_EACH_OBSERVER(ViewObserver, *ViewPrivate(activated).observers(), |
| 473 OnViewActivationChanged(activated, deactivated)); |
| 474 } |
| 475 } |
| 476 |
| 477 //////////////////////////////////////////////////////////////////////////////// |
| 478 // ViewManagerClientImpl, private: |
| 479 |
| 480 void ViewManagerClientImpl::RootDestroyed(View* root) { |
| 481 DCHECK_EQ(root, root_); |
| 482 root_ = nullptr; |
| 483 } |
| 484 |
| 485 void ViewManagerClientImpl::OnActionCompleted(bool success) { |
| 486 if (!change_acked_callback_.is_null()) |
| 487 change_acked_callback_.Run(); |
| 488 } |
| 489 |
| 490 Callback<void(bool)> ViewManagerClientImpl::ActionCompletedCallback() { |
| 491 return [this](bool success) { OnActionCompleted(success); }; |
| 492 } |
| 493 |
| 494 } // namespace mojo |
| OLD | NEW |