#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/logging.h"
-#include "base/stl_util.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/root_window.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/gfx/animation/multi_animation.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)
- : dispatcher_(NULL),
- type_(client::WINDOW_TYPE_UNKNOWN),
+ : host_(NULL),
+ type_(ui::wm::WINDOW_TYPE_UNKNOWN),
owned_by_parent_(true),
delegate_(delegate),
parent_(NULL),
- transient_parent_(NULL),
visible_(false),
id_(-1),
transparent_(false),
}
Window::~Window() {
- // layer_ can be NULL if Init() wasn't invoked, which can happen
- // only in tests.
- if (layer_)
- layer_->SuppressPaint();
+ // |layer()| can be NULL during tests, or if this Window is layerless.
+ if (layer())
+ layer()->SuppressPaint();
// Let the delegate know we're in the processing of destroying.
if (delegate_)
- delegate_->OnWindowDestroying();
+ delegate_->OnWindowDestroying(this);
FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
- // Let the root know so that it can remove any references to us.
- WindowEventDispatcher* dispatcher = GetDispatcher();
- if (dispatcher)
- dispatcher->OnWindowDestroying(this);
+ // 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();
- // Removes ourselves from our transient parent (if it hasn't been done by the
- // RootWindow).
- if (transient_parent_)
- transient_parent_->RemoveTransientChild(this);
-
// The window needs to be removed from the parent before calling the
// WindowDestroyed callbacks of delegate and the observers.
if (parent_)
parent_->RemoveChild(this);
- // Destroy transient children, only after we've removed ourselves from our
- // parent, as destroying an active transient child may otherwise attempt to
- // refocus us.
- Windows transient_children(transient_children_);
- STLDeleteElements(&transient_children);
- DCHECK(transient_children_.empty());
-
- // Delegate and observers need to be notified after transients are deleted.
if (delegate_)
- delegate_->OnWindowDestroyed();
- FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroyed(this));
+ delegate_->OnWindowDestroyed(this);
+ ObserverListBase<WindowObserver>::Iterator iter(observers_);
+ WindowObserver* observer;
+ while ((observer = iter.GetNext())) {
+ RemoveObserver(observer);
+ observer->OnWindowDestroyed(this);
+ }
// Clear properties.
for (std::map<const void*, Value>::const_iterator iter = prop_map_.begin();
}
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, which
- // can happen in tests.
- if (layer_)
- layer_->set_delegate(NULL);
- layer_ = NULL;
+ // 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(ui::LayerType layer_type) {
- layer_ = new ui::Layer(layer_type);
- layer_owner_.reset(layer_);
- layer_->SetVisible(false);
- layer_->set_delegate(this);
- UpdateLayerName(name_);
- layer_->SetFillsBoundsOpaquely(!transparent_);
+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);
}
-ui::Layer* Window::RecreateLayer() {
- // Disconnect the old layer, but don't delete it.
- ui::Layer* old_layer = AcquireLayer();
- if (!old_layer)
- return NULL;
-
- old_layer->set_delegate(NULL);
-
- layer_ = new ui::Layer(old_layer->type());
- layer_owner_.reset(layer_);
- layer_->SetVisible(old_layer->visible());
- layer_->set_scale_content(old_layer->scale_content());
- layer_->set_delegate(this);
- layer_->SetMasksToBounds(old_layer->GetMasksToBounds());
-
- if (delegate_)
- delegate_->DidRecreateLayer(old_layer, layer_);
-
- UpdateLayerName(name_);
- layer_->SetFillsBoundsOpaquely(!transparent_);
- // Install new layer as a sibling of the old layer, stacked below it.
- if (old_layer->parent()) {
- old_layer->parent()->Add(layer_);
- old_layer->parent()->StackBelow(layer_, old_layer);
- }
- // Migrate all the child layers over to the new layer. Copy the list because
- // the items are removed during iteration.
- std::vector<ui::Layer*> children_copy = old_layer->children();
- for (std::vector<ui::Layer*>::const_iterator it = children_copy.begin();
- it != children_copy.end();
- ++it) {
- ui::Layer* child = *it;
- layer_->Add(child);
- }
- return old_layer;
-}
-
-void Window::SetType(client::WindowType type) {
+void Window::SetType(ui::wm::WindowType type) {
// Cannot change type after the window is initialized.
DCHECK(!layer());
type_ = type;
name_ = name;
if (layer())
- UpdateLayerName(name_);
+ UpdateLayerName();
}
void Window::SetTransparent(bool transparent) {
transparent_ = transparent;
if (layer())
- layer_->SetFillsBoundsOpaquely(!transparent_);
+ layer()->SetFillsBoundsOpaquely(!transparent_);
+}
+
+void Window::SetFillsBoundsCompletely(bool fills_bounds) {
+ if (layer())
+ layer()->SetFillsBoundsCompletely(fills_bounds);
}
Window* Window::GetRootWindow() {
}
const Window* Window::GetRootWindow() const {
- return parent_ ? parent_->GetRootWindow() : NULL;
+ return IsRootWindow() ? this : parent_ ? parent_->GetRootWindow() : NULL;
}
-WindowEventDispatcher* Window::GetDispatcher() {
- return const_cast<WindowEventDispatcher*>(const_cast<const Window*>(this)->
- GetDispatcher());
+WindowTreeHost* Window::GetHost() {
+ return const_cast<WindowTreeHost*>(const_cast<const Window*>(this)->
+ GetHost());
}
-const WindowEventDispatcher* Window::GetDispatcher() const {
+const WindowTreeHost* Window::GetHost() const {
const Window* root_window = GetRootWindow();
- return root_window ? root_window->dispatcher_ : NULL;
+ 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.
+ // TODO(skuhne): uncomment and fix issue 351553.
+ // DCHECK(!(visible_ && layer()->GetTargetOpacity() == 0.0f));
+ }
SetVisible(true);
}
void Window::Hide() {
- for (Windows::iterator it = transient_children_.begin();
- it != transient_children_.end(); ++it) {
- (*it)->Hide();
- }
+ // RootWindow::OnVisibilityChanged will call ReleaseCapture.
SetVisible(false);
- ReleaseCapture();
}
bool Window::IsVisible() const {
// 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).
- return visible_ && layer_ && layer_->IsDrawn();
+ 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 {
}
void Window::SetTransform(const gfx::Transform& transform) {
- WindowEventDispatcher* dispatcher = GetDispatcher();
- bool contained_mouse = IsVisible() && dispatcher &&
- ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot());
+ if (!layer()) {
+ // Transforms aren't supported on layerless windows.
+ NOTREACHED();
+ return;
+ }
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowTransforming(this));
layer()->SetTransform(transform);
- if (dispatcher)
- dispatcher->OnWindowTransformed(this, contained_mouse);
+ FOR_EACH_OBSERVER(WindowObserver, observers_,
+ OnWindowTransformed(this));
}
void Window::SetLayoutManager(LayoutManager* layout_manager) {
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
- SetBoundsInternal(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,
}
gfx::Rect Window::GetTargetBounds() const {
- return layer_->GetTargetBounds();
-}
+ if (!layer())
+ return bounds();
+
+ if (!parent_ || parent_->layer())
+ return layer()->GetTargetBounds();
-const gfx::Rect& Window::bounds() const {
- return layer_->bounds();
+ // 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_->SchedulePaint(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)) {
FOR_EACH_OBSERVER(
WindowObserver, observers_, OnWindowPaintScheduled(this, rect));
}
children_.end());
if (child->parent())
child->parent()->RemoveChildImpl(child, this);
+
+ gfx::Vector2d offset;
+ aura::Window* ancestor_with_layer = GetAncestorWithLayer(&offset);
+
child->parent_ = this;
- layer_->Add(child->layer_);
+ if (ancestor_with_layer) {
+ offset += child->bounds().OffsetFromOrigin();
+ child->ReparentLayers(ancestor_with_layer->layer(), offset);
+ }
children_.push_back(child);
if (layout_manager_)
Window* root_window = GetRootWindow();
if (root_window && old_root != root_window) {
- root_window->GetDispatcher()->OnWindowAddedToRootWindow(child);
+ root_window->GetHost()->dispatcher()->OnWindowAddedToRootWindow(child);
child->NotifyAddedToRootWindow();
}
return false;
}
-void Window::AddTransientChild(Window* child) {
- if (child->transient_parent_)
- child->transient_parent_->RemoveTransientChild(child);
- DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
- child) == transient_children_.end());
- transient_children_.push_back(child);
- child->transient_parent_ = this;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnAddTransientChild(this, child));
-}
-
-void Window::RemoveTransientChild(Window* child) {
- Windows::iterator i =
- std::find(transient_children_.begin(), transient_children_.end(), child);
- DCHECK(i != transient_children_.end());
- transient_children_.erase(i);
- if (child->transient_parent_ == this)
- child->transient_parent_ = NULL;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnRemoveTransientChild(this, child));
-}
-
Window* Window::GetChildById(int id) {
return const_cast<Window*>(const_cast<const Window*>(this)->GetChildById(id));
}
if (source->GetRootWindow() != target->GetRootWindow()) {
client::ScreenPositionClient* source_client =
client::GetScreenPositionClient(source->GetRootWindow());
- source_client->ConvertPointToScreen(source, point);
+ // |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->ConvertPointFromScreen(target, point);
+ // |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);
+}
+
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->GetDispatcher()->MoveCursorTo(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::SetEventFilter(ui::EventHandler* event_filter) {
- if (event_filter_)
- RemovePreTargetHandler(event_filter_.get());
- event_filter_.reset(event_filter);
- if (event_filter)
- AddPreTargetHandler(event_filter);
-}
-
void Window::AddObserver(WindowObserver* observer) {
observers_.AddObserver(observer);
}
return gfx::Rect(bounds().size()).Contains(local_point);
}
-bool Window::HitTest(const gfx::Point& local_point) {
- // Expand my bounds for hit testing (override is usually zero but it's
- // probably cheaper to do the math every time than to branch).
- gfx::Rect local_bounds(gfx::Point(), bounds().size());
- local_bounds.Inset(aura::Env::GetInstance()->is_touch_down() ?
- hit_test_bounds_override_outer_touch_ :
- hit_test_bounds_override_outer_mouse_);
-
- 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());
-}
-
Window* Window::GetEventHandlerForPoint(const gfx::Point& local_point) {
return GetWindowForPoint(local_point, true, true);
}
}
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.
}
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());
}
void Window::SuppressPaint() {
- layer_->SuppressPaint();
+ if (layer())
+ layer()->SuppressPaint();
}
// {Set,Get,Clear}Property are implemented in window_property.h.
}
void Window::OnDeviceScaleFactorChanged(float device_scale_factor) {
+ ScopedCursorHider hider(this);
+ if (IsRootWindow())
+ host_->OnDeviceScaleFactorChanged(device_scale_factor);
if (delegate_)
delegate_->OnDeviceScaleFactorChanged(device_scale_factor);
}
-#ifndef NDEBUG
+#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_->GetTargetVisibility() ? "LayerVisible" : "LayerHidden",
- layer_->opacity());
+ layer() ?
+ (layer()->GetTargetVisibility() ? "LayerVisible" : "LayerHidden") :
+ "NoLayer",
+ layer() ? layer()->opacity() : 1.0f);
}
void Window::PrintWindowHierarchy(int depth) const {
- printf("%*s%s\n", depth * 2, "", GetDebugInfo().c_str());
+ 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;
return iter->second.value;
}
-void Window::SetBoundsInternal(const gfx::Rect& new_bounds) {
- gfx::Rect actual_new_bounds(new_bounds);
+bool Window::HitTest(const gfx::Point& local_point) {
+ gfx::Rect local_bounds(bounds().size());
+ if (!delegate_ || !delegate_->HasHitTestMask())
+ return local_bounds.Contains(local_point);
- // Ensure we don't go smaller than our minimum bounds.
- if (delegate_) {
- const gfx::Size& min_size = delegate_->GetMinimumSize();
- actual_new_bounds.set_width(
- std::max(min_size.width(), actual_new_bounds.width()));
- actual_new_bounds.set_height(
- std::max(min_size.height(), actual_new_bounds.height()));
- }
+ 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.
- layer_->SetBounds(actual_new_bounds);
+ 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_->delegate() != this)
- OnLayerBoundsChanged(old_bounds, ContainsMouse());
+ if (!layer() || layer()->delegate() != this)
+ OnWindowBoundsChanged(old_bounds);
}
void Window::SetVisible(bool visible) {
- if (visible == layer_->GetTargetVisibility())
+ if ((layer() && visible == layer()->GetTargetVisibility()) ||
+ (!layer() && visible == visible_))
return; // No change.
FOR_EACH_OBSERVER(WindowObserver, observers_,
OnWindowVisibilityChanging(this, visible));
- WindowEventDispatcher* dispatcher = GetDispatcher();
- if (dispatcher)
- dispatcher->DispatchMouseExitToHidingWindow(this);
-
client::VisibilityClient* visibility_client =
client::GetVisibilityClient(this);
if (visibility_client)
visibility_client->UpdateLayerVisibility(this, visible);
- else
- layer_->SetVisible(visible);
+ else if (layer())
+ layer()->SetVisible(visible);
visible_ = visible;
SchedulePaint();
if (parent_ && parent_->layout_manager_)
delegate_->OnWindowTargetVisibilityChanged(visible);
NotifyWindowVisibilityChanged(this, visible);
-
- if (dispatcher)
- dispatcher->OnWindowVisibilityChanged(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 (client && !client->CanProcessEventsWithinSubtree(child))
continue;
if (delegate_ && !delegate_->ShouldDescendIntoChildForEventHandling(
- child, local_point)) {
+ child, local_point))
continue;
- }
}
gfx::Point point_in_child_coords(local_point);
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) {
- root_window->GetDispatcher()->OnWindowRemovedFromRootWindow(
- child, new_root_window);
- child->NotifyRemovingFromRootWindow();
- }
+ 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;
- // We should only remove the child's layer if the child still owns that layer.
- // Someone else may have acquired ownership of it via AcquireLayer() and may
- // expect the hierarchy to go unchanged as the Window is destroyed.
- if (child->layer_owner_)
- layer_->Remove(child->layer_);
Windows::iterator i = std::find(children_.begin(), children_.end(), child);
DCHECK(i != children_.end());
children_.erase(i);
layout_manager_->OnWindowRemovedFromLayout(child);
}
-void Window::OnParentChanged() {
- FOR_EACH_OBSERVER(
- WindowObserver, observers_, OnWindowParentChanged(this, parent_));
+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;
+ }
+ }
+ }
}
-bool Window::GetAllTransientAncestors(Window* window,
- Windows* ancestors) const {
- for (; window; window = window->transient_parent()) {
- if (window->parent() == this)
- ancestors->push_back(window);
- }
- return (!ancestors->empty());
-}
-
-void Window::FindCommonSiblings(Window** window1, Window** window2) const {
- DCHECK(window1);
- DCHECK(window2);
- DCHECK(*window1);
- DCHECK(*window2);
- // Assemble chains of ancestors of both windows.
- Windows ancestors1;
- Windows ancestors2;
- if (!GetAllTransientAncestors(*window1, &ancestors1) ||
- !GetAllTransientAncestors(*window2, &ancestors2)) {
- return;
- }
- // Walk the two chains backwards and look for the first difference.
- Windows::const_reverse_iterator it1 = ancestors1.rbegin();
- Windows::const_reverse_iterator it2 = ancestors2.rbegin();
- for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) {
- if (*it1 != *it2) {
- *window1 = *it1;
- *window2 = *it2;
- break;
+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;
}
}
-bool Window::HasTransientAncestor(const Window* ancestor) const {
- if (transient_parent_ == ancestor)
- return true;
- return transient_parent_ ?
- transient_parent_->HasTransientAncestor(ancestor) : false;
+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,
DCHECK_EQ(this, child->parent());
DCHECK_EQ(this, target->parent());
- // Consider all transient children of both child's and target's ancestors
- // up to the common ancestor if such exists and stack them as a unit.
- // This prevents one transient group from being inserted in the middle of
- // another.
- FindCommonSiblings(&child, &target);
-
- const size_t target_i =
- std::find(children_.begin(), children_.end(), target) - children_.begin();
-
- // When stacking above skip to the topmost transient descendant of the target.
- size_t final_target_i = target_i;
- if (direction == STACK_ABOVE && !child->HasTransientAncestor(target)) {
- while (final_target_i + 1 < children_.size() &&
- children_[final_target_i + 1]->HasTransientAncestor(target)) {
- ++final_target_i;
- }
- }
-
- // By convention we don't stack on top of windows with layers with NULL
- // delegates. Walk backward to find a valid target window.
- // See tests WindowTest.StackingMadrigal and StackOverClosingTransient
- // for an explanation of this.
- while (final_target_i > 0 &&
- children_[final_target_i]->layer()->delegate() == NULL) {
- --final_target_i;
- }
-
- // Allow stacking immediately below a window with a NULL layer.
- if (direction == STACK_BELOW && target_i != final_target_i)
- direction = STACK_ABOVE;
-
- Window* final_target = children_[final_target_i];
-
- // If we couldn't find a valid target position, don't move anything.
- if (final_target->layer()->delegate() == NULL)
- return;
-
- // Don't try to stack a child above itself.
- if (child == final_target)
+ client::WindowStackingClient* stacking_client =
+ client::GetWindowStackingClient();
+ if (stacking_client &&
+ !stacking_client->AdjustStacking(&child, &target, &direction))
return;
- // Move the child.
- StackChildRelativeToImpl(child, final_target, direction);
-
- // Stack any transient children that share the same parent to be in front of
- // 'child'. Preserve the existing stacking order by iterating in the order
- // those children appear in children_ array.
- Window* last_transient = child;
- Windows children(children_);
- for (Windows::iterator it = children.begin(); it != children.end(); ++it) {
- Window* transient_child = *it;
- if (transient_child != last_transient &&
- transient_child->HasTransientAncestor(child)) {
- StackChildRelativeToImpl(transient_child, last_transient, STACK_ABOVE);
- last_transient = transient_child;
- }
- }
-}
-
-void Window::StackChildRelativeToImpl(Window* child,
- Window* target,
- StackDirection direction) {
- DCHECK_NE(child, target);
- DCHECK(child);
- DCHECK(target);
- DCHECK_EQ(this, child->parent());
- DCHECK_EQ(this, target->parent());
-
const size_t child_i =
std::find(children_.begin(), children_.end(), child) - children_.begin();
const size_t target_i =
children_.erase(children_.begin() + child_i);
children_.insert(children_.begin() + dest_i, child);
- if (direction == STACK_ABOVE)
- layer()->StackAbove(child->layer(), target->layer());
- else
- layer()->StackBelow(child->layer(), target->layer());
+ 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() {
+void Window::NotifyRemovingFromRootWindow(Window* new_root) {
FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnWindowRemovingFromRootWindow(this));
+ OnWindowRemovingFromRootWindow(this, new_root));
for (Window::Windows::const_iterator it = children_.begin();
it != children_.end(); ++it) {
- (*it)->NotifyRemovingFromRootWindow();
+ (*it)->NotifyRemovingFromRootWindow(new_root);
}
}
}
}
-void Window::OnLayerBoundsChanged(const gfx::Rect& old_bounds,
- bool contained_mouse) {
+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_)
FOR_EACH_OBSERVER(WindowObserver,
observers_,
OnWindowBoundsChanged(this, old_bounds, bounds()));
- WindowEventDispatcher* dispatcher = GetDispatcher();
- if (dispatcher)
- dispatcher->OnWindowBoundsChanged(this, contained_mouse);
+}
+
+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) {
- if (delegate_)
- delegate_->OnPaint(canvas);
+ Paint(canvas);
}
base::Closure Window::PrepareForLayerBoundsChange() {
- return base::Bind(&Window::OnLayerBoundsChanged, base::Unretained(this),
- bounds(), ContainsMouse());
+ return base::Bind(&Window::OnWindowBoundsChanged, base::Unretained(this),
+ bounds());
}
bool Window::CanAcceptEvent(const ui::Event& event) {
if (client && !client->CanProcessEventsWithinSubtree(this))
return false;
- bool visible = event.dispatch_to_hidden_targets() || IsVisible();
- return visible && (!parent_ || parent_->CanAcceptEvent(event));
+ // 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 delegate cannot process the event (see more in
+ // GetWindowForPoint()). This assumption is not made for key events.
+ return event.IsKeyEvent() || delegate_;
}
ui::EventTarget* Window::GetParentTarget() {
+ if (IsRootWindow()) {
+ return client::GetEventClient(this) ?
+ client::GetEventClient(this)->GetToplevelEventTarget() :
+ Env::GetInstance();
+ }
return parent_;
}
-void Window::UpdateLayerName(const std::string& name) {
+scoped_ptr<ui::EventTargetIterator> Window::GetChildIterator() const {
+ return scoped_ptr<ui::EventTargetIterator>(
+ 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.append("Unnamed Window");
+ layer_name = "Unnamed Window";
+
+ if (id_ != -1)
+ layer_name += " " + base::IntToString(id_);
- if (id_ != -1) {
- char id_buf[10];
- base::snprintf(id_buf, sizeof(id_buf), " %d", id_);
- layer_name.append(id_buf);
- }
layer()->set_name(layer_name);
#endif
}
bool Window::ContainsMouse() {
bool contains_mouse = false;
if (IsVisible()) {
- WindowEventDispatcher* dispatcher = GetDispatcher();
- contains_mouse = dispatcher &&
- ContainsPointInRoot(dispatcher->GetLastMouseLocationInRoot());
+ WindowTreeHost* host = GetHost();
+ contains_mouse = host &&
+ ContainsPointInRoot(host->dispatcher()->GetLastMouseLocationInRoot());
}
return contains_mouse;
}
+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