| Index: ash/wm/drag_window_controller.cc
|
| diff --git a/ash/wm/drag_window_controller.cc b/ash/wm/drag_window_controller.cc
|
| index 405b86932bc3bafa8a02ac6f27e7de799ac8a17d..ee62ab4412730aa1927438c92874c4b1d36bb116 100644
|
| --- a/ash/wm/drag_window_controller.cc
|
| +++ b/ash/wm/drag_window_controller.cc
|
| @@ -4,11 +4,19 @@
|
|
|
| #include "ash/wm/drag_window_controller.h"
|
|
|
| +#include <algorithm>
|
| +
|
| +#include "ash/display/window_tree_host_manager.h"
|
| +#include "ash/screen_util.h"
|
| +#include "ash/shell.h"
|
| #include "ash/shell_window_ids.h"
|
| #include "ash/wm/window_util.h"
|
| +#include "ui/aura/client/aura_constants.h"
|
| #include "ui/aura/client/screen_position_client.h"
|
| #include "ui/aura/window.h"
|
| +#include "ui/aura/window_delegate.h"
|
| #include "ui/aura/window_event_dispatcher.h"
|
| +#include "ui/base/hit_test.h"
|
| #include "ui/compositor/layer.h"
|
| #include "ui/compositor/layer_tree_owner.h"
|
| #include "ui/compositor/scoped_layer_animation_settings.h"
|
| @@ -19,102 +27,210 @@
|
|
|
| namespace ash {
|
|
|
| -DragWindowController::DragWindowController(aura::Window* window)
|
| - : window_(window),
|
| - drag_widget_(NULL) {
|
| -}
|
| +// This keeps tack of the drag window's state. It creates/destory/updates bounds
|
| +// and opacity based on the current bounds.
|
| +class DragWindowController::DragWindowDetails : public aura::WindowDelegate {
|
| + public:
|
| + DragWindowDetails(const gfx::Display& display, aura::Window* original_window)
|
| + : root_window_(Shell::GetInstance()
|
| + ->window_tree_host_manager()
|
| + ->GetRootWindowForDisplayId(display.id())) {}
|
| +
|
| + ~DragWindowDetails() override {
|
| + delete drag_window_;
|
| + DCHECK(!drag_window_);
|
| + }
|
|
|
| -DragWindowController::~DragWindowController() {
|
| - Hide();
|
| -}
|
| + void Update(aura::Window* original_window,
|
| + const gfx::Rect& bounds_in_screen,
|
| + const gfx::Point& drag_location_in_screen) {
|
| + gfx::Rect root_bounds_in_screen = root_window_->GetBoundsInScreen();
|
| + if (!root_bounds_in_screen.Intersects(bounds_in_screen)) {
|
| + delete drag_window_;
|
| + // Make sure drag_window_ is reset so that new drag window will be created
|
| + // when it becomes necessary again.
|
| + DCHECK(!drag_window_);
|
| + layer_owner_.reset();
|
| + return;
|
| + }
|
| + if (!drag_window_)
|
| + CreateDragWindow(original_window, bounds_in_screen);
|
| +
|
| + gfx::Rect bounds_in_root = ScreenUtil::ConvertRectFromScreen(
|
| + drag_window_->parent(), bounds_in_screen);
|
| + drag_window_->SetBounds(bounds_in_root);
|
| + if (root_bounds_in_screen.Contains(drag_location_in_screen)) {
|
| + SetOpacity(original_window, 1.f);
|
| + } else {
|
| + drag_window_->SetBounds(bounds_in_root);
|
| + gfx::Rect visible_bounds = root_bounds_in_screen;
|
| + visible_bounds.Intersect(bounds_in_screen);
|
| + SetOpacity(original_window,
|
| + GetDragWindowOpacity(bounds_in_screen, visible_bounds));
|
| + }
|
| + }
|
|
|
| -void DragWindowController::SetDestinationDisplay(
|
| - const gfx::Display& dst_display) {
|
| - dst_display_ = dst_display;
|
| -}
|
| + private:
|
| + friend class DragWindowController;
|
| +
|
| + void CreateDragWindow(aura::Window* original_window,
|
| + const gfx::Rect& bounds_in_screen) {
|
| + DCHECK(!drag_window_);
|
| + drag_window_ = new aura::Window(this);
|
| + int parent_id = original_window->parent()->id();
|
| + aura::Window* container = root_window_->GetChildById(parent_id);
|
| +
|
| + drag_window_->SetType(ui::wm::WINDOW_TYPE_POPUP);
|
| + drag_window_->SetTransparent(true);
|
| + drag_window_->Init(ui::LAYER_TEXTURED);
|
| + drag_window_->SetName("DragWindow");
|
| + drag_window_->set_id(kShellWindowId_PhantomWindow);
|
| + drag_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
|
| + container->AddChild(drag_window_);
|
| + drag_window_->SetBounds(bounds_in_screen);
|
| + SetShadowType(drag_window_, ::wm::SHADOW_TYPE_RECTANGULAR);
|
| +
|
| + RecreateWindowLayers(original_window);
|
| + layer_owner_->root()->SetVisible(true);
|
| + drag_window_->layer()->Add(layer_owner_->root());
|
| + drag_window_->layer()->StackAtTop(layer_owner_->root());
|
| +
|
| + // Show the widget after all the setups.
|
| + drag_window_->Show();
|
| +
|
| + // Fade the window in.
|
| + ui::Layer* drag_layer = drag_window_->layer();
|
| + drag_layer->SetOpacity(0);
|
| + ui::ScopedLayerAnimationSettings scoped_setter(drag_layer->GetAnimator());
|
| + drag_layer->SetOpacity(1);
|
| + }
|
|
|
| -void DragWindowController::Show() {
|
| - if (!drag_widget_)
|
| - CreateDragWidget(window_->GetBoundsInScreen());
|
| - drag_widget_->Show();
|
| -}
|
| + void RecreateWindowLayers(aura::Window* original_window) {
|
| + DCHECK(!layer_owner_.get());
|
| + layer_owner_ = ::wm::RecreateLayers(original_window);
|
| + // TODO(oshima): Recreated child layers may not have been painted
|
| + // yet, and may not be able to paint to because it does not have
|
| + // its original delegate.
|
| + layer_owner_->root()->set_delegate(original_window->layer()->delegate());
|
| + // Place the layer at (0, 0) of the DragWindowController's window.
|
| + gfx::Rect layer_bounds = layer_owner_->root()->bounds();
|
| + layer_bounds.set_origin(gfx::Point(0, 0));
|
| + layer_owner_->root()->SetBounds(layer_bounds);
|
| + layer_owner_->root()->SetVisible(false);
|
| + // Detach it from the current container.
|
| + layer_owner_->root()->parent()->Remove(layer_owner_->root());
|
| + }
|
|
|
| -void DragWindowController::SetBounds(const gfx::Rect& bounds) {
|
| - DCHECK(drag_widget_);
|
| - bounds_ = bounds;
|
| - SetBoundsInternal(bounds);
|
| + void SetOpacity(const aura::Window* original_window, float opacity) {
|
| + ui::Layer* layer = drag_window_->layer();
|
| + ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator());
|
| + layer->SetOpacity(opacity);
|
| + layer_owner_->root()->SetOpacity(1.0f);
|
| + }
|
| +
|
| + // aura::WindowDelegate:
|
| + gfx::Size GetMinimumSize() const override { return gfx::Size(); }
|
| + gfx::Size GetMaximumSize() const override { return gfx::Size(); }
|
| + void OnBoundsChanged(const gfx::Rect& old_bounds,
|
| + const gfx::Rect& new_bounds) override {}
|
| + gfx::NativeCursor GetCursor(const gfx::Point& point) override {
|
| + return gfx::kNullCursor;
|
| + }
|
| + int GetNonClientComponent(const gfx::Point& point) const override {
|
| + return HTNOWHERE;
|
| + }
|
| + bool ShouldDescendIntoChildForEventHandling(
|
| + aura::Window* child,
|
| + const gfx::Point& location) override {
|
| + return false;
|
| + }
|
| + bool CanFocus() override { return false; }
|
| + void OnCaptureLost() override {}
|
| + void OnPaint(const ui::PaintContext& context) override {}
|
| + void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
|
| + void OnWindowDestroyed(aura::Window* window) override {}
|
| + void OnWindowTargetVisibilityChanged(bool visible) override {}
|
| + bool HasHitTestMask() const override { return false; }
|
| + void GetHitTestMask(gfx::Path* mask) const override {}
|
| + void OnWindowDestroying(aura::Window* window) override {
|
| + DCHECK_EQ(drag_window_, window);
|
| + drag_window_ = nullptr;
|
| + }
|
| +
|
| + aura::Window* root_window_;
|
| +
|
| + aura::Window* drag_window_ = nullptr; // Owned by the container.
|
| +
|
| + // The copy of window_->layer() and its descendants.
|
| + scoped_ptr<ui::LayerTreeOwner> layer_owner_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DragWindowDetails);
|
| +};
|
| +
|
| +// static
|
| +float DragWindowController::GetDragWindowOpacity(
|
| + const gfx::Rect& window_bounds,
|
| + const gfx::Rect& visible_bounds) {
|
| + // The maximum opacity of the drag phantom window.
|
| + static const float kMaxOpacity = 0.8f;
|
| +
|
| + return kMaxOpacity * visible_bounds.size().GetArea() /
|
| + window_bounds.size().GetArea();
|
| }
|
|
|
| -void DragWindowController::Hide() {
|
| - if (drag_widget_) {
|
| - drag_widget_->Close();
|
| - drag_widget_ = NULL;
|
| +DragWindowController::DragWindowController(aura::Window* window)
|
| + : window_(window) {
|
| + DCHECK(drag_windows_.empty());
|
| + gfx::Screen* screen = gfx::Screen::GetScreen();
|
| + gfx::Display current = screen->GetDisplayNearestWindow(window_);
|
| +
|
| + for (const gfx::Display& display : screen->GetAllDisplays()) {
|
| + if (current.id() == display.id())
|
| + continue;
|
| + drag_windows_.push_back(
|
| + make_scoped_ptr(new DragWindowDetails(display, window_)));
|
| }
|
| - layer_owner_.reset();
|
| }
|
|
|
| -void DragWindowController::SetOpacity(float opacity) {
|
| - DCHECK(drag_widget_);
|
| - ui::Layer* layer = drag_widget_->GetNativeWindow()->layer();
|
| - ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator());
|
| - layer->SetOpacity(opacity);
|
| +DragWindowController::~DragWindowController() {}
|
| +
|
| +void DragWindowController::Update(const gfx::Rect& bounds_in_screen,
|
| + const gfx::Point& drag_location_in_screen) {
|
| + for (scoped_ptr<DragWindowDetails>& details : drag_windows_)
|
| + details->Update(window_, bounds_in_screen, drag_location_in_screen);
|
| }
|
|
|
| -void DragWindowController::CreateDragWidget(const gfx::Rect& bounds) {
|
| - DCHECK(!drag_widget_);
|
| - drag_widget_ = new views::Widget;
|
| - views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
|
| - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
|
| - params.parent = window_->parent();
|
| - params.keep_on_top = true;
|
| - drag_widget_->set_focus_on_creation(false);
|
| - drag_widget_->Init(params);
|
| - drag_widget_->SetVisibilityChangedAnimationsEnabled(false);
|
| - drag_widget_->GetNativeWindow()->SetName("DragWindow");
|
| - drag_widget_->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow);
|
| - // Show shadow for the dragging window.
|
| - SetShadowType(drag_widget_->GetNativeWindow(),
|
| - ::wm::SHADOW_TYPE_RECTANGULAR);
|
| - SetBoundsInternal(bounds);
|
| - drag_widget_->StackAbove(window_);
|
| -
|
| - RecreateWindowLayers();
|
| - aura::Window* window = drag_widget_->GetNativeWindow();
|
| - layer_owner_->root()->SetVisible(true);
|
| - window->layer()->Add(layer_owner_->root());
|
| - window->layer()->StackAtTop(layer_owner_->root());
|
| -
|
| - // Show the widget after all the setups.
|
| - drag_widget_->Show();
|
| -
|
| - // Fade the window in.
|
| - ui::Layer* widget_layer = drag_widget_->GetNativeWindow()->layer();
|
| - widget_layer->SetOpacity(0);
|
| - ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator());
|
| - widget_layer->SetOpacity(1);
|
| +int DragWindowController::GetDragWindowsCountForTest() const {
|
| + int count = 0;
|
| + for (const scoped_ptr<DragWindowDetails>& details : drag_windows_) {
|
| + if (details->drag_window_)
|
| + count++;
|
| + }
|
| + return count;
|
| }
|
|
|
| -void DragWindowController::SetBoundsInternal(const gfx::Rect& bounds) {
|
| - aura::Window* window = drag_widget_->GetNativeWindow();
|
| - aura::client::ScreenPositionClient* screen_position_client =
|
| - aura::client::GetScreenPositionClient(window->GetRootWindow());
|
| - if (screen_position_client && dst_display_.is_valid())
|
| - screen_position_client->SetBounds(window, bounds, dst_display_);
|
| - else
|
| - drag_widget_->SetBounds(bounds);
|
| +const aura::Window* DragWindowController::GetDragWindowForTest(
|
| + size_t index) const {
|
| + for (const scoped_ptr<DragWindowDetails>& details : drag_windows_) {
|
| + if (details->drag_window_) {
|
| + if (index == 0)
|
| + return details->drag_window_;
|
| + index--;
|
| + }
|
| + }
|
| + return nullptr;
|
| }
|
|
|
| -void DragWindowController::RecreateWindowLayers() {
|
| - DCHECK(!layer_owner_.get());
|
| - layer_owner_ = ::wm::RecreateLayers(window_);
|
| - layer_owner_->root()->set_delegate(window_->layer()->delegate());
|
| - // Place the layer at (0, 0) of the DragWindowController's window.
|
| - gfx::Rect layer_bounds = layer_owner_->root()->bounds();
|
| - layer_bounds.set_origin(gfx::Point(0, 0));
|
| - layer_owner_->root()->SetBounds(layer_bounds);
|
| - layer_owner_->root()->SetVisible(false);
|
| - // Detach it from the current container.
|
| - layer_owner_->root()->parent()->Remove(layer_owner_->root());
|
| +const ui::LayerTreeOwner* DragWindowController::GetDragLayerOwnerForTest(
|
| + size_t index) const {
|
| + for (const scoped_ptr<DragWindowDetails>& details : drag_windows_) {
|
| + if (details->layer_owner_) {
|
| + if (index == 0)
|
| + return details->layer_owner_.get();
|
| + index--;
|
| + }
|
| + }
|
| + return nullptr;
|
| }
|
|
|
| } // namespace ash
|
|
|