window.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright (c) 2012 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 "ui/aura/window.h" 6 7#include <algorithm> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/callback.h" 12#include "base/logging.h" 13#include "base/stl_util.h" 14#include "base/strings/string_util.h" 15#include "base/strings/stringprintf.h" 16#include "ui/aura/client/capture_client.h" 17#include "ui/aura/client/event_client.h" 18#include "ui/aura/client/screen_position_client.h" 19#include "ui/aura/client/stacking_client.h" 20#include "ui/aura/client/visibility_client.h" 21#include "ui/aura/env.h" 22#include "ui/aura/focus_manager.h" 23#include "ui/aura/layout_manager.h" 24#include "ui/aura/root_window.h" 25#include "ui/aura/window_delegate.h" 26#include "ui/aura/window_destruction_observer.h" 27#include "ui/aura/window_observer.h" 28#include "ui/base/animation/multi_animation.h" 29#include "ui/compositor/compositor.h" 30#include "ui/compositor/layer.h" 31#include "ui/gfx/canvas.h" 32#include "ui/gfx/path.h" 33#include "ui/gfx/screen.h" 34 35namespace aura { 36 37namespace { 38 39void MailboxReleaseCallback(scoped_ptr<base::SharedMemory> shared_memory, 40 unsigned sync_point, bool lost_resource) { 41 // NOTE: shared_memory will get released when we go out of scope. 42} 43 44} // namespace 45 46Window::Window(WindowDelegate* delegate) 47 : type_(client::WINDOW_TYPE_UNKNOWN), 48 owned_by_parent_(true), 49 delegate_(delegate), 50 parent_(NULL), 51 transient_parent_(NULL), 52 visible_(false), 53 id_(-1), 54 transparent_(false), 55 user_data_(NULL), 56 ignore_events_(false), 57 // Don't notify newly added observers during notification. This causes 58 // problems for code that adds an observer as part of an observer 59 // notification (such as the workspace code). 60 observers_(ObserverList<WindowObserver>::NOTIFY_EXISTING_ONLY) { 61 set_target_handler(delegate_); 62} 63 64Window::~Window() { 65 // layer_ can be NULL if Init() wasn't invoked, which can happen 66 // only in tests. 67 if (layer_) 68 layer_->SuppressPaint(); 69 70 // Let the delegate know we're in the processing of destroying. 71 if (delegate_) 72 delegate_->OnWindowDestroying(); 73 FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this)); 74 75 // Let the root know so that it can remove any references to us. 76 RootWindow* root_window = GetRootWindow(); 77 if (root_window) 78 root_window->OnWindowDestroying(this); 79 80 // Then destroy the children. 81 while (!children_.empty()) { 82 Window* child = children_[0]; 83 if (child->owned_by_parent_) { 84 delete child; 85 // Deleting the child so remove it from out children_ list. 86 DCHECK(std::find(children_.begin(), children_.end(), child) == 87 children_.end()); 88 } else { 89 // Even if we can't delete the child, we still need to remove it from the 90 // parent so that relevant bookkeeping (parent_ back-pointers etc) are 91 // updated. 92 RemoveChild(child); 93 } 94 } 95 96 // Removes ourselves from our transient parent (if it hasn't been done by the 97 // RootWindow). 98 if (transient_parent_) 99 transient_parent_->RemoveTransientChild(this); 100 101 // The window needs to be removed from the parent before calling the 102 // WindowDestroyed callbacks of delegate and the observers. 103 if (parent_) 104 parent_->RemoveChild(this); 105 106 // And let the delegate do any post cleanup. 107 // TODO(beng): Figure out if this notification needs to happen here, or if it 108 // can be moved down adjacent to the observer notification. If it has to be 109 // done here, the reason why should be documented. 110 if (delegate_) 111 delegate_->OnWindowDestroyed(); 112 113 // Destroy transient children, only after we've removed ourselves from our 114 // parent, as destroying an active transient child may otherwise attempt to 115 // refocus us. 116 Windows transient_children(transient_children_); 117 STLDeleteElements(&transient_children); 118 DCHECK(transient_children_.empty()); 119 120 FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroyed(this)); 121 122 // Clear properties. 123 for (std::map<const void*, Value>::const_iterator iter = prop_map_.begin(); 124 iter != prop_map_.end(); 125 ++iter) { 126 if (iter->second.deallocator) 127 (*iter->second.deallocator)(iter->second.value); 128 } 129 prop_map_.clear(); 130 131 // If we have layer it will either be destroyed by layer_owner_'s dtor, or by 132 // whoever acquired it. We don't have a layer if Init() wasn't invoked, which 133 // can happen in tests. 134 if (layer_) 135 layer_->set_delegate(NULL); 136 layer_ = NULL; 137} 138 139void Window::Init(ui::LayerType layer_type) { 140 layer_ = new ui::Layer(layer_type); 141 layer_owner_.reset(layer_); 142 layer_->SetVisible(false); 143 layer_->set_delegate(this); 144 UpdateLayerName(name_); 145 layer_->SetFillsBoundsOpaquely(!transparent_); 146 147 Env::GetInstance()->NotifyWindowInitialized(this); 148} 149 150ui::Layer* Window::RecreateLayer() { 151 // Disconnect the old layer, but don't delete it. 152 ui::Layer* old_layer = AcquireLayer(); 153 if (!old_layer) 154 return NULL; 155 156 old_layer->set_delegate(NULL); 157 float mailbox_scale_factor; 158 cc::TextureMailbox old_mailbox = 159 old_layer->GetTextureMailbox(&mailbox_scale_factor); 160 scoped_refptr<ui::Texture> old_texture = old_layer->external_texture(); 161 if (delegate_ && old_texture.get()) 162 old_layer->SetExternalTexture(delegate_->CopyTexture()); 163 164 layer_ = new ui::Layer(old_layer->type()); 165 layer_owner_.reset(layer_); 166 layer_->SetVisible(old_layer->visible()); 167 layer_->set_scale_content(old_layer->scale_content()); 168 layer_->set_delegate(this); 169 layer_->SetMasksToBounds(old_layer->GetMasksToBounds()); 170 // Move the original texture to the new layer if the old layer has a 171 // texture and we could copy it into the old layer, 172 // crbug.com/175211. 173 if (delegate_ && old_texture.get()) { 174 layer_->SetExternalTexture(old_texture.get()); 175 } else if (old_mailbox.IsSharedMemory()) { 176 base::SharedMemory* old_buffer = old_mailbox.shared_memory(); 177 const size_t size = old_mailbox.shared_memory_size_in_bytes(); 178 179 scoped_ptr<base::SharedMemory> new_buffer(new base::SharedMemory); 180 new_buffer->CreateAndMapAnonymous(size); 181 182 if (old_buffer->memory() && new_buffer->memory()) { 183 memcpy(new_buffer->memory(), old_buffer->memory(), size); 184 base::SharedMemory* new_buffer_raw_ptr = new_buffer.get(); 185 cc::TextureMailbox::ReleaseCallback callback = 186 base::Bind(MailboxReleaseCallback, Passed(&new_buffer)); 187 cc::TextureMailbox new_mailbox(new_buffer_raw_ptr, 188 old_mailbox.shared_memory_size(), 189 callback); 190 layer_->SetTextureMailbox(new_mailbox, mailbox_scale_factor); 191 } 192 } 193 194 UpdateLayerName(name_); 195 layer_->SetFillsBoundsOpaquely(!transparent_); 196 // Install new layer as a sibling of the old layer, stacked below it. 197 if (old_layer->parent()) { 198 old_layer->parent()->Add(layer_); 199 old_layer->parent()->StackBelow(layer_, old_layer); 200 } 201 // Migrate all the child layers over to the new layer. Copy the list because 202 // the items are removed during iteration. 203 std::vector<ui::Layer*> children_copy = old_layer->children(); 204 for (std::vector<ui::Layer*>::const_iterator it = children_copy.begin(); 205 it != children_copy.end(); 206 ++it) { 207 ui::Layer* child = *it; 208 layer_->Add(child); 209 } 210 return old_layer; 211} 212 213void Window::SetType(client::WindowType type) { 214 // Cannot change type after the window is initialized. 215 DCHECK(!layer()); 216 type_ = type; 217} 218 219void Window::SetName(const std::string& name) { 220 name_ = name; 221 222 if (layer()) 223 UpdateLayerName(name_); 224} 225 226void Window::SetTransparent(bool transparent) { 227 // Cannot change transparent flag after the window is initialized. 228 DCHECK(!layer()); 229 transparent_ = transparent; 230} 231 232RootWindow* Window::GetRootWindow() { 233 return const_cast<RootWindow*>( 234 static_cast<const Window*>(this)->GetRootWindow()); 235} 236 237const RootWindow* Window::GetRootWindow() const { 238 return parent_ ? parent_->GetRootWindow() : NULL; 239} 240 241void Window::Show() { 242 SetVisible(true); 243} 244 245void Window::Hide() { 246 for (Windows::iterator it = transient_children_.begin(); 247 it != transient_children_.end(); ++it) { 248 (*it)->Hide(); 249 } 250 SetVisible(false); 251 ReleaseCapture(); 252} 253 254bool Window::IsVisible() const { 255 // Layer visibility can be inconsistent with window visibility, for example 256 // when a Window is hidden, we want this function to return false immediately 257 // after, even though the client may decide to animate the hide effect (and 258 // so the layer will be visible for some time after Hide() is called). 259 return visible_ && layer_ && layer_->IsDrawn(); 260} 261 262gfx::Rect Window::GetBoundsInRootWindow() const { 263 // TODO(beng): There may be a better way to handle this, and the existing code 264 // is likely wrong anyway in a multi-display world, but this will 265 // do for now. 266 if (!GetRootWindow()) 267 return bounds(); 268 gfx::Point origin = bounds().origin(); 269 ConvertPointToTarget(parent_, GetRootWindow(), &origin); 270 return gfx::Rect(origin, bounds().size()); 271} 272 273gfx::Rect Window::GetBoundsInScreen() const { 274 gfx::Rect bounds(GetBoundsInRootWindow()); 275 const RootWindow* root = GetRootWindow(); 276 if (root) { 277 aura::client::ScreenPositionClient* screen_position_client = 278 aura::client::GetScreenPositionClient(root); 279 if (screen_position_client) { 280 gfx::Point origin = bounds.origin(); 281 screen_position_client->ConvertPointToScreen(root, &origin); 282 bounds.set_origin(origin); 283 } 284 } 285 return bounds; 286} 287 288void Window::SetTransform(const gfx::Transform& transform) { 289 RootWindow* root_window = GetRootWindow(); 290 bool contained_mouse = IsVisible() && root_window && 291 ContainsPointInRoot(root_window->GetLastMouseLocationInRoot()); 292 layer()->SetTransform(transform); 293 if (root_window) 294 root_window->OnWindowTransformed(this, contained_mouse); 295} 296 297void Window::SetLayoutManager(LayoutManager* layout_manager) { 298 if (layout_manager == layout_manager_) 299 return; 300 layout_manager_.reset(layout_manager); 301 if (!layout_manager) 302 return; 303 // If we're changing to a new layout manager, ensure it is aware of all the 304 // existing child windows. 305 for (Windows::const_iterator it = children_.begin(); 306 it != children_.end(); 307 ++it) 308 layout_manager_->OnWindowAddedToLayout(*it); 309} 310 311void Window::SetBounds(const gfx::Rect& new_bounds) { 312 if (parent_ && parent_->layout_manager()) 313 parent_->layout_manager()->SetChildBounds(this, new_bounds); 314 else 315 SetBoundsInternal(new_bounds); 316} 317 318void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen, 319 const gfx::Display& dst_display) { 320 RootWindow* root = GetRootWindow(); 321 if (root) { 322 gfx::Point origin = new_bounds_in_screen.origin(); 323 aura::client::ScreenPositionClient* screen_position_client = 324 aura::client::GetScreenPositionClient(root); 325 screen_position_client->SetBounds(this, new_bounds_in_screen, dst_display); 326 return; 327 } 328 SetBounds(new_bounds_in_screen); 329} 330 331gfx::Rect Window::GetTargetBounds() const { 332 return layer_->GetTargetBounds(); 333} 334 335const gfx::Rect& Window::bounds() const { 336 return layer_->bounds(); 337} 338 339void Window::SchedulePaintInRect(const gfx::Rect& rect) { 340 if (layer_->SchedulePaint(rect)) { 341 FOR_EACH_OBSERVER( 342 WindowObserver, observers_, OnWindowPaintScheduled(this, rect)); 343 } 344} 345 346void Window::SetDefaultParentByRootWindow(RootWindow* root_window, 347 const gfx::Rect& bounds_in_screen) { 348 DCHECK(root_window); 349 350 // Stacking clients are mandatory on RootWindow objects. 351 client::StackingClient* client = client::GetStackingClient(root_window); 352 DCHECK(client); 353 354 aura::Window* default_parent = client->GetDefaultParent( 355 root_window, this, bounds_in_screen); 356 default_parent->AddChild(this); 357} 358 359void Window::StackChildAtTop(Window* child) { 360 if (children_.size() <= 1 || child == children_.back()) 361 return; // In the front already. 362 StackChildAbove(child, children_.back()); 363} 364 365void Window::StackChildAbove(Window* child, Window* target) { 366 StackChildRelativeTo(child, target, STACK_ABOVE); 367} 368 369void Window::StackChildAtBottom(Window* child) { 370 if (children_.size() <= 1 || child == children_.front()) 371 return; // At the bottom already. 372 StackChildBelow(child, children_.front()); 373} 374 375void Window::StackChildBelow(Window* child, Window* target) { 376 StackChildRelativeTo(child, target, STACK_BELOW); 377} 378 379void Window::AddChild(Window* child) { 380 WindowObserver::HierarchyChangeParams params; 381 params.target = child; 382 params.new_parent = this; 383 params.old_parent = child->parent(); 384 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING; 385 NotifyWindowHierarchyChange(params); 386 387 RootWindow* old_root = child->GetRootWindow(); 388 389 DCHECK(std::find(children_.begin(), children_.end(), child) == 390 children_.end()); 391 if (child->parent()) 392 child->parent()->RemoveChildImpl(child, this); 393 child->parent_ = this; 394 395 layer_->Add(child->layer_); 396 397 children_.push_back(child); 398 if (layout_manager_) 399 layout_manager_->OnWindowAddedToLayout(child); 400 FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowAdded(child)); 401 child->OnParentChanged(); 402 403 RootWindow* root_window = GetRootWindow(); 404 if (root_window && old_root != root_window) { 405 root_window->OnWindowAddedToRootWindow(child); 406 child->NotifyAddedToRootWindow(); 407 } 408 409 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED; 410 NotifyWindowHierarchyChange(params); 411} 412 413void Window::RemoveChild(Window* child) { 414 WindowObserver::HierarchyChangeParams params; 415 params.target = child; 416 params.new_parent = NULL; 417 params.old_parent = this; 418 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING; 419 NotifyWindowHierarchyChange(params); 420 421 RemoveChildImpl(child, NULL); 422 423 params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED; 424 NotifyWindowHierarchyChange(params); 425} 426 427bool Window::Contains(const Window* other) const { 428 for (const Window* parent = other; parent; parent = parent->parent_) { 429 if (parent == this) 430 return true; 431 } 432 return false; 433} 434 435void Window::AddTransientChild(Window* child) { 436 if (child->transient_parent_) 437 child->transient_parent_->RemoveTransientChild(child); 438 DCHECK(std::find(transient_children_.begin(), transient_children_.end(), 439 child) == transient_children_.end()); 440 transient_children_.push_back(child); 441 child->transient_parent_ = this; 442 FOR_EACH_OBSERVER(WindowObserver, observers_, 443 OnAddTransientChild(this, child)); 444} 445 446void Window::RemoveTransientChild(Window* child) { 447 Windows::iterator i = 448 std::find(transient_children_.begin(), transient_children_.end(), child); 449 DCHECK(i != transient_children_.end()); 450 transient_children_.erase(i); 451 if (child->transient_parent_ == this) 452 child->transient_parent_ = NULL; 453 FOR_EACH_OBSERVER(WindowObserver, observers_, 454 OnRemoveTransientChild(this, child)); 455} 456 457Window* Window::GetChildById(int id) { 458 return const_cast<Window*>(const_cast<const Window*>(this)->GetChildById(id)); 459} 460 461const Window* Window::GetChildById(int id) const { 462 Windows::const_iterator i; 463 for (i = children_.begin(); i != children_.end(); ++i) { 464 if ((*i)->id() == id) 465 return *i; 466 const Window* result = (*i)->GetChildById(id); 467 if (result) 468 return result; 469 } 470 return NULL; 471} 472 473// static 474void Window::ConvertPointToTarget(const Window* source, 475 const Window* target, 476 gfx::Point* point) { 477 if (!source) 478 return; 479 if (source->GetRootWindow() != target->GetRootWindow()) { 480 client::ScreenPositionClient* source_client = 481 GetScreenPositionClient(source->GetRootWindow()); 482 source_client->ConvertPointToScreen(source, point); 483 484 client::ScreenPositionClient* target_client = 485 GetScreenPositionClient(target->GetRootWindow()); 486 target_client->ConvertPointFromScreen(target, point); 487 } else { 488 ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point); 489 } 490} 491 492void Window::MoveCursorTo(const gfx::Point& point_in_window) { 493 RootWindow* root_window = GetRootWindow(); 494 DCHECK(root_window); 495 gfx::Point point_in_root(point_in_window); 496 ConvertPointToTarget(this, root_window, &point_in_root); 497 root_window->MoveCursorTo(point_in_root); 498} 499 500gfx::NativeCursor Window::GetCursor(const gfx::Point& point) const { 501 return delegate_ ? delegate_->GetCursor(point) : gfx::kNullCursor; 502} 503 504void Window::SetEventFilter(ui::EventHandler* event_filter) { 505 if (event_filter_) 506 RemovePreTargetHandler(event_filter_.get()); 507 event_filter_.reset(event_filter); 508 if (event_filter) 509 AddPreTargetHandler(event_filter); 510} 511 512void Window::AddObserver(WindowObserver* observer) { 513 observers_.AddObserver(observer); 514} 515 516void Window::RemoveObserver(WindowObserver* observer) { 517 observers_.RemoveObserver(observer); 518} 519 520bool Window::HasObserver(WindowObserver* observer) { 521 return observers_.HasObserver(observer); 522} 523 524bool Window::ContainsPointInRoot(const gfx::Point& point_in_root) const { 525 const Window* root_window = GetRootWindow(); 526 if (!root_window) 527 return false; 528 gfx::Point local_point(point_in_root); 529 ConvertPointToTarget(root_window, this, &local_point); 530 return gfx::Rect(GetTargetBounds().size()).Contains(local_point); 531} 532 533bool Window::ContainsPoint(const gfx::Point& local_point) const { 534 return gfx::Rect(bounds().size()).Contains(local_point); 535} 536 537bool Window::HitTest(const gfx::Point& local_point) { 538 // Expand my bounds for hit testing (override is usually zero but it's 539 // probably cheaper to do the math every time than to branch). 540 gfx::Rect local_bounds(gfx::Point(), bounds().size()); 541 local_bounds.Inset(aura::Env::GetInstance()->is_touch_down() ? 542 hit_test_bounds_override_outer_touch_ : 543 hit_test_bounds_override_outer_mouse_); 544 545 if (!delegate_ || !delegate_->HasHitTestMask()) 546 return local_bounds.Contains(local_point); 547 548 gfx::Path mask; 549 delegate_->GetHitTestMask(&mask); 550 551 SkRegion clip_region; 552 clip_region.setRect(local_bounds.x(), local_bounds.y(), 553 local_bounds.width(), local_bounds.height()); 554 SkRegion mask_region; 555 return mask_region.setPath(mask, clip_region) && 556 mask_region.contains(local_point.x(), local_point.y()); 557} 558 559Window* Window::GetEventHandlerForPoint(const gfx::Point& local_point) { 560 return GetWindowForPoint(local_point, true, true); 561} 562 563Window* Window::GetTopWindowContainingPoint(const gfx::Point& local_point) { 564 return GetWindowForPoint(local_point, false, false); 565} 566 567Window* Window::GetToplevelWindow() { 568 Window* topmost_window_with_delegate = NULL; 569 for (aura::Window* window = this; window != NULL; window = window->parent()) { 570 if (window->delegate()) 571 topmost_window_with_delegate = window; 572 } 573 return topmost_window_with_delegate; 574} 575 576void Window::Focus() { 577 client::FocusClient* client = client::GetFocusClient(this); 578 DCHECK(client); 579 client->FocusWindow(this); 580} 581 582void Window::Blur() { 583 client::FocusClient* client = client::GetFocusClient(this); 584 DCHECK(client); 585 client->FocusWindow(NULL); 586} 587 588bool Window::HasFocus() const { 589 client::FocusClient* client = client::GetFocusClient(this); 590 return client && client->GetFocusedWindow() == this; 591} 592 593bool Window::CanFocus() const { 594 // NOTE: as part of focusing the window the ActivationClient may make the 595 // window visible (by way of making a hidden ancestor visible). For this 596 // reason we can't check visibility here and assume the client is doing it. 597 if (!parent_ || (delegate_ && !delegate_->CanFocus())) 598 return false; 599 600 // The client may forbid certain windows from receiving focus at a given point 601 // in time. 602 client::EventClient* client = client::GetEventClient(GetRootWindow()); 603 if (client && !client->CanProcessEventsWithinSubtree(this)) 604 return false; 605 606 return parent_->CanFocus(); 607} 608 609bool Window::CanReceiveEvents() const { 610 // The client may forbid certain windows from receiving events at a given 611 // point in time. 612 client::EventClient* client = client::GetEventClient(GetRootWindow()); 613 if (client && !client->CanProcessEventsWithinSubtree(this)) 614 return false; 615 616 return parent_ && IsVisible() && parent_->CanReceiveEvents(); 617} 618 619void Window::SetCapture() { 620 if (!IsVisible()) 621 return; 622 623 RootWindow* root_window = GetRootWindow(); 624 if (!root_window) 625 return; 626 client::GetCaptureClient(root_window)->SetCapture(this); 627} 628 629void Window::ReleaseCapture() { 630 RootWindow* root_window = GetRootWindow(); 631 if (!root_window) 632 return; 633 client::GetCaptureClient(root_window)->ReleaseCapture(this); 634} 635 636bool Window::HasCapture() { 637 RootWindow* root_window = GetRootWindow(); 638 return root_window && 639 client::GetCaptureClient(root_window)->GetCaptureWindow() == this; 640} 641 642void Window::SuppressPaint() { 643 layer_->SuppressPaint(); 644} 645 646// {Set,Get,Clear}Property are implemented in window_property.h. 647 648void Window::SetNativeWindowProperty(const char* key, void* value) { 649 SetPropertyInternal( 650 key, key, NULL, reinterpret_cast<int64>(value), 0); 651} 652 653void* Window::GetNativeWindowProperty(const char* key) const { 654 return reinterpret_cast<void*>(GetPropertyInternal(key, 0)); 655} 656 657void Window::OnDeviceScaleFactorChanged(float device_scale_factor) { 658 if (delegate_) 659 delegate_->OnDeviceScaleFactorChanged(device_scale_factor); 660} 661 662#ifndef NDEBUG 663std::string Window::GetDebugInfo() const { 664 return base::StringPrintf( 665 "%s<%d> bounds(%d, %d, %d, %d) %s %s opacity=%.1f", 666 name().empty() ? "Unknown" : name().c_str(), id(), 667 bounds().x(), bounds().y(), bounds().width(), bounds().height(), 668 visible_ ? "WindowVisible" : "WindowHidden", 669 layer_->GetTargetVisibility() ? "LayerVisible" : "LayerHidden", 670 layer_->opacity()); 671} 672 673void Window::PrintWindowHierarchy(int depth) const { 674 printf("%*s%s\n", depth * 2, "", GetDebugInfo().c_str()); 675 for (Windows::const_iterator it = children_.begin(); 676 it != children_.end(); ++it) { 677 Window* child = *it; 678 child->PrintWindowHierarchy(depth + 1); 679 } 680} 681#endif 682 683/////////////////////////////////////////////////////////////////////////////// 684// Window, private: 685 686int64 Window::SetPropertyInternal(const void* key, 687 const char* name, 688 PropertyDeallocator deallocator, 689 int64 value, 690 int64 default_value) { 691 int64 old = GetPropertyInternal(key, default_value); 692 if (value == default_value) { 693 prop_map_.erase(key); 694 } else { 695 Value prop_value; 696 prop_value.name = name; 697 prop_value.value = value; 698 prop_value.deallocator = deallocator; 699 prop_map_[key] = prop_value; 700 } 701 FOR_EACH_OBSERVER(WindowObserver, observers_, 702 OnWindowPropertyChanged(this, key, old)); 703 return old; 704} 705 706int64 Window::GetPropertyInternal(const void* key, 707 int64 default_value) const { 708 std::map<const void*, Value>::const_iterator iter = prop_map_.find(key); 709 if (iter == prop_map_.end()) 710 return default_value; 711 return iter->second.value; 712} 713 714void Window::SetBoundsInternal(const gfx::Rect& new_bounds) { 715 gfx::Rect actual_new_bounds(new_bounds); 716 717 // Ensure we don't go smaller than our minimum bounds. 718 if (delegate_) { 719 const gfx::Size& min_size = delegate_->GetMinimumSize(); 720 actual_new_bounds.set_width( 721 std::max(min_size.width(), actual_new_bounds.width())); 722 actual_new_bounds.set_height( 723 std::max(min_size.height(), actual_new_bounds.height())); 724 } 725 726 gfx::Rect old_bounds = GetTargetBounds(); 727 728 // Always need to set the layer's bounds -- even if it is to the same thing. 729 // This may cause important side effects such as stopping animation. 730 layer_->SetBounds(actual_new_bounds); 731 732 // If we are currently not the layer's delegate, we will not get bounds 733 // changed notification from the layer (this typically happens after animating 734 // hidden). We must notify ourselves. 735 if (layer_->delegate() != this) 736 OnLayerBoundsChanged(old_bounds, ContainsMouse()); 737} 738 739void Window::SetVisible(bool visible) { 740 if (visible == layer_->GetTargetVisibility()) 741 return; // No change. 742 743 FOR_EACH_OBSERVER(WindowObserver, observers_, 744 OnWindowVisibilityChanging(this, visible)); 745 746 RootWindow* root_window = GetRootWindow(); 747 if (root_window) 748 root_window->DispatchMouseExitToHidingWindow(this); 749 750 client::VisibilityClient* visibility_client = 751 client::GetVisibilityClient(this); 752 if (visibility_client) 753 visibility_client->UpdateLayerVisibility(this, visible); 754 else 755 layer_->SetVisible(visible); 756 visible_ = visible; 757 SchedulePaint(); 758 if (parent_ && parent_->layout_manager_) 759 parent_->layout_manager_->OnChildWindowVisibilityChanged(this, visible); 760 761 if (delegate_) 762 delegate_->OnWindowTargetVisibilityChanged(visible); 763 764 NotifyWindowVisibilityChanged(this, visible); 765 766 if (root_window) 767 root_window->OnWindowVisibilityChanged(this, visible); 768} 769 770void Window::SchedulePaint() { 771 SchedulePaintInRect(gfx::Rect(0, 0, bounds().width(), bounds().height())); 772} 773 774Window* Window::GetWindowForPoint(const gfx::Point& local_point, 775 bool return_tightest, 776 bool for_event_handling) { 777 if (!IsVisible()) 778 return NULL; 779 780 if ((for_event_handling && !HitTest(local_point)) || 781 (!for_event_handling && !ContainsPoint(local_point))) 782 return NULL; 783 784 // Check if I should claim this event and not pass it to my children because 785 // the location is inside my hit test override area. For details, see 786 // set_hit_test_bounds_override_inner(). 787 if (for_event_handling && !hit_test_bounds_override_inner_.empty()) { 788 gfx::Rect inset_local_bounds(gfx::Point(), bounds().size()); 789 inset_local_bounds.Inset(hit_test_bounds_override_inner_); 790 // We know we're inside the normal local bounds, so if we're outside the 791 // inset bounds we must be in the special hit test override area. 792 DCHECK(HitTest(local_point)); 793 if (!inset_local_bounds.Contains(local_point)) 794 return delegate_ ? this : NULL; 795 } 796 797 if (!return_tightest && delegate_) 798 return this; 799 800 for (Windows::const_reverse_iterator it = children_.rbegin(), 801 rend = children_.rend(); 802 it != rend; ++it) { 803 Window* child = *it; 804 805 if (for_event_handling) { 806 // The client may not allow events to be processed by certain subtrees. 807 client::EventClient* client = client::GetEventClient(GetRootWindow()); 808 if (client && !client->CanProcessEventsWithinSubtree(child)) 809 continue; 810 } 811 812 // We don't process events for invisible windows or those that have asked 813 // to ignore events. 814 if (!child->IsVisible() || (for_event_handling && child->ignore_events_)) 815 continue; 816 817 gfx::Point point_in_child_coords(local_point); 818 ConvertPointToTarget(this, child, &point_in_child_coords); 819 if (for_event_handling && delegate_ && 820 !delegate_->ShouldDescendIntoChildForEventHandling( 821 child, local_point)) { 822 continue; 823 } 824 825 Window* match = child->GetWindowForPoint(point_in_child_coords, 826 return_tightest, 827 for_event_handling); 828 if (match) 829 return match; 830 } 831 832 return delegate_ ? this : NULL; 833} 834 835void Window::RemoveChildImpl(Window* child, Window* new_parent) { 836 if (layout_manager_) 837 layout_manager_->OnWillRemoveWindowFromLayout(child); 838 FOR_EACH_OBSERVER(WindowObserver, observers_, OnWillRemoveWindow(child)); 839 RootWindow* root_window = child->GetRootWindow(); 840 RootWindow* new_root_window = new_parent ? new_parent->GetRootWindow() : NULL; 841 if (root_window && root_window != new_root_window) { 842 root_window->OnWindowRemovedFromRootWindow(child, new_root_window); 843 child->NotifyRemovingFromRootWindow(); 844 } 845 child->parent_ = NULL; 846 // We should only remove the child's layer if the child still owns that layer. 847 // Someone else may have acquired ownership of it via AcquireLayer() and may 848 // expect the hierarchy to go unchanged as the Window is destroyed. 849 if (child->layer_owner_) 850 layer_->Remove(child->layer_); 851 Windows::iterator i = std::find(children_.begin(), children_.end(), child); 852 DCHECK(i != children_.end()); 853 children_.erase(i); 854 child->OnParentChanged(); 855 if (layout_manager_) 856 layout_manager_->OnWindowRemovedFromLayout(child); 857} 858 859void Window::OnParentChanged() { 860 FOR_EACH_OBSERVER( 861 WindowObserver, observers_, OnWindowParentChanged(this, parent_)); 862} 863 864void Window::StackChildRelativeTo(Window* child, 865 Window* target, 866 StackDirection direction) { 867 DCHECK_NE(child, target); 868 DCHECK(child); 869 DCHECK(target); 870 DCHECK_EQ(this, child->parent()); 871 DCHECK_EQ(this, target->parent()); 872 873 const size_t target_i = 874 std::find(children_.begin(), children_.end(), target) - children_.begin(); 875 876 // By convention we don't stack on top of windows with layers with NULL 877 // delegates. Walk backward to find a valid target window. 878 // See tests WindowTest.StackingMadrigal and StackOverClosingTransient 879 // for an explanation of this. 880 size_t final_target_i = target_i; 881 while (final_target_i > 0 && 882 children_[final_target_i]->layer()->delegate() == NULL) { 883 --final_target_i; 884 } 885 886 // Allow stacking immediately below a window with a NULL layer. 887 if (direction == STACK_BELOW && target_i != final_target_i) 888 direction = STACK_ABOVE; 889 890 Window* final_target = children_[final_target_i]; 891 892 // If we couldn't find a valid target position, don't move anything. 893 if (final_target->layer()->delegate() == NULL) 894 return; 895 896 // Don't try to stack a child above itself. 897 if (child == final_target) 898 return; 899 900 // Move the child and all its transients. 901 StackChildRelativeToImpl(child, final_target, direction); 902} 903 904void Window::StackChildRelativeToImpl(Window* child, 905 Window* target, 906 StackDirection direction) { 907 DCHECK_NE(child, target); 908 DCHECK(child); 909 DCHECK(target); 910 DCHECK_EQ(this, child->parent()); 911 DCHECK_EQ(this, target->parent()); 912 913 const size_t child_i = 914 std::find(children_.begin(), children_.end(), child) - children_.begin(); 915 const size_t target_i = 916 std::find(children_.begin(), children_.end(), target) - children_.begin(); 917 918 // Don't move the child if it is already in the right place. 919 if ((direction == STACK_ABOVE && child_i == target_i + 1) || 920 (direction == STACK_BELOW && child_i + 1 == target_i)) 921 return; 922 923 const size_t dest_i = 924 direction == STACK_ABOVE ? 925 (child_i < target_i ? target_i : target_i + 1) : 926 (child_i < target_i ? target_i - 1 : target_i); 927 children_.erase(children_.begin() + child_i); 928 children_.insert(children_.begin() + dest_i, child); 929 930 if (direction == STACK_ABOVE) 931 layer()->StackAbove(child->layer(), target->layer()); 932 else 933 layer()->StackBelow(child->layer(), target->layer()); 934 935 // Stack any transient children that share the same parent to be in front of 936 // 'child'. 937 Window* last_transient = child; 938 for (Windows::iterator it = child->transient_children_.begin(); 939 it != child->transient_children_.end(); ++it) { 940 Window* transient_child = *it; 941 if (transient_child->parent_ == this) { 942 StackChildRelativeToImpl(transient_child, last_transient, STACK_ABOVE); 943 last_transient = transient_child; 944 } 945 } 946 947 child->OnStackingChanged(); 948} 949 950void Window::OnStackingChanged() { 951 FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowStackingChanged(this)); 952} 953 954void Window::NotifyRemovingFromRootWindow() { 955 FOR_EACH_OBSERVER(WindowObserver, observers_, 956 OnWindowRemovingFromRootWindow(this)); 957 for (Window::Windows::const_iterator it = children_.begin(); 958 it != children_.end(); ++it) { 959 (*it)->NotifyRemovingFromRootWindow(); 960 } 961} 962 963void Window::NotifyAddedToRootWindow() { 964 FOR_EACH_OBSERVER(WindowObserver, observers_, 965 OnWindowAddedToRootWindow(this)); 966 for (Window::Windows::const_iterator it = children_.begin(); 967 it != children_.end(); ++it) { 968 (*it)->NotifyAddedToRootWindow(); 969 } 970} 971 972void Window::NotifyWindowHierarchyChange( 973 const WindowObserver::HierarchyChangeParams& params) { 974 params.target->NotifyWindowHierarchyChangeDown(params); 975 switch (params.phase) { 976 case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING: 977 if (params.old_parent) 978 params.old_parent->NotifyWindowHierarchyChangeUp(params); 979 break; 980 case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED: 981 if (params.new_parent) 982 params.new_parent->NotifyWindowHierarchyChangeUp(params); 983 break; 984 default: 985 NOTREACHED(); 986 break; 987 } 988} 989 990void Window::NotifyWindowHierarchyChangeDown( 991 const WindowObserver::HierarchyChangeParams& params) { 992 NotifyWindowHierarchyChangeAtReceiver(params); 993 for (Window::Windows::const_iterator it = children_.begin(); 994 it != children_.end(); ++it) { 995 (*it)->NotifyWindowHierarchyChangeDown(params); 996 } 997} 998 999void Window::NotifyWindowHierarchyChangeUp( 1000 const WindowObserver::HierarchyChangeParams& params) { 1001 for (Window* window = this; window; window = window->parent()) 1002 window->NotifyWindowHierarchyChangeAtReceiver(params); 1003} 1004 1005void Window::NotifyWindowHierarchyChangeAtReceiver( 1006 const WindowObserver::HierarchyChangeParams& params) { 1007 WindowObserver::HierarchyChangeParams local_params = params; 1008 local_params.receiver = this; 1009 1010 switch (params.phase) { 1011 case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING: 1012 FOR_EACH_OBSERVER(WindowObserver, observers_, 1013 OnWindowHierarchyChanging(local_params)); 1014 break; 1015 case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED: 1016 FOR_EACH_OBSERVER(WindowObserver, observers_, 1017 OnWindowHierarchyChanged(local_params)); 1018 break; 1019 default: 1020 NOTREACHED(); 1021 break; 1022 } 1023} 1024 1025void Window::NotifyWindowVisibilityChanged(aura::Window* target, 1026 bool visible) { 1027 if (!NotifyWindowVisibilityChangedDown(target, visible)) { 1028 return; // |this| has been deleted. 1029 } 1030 NotifyWindowVisibilityChangedUp(target, visible); 1031} 1032 1033bool Window::NotifyWindowVisibilityChangedAtReceiver(aura::Window* target, 1034 bool visible) { 1035 // |this| may be deleted during a call to OnWindowVisibilityChanged 1036 // on one of the observers. We create an local observer for that. In 1037 // that case we exit without further access to any members. 1038 WindowDestructionObserver destruction_observer(this); 1039 FOR_EACH_OBSERVER(WindowObserver, observers_, 1040 OnWindowVisibilityChanged(target, visible)); 1041 return !destruction_observer.destroyed(); 1042} 1043 1044bool Window::NotifyWindowVisibilityChangedDown(aura::Window* target, 1045 bool visible) { 1046 if (!NotifyWindowVisibilityChangedAtReceiver(target, visible)) 1047 return false; // |this| was deleted. 1048 std::set<const Window*> child_already_processed; 1049 bool child_destroyed = false; 1050 do { 1051 child_destroyed = false; 1052 for (Window::Windows::const_iterator it = children_.begin(); 1053 it != children_.end(); ++it) { 1054 if (!child_already_processed.insert(*it).second) 1055 continue; 1056 if (!(*it)->NotifyWindowVisibilityChangedDown(target, visible)) { 1057 // |*it| was deleted, |it| is invalid and |children_| has changed. 1058 // We exit the current for-loop and enter a new one. 1059 child_destroyed = true; 1060 break; 1061 } 1062 } 1063 } while (child_destroyed); 1064 return true; 1065} 1066 1067void Window::NotifyWindowVisibilityChangedUp(aura::Window* target, 1068 bool visible) { 1069 for (Window* window = this; window; window = window->parent()) { 1070 bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target, visible); 1071 DCHECK(ret); 1072 } 1073} 1074 1075void Window::OnLayerBoundsChanged(const gfx::Rect& old_bounds, 1076 bool contained_mouse) { 1077 if (layout_manager_) 1078 layout_manager_->OnWindowResized(); 1079 if (delegate_) 1080 delegate_->OnBoundsChanged(old_bounds, bounds()); 1081 FOR_EACH_OBSERVER(WindowObserver, 1082 observers_, 1083 OnWindowBoundsChanged(this, old_bounds, bounds())); 1084 RootWindow* root_window = GetRootWindow(); 1085 if (root_window) 1086 root_window->OnWindowBoundsChanged(this, contained_mouse); 1087} 1088 1089void Window::OnPaintLayer(gfx::Canvas* canvas) { 1090 if (delegate_) 1091 delegate_->OnPaint(canvas); 1092} 1093 1094base::Closure Window::PrepareForLayerBoundsChange() { 1095 return base::Bind(&Window::OnLayerBoundsChanged, base::Unretained(this), 1096 bounds(), ContainsMouse()); 1097} 1098 1099bool Window::CanAcceptEvent(const ui::Event& event) { 1100 // The client may forbid certain windows from receiving events at a given 1101 // point in time. 1102 client::EventClient* client = client::GetEventClient(GetRootWindow()); 1103 if (client && !client->CanProcessEventsWithinSubtree(this)) 1104 return false; 1105 1106 bool visible = event.dispatch_to_hidden_targets() || IsVisible(); 1107 return visible && (!parent_ || parent_->CanAcceptEvent(event)); 1108} 1109 1110ui::EventTarget* Window::GetParentTarget() { 1111 return parent_; 1112} 1113 1114void Window::UpdateLayerName(const std::string& name) { 1115#if !defined(NDEBUG) 1116 DCHECK(layer()); 1117 1118 std::string layer_name(name_); 1119 if (layer_name.empty()) 1120 layer_name.append("Unnamed Window"); 1121 1122 if (id_ != -1) { 1123 char id_buf[10]; 1124 base::snprintf(id_buf, sizeof(id_buf), " %d", id_); 1125 layer_name.append(id_buf); 1126 } 1127 layer()->set_name(layer_name); 1128#endif 1129} 1130 1131bool Window::ContainsMouse() { 1132 bool contains_mouse = false; 1133 if (IsVisible()) { 1134 RootWindow* root_window = GetRootWindow(); 1135 contains_mouse = root_window && 1136 ContainsPointInRoot(root_window->GetLastMouseLocationInRoot()); 1137 } 1138 return contains_mouse; 1139} 1140 1141} // namespace aura 1142