| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/aura/window.h" |
| |
| #include <algorithm> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/callback.h" |
| #include "base/logging.h" |
| #include "base/profiler/scoped_tracker.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "ui/aura/client/capture_client.h" |
| #include "ui/aura/client/cursor_client.h" |
| #include "ui/aura/client/event_client.h" |
| #include "ui/aura/client/focus_client.h" |
| #include "ui/aura/client/screen_position_client.h" |
| #include "ui/aura/client/visibility_client.h" |
| #include "ui/aura/client/window_stacking_client.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/layout_manager.h" |
| #include "ui/aura/window_delegate.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/aura/window_tracker.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/compositor/compositor.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/events/event_target_iterator.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/path.h" |
| #include "ui/gfx/scoped_canvas.h" |
| #include "ui/gfx/screen.h" |
| |
| namespace aura { |
| |
| namespace { |
| |
| ui::LayerType WindowLayerTypeToUILayerType(WindowLayerType window_layer_type) { |
| switch (window_layer_type) { |
| case WINDOW_LAYER_NONE: |
| break; |
| case WINDOW_LAYER_NOT_DRAWN: |
| return ui::LAYER_NOT_DRAWN; |
| case WINDOW_LAYER_TEXTURED: |
| return ui::LAYER_TEXTURED; |
| case WINDOW_LAYER_SOLID_COLOR: |
| return ui::LAYER_SOLID_COLOR; |
| } |
| NOTREACHED(); |
| return ui::LAYER_NOT_DRAWN; |
| } |
| |
| // Used when searching for a Window to stack relative to. |
| template <class T> |
| T IteratorForDirectionBegin(aura::Window* window); |
| |
| template <> |
| Window::Windows::const_iterator IteratorForDirectionBegin( |
| aura::Window* window) { |
| return window->children().begin(); |
| } |
| |
| template <> |
| Window::Windows::const_reverse_iterator IteratorForDirectionBegin( |
| aura::Window* window) { |
| return window->children().rbegin(); |
| } |
| |
| template <class T> |
| T IteratorForDirectionEnd(aura::Window* window); |
| |
| template <> |
| Window::Windows::const_iterator IteratorForDirectionEnd(aura::Window* window) { |
| return window->children().end(); |
| } |
| |
| template <> |
| Window::Windows::const_reverse_iterator IteratorForDirectionEnd( |
| aura::Window* window) { |
| return window->children().rend(); |
| } |
| |
| // Depth first search for the first Window with a layer to stack relative |
| // to. Starts at target. Does not descend into |ignore|. |
| template <class T> |
| ui::Layer* FindStackingTargetLayerDown(aura::Window* target, |
| aura::Window* ignore) { |
| if (target == ignore) |
| return NULL; |
| |
| if (target->layer()) |
| return target->layer(); |
| |
| for (T i = IteratorForDirectionBegin<T>(target); |
| i != IteratorForDirectionEnd<T>(target); ++i) { |
| ui::Layer* layer = FindStackingTargetLayerDown<T>(*i, ignore); |
| if (layer) |
| return layer; |
| } |
| return NULL; |
| } |
| |
| // Depth first search through the siblings of |target||. This does not search |
| // all the siblings, only those before/after |target| (depening upon the |
| // template type) and ignoring |ignore|. Returns the Layer of the first Window |
| // encountered with a Layer. |
| template <class T> |
| ui::Layer* FindStackingLayerInSiblings(aura::Window* target, |
| aura::Window* ignore) { |
| aura::Window* parent = target->parent(); |
| for (T i = std::find(IteratorForDirectionBegin<T>(parent), |
| IteratorForDirectionEnd<T>(parent), target); |
| i != IteratorForDirectionEnd<T>(parent); ++i) { |
| ui::Layer* layer = FindStackingTargetLayerDown<T>(*i, ignore); |
| if (layer) |
| return layer; |
| } |
| return NULL; |
| } |
| |
| // Returns the first Window that has a Layer. This does a depth first search |
| // through the descendants of |target| first, then ascends up doing a depth |
| // first search through siblings of all ancestors until a Layer is found or an |
| // ancestor with a layer is found. This is intended to locate a layer to stack |
| // other layers relative to. |
| template <class T> |
| ui::Layer* FindStackingTargetLayer(aura::Window* target, aura::Window* ignore) { |
| ui::Layer* result = FindStackingTargetLayerDown<T>(target, ignore); |
| if (result) |
| return result; |
| while (target->parent()) { |
| ui::Layer* result = FindStackingLayerInSiblings<T>(target, ignore); |
| if (result) |
| return result; |
| target = target->parent(); |
| if (target->layer()) |
| return NULL; |
| } |
| return NULL; |
| } |
| |
| // Does a depth first search for all descendants of |child| that have layers. |
| // This stops at any descendants that have layers (and adds them to |layers|). |
| void GetLayersToStack(aura::Window* child, std::vector<ui::Layer*>* layers) { |
| if (child->layer()) { |
| layers->push_back(child->layer()); |
| return; |
| } |
| for (size_t i = 0; i < child->children().size(); ++i) |
| GetLayersToStack(child->children()[i], layers); |
| } |
| |
| } // namespace |
| |
| class ScopedCursorHider { |
| public: |
| explicit ScopedCursorHider(Window* window) |
| : window_(window), |
| hid_cursor_(false) { |
| if (!window_->IsRootWindow()) |
| return; |
| const bool cursor_is_in_bounds = window_->GetBoundsInScreen().Contains( |
| Env::GetInstance()->last_mouse_location()); |
| client::CursorClient* cursor_client = client::GetCursorClient(window_); |
| if (cursor_is_in_bounds && cursor_client && |
| cursor_client->IsCursorVisible()) { |
| cursor_client->HideCursor(); |
| hid_cursor_ = true; |
| } |
| } |
| ~ScopedCursorHider() { |
| if (!window_->IsRootWindow()) |
| return; |
| |
| // Update the device scale factor of the cursor client only when the last |
| // mouse location is on this root window. |
| if (hid_cursor_) { |
| client::CursorClient* cursor_client = client::GetCursorClient(window_); |
| if (cursor_client) { |
| const gfx::Display& display = |
| gfx::Screen::GetScreenFor(window_)->GetDisplayNearestWindow( |
| window_); |
| cursor_client->SetDisplay(display); |
| cursor_client->ShowCursor(); |
| } |
| } |
| } |
| |
| private: |
| Window* window_; |
| bool hid_cursor_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ScopedCursorHider); |
| }; |
| |
| Window::Window(WindowDelegate* delegate) |
| : host_(NULL), |
| type_(ui::wm::WINDOW_TYPE_UNKNOWN), |
| owned_by_parent_(true), |
| delegate_(delegate), |
| parent_(NULL), |
| visible_(false), |
| id_(-1), |
| transparent_(false), |
| user_data_(NULL), |
| ignore_events_(false), |
| // Don't notify newly added observers during notification. This causes |
| // problems for code that adds an observer as part of an observer |
| // notification (such as the workspace code). |
| observers_(ObserverList<WindowObserver>::NOTIFY_EXISTING_ONLY) { |
| set_target_handler(delegate_); |
| } |
| |
| Window::~Window() { |
| // |layer()| can be NULL during tests, or if this Window is layerless. |
| if (layer()) { |
| if (layer()->owner() == this) |
| layer()->CompleteAllAnimations(); |
| layer()->SuppressPaint(); |
| } |
| |
| // Let the delegate know we're in the processing of destroying. |
| if (delegate_) |
| delegate_->OnWindowDestroying(this); |
| FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this)); |
| |
| // While we are being destroyed, our target handler may also be in the |
| // process of destruction or already destroyed, so do not forward any |
| // input events at the ui::EP_TARGET phase. |
| set_target_handler(nullptr); |
| |
| // TODO(beng): See comment in window_event_dispatcher.h. This shouldn't be |
| // necessary but unfortunately is right now due to ordering |
| // peculiarities. WED must be notified _after_ other observers |
| // are notified of pending teardown but before the hierarchy |
| // is actually torn down. |
| WindowTreeHost* host = GetHost(); |
| if (host) |
| host->dispatcher()->OnPostNotifiedWindowDestroying(this); |
| |
| // The window should have already had its state cleaned up in |
| // WindowEventDispatcher::OnWindowHidden(), but there have been some crashes |
| // involving windows being destroyed without being hidden first. See |
| // crbug.com/342040. This should help us debug the issue. TODO(tdresser): |
| // remove this once we determine why we have windows that are destroyed |
| // without being hidden. |
| bool window_incorrectly_cleaned_up = CleanupGestureState(); |
| CHECK(!window_incorrectly_cleaned_up); |
| |
| // Then destroy the children. |
| RemoveOrDestroyChildren(); |
| |
| // The window needs to be removed from the parent before calling the |
| // WindowDestroyed callbacks of delegate and the observers. |
| if (parent_) |
| parent_->RemoveChild(this); |
| |
| if (delegate_) |
| delegate_->OnWindowDestroyed(this); |
| ObserverListBase<WindowObserver>::Iterator iter(&observers_); |
| for (WindowObserver* observer = iter.GetNext(); observer; |
| observer = iter.GetNext()) { |
| RemoveObserver(observer); |
| observer->OnWindowDestroyed(this); |
| } |
| |
| // Clear properties. |
| for (std::map<const void*, Value>::const_iterator iter = prop_map_.begin(); |
| iter != prop_map_.end(); |
| ++iter) { |
| if (iter->second.deallocator) |
| (*iter->second.deallocator)(iter->second.value); |
| } |
| prop_map_.clear(); |
| |
| // If we have layer it will either be destroyed by |layer_owner_|'s dtor, or |
| // by whoever acquired it. We don't have a layer if Init() wasn't invoked or |
| // we are layerless. |
| if (layer()) |
| layer()->set_delegate(NULL); |
| DestroyLayer(); |
| } |
| |
| void Window::Init(WindowLayerType window_layer_type) { |
| if (window_layer_type != WINDOW_LAYER_NONE) { |
| SetLayer(new ui::Layer(WindowLayerTypeToUILayerType(window_layer_type))); |
| layer()->SetVisible(false); |
| layer()->set_delegate(this); |
| UpdateLayerName(); |
| layer()->SetFillsBoundsOpaquely(!transparent_); |
| } |
| |
| Env::GetInstance()->NotifyWindowInitialized(this); |
| } |
| |
| void Window::SetType(ui::wm::WindowType type) { |
| // Cannot change type after the window is initialized. |
| DCHECK(!layer()); |
| type_ = type; |
| } |
| |
| void Window::SetName(const std::string& name) { |
| name_ = name; |
| |
| if (layer()) |
| UpdateLayerName(); |
| } |
| |
| void Window::SetTitle(const base::string16& title) { |
| title_ = title; |
| FOR_EACH_OBSERVER(WindowObserver, |
| observers_, |
| OnWindowTitleChanged(this)); |
| } |
| |
| void Window::SetTransparent(bool transparent) { |
| transparent_ = transparent; |
| if (layer()) |
| layer()->SetFillsBoundsOpaquely(!transparent_); |
| } |
| |
| void Window::SetFillsBoundsCompletely(bool fills_bounds) { |
| if (layer()) |
| layer()->SetFillsBoundsCompletely(fills_bounds); |
| } |
| |
| Window* Window::GetRootWindow() { |
| return const_cast<Window*>( |
| static_cast<const Window*>(this)->GetRootWindow()); |
| } |
| |
| const Window* Window::GetRootWindow() const { |
| return IsRootWindow() ? this : parent_ ? parent_->GetRootWindow() : NULL; |
| } |
| |
| WindowTreeHost* Window::GetHost() { |
| return const_cast<WindowTreeHost*>(const_cast<const Window*>(this)-> |
| GetHost()); |
| } |
| |
| const WindowTreeHost* Window::GetHost() const { |
| const Window* root_window = GetRootWindow(); |
| return root_window ? root_window->host_ : NULL; |
| } |
| |
| void Window::Show() { |
| if (layer()) { |
| DCHECK_EQ(visible_, layer()->GetTargetVisibility()); |
| // It is not allowed that a window is visible but the layers alpha is fully |
| // transparent since the window would still be considered to be active but |
| // could not be seen. |
| DCHECK(!(visible_ && layer()->GetTargetOpacity() == 0.0f)); |
| } |
| SetVisible(true); |
| } |
| |
| void Window::Hide() { |
| // RootWindow::OnVisibilityChanged will call ReleaseCapture. |
| SetVisible(false); |
| } |
| |
| bool Window::IsVisible() const { |
| // Layer visibility can be inconsistent with window visibility, for example |
| // when a Window is hidden, we want this function to return false immediately |
| // after, even though the client may decide to animate the hide effect (and |
| // so the layer will be visible for some time after Hide() is called). |
| for (const Window* window = this; window; window = window->parent()) { |
| if (!window->visible_) |
| return false; |
| if (window->layer()) |
| return window->layer()->IsDrawn(); |
| } |
| return false; |
| } |
| |
| gfx::Rect Window::GetBoundsInRootWindow() const { |
| // TODO(beng): There may be a better way to handle this, and the existing code |
| // is likely wrong anyway in a multi-display world, but this will |
| // do for now. |
| if (!GetRootWindow()) |
| return bounds(); |
| gfx::Rect bounds_in_root(bounds().size()); |
| ConvertRectToTarget(this, GetRootWindow(), &bounds_in_root); |
| return bounds_in_root; |
| } |
| |
| gfx::Rect Window::GetBoundsInScreen() const { |
| gfx::Rect bounds(GetBoundsInRootWindow()); |
| const Window* root = GetRootWindow(); |
| if (root) { |
| aura::client::ScreenPositionClient* screen_position_client = |
| aura::client::GetScreenPositionClient(root); |
| if (screen_position_client) { |
| gfx::Point origin = bounds.origin(); |
| screen_position_client->ConvertPointToScreen(root, &origin); |
| bounds.set_origin(origin); |
| } |
| } |
| return bounds; |
| } |
| |
| void Window::SetTransform(const gfx::Transform& transform) { |
| if (!layer()) { |
| // Transforms aren't supported on layerless windows. |
| NOTREACHED(); |
| return; |
| } |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowTransforming(this)); |
| layer()->SetTransform(transform); |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowTransformed(this)); |
| NotifyAncestorWindowTransformed(this); |
| } |
| |
| void Window::SetLayoutManager(LayoutManager* layout_manager) { |
| if (layout_manager == layout_manager_) |
| return; |
| layout_manager_.reset(layout_manager); |
| if (!layout_manager) |
| return; |
| // If we're changing to a new layout manager, ensure it is aware of all the |
| // existing child windows. |
| for (Windows::const_iterator it = children_.begin(); |
| it != children_.end(); |
| ++it) |
| layout_manager_->OnWindowAddedToLayout(*it); |
| } |
| |
| scoped_ptr<ui::EventTargeter> |
| Window::SetEventTargeter(scoped_ptr<ui::EventTargeter> targeter) { |
| scoped_ptr<ui::EventTargeter> old_targeter = targeter_.Pass(); |
| targeter_ = targeter.Pass(); |
| return old_targeter.Pass(); |
| } |
| |
| void Window::SetBounds(const gfx::Rect& new_bounds) { |
| if (parent_ && parent_->layout_manager()) |
| parent_->layout_manager()->SetChildBounds(this, new_bounds); |
| else { |
| // Ensure we don't go smaller than our minimum bounds. |
| gfx::Rect final_bounds(new_bounds); |
| if (delegate_) { |
| const gfx::Size& min_size = delegate_->GetMinimumSize(); |
| final_bounds.set_width(std::max(min_size.width(), final_bounds.width())); |
| final_bounds.set_height(std::max(min_size.height(), |
| final_bounds.height())); |
| } |
| SetBoundsInternal(final_bounds); |
| } |
| } |
| |
| void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen, |
| const gfx::Display& dst_display) { |
| Window* root = GetRootWindow(); |
| if (root) { |
| gfx::Point origin = new_bounds_in_screen.origin(); |
| aura::client::ScreenPositionClient* screen_position_client = |
| aura::client::GetScreenPositionClient(root); |
| screen_position_client->SetBounds(this, new_bounds_in_screen, dst_display); |
| return; |
| } |
| SetBounds(new_bounds_in_screen); |
| } |
| |
| gfx::Rect Window::GetTargetBounds() const { |
| if (!layer()) |
| return bounds(); |
| |
| if (!parent_ || parent_->layer()) |
| return layer()->GetTargetBounds(); |
| |
| // We have a layer but our parent (who is valid) doesn't. This means the |
| // coordinates of the layer are relative to the first ancestor with a layer; |
| // convert to be relative to parent. |
| gfx::Vector2d offset; |
| const aura::Window* ancestor_with_layer = |
| parent_->GetAncestorWithLayer(&offset); |
| if (!ancestor_with_layer) |
| return layer()->GetTargetBounds(); |
| |
| gfx::Rect layer_target_bounds = layer()->GetTargetBounds(); |
| layer_target_bounds -= offset; |
| return layer_target_bounds; |
| } |
| |
| void Window::SchedulePaintInRect(const gfx::Rect& rect) { |
| if (!layer() && parent_) { |
| // Notification of paint scheduled happens for the window with a layer. |
| gfx::Rect parent_rect(bounds().size()); |
| parent_rect.Intersect(rect); |
| if (!parent_rect.IsEmpty()) { |
| parent_rect.Offset(bounds().origin().OffsetFromOrigin()); |
| parent_->SchedulePaintInRect(parent_rect); |
| } |
| } else if (layer()) { |
| layer()->SchedulePaint(rect); |
| } |
| } |
| |
| void Window::StackChildAtTop(Window* child) { |
| if (children_.size() <= 1 || child == children_.back()) |
| return; // In the front already. |
| StackChildAbove(child, children_.back()); |
| } |
| |
| void Window::StackChildAbove(Window* child, Window* target) { |
| StackChildRelativeTo(child, target, STACK_ABOVE); |
| } |
| |
| void Window::StackChildAtBottom(Window* child) { |
| if (children_.size() <= 1 || child == children_.front()) |
| return; // At the bottom already. |
| StackChildBelow(child, children_.front()); |
| } |
| |
| void Window::StackChildBelow(Window* child, Window* target) { |
| StackChildRelativeTo(child, target, STACK_BELOW); |
| } |
| |
| void Window::AddChild(Window* child) { |
| WindowObserver::HierarchyChangeParams params; |
| params.target = child; |
| params.new_parent = this; |
| params.old_parent = child->parent(); |
| params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING; |
| NotifyWindowHierarchyChange(params); |
| |
| Window* old_root = child->GetRootWindow(); |
| |
| DCHECK(std::find(children_.begin(), children_.end(), child) == |
| children_.end()); |
| if (child->parent()) |
| child->parent()->RemoveChildImpl(child, this); |
| |
| gfx::Vector2d offset; |
| aura::Window* ancestor_with_layer = GetAncestorWithLayer(&offset); |
| |
| child->parent_ = this; |
| |
| if (ancestor_with_layer) { |
| offset += child->bounds().OffsetFromOrigin(); |
| child->ReparentLayers(ancestor_with_layer->layer(), offset); |
| } |
| |
| children_.push_back(child); |
| if (layout_manager_) |
| layout_manager_->OnWindowAddedToLayout(child); |
| FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowAdded(child)); |
| child->OnParentChanged(); |
| |
| Window* root_window = GetRootWindow(); |
| if (root_window && old_root != root_window) { |
| root_window->GetHost()->dispatcher()->OnWindowAddedToRootWindow(child); |
| child->NotifyAddedToRootWindow(); |
| } |
| |
| params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED; |
| NotifyWindowHierarchyChange(params); |
| } |
| |
| void Window::RemoveChild(Window* child) { |
| WindowObserver::HierarchyChangeParams params; |
| params.target = child; |
| params.new_parent = NULL; |
| params.old_parent = this; |
| params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING; |
| NotifyWindowHierarchyChange(params); |
| |
| RemoveChildImpl(child, NULL); |
| |
| params.phase = WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED; |
| NotifyWindowHierarchyChange(params); |
| } |
| |
| bool Window::Contains(const Window* other) const { |
| for (const Window* parent = other; parent; parent = parent->parent_) { |
| if (parent == this) |
| return true; |
| } |
| return false; |
| } |
| |
| Window* Window::GetChildById(int id) { |
| return const_cast<Window*>(const_cast<const Window*>(this)->GetChildById(id)); |
| } |
| |
| const Window* Window::GetChildById(int id) const { |
| Windows::const_iterator i; |
| for (i = children_.begin(); i != children_.end(); ++i) { |
| if ((*i)->id() == id) |
| return *i; |
| const Window* result = (*i)->GetChildById(id); |
| if (result) |
| return result; |
| } |
| return NULL; |
| } |
| |
| // static |
| void Window::ConvertPointToTarget(const Window* source, |
| const Window* target, |
| gfx::Point* point) { |
| if (!source) |
| return; |
| if (source->GetRootWindow() != target->GetRootWindow()) { |
| client::ScreenPositionClient* source_client = |
| client::GetScreenPositionClient(source->GetRootWindow()); |
| // |source_client| can be NULL in tests. |
| if (source_client) |
| source_client->ConvertPointToScreen(source, point); |
| |
| client::ScreenPositionClient* target_client = |
| client::GetScreenPositionClient(target->GetRootWindow()); |
| // |target_client| can be NULL in tests. |
| if (target_client) |
| target_client->ConvertPointFromScreen(target, point); |
| } else if ((source != target) && (!source->layer() || !target->layer())) { |
| if (!source->layer()) { |
| gfx::Vector2d offset_to_layer; |
| source = source->GetAncestorWithLayer(&offset_to_layer); |
| *point += offset_to_layer; |
| } |
| if (!target->layer()) { |
| gfx::Vector2d offset_to_layer; |
| target = target->GetAncestorWithLayer(&offset_to_layer); |
| *point -= offset_to_layer; |
| } |
| ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point); |
| } else { |
| ui::Layer::ConvertPointToLayer(source->layer(), target->layer(), point); |
| } |
| } |
| |
| // static |
| void Window::ConvertRectToTarget(const Window* source, |
| const Window* target, |
| gfx::Rect* rect) { |
| DCHECK(rect); |
| gfx::Point origin = rect->origin(); |
| ConvertPointToTarget(source, target, &origin); |
| rect->set_origin(origin); |
| } |
| |
| ui::TextInputClient* Window::GetFocusedTextInputClient() { |
| return delegate_ ? delegate_->GetFocusedTextInputClient() : nullptr; |
| } |
| |
| void Window::MoveCursorTo(const gfx::Point& point_in_window) { |
| Window* root_window = GetRootWindow(); |
| DCHECK(root_window); |
| gfx::Point point_in_root(point_in_window); |
| ConvertPointToTarget(this, root_window, &point_in_root); |
| root_window->GetHost()->MoveCursorTo(point_in_root); |
| } |
| |
| gfx::NativeCursor Window::GetCursor(const gfx::Point& point) const { |
| return delegate_ ? delegate_->GetCursor(point) : gfx::kNullCursor; |
| } |
| |
| void Window::AddObserver(WindowObserver* observer) { |
| observer->OnObservingWindow(this); |
| observers_.AddObserver(observer); |
| } |
| |
| void Window::RemoveObserver(WindowObserver* observer) { |
| observer->OnUnobservingWindow(this); |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool Window::HasObserver(const WindowObserver* observer) const { |
| return observers_.HasObserver(observer); |
| } |
| |
| bool Window::ContainsPointInRoot(const gfx::Point& point_in_root) const { |
| const Window* root_window = GetRootWindow(); |
| if (!root_window) |
| return false; |
| gfx::Point local_point(point_in_root); |
| ConvertPointToTarget(root_window, this, &local_point); |
| return gfx::Rect(GetTargetBounds().size()).Contains(local_point); |
| } |
| |
| bool Window::ContainsPoint(const gfx::Point& local_point) const { |
| return gfx::Rect(bounds().size()).Contains(local_point); |
| } |
| |
| Window* Window::GetEventHandlerForPoint(const gfx::Point& local_point) { |
| return GetWindowForPoint(local_point, true, true); |
| } |
| |
| Window* Window::GetTopWindowContainingPoint(const gfx::Point& local_point) { |
| return GetWindowForPoint(local_point, false, false); |
| } |
| |
| Window* Window::GetToplevelWindow() { |
| Window* topmost_window_with_delegate = NULL; |
| for (aura::Window* window = this; window != NULL; window = window->parent()) { |
| if (window->delegate()) |
| topmost_window_with_delegate = window; |
| } |
| return topmost_window_with_delegate; |
| } |
| |
| void Window::Focus() { |
| client::FocusClient* client = client::GetFocusClient(this); |
| DCHECK(client); |
| client->FocusWindow(this); |
| } |
| |
| void Window::Blur() { |
| client::FocusClient* client = client::GetFocusClient(this); |
| DCHECK(client); |
| client->FocusWindow(NULL); |
| } |
| |
| bool Window::HasFocus() const { |
| client::FocusClient* client = client::GetFocusClient(this); |
| return client && client->GetFocusedWindow() == this; |
| } |
| |
| bool Window::CanFocus() const { |
| if (IsRootWindow()) |
| return IsVisible(); |
| |
| // NOTE: as part of focusing the window the ActivationClient may make the |
| // window visible (by way of making a hidden ancestor visible). For this |
| // reason we can't check visibility here and assume the client is doing it. |
| if (!parent_ || (delegate_ && !delegate_->CanFocus())) |
| return false; |
| |
| // The client may forbid certain windows from receiving focus at a given point |
| // in time. |
| client::EventClient* client = client::GetEventClient(GetRootWindow()); |
| if (client && !client->CanProcessEventsWithinSubtree(this)) |
| return false; |
| |
| return parent_->CanFocus(); |
| } |
| |
| bool Window::CanReceiveEvents() const { |
| if (IsRootWindow()) |
| return IsVisible(); |
| |
| // The client may forbid certain windows from receiving events at a given |
| // point in time. |
| client::EventClient* client = client::GetEventClient(GetRootWindow()); |
| if (client && !client->CanProcessEventsWithinSubtree(this)) |
| return false; |
| |
| return parent_ && IsVisible() && parent_->CanReceiveEvents(); |
| } |
| |
| void Window::SetCapture() { |
| if (!IsVisible()) |
| return; |
| |
| Window* root_window = GetRootWindow(); |
| if (!root_window) |
| return; |
| client::CaptureClient* capture_client = client::GetCaptureClient(root_window); |
| if (!capture_client) |
| return; |
| client::GetCaptureClient(root_window)->SetCapture(this); |
| } |
| |
| void Window::ReleaseCapture() { |
| Window* root_window = GetRootWindow(); |
| if (!root_window) |
| return; |
| client::CaptureClient* capture_client = client::GetCaptureClient(root_window); |
| if (!capture_client) |
| return; |
| client::GetCaptureClient(root_window)->ReleaseCapture(this); |
| } |
| |
| bool Window::HasCapture() { |
| Window* root_window = GetRootWindow(); |
| if (!root_window) |
| return false; |
| client::CaptureClient* capture_client = client::GetCaptureClient(root_window); |
| return capture_client && capture_client->GetCaptureWindow() == this; |
| } |
| |
| void Window::SuppressPaint() { |
| if (layer()) |
| layer()->SuppressPaint(); |
| } |
| |
| // {Set,Get,Clear}Property are implemented in window_property.h. |
| |
| void Window::SetNativeWindowProperty(const char* key, void* value) { |
| SetPropertyInternal( |
| key, key, NULL, reinterpret_cast<int64>(value), 0); |
| } |
| |
| void* Window::GetNativeWindowProperty(const char* key) const { |
| return reinterpret_cast<void*>(GetPropertyInternal(key, 0)); |
| } |
| |
| void Window::OnDeviceScaleFactorChanged(float device_scale_factor) { |
| ScopedCursorHider hider(this); |
| if (delegate_) |
| delegate_->OnDeviceScaleFactorChanged(device_scale_factor); |
| } |
| |
| #if !defined(NDEBUG) |
| std::string Window::GetDebugInfo() const { |
| return base::StringPrintf( |
| "%s<%d> bounds(%d, %d, %d, %d) %s %s opacity=%.1f", |
| name().empty() ? "Unknown" : name().c_str(), id(), |
| bounds().x(), bounds().y(), bounds().width(), bounds().height(), |
| visible_ ? "WindowVisible" : "WindowHidden", |
| layer() ? |
| (layer()->GetTargetVisibility() ? "LayerVisible" : "LayerHidden") : |
| "NoLayer", |
| layer() ? layer()->opacity() : 1.0f); |
| } |
| |
| void Window::PrintWindowHierarchy(int depth) const { |
| VLOG(0) << base::StringPrintf( |
| "%*s%s", depth * 2, "", GetDebugInfo().c_str()); |
| for (Windows::const_iterator it = children_.begin(); |
| it != children_.end(); ++it) { |
| Window* child = *it; |
| child->PrintWindowHierarchy(depth + 1); |
| } |
| } |
| #endif |
| |
| void Window::RemoveOrDestroyChildren() { |
| while (!children_.empty()) { |
| Window* child = children_[0]; |
| if (child->owned_by_parent_) { |
| delete child; |
| // Deleting the child so remove it from out children_ list. |
| DCHECK(std::find(children_.begin(), children_.end(), child) == |
| children_.end()); |
| } else { |
| // Even if we can't delete the child, we still need to remove it from the |
| // parent so that relevant bookkeeping (parent_ back-pointers etc) are |
| // updated. |
| RemoveChild(child); |
| } |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Window, private: |
| |
| int64 Window::SetPropertyInternal(const void* key, |
| const char* name, |
| PropertyDeallocator deallocator, |
| int64 value, |
| int64 default_value) { |
| int64 old = GetPropertyInternal(key, default_value); |
| if (value == default_value) { |
| prop_map_.erase(key); |
| } else { |
| Value prop_value; |
| prop_value.name = name; |
| prop_value.value = value; |
| prop_value.deallocator = deallocator; |
| prop_map_[key] = prop_value; |
| } |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowPropertyChanged(this, key, old)); |
| return old; |
| } |
| |
| int64 Window::GetPropertyInternal(const void* key, |
| int64 default_value) const { |
| std::map<const void*, Value>::const_iterator iter = prop_map_.find(key); |
| if (iter == prop_map_.end()) |
| return default_value; |
| return iter->second.value; |
| } |
| |
| bool Window::HitTest(const gfx::Point& local_point) { |
| gfx::Rect local_bounds(bounds().size()); |
| if (!delegate_ || !delegate_->HasHitTestMask()) |
| return local_bounds.Contains(local_point); |
| |
| gfx::Path mask; |
| delegate_->GetHitTestMask(&mask); |
| |
| SkRegion clip_region; |
| clip_region.setRect(local_bounds.x(), local_bounds.y(), |
| local_bounds.width(), local_bounds.height()); |
| SkRegion mask_region; |
| return mask_region.setPath(mask, clip_region) && |
| mask_region.contains(local_point.x(), local_point.y()); |
| } |
| |
| void Window::SetBoundsInternal(const gfx::Rect& new_bounds) { |
| gfx::Rect actual_new_bounds(new_bounds); |
| gfx::Rect old_bounds = GetTargetBounds(); |
| |
| // Always need to set the layer's bounds -- even if it is to the same thing. |
| // This may cause important side effects such as stopping animation. |
| if (!layer()) { |
| const gfx::Vector2d origin_delta = new_bounds.OffsetFromOrigin() - |
| bounds_.OffsetFromOrigin(); |
| bounds_ = new_bounds; |
| OffsetLayerBounds(origin_delta); |
| } else { |
| if (parent_ && !parent_->layer()) { |
| gfx::Vector2d offset; |
| const aura::Window* ancestor_with_layer = |
| parent_->GetAncestorWithLayer(&offset); |
| if (ancestor_with_layer) |
| actual_new_bounds.Offset(offset); |
| } |
| layer()->SetBounds(actual_new_bounds); |
| } |
| |
| // If we are currently not the layer's delegate, we will not get bounds |
| // changed notification from the layer (this typically happens after animating |
| // hidden). We must notify ourselves. |
| if (!layer() || layer()->delegate() != this) |
| OnWindowBoundsChanged(old_bounds); |
| } |
| |
| void Window::SetVisible(bool visible) { |
| // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
| tracked_objects::ScopedTracker tracking_profile( |
| FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 Window::SetVisible")); |
| |
| if ((layer() && visible == layer()->GetTargetVisibility()) || |
| (!layer() && visible == visible_)) |
| return; // No change. |
| |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowVisibilityChanging(this, visible)); |
| |
| client::VisibilityClient* visibility_client = |
| client::GetVisibilityClient(this); |
| if (visibility_client) |
| visibility_client->UpdateLayerVisibility(this, visible); |
| else if (layer()) |
| layer()->SetVisible(visible); |
| visible_ = visible; |
| SchedulePaint(); |
| if (parent_ && parent_->layout_manager_) |
| parent_->layout_manager_->OnChildWindowVisibilityChanged(this, visible); |
| |
| if (delegate_) |
| delegate_->OnWindowTargetVisibilityChanged(visible); |
| |
| NotifyWindowVisibilityChanged(this, visible); |
| } |
| |
| void Window::SchedulePaint() { |
| SchedulePaintInRect(gfx::Rect(0, 0, bounds().width(), bounds().height())); |
| } |
| |
| void Window::Paint(gfx::Canvas* canvas) { |
| if (delegate_) |
| delegate_->OnPaint(canvas); |
| PaintLayerlessChildren(canvas); |
| } |
| |
| void Window::PaintLayerlessChildren(gfx::Canvas* canvas) { |
| for (size_t i = 0, count = children_.size(); i < count; ++i) { |
| Window* child = children_[i]; |
| if (!child->layer() && child->visible_) { |
| gfx::ScopedCanvas scoped_canvas(canvas); |
| canvas->ClipRect(child->bounds()); |
| if (!canvas->IsClipEmpty()) { |
| canvas->Translate(child->bounds().OffsetFromOrigin()); |
| child->Paint(canvas); |
| } |
| } |
| } |
| } |
| |
| Window* Window::GetWindowForPoint(const gfx::Point& local_point, |
| bool return_tightest, |
| bool for_event_handling) { |
| if (!IsVisible()) |
| return NULL; |
| |
| if ((for_event_handling && !HitTest(local_point)) || |
| (!for_event_handling && !ContainsPoint(local_point))) |
| return NULL; |
| |
| // Check if I should claim this event and not pass it to my children because |
| // the location is inside my hit test override area. For details, see |
| // set_hit_test_bounds_override_inner(). |
| if (for_event_handling && !hit_test_bounds_override_inner_.empty()) { |
| gfx::Rect inset_local_bounds(gfx::Point(), bounds().size()); |
| inset_local_bounds.Inset(hit_test_bounds_override_inner_); |
| // We know we're inside the normal local bounds, so if we're outside the |
| // inset bounds we must be in the special hit test override area. |
| DCHECK(HitTest(local_point)); |
| if (!inset_local_bounds.Contains(local_point)) |
| return delegate_ ? this : NULL; |
| } |
| |
| if (!return_tightest && delegate_) |
| return this; |
| |
| for (Windows::const_reverse_iterator it = children_.rbegin(), |
| rend = children_.rend(); |
| it != rend; ++it) { |
| Window* child = *it; |
| |
| if (for_event_handling) { |
| if (child->ignore_events_) |
| continue; |
| // The client may not allow events to be processed by certain subtrees. |
| client::EventClient* client = client::GetEventClient(GetRootWindow()); |
| if (client && !client->CanProcessEventsWithinSubtree(child)) |
| continue; |
| if (delegate_ && !delegate_->ShouldDescendIntoChildForEventHandling( |
| child, local_point)) |
| continue; |
| } |
| |
| gfx::Point point_in_child_coords(local_point); |
| ConvertPointToTarget(this, child, &point_in_child_coords); |
| Window* match = child->GetWindowForPoint(point_in_child_coords, |
| return_tightest, |
| for_event_handling); |
| if (match) |
| return match; |
| } |
| |
| return delegate_ ? this : NULL; |
| } |
| |
| void Window::RemoveChildImpl(Window* child, Window* new_parent) { |
| if (layout_manager_) |
| layout_manager_->OnWillRemoveWindowFromLayout(child); |
| FOR_EACH_OBSERVER(WindowObserver, observers_, OnWillRemoveWindow(child)); |
| Window* root_window = child->GetRootWindow(); |
| Window* new_root_window = new_parent ? new_parent->GetRootWindow() : NULL; |
| if (root_window && root_window != new_root_window) |
| child->NotifyRemovingFromRootWindow(new_root_window); |
| |
| gfx::Vector2d offset; |
| GetAncestorWithLayer(&offset); |
| child->UnparentLayers(!layer(), offset); |
| child->parent_ = NULL; |
| Windows::iterator i = std::find(children_.begin(), children_.end(), child); |
| DCHECK(i != children_.end()); |
| children_.erase(i); |
| child->OnParentChanged(); |
| if (layout_manager_) |
| layout_manager_->OnWindowRemovedFromLayout(child); |
| } |
| |
| void Window::UnparentLayers(bool has_layerless_ancestor, |
| const gfx::Vector2d& offset) { |
| if (!layer()) { |
| const gfx::Vector2d new_offset = offset + bounds().OffsetFromOrigin(); |
| for (size_t i = 0; i < children_.size(); ++i) { |
| children_[i]->UnparentLayers(true, new_offset); |
| } |
| } else { |
| // Only remove the layer if we still own it. Someone else may have acquired |
| // ownership of it via AcquireLayer() and may expect the hierarchy to go |
| // unchanged as the Window is destroyed. |
| if (OwnsLayer()) { |
| if (layer()->parent()) |
| layer()->parent()->Remove(layer()); |
| if (has_layerless_ancestor) { |
| const gfx::Rect real_bounds(bounds_); |
| gfx::Rect layer_bounds(layer()->bounds()); |
| layer_bounds.Offset(-offset); |
| layer()->SetBounds(layer_bounds); |
| bounds_ = real_bounds; |
| } |
| } |
| } |
| } |
| |
| void Window::ReparentLayers(ui::Layer* parent_layer, |
| const gfx::Vector2d& offset) { |
| if (!layer()) { |
| for (size_t i = 0; i < children_.size(); ++i) { |
| children_[i]->ReparentLayers( |
| parent_layer, |
| offset + children_[i]->bounds().OffsetFromOrigin()); |
| } |
| } else { |
| const gfx::Rect real_bounds(bounds()); |
| parent_layer->Add(layer()); |
| gfx::Rect layer_bounds(layer()->bounds().size()); |
| layer_bounds += offset; |
| layer()->SetBounds(layer_bounds); |
| bounds_ = real_bounds; |
| } |
| } |
| |
| void Window::OffsetLayerBounds(const gfx::Vector2d& offset) { |
| if (!layer()) { |
| for (size_t i = 0; i < children_.size(); ++i) |
| children_[i]->OffsetLayerBounds(offset); |
| } else { |
| gfx::Rect layer_bounds(layer()->bounds()); |
| layer_bounds += offset; |
| layer()->SetBounds(layer_bounds); |
| } |
| } |
| |
| void Window::OnParentChanged() { |
| FOR_EACH_OBSERVER( |
| WindowObserver, observers_, OnWindowParentChanged(this, parent_)); |
| } |
| |
| void Window::StackChildRelativeTo(Window* child, |
| Window* target, |
| StackDirection direction) { |
| DCHECK_NE(child, target); |
| DCHECK(child); |
| DCHECK(target); |
| DCHECK_EQ(this, child->parent()); |
| DCHECK_EQ(this, target->parent()); |
| |
| client::WindowStackingClient* stacking_client = |
| client::GetWindowStackingClient(); |
| if (stacking_client && |
| !stacking_client->AdjustStacking(&child, &target, &direction)) |
| return; |
| |
| const size_t child_i = |
| std::find(children_.begin(), children_.end(), child) - children_.begin(); |
| const size_t target_i = |
| std::find(children_.begin(), children_.end(), target) - children_.begin(); |
| |
| // Don't move the child if it is already in the right place. |
| if ((direction == STACK_ABOVE && child_i == target_i + 1) || |
| (direction == STACK_BELOW && child_i + 1 == target_i)) |
| return; |
| |
| const size_t dest_i = |
| direction == STACK_ABOVE ? |
| (child_i < target_i ? target_i : target_i + 1) : |
| (child_i < target_i ? target_i - 1 : target_i); |
| children_.erase(children_.begin() + child_i); |
| children_.insert(children_.begin() + dest_i, child); |
| |
| StackChildLayerRelativeTo(child, target, direction); |
| |
| child->OnStackingChanged(); |
| } |
| |
| void Window::StackChildLayerRelativeTo(Window* child, |
| Window* target, |
| StackDirection direction) { |
| Window* ancestor_with_layer = GetAncestorWithLayer(NULL); |
| ui::Layer* ancestor_layer = |
| ancestor_with_layer ? ancestor_with_layer->layer() : NULL; |
| if (!ancestor_layer) |
| return; |
| |
| if (child->layer() && target->layer()) { |
| if (direction == STACK_ABOVE) |
| ancestor_layer->StackAbove(child->layer(), target->layer()); |
| else |
| ancestor_layer->StackBelow(child->layer(), target->layer()); |
| return; |
| } |
| typedef std::vector<ui::Layer*> Layers; |
| Layers layers; |
| GetLayersToStack(child, &layers); |
| if (layers.empty()) |
| return; |
| |
| ui::Layer* target_layer; |
| if (direction == STACK_ABOVE) { |
| target_layer = |
| FindStackingTargetLayer<Windows::const_reverse_iterator>(target, child); |
| } else { |
| target_layer = |
| FindStackingTargetLayer<Windows::const_iterator>(target, child); |
| } |
| |
| if (!target_layer) { |
| if (direction == STACK_ABOVE) { |
| for (Layers::const_reverse_iterator i = layers.rbegin(), |
| rend = layers.rend(); i != rend; ++i) { |
| ancestor_layer->StackAtBottom(*i); |
| } |
| } else { |
| for (Layers::const_iterator i = layers.begin(); i != layers.end(); ++i) |
| ancestor_layer->StackAtTop(*i); |
| } |
| return; |
| } |
| |
| if (direction == STACK_ABOVE) { |
| for (Layers::const_reverse_iterator i = layers.rbegin(), |
| rend = layers.rend(); i != rend; ++i) { |
| ancestor_layer->StackAbove(*i, target_layer); |
| } |
| } else { |
| for (Layers::const_iterator i = layers.begin(); i != layers.end(); ++i) |
| ancestor_layer->StackBelow(*i, target_layer); |
| } |
| } |
| |
| void Window::OnStackingChanged() { |
| FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowStackingChanged(this)); |
| } |
| |
| void Window::NotifyRemovingFromRootWindow(Window* new_root) { |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowRemovingFromRootWindow(this, new_root)); |
| for (Window::Windows::const_iterator it = children_.begin(); |
| it != children_.end(); ++it) { |
| (*it)->NotifyRemovingFromRootWindow(new_root); |
| } |
| } |
| |
| void Window::NotifyAddedToRootWindow() { |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowAddedToRootWindow(this)); |
| for (Window::Windows::const_iterator it = children_.begin(); |
| it != children_.end(); ++it) { |
| (*it)->NotifyAddedToRootWindow(); |
| } |
| } |
| |
| void Window::NotifyWindowHierarchyChange( |
| const WindowObserver::HierarchyChangeParams& params) { |
| params.target->NotifyWindowHierarchyChangeDown(params); |
| switch (params.phase) { |
| case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING: |
| if (params.old_parent) |
| params.old_parent->NotifyWindowHierarchyChangeUp(params); |
| break; |
| case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED: |
| if (params.new_parent) |
| params.new_parent->NotifyWindowHierarchyChangeUp(params); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void Window::NotifyWindowHierarchyChangeDown( |
| const WindowObserver::HierarchyChangeParams& params) { |
| NotifyWindowHierarchyChangeAtReceiver(params); |
| for (Window::Windows::const_iterator it = children_.begin(); |
| it != children_.end(); ++it) { |
| (*it)->NotifyWindowHierarchyChangeDown(params); |
| } |
| } |
| |
| void Window::NotifyWindowHierarchyChangeUp( |
| const WindowObserver::HierarchyChangeParams& params) { |
| for (Window* window = this; window; window = window->parent()) |
| window->NotifyWindowHierarchyChangeAtReceiver(params); |
| } |
| |
| void Window::NotifyWindowHierarchyChangeAtReceiver( |
| const WindowObserver::HierarchyChangeParams& params) { |
| WindowObserver::HierarchyChangeParams local_params = params; |
| local_params.receiver = this; |
| |
| switch (params.phase) { |
| case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGING: |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowHierarchyChanging(local_params)); |
| break; |
| case WindowObserver::HierarchyChangeParams::HIERARCHY_CHANGED: |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowHierarchyChanged(local_params)); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void Window::NotifyWindowVisibilityChanged(aura::Window* target, |
| bool visible) { |
| if (!NotifyWindowVisibilityChangedDown(target, visible)) { |
| return; // |this| has been deleted. |
| } |
| NotifyWindowVisibilityChangedUp(target, visible); |
| } |
| |
| bool Window::NotifyWindowVisibilityChangedAtReceiver(aura::Window* target, |
| bool visible) { |
| // |this| may be deleted during a call to OnWindowVisibilityChanged() on one |
| // of the observers. We create an local observer for that. In that case we |
| // exit without further access to any members. |
| WindowTracker tracker; |
| tracker.Add(this); |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnWindowVisibilityChanged(target, visible)); |
| return tracker.Contains(this); |
| } |
| |
| bool Window::NotifyWindowVisibilityChangedDown(aura::Window* target, |
| bool visible) { |
| if (!NotifyWindowVisibilityChangedAtReceiver(target, visible)) |
| return false; // |this| was deleted. |
| std::set<const Window*> child_already_processed; |
| bool child_destroyed = false; |
| do { |
| child_destroyed = false; |
| for (Window::Windows::const_iterator it = children_.begin(); |
| it != children_.end(); ++it) { |
| if (!child_already_processed.insert(*it).second) |
| continue; |
| if (!(*it)->NotifyWindowVisibilityChangedDown(target, visible)) { |
| // |*it| was deleted, |it| is invalid and |children_| has changed. |
| // We exit the current for-loop and enter a new one. |
| child_destroyed = true; |
| break; |
| } |
| } |
| } while (child_destroyed); |
| return true; |
| } |
| |
| void Window::NotifyWindowVisibilityChangedUp(aura::Window* target, |
| bool visible) { |
| // Start with the parent as we already notified |this| |
| // in NotifyWindowVisibilityChangedDown. |
| for (Window* window = parent(); window; window = window->parent()) { |
| bool ret = window->NotifyWindowVisibilityChangedAtReceiver(target, visible); |
| DCHECK(ret); |
| } |
| } |
| |
| void Window::NotifyAncestorWindowTransformed(Window* source) { |
| FOR_EACH_OBSERVER(WindowObserver, observers_, |
| OnAncestorWindowTransformed(source, this)); |
| for (Window::Windows::const_iterator it = children_.begin(); |
| it != children_.end(); ++it) { |
| (*it)->NotifyAncestorWindowTransformed(source); |
| } |
| } |
| |
| void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds) { |
| if (layer()) { |
| bounds_ = layer()->bounds(); |
| if (parent_ && !parent_->layer()) { |
| gfx::Vector2d offset; |
| aura::Window* ancestor_with_layer = |
| parent_->GetAncestorWithLayer(&offset); |
| if (ancestor_with_layer) |
| bounds_.Offset(-offset); |
| } |
| } |
| |
| if (layout_manager_) |
| layout_manager_->OnWindowResized(); |
| if (delegate_) |
| delegate_->OnBoundsChanged(old_bounds, bounds()); |
| FOR_EACH_OBSERVER(WindowObserver, |
| observers_, |
| OnWindowBoundsChanged(this, old_bounds, bounds())); |
| } |
| |
| bool Window::CleanupGestureState() { |
| bool state_modified = false; |
| state_modified |= ui::GestureRecognizer::Get()->CancelActiveTouches(this); |
| state_modified |= |
| ui::GestureRecognizer::Get()->CleanupStateForConsumer(this); |
| for (Window::Windows::iterator iter = children_.begin(); |
| iter != children_.end(); |
| ++iter) { |
| state_modified |= (*iter)->CleanupGestureState(); |
| } |
| return state_modified; |
| } |
| |
| void Window::OnPaintLayer(gfx::Canvas* canvas) { |
| Paint(canvas); |
| } |
| |
| void Window::OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) { |
| DCHECK(layer()); |
| FOR_EACH_OBSERVER(WindowObserver, |
| observers_, |
| OnDelegatedFrameDamage(this, damage_rect_in_dip)); |
| } |
| |
| base::Closure Window::PrepareForLayerBoundsChange() { |
| return base::Bind(&Window::OnWindowBoundsChanged, base::Unretained(this), |
| bounds()); |
| } |
| |
| bool Window::CanAcceptEvent(const ui::Event& event) { |
| // The client may forbid certain windows from receiving events at a given |
| // point in time. |
| client::EventClient* client = client::GetEventClient(GetRootWindow()); |
| if (client && !client->CanProcessEventsWithinSubtree(this)) |
| return false; |
| |
| // We need to make sure that a touch cancel event and any gesture events it |
| // creates can always reach the window. This ensures that we receive a valid |
| // touch / gesture stream. |
| if (event.IsEndingEvent()) |
| return true; |
| |
| if (!IsVisible()) |
| return false; |
| |
| // The top-most window can always process an event. |
| if (!parent_) |
| return true; |
| |
| // For located events (i.e. mouse, touch etc.), an assumption is made that |
| // windows that don't have a default event-handler cannot process the event |
| // (see more in GetWindowForPoint()). This assumption is not made for key |
| // events. |
| return event.IsKeyEvent() || target_handler(); |
| } |
| |
| ui::EventTarget* Window::GetParentTarget() { |
| if (IsRootWindow()) { |
| return client::GetEventClient(this) ? |
| client::GetEventClient(this)->GetToplevelEventTarget() : |
| Env::GetInstance(); |
| } |
| return parent_; |
| } |
| |
| scoped_ptr<ui::EventTargetIterator> Window::GetChildIterator() const { |
| return make_scoped_ptr(new ui::EventTargetIteratorImpl<Window>(children())); |
| } |
| |
| ui::EventTargeter* Window::GetEventTargeter() { |
| return targeter_.get(); |
| } |
| |
| void Window::ConvertEventToTarget(ui::EventTarget* target, |
| ui::LocatedEvent* event) { |
| event->ConvertLocationToTarget(this, |
| static_cast<Window*>(target)); |
| } |
| |
| void Window::UpdateLayerName() { |
| #if !defined(NDEBUG) |
| DCHECK(layer()); |
| |
| std::string layer_name(name_); |
| if (layer_name.empty()) |
| layer_name = "Unnamed Window"; |
| |
| if (id_ != -1) |
| layer_name += " " + base::IntToString(id_); |
| |
| layer()->set_name(layer_name); |
| #endif |
| } |
| |
| const Window* Window::GetAncestorWithLayer(gfx::Vector2d* offset) const { |
| for (const aura::Window* window = this; window; window = window->parent()) { |
| if (window->layer()) |
| return window; |
| if (offset) |
| *offset += window->bounds().OffsetFromOrigin(); |
| } |
| if (offset) |
| *offset = gfx::Vector2d(); |
| return NULL; |
| } |
| |
| } // namespace aura |