Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / ash / wm / panels / panel_window_resizer.cc
blobcb151b8bae08370bb7a48074a8092fd74cd3e3a1
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/panels/panel_window_resizer.h"
7 #include "ash/display/display_controller.h"
8 #include "ash/launcher/launcher.h"
9 #include "ash/screen_ash.h"
10 #include "ash/shelf/shelf_types.h"
11 #include "ash/shelf/shelf_widget.h"
12 #include "ash/shell.h"
13 #include "ash/shell_window_ids.h"
14 #include "ash/wm/coordinate_conversion.h"
15 #include "ash/wm/panels/panel_layout_manager.h"
16 #include "ash/wm/property_util.h"
17 #include "ash/wm/window_properties.h"
18 #include "ui/aura/client/aura_constants.h"
19 #include "ui/aura/env.h"
20 #include "ui/aura/root_window.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_delegate.h"
23 #include "ui/base/hit_test.h"
24 #include "ui/base/ui_base_types.h"
25 #include "ui/gfx/screen.h"
26 #include "ui/views/widget/widget.h"
28 namespace ash {
30 namespace {
31 const int kPanelSnapToLauncherDistance = 30;
33 internal::PanelLayoutManager* GetPanelLayoutManager(
34 aura::Window* panel_container) {
35 DCHECK(panel_container->id() == internal::kShellWindowId_PanelContainer);
36 return static_cast<internal::PanelLayoutManager*>(
37 panel_container->layout_manager());
40 } // namespace
42 PanelWindowResizer::~PanelWindowResizer() {
43 if (destroyed_)
44 *destroyed_ = true;
47 // static
48 PanelWindowResizer*
49 PanelWindowResizer::Create(WindowResizer* next_window_resizer,
50 aura::Window* window,
51 const gfx::Point& location,
52 int window_component,
53 aura::client::WindowMoveSource source) {
54 Details details(window, location, window_component, source);
55 return details.is_resizable ?
56 new PanelWindowResizer(next_window_resizer, details) : NULL;
59 void PanelWindowResizer::Drag(const gfx::Point& location, int event_flags) {
60 last_location_ = location;
61 wm::ConvertPointToScreen(GetTarget()->parent(), &last_location_);
62 bool destroyed = false;
63 if (!did_move_or_resize_) {
64 did_move_or_resize_ = true;
65 StartedDragging();
68 // Check if the destination has changed displays.
69 gfx::Screen* screen = Shell::GetScreen();
70 const gfx::Display dst_display =
71 screen->GetDisplayNearestPoint(last_location_);
72 if (dst_display.id() !=
73 screen->GetDisplayNearestWindow(panel_container_->GetRootWindow()).id()) {
74 // The panel is being dragged to a new display. If the previous container is
75 // the current parent of the panel it will be informed of the end of drag
76 // when the panel is reparented, otherwise let the previous container know
77 // the drag is complete. If we told the panel's parent that the drag was
78 // complete it would begin positioning the panel.
79 if (GetTarget()->parent() != panel_container_)
80 GetPanelLayoutManager(panel_container_)->FinishDragging();
81 aura::RootWindow* dst_root = Shell::GetInstance()->display_controller()->
82 GetRootWindowForDisplayId(dst_display.id());
83 panel_container_ = Shell::GetContainer(
84 dst_root, internal::kShellWindowId_PanelContainer);
86 // The panel's parent already knows that the drag is in progress for this
87 // panel.
88 if (panel_container_ && GetTarget()->parent() != panel_container_)
89 GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget());
91 gfx::Point offset;
92 gfx::Rect bounds(CalculateBoundsForDrag(details_, location));
93 should_attach_ = AttachToLauncher(bounds, &offset);
94 gfx::Point modified_location(location.x() + offset.x(),
95 location.y() + offset.y());
96 destroyed_ = &destroyed;
97 next_window_resizer_->Drag(modified_location, event_flags);
99 // TODO(flackr): Refactor the way WindowResizer calls into other window
100 // resizers to avoid the awkward pattern here for checking if
101 // next_window_resizer_ destroys the resizer object.
102 if (destroyed)
103 return;
104 destroyed_ = NULL;
105 if (should_attach_ &&
106 !(details_.bounds_change & WindowResizer::kBoundsChange_Resizes)) {
107 UpdateLauncherPosition();
111 void PanelWindowResizer::CompleteDrag(int event_flags) {
112 // The root window can change when dragging into a different screen.
113 next_window_resizer_->CompleteDrag(event_flags);
114 FinishDragging();
117 void PanelWindowResizer::RevertDrag() {
118 next_window_resizer_->RevertDrag();
119 should_attach_ = was_attached_;
120 FinishDragging();
123 aura::Window* PanelWindowResizer::GetTarget() {
124 return next_window_resizer_->GetTarget();
127 const gfx::Point& PanelWindowResizer::GetInitialLocation() const {
128 return details_.initial_location_in_parent;
131 PanelWindowResizer::PanelWindowResizer(WindowResizer* next_window_resizer,
132 const Details& details)
133 : details_(details),
134 next_window_resizer_(next_window_resizer),
135 panel_container_(NULL),
136 initial_panel_container_(NULL),
137 did_move_or_resize_(false),
138 was_attached_(GetTarget()->GetProperty(internal::kPanelAttachedKey)),
139 should_attach_(was_attached_),
140 destroyed_(NULL) {
141 DCHECK(details_.is_resizable);
142 panel_container_ = Shell::GetContainer(
143 details.window->GetRootWindow(),
144 internal::kShellWindowId_PanelContainer);
145 initial_panel_container_ = panel_container_;
148 bool PanelWindowResizer::AttachToLauncher(const gfx::Rect& bounds,
149 gfx::Point* offset) {
150 bool should_attach = false;
151 if (panel_container_) {
152 internal::PanelLayoutManager* panel_layout_manager =
153 GetPanelLayoutManager(panel_container_);
154 gfx::Rect launcher_bounds = ScreenAsh::ConvertRectFromScreen(
155 GetTarget()->parent(),
156 panel_layout_manager->launcher()->
157 shelf_widget()->GetWindowBoundsInScreen());
158 switch (panel_layout_manager->launcher()->alignment()) {
159 case SHELF_ALIGNMENT_BOTTOM:
160 if (bounds.bottom() >= (launcher_bounds.y() -
161 kPanelSnapToLauncherDistance)) {
162 should_attach = true;
163 offset->set_y(launcher_bounds.y() - bounds.height() - bounds.y());
165 break;
166 case SHELF_ALIGNMENT_LEFT:
167 if (bounds.x() <= (launcher_bounds.right() +
168 kPanelSnapToLauncherDistance)) {
169 should_attach = true;
170 offset->set_x(launcher_bounds.right() - bounds.x());
172 break;
173 case SHELF_ALIGNMENT_RIGHT:
174 if (bounds.right() >= (launcher_bounds.x() -
175 kPanelSnapToLauncherDistance)) {
176 should_attach = true;
177 offset->set_x(launcher_bounds.x() - bounds.width() - bounds.x());
179 break;
180 case SHELF_ALIGNMENT_TOP:
181 if (bounds.y() <= (launcher_bounds.bottom() +
182 kPanelSnapToLauncherDistance)) {
183 should_attach = true;
184 offset->set_y(launcher_bounds.bottom() - bounds.y());
186 break;
189 return should_attach;
192 void PanelWindowResizer::StartedDragging() {
193 // Tell the panel layout manager that we are dragging this panel before
194 // attaching it so that it does not get repositioned.
195 if (panel_container_)
196 GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget());
197 if (!was_attached_) {
198 // Attach the panel while dragging placing it in front of other panels.
199 GetTarget()->SetProperty(internal::kContinueDragAfterReparent, true);
200 GetTarget()->SetProperty(internal::kPanelAttachedKey, true);
201 // We use root window coordinates to ensure that during the drag the panel
202 // is reparented to a container in the root window that has that window.
203 GetTarget()->SetDefaultParentByRootWindow(
204 GetTarget()->GetRootWindow(),
205 GetTarget()->GetRootWindow()->GetBoundsInScreen());
209 void PanelWindowResizer::FinishDragging() {
210 if (!did_move_or_resize_)
211 return;
212 if (GetTarget()->GetProperty(internal::kPanelAttachedKey) !=
213 should_attach_) {
214 GetTarget()->SetProperty(internal::kPanelAttachedKey, should_attach_);
215 // We use last known location to ensure that after the drag the panel
216 // is reparented to a container in the root window that has that location.
217 GetTarget()->SetDefaultParentByRootWindow(
218 GetTarget()->GetRootWindow(),
219 gfx::Rect(last_location_, gfx::Size()));
222 // If we started the drag in one root window and moved into another root
223 // but then canceled the drag we may need to inform the original layout
224 // manager that the drag is finished.
225 if (initial_panel_container_ != panel_container_)
226 GetPanelLayoutManager(initial_panel_container_)->FinishDragging();
227 if (panel_container_)
228 GetPanelLayoutManager(panel_container_)->FinishDragging();
231 void PanelWindowResizer::UpdateLauncherPosition() {
232 if (panel_container_) {
233 GetPanelLayoutManager(panel_container_)->launcher()->
234 UpdateIconPositionForWindow(GetTarget());
238 } // namespace aura