| 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 "services/ui/public/cpp/window.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <set> | |
| 11 #include <string> | |
| 12 | |
| 13 #include "base/bind.h" | |
| 14 #include "base/macros.h" | |
| 15 #include "services/ui/common/transient_window_utils.h" | |
| 16 #include "services/ui/public/cpp/property_type_converters.h" | |
| 17 #include "services/ui/public/cpp/window_compositor_frame_sink.h" | |
| 18 #include "services/ui/public/cpp/window_observer.h" | |
| 19 #include "services/ui/public/cpp/window_private.h" | |
| 20 #include "services/ui/public/cpp/window_property.h" | |
| 21 #include "services/ui/public/cpp/window_tracker.h" | |
| 22 #include "services/ui/public/cpp/window_tree_client.h" | |
| 23 #include "services/ui/public/interfaces/window_manager.mojom.h" | |
| 24 #include "ui/display/display.h" | |
| 25 #include "ui/display/types/display_constants.h" | |
| 26 #include "ui/gfx/geometry/rect.h" | |
| 27 #include "ui/gfx/geometry/size.h" | |
| 28 | |
| 29 namespace ui { | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 void NotifyWindowTreeChangeAtReceiver( | |
| 34 Window* receiver, | |
| 35 const WindowObserver::TreeChangeParams& params, | |
| 36 bool change_applied) { | |
| 37 WindowObserver::TreeChangeParams local_params = params; | |
| 38 local_params.receiver = receiver; | |
| 39 if (change_applied) { | |
| 40 for (auto& observer : *WindowPrivate(receiver).observers()) | |
| 41 observer.OnTreeChanged(local_params); | |
| 42 } else { | |
| 43 for (auto& observer : *WindowPrivate(receiver).observers()) | |
| 44 observer.OnTreeChanging(local_params); | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 void NotifyWindowTreeChangeUp(Window* start_at, | |
| 49 const WindowObserver::TreeChangeParams& params, | |
| 50 bool change_applied) { | |
| 51 for (Window* current = start_at; current; current = current->parent()) | |
| 52 NotifyWindowTreeChangeAtReceiver(current, params, change_applied); | |
| 53 } | |
| 54 | |
| 55 void NotifyWindowTreeChangeDown(Window* start_at, | |
| 56 const WindowObserver::TreeChangeParams& params, | |
| 57 bool change_applied) { | |
| 58 NotifyWindowTreeChangeAtReceiver(start_at, params, change_applied); | |
| 59 Window::Children::const_iterator it = start_at->children().begin(); | |
| 60 for (; it != start_at->children().end(); ++it) | |
| 61 NotifyWindowTreeChangeDown(*it, params, change_applied); | |
| 62 } | |
| 63 | |
| 64 void NotifyWindowTreeChange(const WindowObserver::TreeChangeParams& params, | |
| 65 bool change_applied) { | |
| 66 NotifyWindowTreeChangeDown(params.target, params, change_applied); | |
| 67 if (params.old_parent) | |
| 68 NotifyWindowTreeChangeUp(params.old_parent, params, change_applied); | |
| 69 if (params.new_parent) | |
| 70 NotifyWindowTreeChangeUp(params.new_parent, params, change_applied); | |
| 71 } | |
| 72 | |
| 73 class ScopedTreeNotifier { | |
| 74 public: | |
| 75 ScopedTreeNotifier(Window* target, Window* old_parent, Window* new_parent) { | |
| 76 params_.target = target; | |
| 77 params_.old_parent = old_parent; | |
| 78 params_.new_parent = new_parent; | |
| 79 NotifyWindowTreeChange(params_, false); | |
| 80 } | |
| 81 ~ScopedTreeNotifier() { NotifyWindowTreeChange(params_, true); } | |
| 82 | |
| 83 private: | |
| 84 WindowObserver::TreeChangeParams params_; | |
| 85 | |
| 86 DISALLOW_COPY_AND_ASSIGN(ScopedTreeNotifier); | |
| 87 }; | |
| 88 | |
| 89 void RemoveChildImpl(Window* child, Window::Children* children) { | |
| 90 Window::Children::iterator it = | |
| 91 std::find(children->begin(), children->end(), child); | |
| 92 if (it != children->end()) { | |
| 93 children->erase(it); | |
| 94 WindowPrivate(child).ClearParent(); | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 class OrderChangedNotifier { | |
| 99 public: | |
| 100 OrderChangedNotifier(Window* window, | |
| 101 Window* relative_window, | |
| 102 mojom::OrderDirection direction) | |
| 103 : window_(window), | |
| 104 relative_window_(relative_window), | |
| 105 direction_(direction) {} | |
| 106 | |
| 107 ~OrderChangedNotifier() {} | |
| 108 | |
| 109 void NotifyWindowReordering() { | |
| 110 for (auto& observer : *WindowPrivate(window_).observers()) | |
| 111 observer.OnWindowReordering(window_, relative_window_, direction_); | |
| 112 } | |
| 113 | |
| 114 void NotifyWindowReordered() { | |
| 115 for (auto& observer : *WindowPrivate(window_).observers()) | |
| 116 observer.OnWindowReordered(window_, relative_window_, direction_); | |
| 117 } | |
| 118 | |
| 119 private: | |
| 120 Window* window_; | |
| 121 Window* relative_window_; | |
| 122 mojom::OrderDirection direction_; | |
| 123 | |
| 124 DISALLOW_COPY_AND_ASSIGN(OrderChangedNotifier); | |
| 125 }; | |
| 126 | |
| 127 class ScopedSetBoundsNotifier { | |
| 128 public: | |
| 129 ScopedSetBoundsNotifier(Window* window, | |
| 130 const gfx::Rect& old_bounds, | |
| 131 const gfx::Rect& new_bounds) | |
| 132 : window_(window), old_bounds_(old_bounds), new_bounds_(new_bounds) { | |
| 133 for (auto& observer : *WindowPrivate(window_).observers()) | |
| 134 observer.OnWindowBoundsChanging(window_, old_bounds_, new_bounds_); | |
| 135 } | |
| 136 ~ScopedSetBoundsNotifier() { | |
| 137 for (auto& observer : *WindowPrivate(window_).observers()) | |
| 138 observer.OnWindowBoundsChanged(window_, old_bounds_, new_bounds_); | |
| 139 } | |
| 140 | |
| 141 private: | |
| 142 Window* window_; | |
| 143 const gfx::Rect old_bounds_; | |
| 144 const gfx::Rect new_bounds_; | |
| 145 | |
| 146 DISALLOW_COPY_AND_ASSIGN(ScopedSetBoundsNotifier); | |
| 147 }; | |
| 148 | |
| 149 bool IsClientRoot(Window* window) { | |
| 150 return window->window_tree() && | |
| 151 window->window_tree()->GetRoots().count(window) > 0; | |
| 152 } | |
| 153 | |
| 154 bool WasCreatedByThisClientOrIsRoot(Window* window) { | |
| 155 return window->WasCreatedByThisClient() || IsClientRoot(window); | |
| 156 } | |
| 157 | |
| 158 void EmptyEmbedCallback(bool result) {} | |
| 159 | |
| 160 } // namespace | |
| 161 | |
| 162 //////////////////////////////////////////////////////////////////////////////// | |
| 163 // Window, public: | |
| 164 | |
| 165 void Window::Destroy() { | |
| 166 if (!WasCreatedByThisClientOrIsRoot(this)) | |
| 167 return; | |
| 168 | |
| 169 if (client_) | |
| 170 client_->DestroyWindow(this); | |
| 171 while (!children_.empty()) { | |
| 172 Window* child = children_.front(); | |
| 173 if (!child->WasCreatedByThisClient()) { | |
| 174 WindowPrivate(child).ClearParent(); | |
| 175 children_.erase(children_.begin()); | |
| 176 } else { | |
| 177 child->Destroy(); | |
| 178 DCHECK(std::find(children_.begin(), children_.end(), child) == | |
| 179 children_.end()); | |
| 180 } | |
| 181 } | |
| 182 LocalDestroy(); | |
| 183 } | |
| 184 | |
| 185 bool Window::WasCreatedByThisClient() const { | |
| 186 return !client_ || client_->WasCreatedByThisClient(this); | |
| 187 } | |
| 188 | |
| 189 void Window::SetBounds(const gfx::Rect& bounds) { | |
| 190 if (!WasCreatedByThisClientOrIsRoot(this)) | |
| 191 return; | |
| 192 if (bounds_ == bounds) | |
| 193 return; | |
| 194 if (client_) | |
| 195 client_->SetBounds(this, bounds_, bounds); | |
| 196 LocalSetBounds(bounds_, bounds); | |
| 197 } | |
| 198 | |
| 199 gfx::Rect Window::GetBoundsInRoot() const { | |
| 200 gfx::Vector2d offset; | |
| 201 for (const Window* w = parent(); w != nullptr; w = w->parent()) | |
| 202 offset += w->bounds().OffsetFromOrigin(); | |
| 203 return bounds() + offset; | |
| 204 } | |
| 205 | |
| 206 void Window::SetClientArea( | |
| 207 const gfx::Insets& client_area, | |
| 208 const std::vector<gfx::Rect>& additional_client_areas) { | |
| 209 if (!WasCreatedByThisClientOrIsRoot(this)) | |
| 210 return; | |
| 211 | |
| 212 if (client_) | |
| 213 client_->SetClientArea(server_id_, client_area, | |
| 214 additional_client_areas); | |
| 215 LocalSetClientArea(client_area, additional_client_areas); | |
| 216 } | |
| 217 | |
| 218 void Window::SetHitTestMask(const gfx::Rect& mask) { | |
| 219 if (!WasCreatedByThisClientOrIsRoot(this)) | |
| 220 return; | |
| 221 | |
| 222 if (hit_test_mask_ && *hit_test_mask_ == mask) | |
| 223 return; | |
| 224 | |
| 225 if (client_) | |
| 226 client_->SetHitTestMask(server_id_, mask); | |
| 227 hit_test_mask_.reset(new gfx::Rect(mask)); | |
| 228 } | |
| 229 | |
| 230 void Window::ClearHitTestMask() { | |
| 231 if (!WasCreatedByThisClientOrIsRoot(this)) | |
| 232 return; | |
| 233 | |
| 234 if (!hit_test_mask_) | |
| 235 return; | |
| 236 | |
| 237 if (client_) | |
| 238 client_->ClearHitTestMask(server_id_); | |
| 239 hit_test_mask_.reset(); | |
| 240 } | |
| 241 | |
| 242 void Window::SetVisible(bool value) { | |
| 243 if (visible_ == value) | |
| 244 return; | |
| 245 | |
| 246 if (client_) | |
| 247 client_->SetVisible(this, value); | |
| 248 LocalSetVisible(value); | |
| 249 } | |
| 250 | |
| 251 void Window::SetOpacity(float opacity) { | |
| 252 if (client_) | |
| 253 client_->SetOpacity(this, opacity); | |
| 254 LocalSetOpacity(opacity); | |
| 255 } | |
| 256 | |
| 257 void Window::SetPredefinedCursor(ui::mojom::Cursor cursor_id) { | |
| 258 if (cursor_id_ == cursor_id) | |
| 259 return; | |
| 260 | |
| 261 if (client_) | |
| 262 client_->SetPredefinedCursor(server_id_, cursor_id); | |
| 263 LocalSetPredefinedCursor(cursor_id); | |
| 264 } | |
| 265 | |
| 266 bool Window::IsDrawn() const { | |
| 267 if (!visible_) | |
| 268 return false; | |
| 269 return parent_ ? parent_->IsDrawn() : parent_drawn_; | |
| 270 } | |
| 271 | |
| 272 std::unique_ptr<WindowCompositorFrameSink> Window::RequestCompositorFrameSink( | |
| 273 scoped_refptr<cc::ContextProvider> context_provider, | |
| 274 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) { | |
| 275 std::unique_ptr<WindowCompositorFrameSinkBinding> | |
| 276 compositor_frame_sink_binding; | |
| 277 std::unique_ptr<WindowCompositorFrameSink> compositor_frame_sink = | |
| 278 WindowCompositorFrameSink::Create( | |
| 279 cc::FrameSinkId(server_id(), 0), std::move(context_provider), | |
| 280 gpu_memory_buffer_manager, &compositor_frame_sink_binding); | |
| 281 AttachCompositorFrameSink(std::move(compositor_frame_sink_binding)); | |
| 282 return compositor_frame_sink; | |
| 283 } | |
| 284 | |
| 285 void Window::AttachCompositorFrameSink( | |
| 286 std::unique_ptr<WindowCompositorFrameSinkBinding> | |
| 287 compositor_frame_sink_binding) { | |
| 288 window_tree()->AttachCompositorFrameSink( | |
| 289 server_id_, | |
| 290 std::move(compositor_frame_sink_binding->compositor_frame_sink_request_), | |
| 291 mojo::MakeProxy(std::move( | |
| 292 compositor_frame_sink_binding->compositor_frame_sink_client_))); | |
| 293 } | |
| 294 | |
| 295 void Window::ClearSharedProperty(const std::string& name) { | |
| 296 SetSharedPropertyInternal(name, nullptr); | |
| 297 } | |
| 298 | |
| 299 bool Window::HasSharedProperty(const std::string& name) const { | |
| 300 return properties_.count(name) > 0; | |
| 301 } | |
| 302 | |
| 303 void Window::AddObserver(WindowObserver* observer) { | |
| 304 observers_.AddObserver(observer); | |
| 305 } | |
| 306 | |
| 307 void Window::RemoveObserver(WindowObserver* observer) { | |
| 308 observers_.RemoveObserver(observer); | |
| 309 } | |
| 310 | |
| 311 const Window* Window::GetRoot() const { | |
| 312 const Window* root = this; | |
| 313 for (const Window* parent = this; parent; parent = parent->parent()) | |
| 314 root = parent; | |
| 315 return root; | |
| 316 } | |
| 317 | |
| 318 void Window::AddChild(Window* child) { | |
| 319 // TODO(beng): not necessarily valid to all clients, but possibly to the | |
| 320 // embeddee in an embedder-embeddee relationship. | |
| 321 if (client_) | |
| 322 CHECK_EQ(child->client_, client_); | |
| 323 // Roots can not be added as children of other windows. | |
| 324 if (window_tree() && window_tree()->IsRoot(child)) | |
| 325 return; | |
| 326 LocalAddChild(child); | |
| 327 if (client_) | |
| 328 client_->AddChild(this, child->server_id()); | |
| 329 } | |
| 330 | |
| 331 void Window::RemoveChild(Window* child) { | |
| 332 // TODO(beng): not necessarily valid to all clients, but possibly to the | |
| 333 // embeddee in an embedder-embeddee relationship. | |
| 334 if (client_) | |
| 335 CHECK_EQ(child->client_, client_); | |
| 336 LocalRemoveChild(child); | |
| 337 if (client_) | |
| 338 client_->RemoveChild(this, child->server_id()); | |
| 339 } | |
| 340 | |
| 341 void Window::Reorder(Window* relative, mojom::OrderDirection direction) { | |
| 342 if (!LocalReorder(relative, direction)) | |
| 343 return; | |
| 344 if (client_) | |
| 345 client_->Reorder(this, relative->server_id(), direction); | |
| 346 } | |
| 347 | |
| 348 void Window::MoveToFront() { | |
| 349 if (!parent_ || parent_->children_.back() == this) | |
| 350 return; | |
| 351 Reorder(parent_->children_.back(), mojom::OrderDirection::ABOVE); | |
| 352 } | |
| 353 | |
| 354 void Window::MoveToBack() { | |
| 355 if (!parent_ || parent_->children_.front() == this) | |
| 356 return; | |
| 357 Reorder(parent_->children_.front(), mojom::OrderDirection::BELOW); | |
| 358 } | |
| 359 | |
| 360 bool Window::Contains(const Window* child) const { | |
| 361 if (!child) | |
| 362 return false; | |
| 363 if (child == this) | |
| 364 return true; | |
| 365 if (client_) | |
| 366 CHECK_EQ(child->client_, client_); | |
| 367 for (const Window* p = child->parent(); p; p = p->parent()) { | |
| 368 if (p == this) | |
| 369 return true; | |
| 370 } | |
| 371 return false; | |
| 372 } | |
| 373 | |
| 374 void Window::AddTransientWindow(Window* transient_window) { | |
| 375 // A system modal window cannot become a transient child. | |
| 376 DCHECK(!transient_window->is_modal() || transient_window->transient_parent()); | |
| 377 | |
| 378 if (client_) | |
| 379 CHECK_EQ(transient_window->client_, client_); | |
| 380 LocalAddTransientWindow(transient_window); | |
| 381 if (client_) | |
| 382 client_->AddTransientWindow(this, transient_window->server_id()); | |
| 383 } | |
| 384 | |
| 385 void Window::RemoveTransientWindow(Window* transient_window) { | |
| 386 if (client_) | |
| 387 CHECK_EQ(transient_window->window_tree(), client_); | |
| 388 LocalRemoveTransientWindow(transient_window); | |
| 389 if (client_) | |
| 390 client_->RemoveTransientWindowFromParent(transient_window); | |
| 391 } | |
| 392 | |
| 393 void Window::SetModal() { | |
| 394 if (is_modal_) | |
| 395 return; | |
| 396 | |
| 397 LocalSetModal(); | |
| 398 if (client_) | |
| 399 client_->SetModal(this); | |
| 400 } | |
| 401 | |
| 402 Window* Window::GetChildByLocalId(int id) { | |
| 403 if (id == local_id_) | |
| 404 return this; | |
| 405 // TODO(beng): this could be improved depending on how we decide to own | |
| 406 // windows. | |
| 407 for (Window* child : children_) { | |
| 408 Window* matching_child = child->GetChildByLocalId(id); | |
| 409 if (matching_child) | |
| 410 return matching_child; | |
| 411 } | |
| 412 return nullptr; | |
| 413 } | |
| 414 | |
| 415 void Window::SetTextInputState(mojo::TextInputStatePtr state) { | |
| 416 if (client_) | |
| 417 client_->SetWindowTextInputState(server_id_, std::move(state)); | |
| 418 } | |
| 419 | |
| 420 void Window::SetImeVisibility(bool visible, mojo::TextInputStatePtr state) { | |
| 421 // SetImeVisibility() shouldn't be used if the window is not editable. | |
| 422 DCHECK(state.is_null() || state->type != mojo::TextInputType::NONE); | |
| 423 if (client_) | |
| 424 client_->SetImeVisibility(server_id_, visible, std::move(state)); | |
| 425 } | |
| 426 | |
| 427 bool Window::HasCapture() const { | |
| 428 return client_ && client_->GetCaptureWindow() == this; | |
| 429 } | |
| 430 | |
| 431 void Window::SetCapture() { | |
| 432 if (client_) | |
| 433 client_->SetCapture(this); | |
| 434 } | |
| 435 | |
| 436 void Window::ReleaseCapture() { | |
| 437 if (client_) | |
| 438 client_->ReleaseCapture(this); | |
| 439 } | |
| 440 | |
| 441 void Window::SetFocus() { | |
| 442 if (client_ && IsDrawn()) | |
| 443 client_->SetFocus(this); | |
| 444 } | |
| 445 | |
| 446 bool Window::HasFocus() const { | |
| 447 return client_ && client_->GetFocusedWindow() == this; | |
| 448 } | |
| 449 | |
| 450 void Window::SetCanFocus(bool can_focus) { | |
| 451 if (client_) | |
| 452 client_->SetCanFocus(server_id_, can_focus); | |
| 453 } | |
| 454 | |
| 455 void Window::SetCanAcceptDrops(WindowDropTarget* drop_target) { | |
| 456 if (drop_target_ == drop_target) | |
| 457 return; | |
| 458 drop_target_ = drop_target; | |
| 459 if (client_) | |
| 460 client_->SetCanAcceptDrops(server_id_, !!drop_target_); | |
| 461 } | |
| 462 | |
| 463 void Window::SetCanAcceptEvents(bool can_accept_events) { | |
| 464 if (can_accept_events_ == can_accept_events) | |
| 465 return; | |
| 466 can_accept_events_ = can_accept_events; | |
| 467 if (client_) | |
| 468 client_->SetCanAcceptEvents(server_id_, can_accept_events_); | |
| 469 } | |
| 470 | |
| 471 void Window::Embed(ui::mojom::WindowTreeClientPtr client, uint32_t flags) { | |
| 472 Embed(std::move(client), base::Bind(&EmptyEmbedCallback), flags); | |
| 473 } | |
| 474 | |
| 475 void Window::Embed(ui::mojom::WindowTreeClientPtr client, | |
| 476 const EmbedCallback& callback, | |
| 477 uint32_t flags) { | |
| 478 if (PrepareForEmbed()) | |
| 479 client_->Embed(server_id_, std::move(client), flags, callback); | |
| 480 else | |
| 481 callback.Run(false); | |
| 482 } | |
| 483 | |
| 484 void Window::RequestClose() { | |
| 485 if (client_) | |
| 486 client_->RequestClose(this); | |
| 487 } | |
| 488 | |
| 489 void Window::PerformDragDrop( | |
| 490 const std::map<std::string, std::vector<uint8_t>>& drag_data, | |
| 491 int drag_operation, | |
| 492 const gfx::Point& cursor_location, | |
| 493 const SkBitmap& bitmap, | |
| 494 const base::Callback<void(bool, uint32_t)>& callback) { | |
| 495 client_->PerformDragDrop(this, drag_data, drag_operation, cursor_location, | |
| 496 bitmap, callback); | |
| 497 } | |
| 498 | |
| 499 void Window::CancelDragDrop() { | |
| 500 client_->CancelDragDrop(this); | |
| 501 } | |
| 502 | |
| 503 void Window::PerformWindowMove(mojom::MoveLoopSource source, | |
| 504 const gfx::Point& cursor_location, | |
| 505 const base::Callback<void(bool)>& callback) { | |
| 506 client_->PerformWindowMove(this, source, cursor_location, callback); | |
| 507 } | |
| 508 | |
| 509 void Window::CancelWindowMove() { | |
| 510 client_->CancelWindowMove(this); | |
| 511 } | |
| 512 | |
| 513 std::string Window::GetName() const { | |
| 514 if (HasSharedProperty(mojom::WindowManager::kName_Property)) | |
| 515 return GetSharedProperty<std::string>(mojom::WindowManager::kName_Property); | |
| 516 | |
| 517 return std::string(); | |
| 518 } | |
| 519 | |
| 520 //////////////////////////////////////////////////////////////////////////////// | |
| 521 // Window, protected: | |
| 522 | |
| 523 Window::Window() : Window(nullptr, static_cast<Id>(-1)) {} | |
| 524 | |
| 525 Window::~Window() { | |
| 526 for (auto& observer : observers_) | |
| 527 observer.OnWindowDestroying(this); | |
| 528 if (client_) | |
| 529 client_->OnWindowDestroying(this); | |
| 530 | |
| 531 if (HasFocus()) { | |
| 532 // The focused window is being removed. When this happens the server | |
| 533 // advances focus. We don't want to randomly pick a Window to get focus, so | |
| 534 // we update local state only, and wait for the next focus change from the | |
| 535 // server. | |
| 536 client_->LocalSetFocus(nullptr); | |
| 537 } | |
| 538 | |
| 539 // Remove from transient parent. | |
| 540 if (transient_parent_) | |
| 541 transient_parent_->LocalRemoveTransientWindow(this); | |
| 542 | |
| 543 // Return the surface reference if there is one. | |
| 544 if (surface_info_.id().is_valid()) | |
| 545 LocalSetSurfaceInfo(cc::SurfaceInfo()); | |
| 546 | |
| 547 // Remove transient children. | |
| 548 while (!transient_children_.empty()) { | |
| 549 Window* transient_child = transient_children_.front(); | |
| 550 LocalRemoveTransientWindow(transient_child); | |
| 551 transient_child->LocalDestroy(); | |
| 552 DCHECK(transient_children_.empty() || | |
| 553 transient_children_.front() != transient_child); | |
| 554 } | |
| 555 | |
| 556 if (parent_) | |
| 557 parent_->LocalRemoveChild(this); | |
| 558 | |
| 559 // We may still have children. This can happen if the embedder destroys the | |
| 560 // root while we're still alive. | |
| 561 while (!children_.empty()) { | |
| 562 Window* child = children_.front(); | |
| 563 LocalRemoveChild(child); | |
| 564 DCHECK(children_.empty() || children_.front() != child); | |
| 565 } | |
| 566 | |
| 567 // Notify observers before clearing properties (order matches aura::Window). | |
| 568 for (auto& observer : observers_) | |
| 569 observer.OnWindowDestroyed(this); | |
| 570 | |
| 571 // Clear properties. | |
| 572 for (auto& pair : prop_map_) { | |
| 573 if (pair.second.deallocator) | |
| 574 (*pair.second.deallocator)(pair.second.value); | |
| 575 } | |
| 576 prop_map_.clear(); | |
| 577 | |
| 578 // Invoke after observers so that can clean up any internal state observers | |
| 579 // may have changed. | |
| 580 if (window_tree()) | |
| 581 window_tree()->OnWindowDestroyed(this); | |
| 582 } | |
| 583 | |
| 584 //////////////////////////////////////////////////////////////////////////////// | |
| 585 // Window, private: | |
| 586 | |
| 587 Window::Window(WindowTreeClient* client, Id id) | |
| 588 : client_(client), | |
| 589 server_id_(id), | |
| 590 parent_(nullptr), | |
| 591 stacking_target_(nullptr), | |
| 592 transient_parent_(nullptr), | |
| 593 is_modal_(false), | |
| 594 // Matches aura, see aura::Window for details. | |
| 595 observers_(base::ObserverList<WindowObserver>::NOTIFY_EXISTING_ONLY), | |
| 596 input_event_handler_(nullptr), | |
| 597 visible_(false), | |
| 598 opacity_(1.0f), | |
| 599 display_id_(display::kInvalidDisplayId), | |
| 600 cursor_id_(mojom::Cursor::CURSOR_NULL), | |
| 601 parent_drawn_(false) {} | |
| 602 | |
| 603 void Window::SetSharedPropertyInternal(const std::string& name, | |
| 604 const std::vector<uint8_t>* value) { | |
| 605 if (!WasCreatedByThisClientOrIsRoot(this)) | |
| 606 return; | |
| 607 | |
| 608 if (client_) { | |
| 609 base::Optional<std::vector<uint8_t>> transport_value; | |
| 610 if (value) { | |
| 611 transport_value.emplace(value->size()); | |
| 612 if (value->size()) | |
| 613 memcpy(&transport_value.value().front(), &(value->front()), | |
| 614 value->size()); | |
| 615 } | |
| 616 // TODO: add test coverage of this (450303). | |
| 617 client_->SetProperty(this, name, std::move(transport_value)); | |
| 618 } | |
| 619 LocalSetSharedProperty(name, value); | |
| 620 } | |
| 621 | |
| 622 int64_t Window::SetLocalPropertyInternal(const void* key, | |
| 623 const char* name, | |
| 624 PropertyDeallocator deallocator, | |
| 625 int64_t value, | |
| 626 int64_t default_value) { | |
| 627 int64_t old = GetLocalPropertyInternal(key, default_value); | |
| 628 if (value == default_value) { | |
| 629 prop_map_.erase(key); | |
| 630 } else { | |
| 631 Value prop_value; | |
| 632 prop_value.name = name; | |
| 633 prop_value.value = value; | |
| 634 prop_value.deallocator = deallocator; | |
| 635 prop_map_[key] = prop_value; | |
| 636 } | |
| 637 for (auto& observer : observers_) | |
| 638 observer.OnWindowLocalPropertyChanged(this, key, old); | |
| 639 return old; | |
| 640 } | |
| 641 | |
| 642 int64_t Window::GetLocalPropertyInternal(const void* key, | |
| 643 int64_t default_value) const { | |
| 644 std::map<const void*, Value>::const_iterator iter = prop_map_.find(key); | |
| 645 if (iter == prop_map_.end()) | |
| 646 return default_value; | |
| 647 return iter->second.value; | |
| 648 } | |
| 649 | |
| 650 void Window::LocalDestroy() { | |
| 651 delete this; | |
| 652 } | |
| 653 | |
| 654 void Window::LocalAddChild(Window* child) { | |
| 655 ScopedTreeNotifier notifier(child, child->parent(), this); | |
| 656 if (child->parent()) | |
| 657 RemoveChildImpl(child, &child->parent_->children_); | |
| 658 children_.push_back(child); | |
| 659 child->parent_ = this; | |
| 660 child->display_id_ = display_id_; | |
| 661 } | |
| 662 | |
| 663 void Window::LocalRemoveChild(Window* child) { | |
| 664 DCHECK_EQ(this, child->parent()); | |
| 665 ScopedTreeNotifier notifier(child, this, nullptr); | |
| 666 RemoveChildImpl(child, &children_); | |
| 667 } | |
| 668 | |
| 669 void Window::LocalAddTransientWindow(Window* transient_window) { | |
| 670 if (transient_window->transient_parent()) | |
| 671 RemoveTransientWindowImpl(transient_window); | |
| 672 transient_children_.push_back(transient_window); | |
| 673 transient_window->transient_parent_ = this; | |
| 674 | |
| 675 // Restack |transient_window| properly above its transient parent, if they | |
| 676 // share the same parent. | |
| 677 if (transient_window->parent() == parent()) | |
| 678 RestackTransientDescendants(this, &GetStackingTarget, | |
| 679 &ReorderWithoutNotification); | |
| 680 | |
| 681 for (auto& observer : observers_) | |
| 682 observer.OnTransientChildAdded(this, transient_window); | |
| 683 } | |
| 684 | |
| 685 void Window::LocalRemoveTransientWindow(Window* transient_window) { | |
| 686 DCHECK_EQ(this, transient_window->transient_parent()); | |
| 687 RemoveTransientWindowImpl(transient_window); | |
| 688 for (auto& observer : observers_) | |
| 689 observer.OnTransientChildRemoved(this, transient_window); | |
| 690 } | |
| 691 | |
| 692 void Window::LocalSetModal() { | |
| 693 is_modal_ = true; | |
| 694 } | |
| 695 | |
| 696 bool Window::LocalReorder(Window* relative, mojom::OrderDirection direction) { | |
| 697 OrderChangedNotifier notifier(this, relative, direction); | |
| 698 return ReorderImpl(this, relative, direction, ¬ifier); | |
| 699 } | |
| 700 | |
| 701 void Window::LocalSetBounds(const gfx::Rect& old_bounds, | |
| 702 const gfx::Rect& new_bounds) { | |
| 703 // If this client owns the window, then it should be the only one to change | |
| 704 // the bounds. | |
| 705 DCHECK(!WasCreatedByThisClient() || old_bounds == bounds_); | |
| 706 ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds); | |
| 707 bounds_ = new_bounds; | |
| 708 } | |
| 709 | |
| 710 void Window::LocalSetClientArea( | |
| 711 const gfx::Insets& new_client_area, | |
| 712 const std::vector<gfx::Rect>& additional_client_areas) { | |
| 713 const std::vector<gfx::Rect> old_additional_client_areas = | |
| 714 additional_client_areas_; | |
| 715 const gfx::Insets old_client_area = client_area_; | |
| 716 client_area_ = new_client_area; | |
| 717 additional_client_areas_ = additional_client_areas; | |
| 718 for (auto& observer : observers_) { | |
| 719 observer.OnWindowClientAreaChanged(this, old_client_area, | |
| 720 old_additional_client_areas); | |
| 721 } | |
| 722 } | |
| 723 | |
| 724 void Window::LocalSetDisplay(int64_t display_id) { | |
| 725 display_id_ = display_id; | |
| 726 // TODO(sad): Notify observers (of this window, and of the descendant windows) | |
| 727 // when a window moves from one display into another. https://crbug.com/614887 | |
| 728 } | |
| 729 | |
| 730 void Window::LocalSetParentDrawn(bool value) { | |
| 731 if (parent_drawn_ == value) | |
| 732 return; | |
| 733 | |
| 734 // As IsDrawn() is derived from |visible_| and |parent_drawn_|, only send | |
| 735 // drawn notification is the value of IsDrawn() is really changing. | |
| 736 if (IsDrawn() == value) { | |
| 737 parent_drawn_ = value; | |
| 738 return; | |
| 739 } | |
| 740 for (auto& observer : observers_) | |
| 741 observer.OnWindowDrawnChanging(this); | |
| 742 parent_drawn_ = value; | |
| 743 for (auto& observer : observers_) | |
| 744 observer.OnWindowDrawnChanged(this); | |
| 745 } | |
| 746 | |
| 747 void Window::LocalSetVisible(bool visible) { | |
| 748 if (visible_ == visible) | |
| 749 return; | |
| 750 | |
| 751 for (auto& observer : observers_) | |
| 752 observer.OnWindowVisibilityChanging(this, visible); | |
| 753 visible_ = visible; | |
| 754 if (parent_) { | |
| 755 for (auto& observer : parent_->observers_) | |
| 756 observer.OnChildWindowVisibilityChanged(this, visible); | |
| 757 } | |
| 758 | |
| 759 NotifyWindowVisibilityChanged(this, visible); | |
| 760 } | |
| 761 | |
| 762 void Window::LocalSetOpacity(float opacity) { | |
| 763 if (opacity_ == opacity) | |
| 764 return; | |
| 765 | |
| 766 float old_opacity = opacity_; | |
| 767 opacity_ = opacity; | |
| 768 for (auto& observer : observers_) | |
| 769 observer.OnWindowOpacityChanged(this, old_opacity, opacity_); | |
| 770 } | |
| 771 | |
| 772 void Window::LocalSetPredefinedCursor(mojom::Cursor cursor_id) { | |
| 773 if (cursor_id_ == cursor_id) | |
| 774 return; | |
| 775 | |
| 776 cursor_id_ = cursor_id; | |
| 777 for (auto& observer : observers_) | |
| 778 observer.OnWindowPredefinedCursorChanged(this, cursor_id); | |
| 779 } | |
| 780 | |
| 781 void Window::LocalSetSharedProperty(const std::string& name, | |
| 782 const std::vector<uint8_t>* value) { | |
| 783 std::vector<uint8_t> old_value; | |
| 784 std::vector<uint8_t>* old_value_ptr = nullptr; | |
| 785 auto it = properties_.find(name); | |
| 786 if (it != properties_.end()) { | |
| 787 old_value = it->second; | |
| 788 old_value_ptr = &old_value; | |
| 789 | |
| 790 if (value && old_value == *value) | |
| 791 return; | |
| 792 } else if (!value) { | |
| 793 // This property isn't set in |properties_| and |value| is nullptr, so | |
| 794 // there's no change. | |
| 795 return; | |
| 796 } | |
| 797 | |
| 798 if (value) { | |
| 799 properties_[name] = *value; | |
| 800 } else if (it != properties_.end()) { | |
| 801 properties_.erase(it); | |
| 802 } | |
| 803 | |
| 804 for (auto& observer : observers_) | |
| 805 observer.OnWindowSharedPropertyChanged(this, name, old_value_ptr, value); | |
| 806 } | |
| 807 | |
| 808 void Window::LocalSetSurfaceInfo(const cc::SurfaceInfo& surface_info) { | |
| 809 if (surface_info_.id().is_valid()) { | |
| 810 const cc::SurfaceId& existing_surface_id = surface_info_.id(); | |
| 811 const cc::SurfaceId& new_surface_id = surface_info.id(); | |
| 812 if (existing_surface_id.is_valid() && | |
| 813 existing_surface_id != new_surface_id) { | |
| 814 // TODO(kylechar): Start return reference here? | |
| 815 } | |
| 816 } | |
| 817 surface_info_ = surface_info; | |
| 818 } | |
| 819 | |
| 820 void Window::NotifyWindowStackingChanged() { | |
| 821 if (stacking_target_) { | |
| 822 Children::const_iterator window_i = std::find( | |
| 823 parent()->children().begin(), parent()->children().end(), this); | |
| 824 DCHECK(window_i != parent()->children().end()); | |
| 825 if (window_i != parent()->children().begin() && | |
| 826 (*(window_i - 1) == stacking_target_)) | |
| 827 return; | |
| 828 } | |
| 829 RestackTransientDescendants(this, &GetStackingTarget, | |
| 830 &ReorderWithoutNotification); | |
| 831 } | |
| 832 | |
| 833 void Window::NotifyWindowVisibilityChanged(Window* target, bool visible) { | |
| 834 if (!NotifyWindowVisibilityChangedDown(target, visible)) | |
| 835 return; // |this| has been deleted. | |
| 836 | |
| 837 NotifyWindowVisibilityChangedUp(target, visible); | |
| 838 } | |
| 839 | |
| 840 bool Window::NotifyWindowVisibilityChangedAtReceiver(Window* target, | |
| 841 bool visible) { | |
| 842 // |this| may be deleted during a call to OnWindowVisibilityChanged() on one | |
| 843 // of the observers. We create an local observer for that. In that case we | |
| 844 // exit without further access to any members. | |
| 845 WindowTracker tracker; | |
| 846 tracker.Add(this); | |
| 847 for (auto& observer : observers_) | |
| 848 observer.OnWindowVisibilityChanged(target, visible); | |
| 849 return tracker.Contains(this); | |
| 850 } | |
| 851 | |
| 852 bool Window::NotifyWindowVisibilityChangedDown(Window* target, bool visible) { | |
| 853 if (!NotifyWindowVisibilityChangedAtReceiver(target, visible)) | |
| 854 return false; // |this| was deleted. | |
| 855 std::set<const Window*> child_already_processed; | |
| 856 bool child_destroyed = false; | |
| 857 do { | |
| 858 child_destroyed = false; | |
| 859 for (Window::Children::const_iterator it = children_.begin(); | |
| 860 it != children_.end(); ++it) { | |
| 861 if (!child_already_processed.insert(*it).second) | |
| 862 continue; | |
| 863 if (!(*it)->NotifyWindowVisibilityChangedDown(target, visible)) { | |
| 864 // |*it| was deleted, |it| is invalid and |children_| has changed. We | |
| 865 // exit the current for-loop and enter a new one. | |
| 866 child_destroyed = true; | |
| 867 break; | |
| 868 } | |
| 869 } | |
| 870 } while (child_destroyed); | |
| 871 return true; | |
| 872 } | |
| 873 | |
| 874 void Window::NotifyWindowVisibilityChangedUp(Window* target, bool visible) { | |
| 875 // Start with the parent as we already notified |this| | |
| 876 // in NotifyWindowVisibilityChangedDown. | |
| 877 for (Window* window = parent(); window; window = window->parent()) { | |
| 878 bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target, visible); | |
| 879 DCHECK(ret); | |
| 880 } | |
| 881 } | |
| 882 | |
| 883 bool Window::PrepareForEmbed() { | |
| 884 if (!WasCreatedByThisClient()) | |
| 885 return false; | |
| 886 | |
| 887 while (!children_.empty()) | |
| 888 RemoveChild(children_[0]); | |
| 889 return true; | |
| 890 } | |
| 891 | |
| 892 void Window::RemoveTransientWindowImpl(Window* transient_window) { | |
| 893 Window::Children::iterator it = std::find( | |
| 894 transient_children_.begin(), transient_children_.end(), transient_window); | |
| 895 if (it != transient_children_.end()) { | |
| 896 transient_children_.erase(it); | |
| 897 transient_window->transient_parent_ = nullptr; | |
| 898 } | |
| 899 // If |transient_window| and its former transient parent share the same | |
| 900 // parent, |transient_window| should be restacked properly so it is not among | |
| 901 // transient children of its former parent, anymore. | |
| 902 if (parent() == transient_window->parent()) | |
| 903 RestackTransientDescendants(this, &GetStackingTarget, | |
| 904 &ReorderWithoutNotification); | |
| 905 | |
| 906 // TOOD(fsamuel): We might want to notify observers here. | |
| 907 } | |
| 908 | |
| 909 // static | |
| 910 void Window::ReorderWithoutNotification(Window* window, | |
| 911 Window* relative, | |
| 912 mojom::OrderDirection direction) { | |
| 913 ReorderImpl(window, relative, direction, nullptr); | |
| 914 } | |
| 915 | |
| 916 // static | |
| 917 bool Window::ReorderImpl(Window* window, | |
| 918 Window* relative, | |
| 919 mojom::OrderDirection direction, | |
| 920 OrderChangedNotifier* notifier) { | |
| 921 DCHECK(relative); | |
| 922 DCHECK_NE(window, relative); | |
| 923 DCHECK_EQ(window->parent(), relative->parent()); | |
| 924 DCHECK(window->parent()); | |
| 925 | |
| 926 if (!AdjustStackingForTransientWindows(&window, &relative, &direction, | |
| 927 window->stacking_target_)) | |
| 928 return false; | |
| 929 | |
| 930 const size_t child_i = std::find(window->parent_->children_.begin(), | |
| 931 window->parent_->children_.end(), window) - | |
| 932 window->parent_->children_.begin(); | |
| 933 const size_t target_i = | |
| 934 std::find(window->parent_->children_.begin(), | |
| 935 window->parent_->children_.end(), relative) - | |
| 936 window->parent_->children_.begin(); | |
| 937 if ((direction == mojom::OrderDirection::ABOVE && child_i == target_i + 1) || | |
| 938 (direction == mojom::OrderDirection::BELOW && child_i + 1 == target_i)) { | |
| 939 return false; | |
| 940 } | |
| 941 | |
| 942 if (notifier) | |
| 943 notifier->NotifyWindowReordering(); | |
| 944 | |
| 945 const size_t dest_i = direction == mojom::OrderDirection::ABOVE | |
| 946 ? (child_i < target_i ? target_i : target_i + 1) | |
| 947 : (child_i < target_i ? target_i - 1 : target_i); | |
| 948 window->parent_->children_.erase(window->parent_->children_.begin() + | |
| 949 child_i); | |
| 950 window->parent_->children_.insert(window->parent_->children_.begin() + dest_i, | |
| 951 window); | |
| 952 | |
| 953 window->NotifyWindowStackingChanged(); | |
| 954 | |
| 955 if (notifier) | |
| 956 notifier->NotifyWindowReordered(); | |
| 957 | |
| 958 return true; | |
| 959 } | |
| 960 | |
| 961 // static | |
| 962 Window** Window::GetStackingTarget(Window* window) { | |
| 963 return &window->stacking_target_; | |
| 964 } | |
| 965 } // namespace ui | |
| OLD | NEW |