• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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/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/root_window.h"
23 #include "ui/aura/window.h"
24 #include "ui/aura/window_delegate.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 
GetPanelLayoutManager(aura::Window * panel_container)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 
~PanelWindowResizer()44 PanelWindowResizer::~PanelWindowResizer() {
45 }
46 
47 // static
48 PanelWindowResizer*
Create(WindowResizer * next_window_resizer,aura::Window * window,const gfx::Point & location,int window_component,aura::client::WindowMoveSource source)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;
57 }
58 
Drag(const gfx::Point & location,int event_flags)59 void PanelWindowResizer::Drag(const gfx::Point& location, int event_flags) {
60   last_location_ = location;
61   wm::ConvertPointToScreen(GetTarget()->parent(), &last_location_);
62   if (!did_move_or_resize_) {
63     did_move_or_resize_ = true;
64     StartedDragging();
65   }
66 
67   // Check if the destination has changed displays.
68   gfx::Screen* screen = Shell::GetScreen();
69   const gfx::Display dst_display =
70       screen->GetDisplayNearestPoint(last_location_);
71   if (dst_display.id() !=
72       screen->GetDisplayNearestWindow(panel_container_->GetRootWindow()).id()) {
73     // The panel is being dragged to a new display. If the previous container is
74     // the current parent of the panel it will be informed of the end of drag
75     // when the panel is reparented, otherwise let the previous container know
76     // the drag is complete. If we told the panel's parent that the drag was
77     // complete it would begin positioning the panel.
78     if (GetTarget()->parent() != panel_container_)
79       GetPanelLayoutManager(panel_container_)->FinishDragging();
80     aura::Window* dst_root = Shell::GetInstance()->display_controller()->
81         GetRootWindowForDisplayId(dst_display.id());
82     panel_container_ = Shell::GetContainer(
83         dst_root, internal::kShellWindowId_PanelContainer);
84 
85     // The panel's parent already knows that the drag is in progress for this
86     // panel.
87     if (panel_container_ && GetTarget()->parent() != panel_container_)
88       GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget());
89   }
90   gfx::Point offset;
91   gfx::Rect bounds(CalculateBoundsForDrag(details_, location));
92   should_attach_ = AttachToLauncher(bounds, &offset);
93   gfx::Point modified_location(location.x() + offset.x(),
94                                location.y() + offset.y());
95 
96   base::WeakPtr<PanelWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr());
97   next_window_resizer_->Drag(modified_location, event_flags);
98   if (!resizer)
99     return;
100 
101   if (should_attach_ &&
102       !(details_.bounds_change & WindowResizer::kBoundsChange_Resizes)) {
103     UpdateLauncherPosition();
104   }
105 }
106 
CompleteDrag(int event_flags)107 void PanelWindowResizer::CompleteDrag(int event_flags) {
108   // The root window can change when dragging into a different screen.
109   next_window_resizer_->CompleteDrag(event_flags);
110   FinishDragging();
111 }
112 
RevertDrag()113 void PanelWindowResizer::RevertDrag() {
114   next_window_resizer_->RevertDrag();
115   should_attach_ = was_attached_;
116   FinishDragging();
117 }
118 
GetTarget()119 aura::Window* PanelWindowResizer::GetTarget() {
120   return next_window_resizer_->GetTarget();
121 }
122 
GetInitialLocation() const123 const gfx::Point& PanelWindowResizer::GetInitialLocation() const {
124   return details_.initial_location_in_parent;
125 }
126 
PanelWindowResizer(WindowResizer * next_window_resizer,const Details & details)127 PanelWindowResizer::PanelWindowResizer(WindowResizer* next_window_resizer,
128                                        const Details& details)
129     : details_(details),
130       next_window_resizer_(next_window_resizer),
131       panel_container_(NULL),
132       initial_panel_container_(NULL),
133       did_move_or_resize_(false),
134       was_attached_(wm::GetWindowState(GetTarget())->panel_attached()),
135       should_attach_(was_attached_),
136       weak_ptr_factory_(this) {
137   DCHECK(details_.is_resizable);
138   panel_container_ = Shell::GetContainer(
139       details.window->GetRootWindow(),
140       internal::kShellWindowId_PanelContainer);
141   initial_panel_container_ = panel_container_;
142 }
143 
AttachToLauncher(const gfx::Rect & bounds,gfx::Point * offset)144 bool PanelWindowResizer::AttachToLauncher(const gfx::Rect& bounds,
145                                           gfx::Point* offset) {
146   bool should_attach = false;
147   if (panel_container_) {
148     internal::PanelLayoutManager* panel_layout_manager =
149         GetPanelLayoutManager(panel_container_);
150     gfx::Rect launcher_bounds = ScreenAsh::ConvertRectFromScreen(
151         GetTarget()->parent(),
152         panel_layout_manager->launcher()->
153         shelf_widget()->GetWindowBoundsInScreen());
154     switch (panel_layout_manager->launcher()->alignment()) {
155       case SHELF_ALIGNMENT_BOTTOM:
156         if (bounds.bottom() >= (launcher_bounds.y() -
157                                 kPanelSnapToLauncherDistance)) {
158           should_attach = true;
159           offset->set_y(launcher_bounds.y() - bounds.height() - bounds.y());
160         }
161         break;
162       case SHELF_ALIGNMENT_LEFT:
163         if (bounds.x() <= (launcher_bounds.right() +
164                            kPanelSnapToLauncherDistance)) {
165           should_attach = true;
166           offset->set_x(launcher_bounds.right() - bounds.x());
167         }
168         break;
169       case SHELF_ALIGNMENT_RIGHT:
170         if (bounds.right() >= (launcher_bounds.x() -
171                                kPanelSnapToLauncherDistance)) {
172           should_attach = true;
173           offset->set_x(launcher_bounds.x() - bounds.width() - bounds.x());
174         }
175         break;
176       case SHELF_ALIGNMENT_TOP:
177         if (bounds.y() <= (launcher_bounds.bottom() +
178                            kPanelSnapToLauncherDistance)) {
179           should_attach = true;
180           offset->set_y(launcher_bounds.bottom() - bounds.y());
181         }
182         break;
183     }
184   }
185   return should_attach;
186 }
187 
StartedDragging()188 void PanelWindowResizer::StartedDragging() {
189   // Tell the panel layout manager that we are dragging this panel before
190   // attaching it so that it does not get repositioned.
191   if (panel_container_)
192     GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget());
193   if (!was_attached_) {
194     // Attach the panel while dragging placing it in front of other panels.
195     wm::GetWindowState(GetTarget())->set_continue_drag_after_reparent(true);
196     wm::GetWindowState(GetTarget())->set_panel_attached(true);
197     // We use root window coordinates to ensure that during the drag the panel
198     // is reparented to a container in the root window that has that window.
199     aura::Window* target = GetTarget();
200     aura::Window* target_root = target->GetRootWindow();
201     aura::Window* old_parent = target->parent();
202     aura::client::ParentWindowWithContext(
203         target, target_root, target_root->GetBoundsInScreen());
204     wm::ReparentTransientChildrenOfChild(target, old_parent, target->parent());
205   }
206 }
207 
FinishDragging()208 void PanelWindowResizer::FinishDragging() {
209   if (!did_move_or_resize_)
210     return;
211   if (details_.bounds_change & WindowResizer::kBoundsChange_Resizes)
212     should_attach_ = was_attached_;
213   if (wm::GetWindowState(GetTarget())->panel_attached() != should_attach_) {
214     wm::GetWindowState(GetTarget())->set_panel_attached(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     aura::Window* target = GetTarget();
218     aura::Window* target_root = target->GetRootWindow();
219     aura::Window* old_parent = target->parent();
220     aura::client::ParentWindowWithContext(
221         target, target_root, gfx::Rect(last_location_, gfx::Size()));
222     wm::ReparentTransientChildrenOfChild(target, old_parent, target->parent());
223   }
224 
225   // If we started the drag in one root window and moved into another root
226   // but then canceled the drag we may need to inform the original layout
227   // manager that the drag is finished.
228   if (initial_panel_container_ != panel_container_)
229      GetPanelLayoutManager(initial_panel_container_)->FinishDragging();
230   if (panel_container_)
231     GetPanelLayoutManager(panel_container_)->FinishDragging();
232 }
233 
UpdateLauncherPosition()234 void PanelWindowResizer::UpdateLauncherPosition() {
235   if (panel_container_) {
236     GetPanelLayoutManager(panel_container_)->launcher()->
237         UpdateIconPositionForWindow(GetTarget());
238   }
239 }
240 
241 }  // namespace aura
242