summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
Diffstat (limited to 'ash')
-rw-r--r--ash/wm/window_resizer.cc1
-rw-r--r--ash/wm/window_resizer.h3
-rw-r--r--ash/wm/workspace/phantom_window_controller.cc95
-rw-r--r--ash/wm/workspace/phantom_window_controller.h30
-rw-r--r--ash/wm/workspace/workspace_window_resizer.cc38
-rw-r--r--ash/wm/workspace/workspace_window_resizer.h12
-rw-r--r--ash/wm/workspace/workspace_window_resizer_unittest.cc78
7 files changed, 236 insertions, 21 deletions
diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc
index 9875106..623be33 100644
--- a/ash/wm/window_resizer.cc
+++ b/ash/wm/window_resizer.cc
@@ -113,6 +113,7 @@ WindowResizer::Details::Details(aura::Window* window,
: window(window),
initial_bounds(window->bounds()),
initial_location_in_parent(location),
+ initial_opacity(window->layer()->opacity()),
window_component(window_component),
bounds_change(GetBoundsChangeForWindowComponent(window_component)),
position_change_direction(
diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h
index 80ae948..ab37ce5 100644
--- a/ash/wm/window_resizer.h
+++ b/ash/wm/window_resizer.h
@@ -74,6 +74,9 @@ class ASH_EXPORT WindowResizer {
// Location passed to the constructor, in |window->parent()|'s coordinates.
gfx::Point initial_location_in_parent;
+ // Initial opacity of the window.
+ float initial_opacity;
+
// The component the user pressed on.
int window_component;
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc
index cebcb2a..5d756cc 100644
--- a/ash/wm/workspace/phantom_window_controller.cc
+++ b/ash/wm/workspace/phantom_window_controller.cc
@@ -8,12 +8,16 @@
#include "ash/shell_window_ids.h"
#include "ash/wm/coordinate_conversion.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/aura/client/screen_position_client.h"
+#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
#include "ui/aura/window_observer.h"
#include "ui/base/animation/slide_animation.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/painter.h"
#include "ui/views/view.h"
@@ -30,7 +34,7 @@ const int kInsetSize = 4;
// Size of the round rect used by EdgePainter.
const int kRoundRectSize = 4;
-// Paints the background of the phantom window.
+// Paints the background of the phantom window for window snapping.
class EdgePainter : public views::Painter {
public:
EdgePainter() {}
@@ -70,18 +74,58 @@ class EdgePainter : public views::Painter {
DISALLOW_COPY_AND_ASSIGN(EdgePainter);
};
+// Paints the background of the phantom window for window dragging.
+class WindowPainter : public views::Painter,
+ public aura::WindowObserver {
+ public:
+ explicit WindowPainter(aura::Window* window)
+ : window_(window) {
+ window_->AddObserver(this);
+ }
+
+ virtual ~WindowPainter() {
+ if (window_)
+ window_->RemoveObserver(this);
+ }
+
+ // views::Painter overrides:
+ virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE {
+ // TODO(yusukes): Paint child windows of the |window_| correctly. Current
+ // code does not paint e.g. web content area in the window. crbug.com/141766
+ if (window_ && window_->delegate())
+ window_->delegate()->OnPaint(canvas);
+ }
+
+ private:
+ // aura::WindowObserver overrides:
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
+ DCHECK_EQ(window_, window);
+ window_ = NULL;
+ }
+
+ aura::Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowPainter);
+};
+
} // namespace
PhantomWindowController::PhantomWindowController(aura::Window* window)
: window_(window),
phantom_below_window_(NULL),
- phantom_widget_(NULL) {
+ phantom_widget_(NULL),
+ style_(STYLE_SHADOW) {
}
PhantomWindowController::~PhantomWindowController() {
Hide();
}
+void PhantomWindowController::SetDestinationDisplay(
+ const gfx::Display& dst_display) {
+ dst_display_ = dst_display;
+}
+
void PhantomWindowController::Show(const gfx::Rect& bounds) {
if (bounds == bounds_)
return;
@@ -102,7 +146,7 @@ void PhantomWindowController::SetBounds(const gfx::Rect& bounds) {
DCHECK(IsShowing());
animation_.reset();
bounds_ = bounds;
- phantom_widget_->SetBounds(bounds_);
+ SetBoundsInternal(bounds);
}
void PhantomWindowController::Hide() {
@@ -115,10 +159,27 @@ bool PhantomWindowController::IsShowing() const {
return phantom_widget_ != NULL;
}
+void PhantomWindowController::set_style(Style style) {
+ // Cannot change |style_| after the widget is initialized.
+ DCHECK(!phantom_widget_);
+ style_ = style;
+}
+
+void PhantomWindowController::SetOpacity(float opacity) {
+ DCHECK(phantom_widget_);
+ ui::Layer* layer = phantom_widget_->GetNativeWindow()->layer();
+ ui::ScopedLayerAnimationSettings scoped_setter(layer->GetAnimator());
+ layer->SetOpacity(opacity);
+}
+
+float PhantomWindowController::GetOpacity() const {
+ DCHECK(phantom_widget_);
+ return phantom_widget_->GetNativeWindow()->layer()->opacity();
+}
+
void PhantomWindowController::AnimationProgressed(
const ui::Animation* animation) {
- phantom_widget_->SetBounds(
- animation->CurrentValueBetween(start_bounds_, bounds_));
+ SetBoundsInternal(animation->CurrentValueBetween(start_bounds_, bounds_));
}
void PhantomWindowController::CreatePhantomWidget(const gfx::Rect& bounds) {
@@ -138,10 +199,18 @@ void PhantomWindowController::CreatePhantomWidget(const gfx::Rect& bounds) {
phantom_widget_->SetVisibilityChangedAnimationsEnabled(false);
phantom_widget_->GetNativeWindow()->SetName("PhantomWindow");
views::View* content_view = new views::View;
- content_view->set_background(
- views::Background::CreateBackgroundPainter(true, new EdgePainter));
+ switch (style_) {
+ case STYLE_SHADOW:
+ content_view->set_background(
+ views::Background::CreateBackgroundPainter(true, new EdgePainter));
+ break;
+ case STYLE_WINDOW:
+ content_view->set_background(views::Background::CreateBackgroundPainter(
+ true, new WindowPainter(window_)));
+ break;
+ }
phantom_widget_->SetContentsView(content_view);
- phantom_widget_->SetBounds(bounds);
+ SetBoundsInternal(bounds);
if (phantom_below_window_)
phantom_widget_->StackBelow(phantom_below_window_);
else
@@ -154,5 +223,15 @@ void PhantomWindowController::CreatePhantomWidget(const gfx::Rect& bounds) {
layer->SetOpacity(1);
}
+void PhantomWindowController::SetBoundsInternal(const gfx::Rect& bounds) {
+ aura::Window* window = phantom_widget_->GetNativeWindow();
+ aura::client::ScreenPositionClient* screen_position_client =
+ aura::client::GetScreenPositionClient(window->GetRootWindow());
+ if (screen_position_client && dst_display_.id() != -1)
+ screen_position_client->SetBounds(window, bounds, dst_display_);
+ else
+ phantom_widget_->SetBounds(bounds);
+}
+
} // namespace internal
} // namespace ash
diff --git a/ash/wm/workspace/phantom_window_controller.h b/ash/wm/workspace/phantom_window_controller.h
index 7ea76c4..44262ea 100644
--- a/ash/wm/workspace/phantom_window_controller.h
+++ b/ash/wm/workspace/phantom_window_controller.h
@@ -9,10 +9,12 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/animation/animation_delegate.h"
+#include "ui/gfx/display.h"
#include "ui/gfx/rect.h"
namespace aura {
class Window;
+class RootWindow;
}
namespace ui {
@@ -30,9 +32,17 @@ namespace internal {
// of a window. It's used used during dragging a window to show a snap location.
class ASH_EXPORT PhantomWindowController : public ui::AnimationDelegate {
public:
+ enum Style {
+ STYLE_SHADOW, // for window snapping.
+ STYLE_WINDOW, // for window dragging.
+ };
+
explicit PhantomWindowController(aura::Window* window);
virtual ~PhantomWindowController();
+ // Sets the display where the phantom is placed.
+ void SetDestinationDisplay(const gfx::Display& dst_display);
+
// Bounds last passed to Show().
const gfx::Rect& bounds() const { return bounds_; }
@@ -56,6 +66,14 @@ class ASH_EXPORT PhantomWindowController : public ui::AnimationDelegate {
phantom_below_window_ = phantom_below_window;
}
+ // Sets/gets the style of the phantom window.
+ void set_style(Style style);
+ Style style() const { return style_; }
+
+ // Sets/gets the opacity of the phantom window.
+ void SetOpacity(float opacity);
+ float GetOpacity() const;
+
// ui::AnimationDelegate overrides:
virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
@@ -63,9 +81,18 @@ class ASH_EXPORT PhantomWindowController : public ui::AnimationDelegate {
// Creates and shows the |phantom_widget_| at |bounds|.
void CreatePhantomWidget(const gfx::Rect& bounds);
+ // Sets bounds of the phantom window. The window is shown on |dst_display_|
+ // if its id() is valid. Otherwise, a display nearest to |bounds| is chosen.
+ void SetBoundsInternal(const gfx::Rect& bounds);
+
// Window the phantom is placed beneath.
aura::Window* window_;
+ // The display where the phantom is placed. When dst_display_.id() is -1 (i.e.
+ // the default), a display nearest to the current |bounds_| is automatically
+ // used.
+ gfx::Display dst_display_;
+
// If set, the phantom window should get stacked below this window.
aura::Window* phantom_below_window_;
@@ -81,6 +108,9 @@ class ASH_EXPORT PhantomWindowController : public ui::AnimationDelegate {
// Used to transition the bounds.
scoped_ptr<ui::SlideAnimation> animation_;
+ // The style of the phantom window.
+ Style style_;
+
DISALLOW_COPY_AND_ASSIGN(PhantomWindowController);
};
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 978ca72..a936679 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -34,6 +34,9 @@ namespace {
// Duration of the animation when snapping the window into place.
const int kSnapDurationMS = 100;
+// The maximum opacity of the drag phantom window.
+const float kMaxOpacity = 0.8f;
+
// Returns true if should snap to the edge.
bool ShouldSnapToEdge(int distance_from_edge, int grid_size) {
return distance_from_edge <= grid_size / 2 &&
@@ -121,7 +124,7 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) {
// Show a phantom window for dragging in another root window.
if (HasSecondaryRootWindow())
- UpdateDragPhantomWindow(bounds);
+ UpdateDragPhantomWindow(bounds, in_original_root);
else
drag_phantom_window_controller_.reset();
@@ -133,6 +136,7 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location, int event_flags) {
}
void WorkspaceWindowResizer::CompleteDrag(int event_flags) {
+ window()->layer()->SetOpacity(details_.initial_opacity);
drag_phantom_window_controller_.reset();
snap_phantom_window_controller_.reset();
if (!did_move_or_resize_ || details_.window_component != HTCAPTION)
@@ -182,6 +186,7 @@ void WorkspaceWindowResizer::CompleteDrag(int event_flags) {
}
void WorkspaceWindowResizer::RevertDrag() {
+ window()->layer()->SetOpacity(details_.initial_opacity);
drag_phantom_window_controller_.reset();
snap_phantom_window_controller_.reset();
@@ -439,7 +444,8 @@ int WorkspaceWindowResizer::PrimaryAxisCoordinate(int x, int y) const {
return 0;
}
-void WorkspaceWindowResizer::UpdateDragPhantomWindow(const gfx::Rect& bounds) {
+void WorkspaceWindowResizer::UpdateDragPhantomWindow(const gfx::Rect& bounds,
+ bool in_original_root) {
if (!did_move_or_resize_ || details_.window_component != HTCAPTION ||
!ShouldAllowMouseWarp()) {
return;
@@ -451,18 +457,36 @@ void WorkspaceWindowResizer::UpdateDragPhantomWindow(const gfx::Rect& bounds) {
const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen());
const gfx::Rect bounds_in_screen =
ScreenAsh::ConvertRectToScreen(window()->parent(), bounds);
- const gfx::Rect phantom(root_bounds_in_screen.Intersect(bounds_in_screen));
-
- if (!phantom.IsEmpty()) {
+ const gfx::Rect bounds_in_another_root =
+ root_bounds_in_screen.Intersect(bounds_in_screen);
+
+ const float fraction_in_another_window =
+ (bounds_in_another_root.width() * bounds_in_another_root.height()) /
+ static_cast<float>(bounds.width() * bounds.height());
+ const float phantom_opacity =
+ !in_original_root ? 1 : (kMaxOpacity * fraction_in_another_window);
+ const float window_opacity =
+ in_original_root ? 1 : (kMaxOpacity * (1 - fraction_in_another_window));
+
+ if (fraction_in_another_window > 0) {
if (!drag_phantom_window_controller_.get()) {
drag_phantom_window_controller_.reset(
new PhantomWindowController(window()));
- drag_phantom_window_controller_->Show(phantom);
+ drag_phantom_window_controller_->set_style(
+ PhantomWindowController::STYLE_WINDOW);
+ // Always show the drag phantom on the |another_root| window.
+ drag_phantom_window_controller_->SetDestinationDisplay(
+ gfx::Screen::GetDisplayMatching(another_root->GetBoundsInScreen()));
+ drag_phantom_window_controller_->Show(bounds_in_screen);
} else {
- drag_phantom_window_controller_->SetBounds(phantom); // no animation
+ // No animation.
+ drag_phantom_window_controller_->SetBounds(bounds_in_screen);
}
+ drag_phantom_window_controller_->SetOpacity(phantom_opacity);
+ window()->layer()->SetOpacity(window_opacity);
} else {
drag_phantom_window_controller_.reset();
+ window()->layer()->SetOpacity(1.0f);
}
}
diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h
index 51e06ab..9667b7a 100644
--- a/ash/wm/workspace/workspace_window_resizer.h
+++ b/ash/wm/workspace/workspace_window_resizer.h
@@ -9,6 +9,7 @@
#include "ash/wm/window_resizer.h"
#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
namespace aura {
@@ -62,6 +63,8 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
const std::vector<aura::Window*>& attached_windows);
private:
+ FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, PhantomStyle);
+
// Type of snapping.
enum SnapType {
// Snap to the left/right edge of the screen.
@@ -114,8 +117,9 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
const gfx::Rect& bounds,
int grid_size);
- // Updates the bounds of the phantom window for window dragging.
- void UpdateDragPhantomWindow(const gfx::Rect& bounds);
+ // Updates the bounds of the phantom window for window dragging. Set true on
+ // |in_original_root| if the pointer is still in |window()->GetRootWindow()|.
+ void UpdateDragPhantomWindow(const gfx::Rect& bounds, bool in_original_root);
// Restacks the windows z-order position so that one of the windows is at the
// top of the z-order, and the rest directly underneath it.
@@ -165,9 +169,7 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
// is a grid and the caption is being dragged.
scoped_ptr<PhantomWindowController> snap_phantom_window_controller_;
- // For now, we show a phantom window on the other root window during dragging.
- // TODO(yusukes): Show a semi-transparent image (screen shot) of the window
- // instead.
+ // Shows a semi-transparent image of the window being dragged.
scoped_ptr<PhantomWindowController> drag_phantom_window_controller_;
// Used to determine the target position of a snap.
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index 8291dfc..72eca4b 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -10,6 +10,7 @@
#include "ash/test/ash_test_base.h"
#include "ash/wm/property_util.h"
#include "ash/wm/workspace_controller.h"
+#include "ash/wm/workspace/phantom_window_controller.h"
#include "base/string_number_conversions.h"
#include "ui/aura/root_window.h"
#include "ui/aura/test/test_window_delegate.h"
@@ -62,16 +63,19 @@ class WorkspaceWindowResizerTest : public test::AshTestBase {
EXPECT_EQ(kRootHeight, root_bounds.height());
Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
window_.reset(new aura::Window(&delegate_));
+ window_->SetType(aura::client::WINDOW_TYPE_NORMAL);
window_->Init(ui::LAYER_NOT_DRAWN);
window_->SetParent(default_container);
window_->set_id(1);
window2_.reset(new aura::Window(&delegate2_));
+ window2_->SetType(aura::client::WINDOW_TYPE_NORMAL);
window2_->Init(ui::LAYER_NOT_DRAWN);
window2_->SetParent(default_container);
window2_->set_id(2);
window3_.reset(new aura::Window(&delegate3_));
+ window3_->SetType(aura::client::WINDOW_TYPE_NORMAL);
window3_->Init(ui::LAYER_NOT_DRAWN);
window3_->SetParent(default_container);
window3_->set_id(3);
@@ -133,6 +137,8 @@ class WorkspaceWindowResizerTest : public test::AshTestBase {
DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTest);
};
+} // namespace
+
// Fails on win_aura since wm::GetRootWindowRelativeToWindow is not implemented
// yet for the platform.
#if defined(OS_WIN)
@@ -140,10 +146,12 @@ class WorkspaceWindowResizerTest : public test::AshTestBase {
DISABLED_WindowDragWithMultiMonitors
#define MAYBE_WindowDragWithMultiMonitorsRightToLeft \
DISABLED_WindowDragWithMultiMonitorsRightToLeft
+#define MAYBE_PhantomStyle DISABLED_PhantomStyle
#else
#define MAYBE_WindowDragWithMultiMonitors WindowDragWithMultiMonitors
#define MAYBE_WindowDragWithMultiMonitorsRightToLeft \
WindowDragWithMultiMonitorsRightToLeft
+#define MAYBE_PhantomStyle PhantomStyle
#endif
// Assertions around attached window resize dragging from the right with 2
@@ -569,6 +577,75 @@ TEST_F(WorkspaceWindowResizerTest,
}
}
+// Verifies the style of the drag phantom window is correct.
+TEST_F(WorkspaceWindowResizerTest, MAYBE_PhantomStyle) {
+ UpdateDisplay("800x600,800x600");
+ Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
+ ASSERT_EQ(2U, root_windows.size());
+
+ window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
+ gfx::Screen::GetPrimaryDisplay());
+ EXPECT_EQ(root_windows[0], window_->GetRootWindow());
+ EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
+ {
+ SetGridSize(0);
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTCAPTION, empty_windows()));
+ ASSERT_TRUE(resizer.get());
+ EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
+ EXPECT_FALSE(resizer->drag_phantom_window_controller_.get());
+
+ // The pointer is inside the primary root. Both phantoms should be NULL.
+ resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
+ EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
+ EXPECT_FALSE(resizer->drag_phantom_window_controller_.get());
+
+ // The window spans both root windows.
+ resizer->Drag(CalculateDragPoint(*resizer, 798, 10), 0);
+ EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
+ PhantomWindowController* controller =
+ resizer->drag_phantom_window_controller_.get();
+ ASSERT_TRUE(controller);
+ EXPECT_EQ(PhantomWindowController::STYLE_WINDOW, controller->style());
+ // |window_| should be opaque since the pointer is still on the primary
+ // root window. The phantom should be semi-transparent.
+ EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
+ EXPECT_GT(1.0f, controller->GetOpacity());
+
+ // Enter the pointer to the secondary display.
+ resizer->Drag(CalculateDragPoint(*resizer, 0, 610), 0);
+ EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
+ controller = resizer->drag_phantom_window_controller_.get();
+ ASSERT_TRUE(controller);
+ EXPECT_EQ(PhantomWindowController::STYLE_WINDOW, controller->style());
+ // |window_| should be transparent, and the phantom should be opaque.
+ EXPECT_GT(1.0f, window_->layer()->opacity());
+ EXPECT_FLOAT_EQ(1.0f, controller->GetOpacity());
+
+ resizer->CompleteDrag(0);
+ EXPECT_EQ(root_windows[1], window_->GetRootWindow());
+ EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
+ }
+
+ // Do the same test with RevertDrag().
+ window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
+ gfx::Screen::GetPrimaryDisplay());
+ EXPECT_EQ(root_windows[0], window_->GetRootWindow());
+ EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
+ {
+ scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+ window_.get(), gfx::Point(), HTCAPTION, empty_windows()));
+ ASSERT_TRUE(resizer.get());
+ EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
+ EXPECT_FALSE(resizer->drag_phantom_window_controller_.get());
+
+ resizer->Drag(CalculateDragPoint(*resizer, 0, 610), 0);
+ resizer->RevertDrag();
+ EXPECT_EQ(root_windows[0], window_->GetRootWindow());
+ EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
+ }
+}
+
// Verifies windows are correctly restacked when reordering multiple windows.
TEST_F(WorkspaceWindowResizerTest, RestackAttached) {
window_->SetBounds(gfx::Rect( 0, 0, 200, 300));
@@ -765,6 +842,5 @@ TEST_F(WorkspaceWindowResizerTest, CtrlCompleteDragMoveToExactPosition) {
EXPECT_EQ("106,124 320x160", window_->bounds().ToString());
}
-} // namespace
} // namespace test
} // namespace ash