| 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 "components/mus/ws/server_window.h" | |
| 6 | |
| 7 #include <inttypes.h> | |
| 8 #include <stddef.h> | |
| 9 | |
| 10 #include "base/strings/stringprintf.h" | |
| 11 #include "components/mus/common/transient_window_utils.h" | |
| 12 #include "components/mus/public/interfaces/window_manager.mojom.h" | |
| 13 #include "components/mus/ws/server_window_delegate.h" | |
| 14 #include "components/mus/ws/server_window_observer.h" | |
| 15 #include "components/mus/ws/server_window_surface_manager.h" | |
| 16 | |
| 17 namespace mus { | |
| 18 | |
| 19 namespace ws { | |
| 20 | |
| 21 ServerWindow::ServerWindow(ServerWindowDelegate* delegate, const WindowId& id) | |
| 22 : ServerWindow(delegate, id, Properties()) {} | |
| 23 | |
| 24 ServerWindow::ServerWindow(ServerWindowDelegate* delegate, | |
| 25 const WindowId& id, | |
| 26 const Properties& properties) | |
| 27 : delegate_(delegate), | |
| 28 id_(id), | |
| 29 parent_(nullptr), | |
| 30 stacking_target_(nullptr), | |
| 31 transient_parent_(nullptr), | |
| 32 is_modal_(false), | |
| 33 visible_(false), | |
| 34 cursor_id_(mojom::Cursor::CURSOR_NULL), | |
| 35 non_client_cursor_id_(mojom::Cursor::CURSOR_NULL), | |
| 36 opacity_(1), | |
| 37 can_focus_(true), | |
| 38 properties_(properties), | |
| 39 // Don't notify newly added observers during notification. This causes | |
| 40 // problems for code that adds an observer as part of an observer | |
| 41 // notification (such as ServerWindowDrawTracker). | |
| 42 observers_( | |
| 43 base::ObserverList<ServerWindowObserver>::NOTIFY_EXISTING_ONLY) { | |
| 44 DCHECK(delegate); // Must provide a delegate. | |
| 45 } | |
| 46 | |
| 47 ServerWindow::~ServerWindow() { | |
| 48 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, OnWindowDestroying(this)); | |
| 49 | |
| 50 if (transient_parent_) | |
| 51 transient_parent_->RemoveTransientWindow(this); | |
| 52 | |
| 53 // Destroy transient children, only after we've removed ourselves from our | |
| 54 // parent, as destroying an active transient child may otherwise attempt to | |
| 55 // refocus us. | |
| 56 Windows transient_children(transient_children_); | |
| 57 STLDeleteElements(&transient_children); | |
| 58 DCHECK(transient_children_.empty()); | |
| 59 | |
| 60 while (!children_.empty()) | |
| 61 children_.front()->parent()->Remove(children_.front()); | |
| 62 | |
| 63 if (parent_) | |
| 64 parent_->Remove(this); | |
| 65 | |
| 66 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, OnWindowDestroyed(this)); | |
| 67 } | |
| 68 | |
| 69 void ServerWindow::AddObserver(ServerWindowObserver* observer) { | |
| 70 observers_.AddObserver(observer); | |
| 71 } | |
| 72 | |
| 73 void ServerWindow::RemoveObserver(ServerWindowObserver* observer) { | |
| 74 DCHECK(observers_.HasObserver(observer)); | |
| 75 observers_.RemoveObserver(observer); | |
| 76 } | |
| 77 | |
| 78 void ServerWindow::CreateSurface(mojom::SurfaceType surface_type, | |
| 79 mojo::InterfaceRequest<mojom::Surface> request, | |
| 80 mojom::SurfaceClientPtr client) { | |
| 81 GetOrCreateSurfaceManager()->CreateSurface(surface_type, std::move(request), | |
| 82 std::move(client)); | |
| 83 } | |
| 84 | |
| 85 void ServerWindow::Add(ServerWindow* child) { | |
| 86 // We assume validation checks happened already. | |
| 87 DCHECK(child); | |
| 88 DCHECK(child != this); | |
| 89 DCHECK(!child->Contains(this)); | |
| 90 if (child->parent() == this) { | |
| 91 if (children_.size() == 1) | |
| 92 return; // Already in the right position. | |
| 93 child->Reorder(children_.back(), mojom::OrderDirection::ABOVE); | |
| 94 return; | |
| 95 } | |
| 96 | |
| 97 ServerWindow* old_parent = child->parent(); | |
| 98 FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_, | |
| 99 OnWillChangeWindowHierarchy(child, this, old_parent)); | |
| 100 | |
| 101 if (child->parent()) | |
| 102 child->parent()->RemoveImpl(child); | |
| 103 | |
| 104 child->parent_ = this; | |
| 105 children_.push_back(child); | |
| 106 | |
| 107 // Stack the child properly if it is a transient child of a sibling. | |
| 108 if (child->transient_parent_ && child->transient_parent_->parent() == this) | |
| 109 RestackTransientDescendants(child->transient_parent_, &GetStackingTarget, | |
| 110 &ReorderImpl); | |
| 111 | |
| 112 FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_, | |
| 113 OnWindowHierarchyChanged(child, this, old_parent)); | |
| 114 } | |
| 115 | |
| 116 void ServerWindow::Remove(ServerWindow* child) { | |
| 117 // We assume validation checks happened else where. | |
| 118 DCHECK(child); | |
| 119 DCHECK(child != this); | |
| 120 DCHECK(child->parent() == this); | |
| 121 | |
| 122 FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_, | |
| 123 OnWillChangeWindowHierarchy(child, nullptr, this)); | |
| 124 RemoveImpl(child); | |
| 125 | |
| 126 // Stack the child properly if it is a transient child of a sibling. | |
| 127 if (child->transient_parent_ && child->transient_parent_->parent() == this) | |
| 128 RestackTransientDescendants(child->transient_parent_, &GetStackingTarget, | |
| 129 &ReorderImpl); | |
| 130 | |
| 131 FOR_EACH_OBSERVER(ServerWindowObserver, child->observers_, | |
| 132 OnWindowHierarchyChanged(child, nullptr, this)); | |
| 133 } | |
| 134 | |
| 135 void ServerWindow::Reorder(ServerWindow* relative, | |
| 136 mojom::OrderDirection direction) { | |
| 137 ReorderImpl(this, relative, direction); | |
| 138 } | |
| 139 | |
| 140 void ServerWindow::StackChildAtBottom(ServerWindow* child) { | |
| 141 // There's nothing to do if the child is already at the bottom. | |
| 142 if (children_.size() <= 1 || child == children_.front()) | |
| 143 return; | |
| 144 child->Reorder(children_.front(), mojom::OrderDirection::BELOW); | |
| 145 } | |
| 146 | |
| 147 void ServerWindow::StackChildAtTop(ServerWindow* child) { | |
| 148 // There's nothing to do if the child is already at the top. | |
| 149 if (children_.size() <= 1 || child == children_.back()) | |
| 150 return; | |
| 151 child->Reorder(children_.back(), mojom::OrderDirection::ABOVE); | |
| 152 } | |
| 153 | |
| 154 void ServerWindow::SetBounds(const gfx::Rect& bounds) { | |
| 155 if (bounds_ == bounds) | |
| 156 return; | |
| 157 | |
| 158 // TODO(fsamuel): figure out how will this work with CompositorFrames. | |
| 159 | |
| 160 const gfx::Rect old_bounds = bounds_; | |
| 161 bounds_ = bounds; | |
| 162 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 163 OnWindowBoundsChanged(this, old_bounds, bounds)); | |
| 164 } | |
| 165 | |
| 166 void ServerWindow::SetClientArea( | |
| 167 const gfx::Insets& insets, | |
| 168 const std::vector<gfx::Rect>& additional_client_areas) { | |
| 169 if (client_area_ == insets && | |
| 170 additional_client_areas == additional_client_areas_) { | |
| 171 return; | |
| 172 } | |
| 173 | |
| 174 additional_client_areas_ = additional_client_areas; | |
| 175 client_area_ = insets; | |
| 176 FOR_EACH_OBSERVER( | |
| 177 ServerWindowObserver, observers_, | |
| 178 OnWindowClientAreaChanged(this, insets, additional_client_areas)); | |
| 179 } | |
| 180 | |
| 181 void ServerWindow::SetHitTestMask(const gfx::Rect& mask) { | |
| 182 hit_test_mask_.reset(new gfx::Rect(mask)); | |
| 183 } | |
| 184 | |
| 185 void ServerWindow::ClearHitTestMask() { | |
| 186 hit_test_mask_.reset(); | |
| 187 } | |
| 188 | |
| 189 const ServerWindow* ServerWindow::GetRoot() const { | |
| 190 return delegate_->GetRootWindow(this); | |
| 191 } | |
| 192 | |
| 193 std::vector<const ServerWindow*> ServerWindow::GetChildren() const { | |
| 194 std::vector<const ServerWindow*> children; | |
| 195 children.reserve(children_.size()); | |
| 196 for (size_t i = 0; i < children_.size(); ++i) | |
| 197 children.push_back(children_[i]); | |
| 198 return children; | |
| 199 } | |
| 200 | |
| 201 std::vector<ServerWindow*> ServerWindow::GetChildren() { | |
| 202 // TODO(sky): rename to children() and fix return type. | |
| 203 return children_; | |
| 204 } | |
| 205 | |
| 206 ServerWindow* ServerWindow::GetChildWindow(const WindowId& window_id) { | |
| 207 if (id_ == window_id) | |
| 208 return this; | |
| 209 | |
| 210 for (ServerWindow* child : children_) { | |
| 211 ServerWindow* window = child->GetChildWindow(window_id); | |
| 212 if (window) | |
| 213 return window; | |
| 214 } | |
| 215 | |
| 216 return nullptr; | |
| 217 } | |
| 218 | |
| 219 bool ServerWindow::AddTransientWindow(ServerWindow* child) { | |
| 220 // A system modal window cannot become a transient child. | |
| 221 if (child->is_modal() && !child->transient_parent()) | |
| 222 return false; | |
| 223 | |
| 224 if (child->transient_parent()) | |
| 225 child->transient_parent()->RemoveTransientWindow(child); | |
| 226 | |
| 227 DCHECK(std::find(transient_children_.begin(), transient_children_.end(), | |
| 228 child) == transient_children_.end()); | |
| 229 transient_children_.push_back(child); | |
| 230 child->transient_parent_ = this; | |
| 231 | |
| 232 // Restack |child| properly above its transient parent, if they share the same | |
| 233 // parent. | |
| 234 if (child->parent() == parent()) | |
| 235 RestackTransientDescendants(this, &GetStackingTarget, &ReorderImpl); | |
| 236 | |
| 237 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 238 OnTransientWindowAdded(this, child)); | |
| 239 return true; | |
| 240 } | |
| 241 | |
| 242 void ServerWindow::RemoveTransientWindow(ServerWindow* child) { | |
| 243 Windows::iterator i = | |
| 244 std::find(transient_children_.begin(), transient_children_.end(), child); | |
| 245 DCHECK(i != transient_children_.end()); | |
| 246 transient_children_.erase(i); | |
| 247 DCHECK_EQ(this, child->transient_parent()); | |
| 248 child->transient_parent_ = nullptr; | |
| 249 | |
| 250 // If |child| and its former transient parent share the same parent, |child| | |
| 251 // should be restacked properly so it is not among transient children of its | |
| 252 // former parent, anymore. | |
| 253 if (parent() == child->parent()) | |
| 254 RestackTransientDescendants(this, &GetStackingTarget, &ReorderImpl); | |
| 255 | |
| 256 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 257 OnTransientWindowRemoved(this, child)); | |
| 258 } | |
| 259 | |
| 260 void ServerWindow::SetModal() { | |
| 261 is_modal_ = true; | |
| 262 } | |
| 263 | |
| 264 bool ServerWindow::Contains(const ServerWindow* window) const { | |
| 265 for (const ServerWindow* parent = window; parent; parent = parent->parent_) { | |
| 266 if (parent == this) | |
| 267 return true; | |
| 268 } | |
| 269 return false; | |
| 270 } | |
| 271 | |
| 272 void ServerWindow::SetVisible(bool value) { | |
| 273 if (visible_ == value) | |
| 274 return; | |
| 275 | |
| 276 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 277 OnWillChangeWindowVisibility(this)); | |
| 278 visible_ = value; | |
| 279 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 280 OnWindowVisibilityChanged(this)); | |
| 281 } | |
| 282 | |
| 283 void ServerWindow::SetOpacity(float value) { | |
| 284 if (value == opacity_) | |
| 285 return; | |
| 286 float old_opacity = opacity_; | |
| 287 opacity_ = value; | |
| 288 delegate_->OnScheduleWindowPaint(this); | |
| 289 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 290 OnWindowOpacityChanged(this, old_opacity, opacity_)); | |
| 291 } | |
| 292 | |
| 293 void ServerWindow::SetPredefinedCursor(mus::mojom::Cursor value) { | |
| 294 if (value == cursor_id_) | |
| 295 return; | |
| 296 cursor_id_ = value; | |
| 297 FOR_EACH_OBSERVER( | |
| 298 ServerWindowObserver, observers_, | |
| 299 OnWindowPredefinedCursorChanged(this, static_cast<int32_t>(value))); | |
| 300 } | |
| 301 | |
| 302 void ServerWindow::SetNonClientCursor(mus::mojom::Cursor value) { | |
| 303 if (value == non_client_cursor_id_) | |
| 304 return; | |
| 305 non_client_cursor_id_ = value; | |
| 306 FOR_EACH_OBSERVER( | |
| 307 ServerWindowObserver, observers_, | |
| 308 OnWindowNonClientCursorChanged(this, static_cast<int32_t>(value))); | |
| 309 } | |
| 310 | |
| 311 void ServerWindow::SetTransform(const gfx::Transform& transform) { | |
| 312 if (transform_ == transform) | |
| 313 return; | |
| 314 | |
| 315 transform_ = transform; | |
| 316 delegate_->OnScheduleWindowPaint(this); | |
| 317 } | |
| 318 | |
| 319 void ServerWindow::SetProperty(const std::string& name, | |
| 320 const std::vector<uint8_t>* value) { | |
| 321 auto it = properties_.find(name); | |
| 322 if (it != properties_.end()) { | |
| 323 if (value && it->second == *value) | |
| 324 return; | |
| 325 } else if (!value) { | |
| 326 // This property isn't set in |properties_| and |value| is nullptr, so | |
| 327 // there's | |
| 328 // no change. | |
| 329 return; | |
| 330 } | |
| 331 | |
| 332 if (value) { | |
| 333 properties_[name] = *value; | |
| 334 } else if (it != properties_.end()) { | |
| 335 properties_.erase(it); | |
| 336 } | |
| 337 | |
| 338 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 339 OnWindowSharedPropertyChanged(this, name, value)); | |
| 340 } | |
| 341 | |
| 342 std::string ServerWindow::GetName() const { | |
| 343 auto it = properties_.find(mojom::WindowManager::kName_Property); | |
| 344 if (it == properties_.end()) | |
| 345 return std::string(); | |
| 346 return std::string(it->second.begin(), it->second.end()); | |
| 347 } | |
| 348 | |
| 349 void ServerWindow::SetTextInputState(const ui::TextInputState& state) { | |
| 350 const bool changed = !(text_input_state_ == state); | |
| 351 if (changed) { | |
| 352 text_input_state_ = state; | |
| 353 // keyboard even if the state is not changed. So we have to notify | |
| 354 // |observers_|. | |
| 355 FOR_EACH_OBSERVER(ServerWindowObserver, observers_, | |
| 356 OnWindowTextInputStateChanged(this, state)); | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 bool ServerWindow::IsDrawn() const { | |
| 361 const ServerWindow* root = delegate_->GetRootWindow(this); | |
| 362 if (!root || !root->visible()) | |
| 363 return false; | |
| 364 const ServerWindow* window = this; | |
| 365 while (window && window != root && window->visible()) | |
| 366 window = window->parent(); | |
| 367 return root == window; | |
| 368 } | |
| 369 | |
| 370 void ServerWindow::DestroySurfacesScheduledForDestruction() { | |
| 371 if (!surface_manager_) | |
| 372 return; | |
| 373 ServerWindowSurface* surface = surface_manager_->GetDefaultSurface(); | |
| 374 if (surface) | |
| 375 surface->DestroySurfacesScheduledForDestruction(); | |
| 376 | |
| 377 surface = surface_manager_->GetUnderlaySurface(); | |
| 378 if (surface) | |
| 379 surface->DestroySurfacesScheduledForDestruction(); | |
| 380 } | |
| 381 | |
| 382 ServerWindowSurfaceManager* ServerWindow::GetOrCreateSurfaceManager() { | |
| 383 if (!surface_manager_.get()) | |
| 384 surface_manager_.reset(new ServerWindowSurfaceManager(this)); | |
| 385 return surface_manager_.get(); | |
| 386 } | |
| 387 | |
| 388 void ServerWindow::SetUnderlayOffset(const gfx::Vector2d& offset) { | |
| 389 if (offset == underlay_offset_) | |
| 390 return; | |
| 391 | |
| 392 underlay_offset_ = offset; | |
| 393 delegate_->OnScheduleWindowPaint(this); | |
| 394 } | |
| 395 | |
| 396 #if !defined(NDEBUG) | |
| 397 std::string ServerWindow::GetDebugWindowHierarchy() const { | |
| 398 std::string result; | |
| 399 BuildDebugInfo(std::string(), &result); | |
| 400 return result; | |
| 401 } | |
| 402 | |
| 403 void ServerWindow::BuildDebugInfo(const std::string& depth, | |
| 404 std::string* result) const { | |
| 405 std::string name = GetName(); | |
| 406 *result += base::StringPrintf( | |
| 407 "%sid=%d,%d visible=%s bounds=%d,%d %dx%d %s\n", depth.c_str(), | |
| 408 static_cast<int>(id_.client_id), static_cast<int>(id_.window_id), | |
| 409 visible_ ? "true" : "false", bounds_.x(), bounds_.y(), bounds_.width(), | |
| 410 bounds_.height(), !name.empty() ? name.c_str() : "(no name)"); | |
| 411 for (const ServerWindow* child : children_) | |
| 412 child->BuildDebugInfo(depth + " ", result); | |
| 413 } | |
| 414 #endif | |
| 415 | |
| 416 void ServerWindow::RemoveImpl(ServerWindow* window) { | |
| 417 window->parent_ = nullptr; | |
| 418 children_.erase(std::find(children_.begin(), children_.end(), window)); | |
| 419 } | |
| 420 | |
| 421 void ServerWindow::OnStackingChanged() { | |
| 422 if (stacking_target_) { | |
| 423 Windows::const_iterator window_i = std::find( | |
| 424 parent()->children().begin(), parent()->children().end(), this); | |
| 425 DCHECK(window_i != parent()->children().end()); | |
| 426 if (window_i != parent()->children().begin() && | |
| 427 (*(window_i - 1) == stacking_target_)) { | |
| 428 return; | |
| 429 } | |
| 430 } | |
| 431 RestackTransientDescendants(this, &GetStackingTarget, &ReorderImpl); | |
| 432 } | |
| 433 | |
| 434 // static | |
| 435 void ServerWindow::ReorderImpl(ServerWindow* window, | |
| 436 ServerWindow* relative, | |
| 437 mojom::OrderDirection direction) { | |
| 438 DCHECK(relative); | |
| 439 DCHECK_NE(window, relative); | |
| 440 DCHECK_EQ(window->parent(), relative->parent()); | |
| 441 | |
| 442 if (!AdjustStackingForTransientWindows(&window, &relative, &direction, | |
| 443 window->stacking_target_)) | |
| 444 return; | |
| 445 | |
| 446 window->parent_->children_.erase(std::find(window->parent_->children_.begin(), | |
| 447 window->parent_->children_.end(), | |
| 448 window)); | |
| 449 Windows::iterator i = std::find(window->parent_->children_.begin(), | |
| 450 window->parent_->children_.end(), relative); | |
| 451 if (direction == mojom::OrderDirection::ABOVE) { | |
| 452 DCHECK(i != window->parent_->children_.end()); | |
| 453 window->parent_->children_.insert(++i, window); | |
| 454 } else if (direction == mojom::OrderDirection::BELOW) { | |
| 455 DCHECK(i != window->parent_->children_.end()); | |
| 456 window->parent_->children_.insert(i, window); | |
| 457 } | |
| 458 FOR_EACH_OBSERVER(ServerWindowObserver, window->observers_, | |
| 459 OnWindowReordered(window, relative, direction)); | |
| 460 window->OnStackingChanged(); | |
| 461 } | |
| 462 | |
| 463 // static | |
| 464 ServerWindow** ServerWindow::GetStackingTarget(ServerWindow* window) { | |
| 465 return &window->stacking_target_; | |
| 466 } | |
| 467 | |
| 468 } // namespace ws | |
| 469 | |
| 470 } // namespace mus | |
| OLD | NEW |