Chromium Code Reviews| 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..6bd78bfbb60f11f2c700741c58eac2335d7de6cf 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 { |
| + if (drag_window_) { |
| + delete drag_window_; |
|
stevenjb
2016/03/29 18:56:13
nit: I had to remind myself that this was safe, ma
|
| + drag_window_ = nullptr; |
|
stevenjb
2016/03/29 18:56:13
This should be handled in OnWindowDestroying, rig
oshima
2016/03/30 21:21:02
Yep, changed to DCHECK.
|
| + } |
| + } |
| -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_; |
| + drag_window_ = nullptr; |
|
stevenjb
2016/03/29 18:56:13
Same here? This pattern implies ownership. Perhaps
oshima
2016/03/30 21:21:02
per offline chat, I changed to DCHECK and added co
|
| + 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 |