Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / ash / wm / panels / panel_window_resizer.cc
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.
4
5 #include "ash/wm/panels/panel_window_resizer.h"
6
7 #include "ash/display/display_controller.h"
8 #include "ash/screen_util.h"
9 #include "ash/shelf/shelf.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/window_state.h"
17 #include "ash/wm/window_util.h"
18 #include "base/memory/weak_ptr.h"
19 #include "ui/aura/client/aura_constants.h"
20 #include "ui/aura/client/window_tree_client.h"
21 #include "ui/aura/env.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_delegate.h"
24 #include "ui/aura/window_event_dispatcher.h"
25 #include "ui/base/hit_test.h"
26 #include "ui/base/ui_base_types.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/views/widget/widget.h"
29
30 namespace ash {
31
32 namespace {
33 const int kPanelSnapToLauncherDistance = 30;
34
35 internal::PanelLayoutManager* GetPanelLayoutManager(
36     aura::Window* panel_container) {
37   DCHECK(panel_container->id() == internal::kShellWindowId_PanelContainer);
38   return static_cast<internal::PanelLayoutManager*>(
39       panel_container->layout_manager());
40 }
41
42 }  // namespace
43
44 PanelWindowResizer::~PanelWindowResizer() {
45 }
46
47 // static
48 PanelWindowResizer*
49 PanelWindowResizer::Create(WindowResizer* next_window_resizer,
50                            wm::WindowState* window_state) {
51   return new PanelWindowResizer(next_window_resizer, window_state);
52 }
53
54 void PanelWindowResizer::Drag(const gfx::Point& location, int event_flags) {
55   last_location_ = location;
56   wm::ConvertPointToScreen(GetTarget()->parent(), &last_location_);
57   if (!did_move_or_resize_) {
58     did_move_or_resize_ = true;
59     StartedDragging();
60   }
61
62   // Check if the destination has changed displays.
63   gfx::Screen* screen = Shell::GetScreen();
64   const gfx::Display dst_display =
65       screen->GetDisplayNearestPoint(last_location_);
66   if (dst_display.id() !=
67       screen->GetDisplayNearestWindow(panel_container_->GetRootWindow()).id()) {
68     // The panel is being dragged to a new display. If the previous container is
69     // the current parent of the panel it will be informed of the end of drag
70     // when the panel is reparented, otherwise let the previous container know
71     // the drag is complete. If we told the panel's parent that the drag was
72     // complete it would begin positioning the panel.
73     if (GetTarget()->parent() != panel_container_)
74       GetPanelLayoutManager(panel_container_)->FinishDragging();
75     aura::Window* dst_root = Shell::GetInstance()->display_controller()->
76         GetRootWindowForDisplayId(dst_display.id());
77     panel_container_ = Shell::GetContainer(
78         dst_root, internal::kShellWindowId_PanelContainer);
79
80     // The panel's parent already knows that the drag is in progress for this
81     // panel.
82     if (panel_container_ && GetTarget()->parent() != panel_container_)
83       GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget());
84   }
85   gfx::Point offset;
86   gfx::Rect bounds(CalculateBoundsForDrag(location));
87   if (!(details().bounds_change & WindowResizer::kBoundsChange_Resizes)) {
88     window_state_->drag_details()->should_attach_to_shelf =
89         AttachToLauncher(bounds, &offset);
90   }
91   gfx::Point modified_location(location.x() + offset.x(),
92                                location.y() + offset.y());
93
94   base::WeakPtr<PanelWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr());
95   next_window_resizer_->Drag(modified_location, event_flags);
96   if (!resizer)
97     return;
98
99   if (details().should_attach_to_shelf &&
100       !(details().bounds_change & WindowResizer::kBoundsChange_Resizes)) {
101     UpdateLauncherPosition();
102   }
103 }
104
105 void PanelWindowResizer::CompleteDrag() {
106   // The root window can change when dragging into a different screen.
107   next_window_resizer_->CompleteDrag();
108   FinishDragging();
109 }
110
111 void PanelWindowResizer::RevertDrag() {
112   next_window_resizer_->RevertDrag();
113   window_state_->drag_details()->should_attach_to_shelf = was_attached_;
114   FinishDragging();
115 }
116
117 PanelWindowResizer::PanelWindowResizer(WindowResizer* next_window_resizer,
118                                        wm::WindowState* window_state)
119     : WindowResizer(window_state),
120       next_window_resizer_(next_window_resizer),
121       panel_container_(NULL),
122       initial_panel_container_(NULL),
123       did_move_or_resize_(false),
124       was_attached_(window_state->panel_attached()),
125       weak_ptr_factory_(this) {
126   DCHECK(details().is_resizable);
127   panel_container_ = Shell::GetContainer(
128       GetTarget()->GetRootWindow(),
129       internal::kShellWindowId_PanelContainer);
130   initial_panel_container_ = panel_container_;
131 }
132
133 bool PanelWindowResizer::AttachToLauncher(const gfx::Rect& bounds,
134                                           gfx::Point* offset) {
135   bool should_attach = false;
136   if (panel_container_) {
137     internal::PanelLayoutManager* panel_layout_manager =
138         GetPanelLayoutManager(panel_container_);
139     gfx::Rect launcher_bounds = ScreenUtil::ConvertRectFromScreen(
140         GetTarget()->parent(),
141         panel_layout_manager->shelf()->
142         shelf_widget()->GetWindowBoundsInScreen());
143     switch (panel_layout_manager->shelf()->alignment()) {
144       case SHELF_ALIGNMENT_BOTTOM:
145         if (bounds.bottom() >= (launcher_bounds.y() -
146                                 kPanelSnapToLauncherDistance)) {
147           should_attach = true;
148           offset->set_y(launcher_bounds.y() - bounds.height() - bounds.y());
149         }
150         break;
151       case SHELF_ALIGNMENT_LEFT:
152         if (bounds.x() <= (launcher_bounds.right() +
153                            kPanelSnapToLauncherDistance)) {
154           should_attach = true;
155           offset->set_x(launcher_bounds.right() - bounds.x());
156         }
157         break;
158       case SHELF_ALIGNMENT_RIGHT:
159         if (bounds.right() >= (launcher_bounds.x() -
160                                kPanelSnapToLauncherDistance)) {
161           should_attach = true;
162           offset->set_x(launcher_bounds.x() - bounds.width() - bounds.x());
163         }
164         break;
165       case SHELF_ALIGNMENT_TOP:
166         if (bounds.y() <= (launcher_bounds.bottom() +
167                            kPanelSnapToLauncherDistance)) {
168           should_attach = true;
169           offset->set_y(launcher_bounds.bottom() - bounds.y());
170         }
171         break;
172     }
173   }
174   return should_attach;
175 }
176
177 void PanelWindowResizer::StartedDragging() {
178   // Tell the panel layout manager that we are dragging this panel before
179   // attaching it so that it does not get repositioned.
180   if (panel_container_)
181     GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget());
182   if (!was_attached_) {
183     // Attach the panel while dragging placing it in front of other panels.
184     window_state_->set_panel_attached(true);
185     // We use root window coordinates to ensure that during the drag the panel
186     // is reparented to a container in the root window that has that window.
187     aura::Window* target = GetTarget();
188     aura::Window* target_root = target->GetRootWindow();
189     aura::Window* old_parent = target->parent();
190     aura::client::ParentWindowWithContext(
191         target, target_root, target_root->GetBoundsInScreen());
192     wm::ReparentTransientChildrenOfChild(target, old_parent, target->parent());
193   }
194 }
195
196 void PanelWindowResizer::FinishDragging() {
197   if (!did_move_or_resize_)
198     return;
199   if (window_state_->panel_attached() != details().should_attach_to_shelf) {
200     window_state_->set_panel_attached(details().should_attach_to_shelf);
201     // We use last known location to ensure that after the drag the panel
202     // is reparented to a container in the root window that has that location.
203     aura::Window* target = GetTarget();
204     aura::Window* target_root = target->GetRootWindow();
205     aura::Window* old_parent = target->parent();
206     aura::client::ParentWindowWithContext(
207         target, target_root, gfx::Rect(last_location_, gfx::Size()));
208     wm::ReparentTransientChildrenOfChild(target, old_parent, target->parent());
209   }
210
211   // If we started the drag in one root window and moved into another root
212   // but then canceled the drag we may need to inform the original layout
213   // manager that the drag is finished.
214   if (initial_panel_container_ != panel_container_)
215      GetPanelLayoutManager(initial_panel_container_)->FinishDragging();
216   if (panel_container_)
217     GetPanelLayoutManager(panel_container_)->FinishDragging();
218 }
219
220 void PanelWindowResizer::UpdateLauncherPosition() {
221   if (panel_container_) {
222     GetPanelLayoutManager(panel_container_)->shelf()->
223         UpdateIconPositionForWindow(GetTarget());
224   }
225 }
226
227 }  // namespace aura