panel_window_resizer.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/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 30namespace ash { 31 32namespace { 33const int kPanelSnapToLauncherDistance = 30; 34 35internal::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 44PanelWindowResizer::~PanelWindowResizer() { 45} 46 47// static 48PanelWindowResizer* 49PanelWindowResizer::Create(WindowResizer* next_window_resizer, 50 wm::WindowState* window_state) { 51 return new PanelWindowResizer(next_window_resizer, window_state); 52} 53 54void 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 105void PanelWindowResizer::CompleteDrag() { 106 // The root window can change when dragging into a different screen. 107 next_window_resizer_->CompleteDrag(); 108 FinishDragging(); 109} 110 111void PanelWindowResizer::RevertDrag() { 112 next_window_resizer_->RevertDrag(); 113 window_state_->drag_details()->should_attach_to_shelf = was_attached_; 114 FinishDragging(); 115} 116 117PanelWindowResizer::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 133bool 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 177void 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_continue_drag_after_reparent(true); 185 window_state_->set_panel_attached(true); 186 // We use root window coordinates to ensure that during the drag the panel 187 // is reparented to a container in the root window that has that window. 188 aura::Window* target = GetTarget(); 189 aura::Window* target_root = target->GetRootWindow(); 190 aura::Window* old_parent = target->parent(); 191 aura::client::ParentWindowWithContext( 192 target, target_root, target_root->GetBoundsInScreen()); 193 wm::ReparentTransientChildrenOfChild(target, old_parent, target->parent()); 194 } 195} 196 197void PanelWindowResizer::FinishDragging() { 198 if (!did_move_or_resize_) 199 return; 200 if (window_state_->panel_attached() != details().should_attach_to_shelf) { 201 window_state_->set_panel_attached(details().should_attach_to_shelf); 202 // We use last known location to ensure that after the drag the panel 203 // is reparented to a container in the root window that has that location. 204 aura::Window* target = GetTarget(); 205 aura::Window* target_root = target->GetRootWindow(); 206 aura::Window* old_parent = target->parent(); 207 aura::client::ParentWindowWithContext( 208 target, target_root, gfx::Rect(last_location_, gfx::Size())); 209 wm::ReparentTransientChildrenOfChild(target, old_parent, target->parent()); 210 } 211 212 // If we started the drag in one root window and moved into another root 213 // but then canceled the drag we may need to inform the original layout 214 // manager that the drag is finished. 215 if (initial_panel_container_ != panel_container_) 216 GetPanelLayoutManager(initial_panel_container_)->FinishDragging(); 217 if (panel_container_) 218 GetPanelLayoutManager(panel_container_)->FinishDragging(); 219} 220 221void PanelWindowResizer::UpdateLauncherPosition() { 222 if (panel_container_) { 223 GetPanelLayoutManager(panel_container_)->shelf()-> 224 UpdateIconPositionForWindow(GetTarget()); 225 } 226} 227 228} // namespace aura 229