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