panel_window_resizer.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/root_window_controller.h" 10#include "ash/screen_ash.h" 11#include "ash/shelf/shelf_types.h" 12#include "ash/shelf/shelf_widget.h" 13#include "ash/shell.h" 14#include "ash/shell_window_ids.h" 15#include "ash/wm/coordinate_conversion.h" 16#include "ash/wm/panels/panel_layout_manager.h" 17#include "ash/wm/property_util.h" 18#include "ash/wm/window_properties.h" 19#include "ui/aura/client/aura_constants.h" 20#include "ui/aura/env.h" 21#include "ui/aura/root_window.h" 22#include "ui/aura/window.h" 23#include "ui/aura/window_delegate.h" 24#include "ui/base/hit_test.h" 25#include "ui/base/ui_base_types.h" 26#include "ui/gfx/screen.h" 27#include "ui/views/widget/widget.h" 28 29namespace ash { 30 31namespace { 32const int kPanelSnapToLauncherDistance = 30; 33 34internal::PanelLayoutManager* GetPanelLayoutManager( 35 aura::Window* panel_container) { 36 DCHECK(panel_container->id() == internal::kShellWindowId_PanelContainer); 37 return static_cast<internal::PanelLayoutManager*>( 38 panel_container->layout_manager()); 39} 40 41} // namespace 42 43PanelWindowResizer::~PanelWindowResizer() { 44 if (destroyed_) 45 *destroyed_ = true; 46} 47 48// static 49PanelWindowResizer* 50PanelWindowResizer::Create(WindowResizer* next_window_resizer, 51 aura::Window* window, 52 const gfx::Point& location, 53 int window_component) { 54 Details details(window, location, window_component); 55 return details.is_resizable ? 56 new PanelWindowResizer(next_window_resizer, details) : NULL; 57} 58 59void PanelWindowResizer::Drag(const gfx::Point& location, int event_flags) { 60 bool destroyed = false; 61 if (!did_move_or_resize_) { 62 did_move_or_resize_ = true; 63 StartedDragging(); 64 } 65 gfx::Point location_in_screen = location; 66 wm::ConvertPointToScreen(GetTarget()->parent(), &location_in_screen); 67 68 // Check if the destination has changed displays. 69 gfx::Screen* screen = Shell::GetScreen(); 70 const gfx::Display dst_display = 71 screen->GetDisplayNearestPoint(location_in_screen); 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); 85 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()); 90 } 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); 98 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(); 108 } 109} 110 111void 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(); 115} 116 117void PanelWindowResizer::RevertDrag() { 118 next_window_resizer_->RevertDrag(); 119 should_attach_ = was_attached_; 120 FinishDragging(); 121} 122 123aura::Window* PanelWindowResizer::GetTarget() { 124 return next_window_resizer_->GetTarget(); 125} 126 127PanelWindowResizer::PanelWindowResizer(WindowResizer* next_window_resizer, 128 const Details& details) 129 : details_(details), 130 next_window_resizer_(next_window_resizer), 131 panel_container_(NULL), 132 did_move_or_resize_(false), 133 was_attached_(GetTarget()->GetProperty(internal::kPanelAttachedKey)), 134 should_attach_(was_attached_), 135 destroyed_(NULL) { 136 DCHECK(details_.is_resizable); 137 panel_container_ = Shell::GetContainer( 138 details.window->GetRootWindow(), 139 internal::kShellWindowId_PanelContainer); 140} 141 142bool PanelWindowResizer::AttachToLauncher(const gfx::Rect& bounds, 143 gfx::Point* offset) { 144 bool should_attach = false; 145 if (panel_container_) { 146 internal::PanelLayoutManager* panel_layout_manager = 147 GetPanelLayoutManager(panel_container_); 148 gfx::Rect launcher_bounds = ScreenAsh::ConvertRectFromScreen( 149 GetTarget()->parent(), 150 panel_layout_manager->launcher()-> 151 shelf_widget()->GetWindowBoundsInScreen()); 152 switch (panel_layout_manager->launcher()->alignment()) { 153 case SHELF_ALIGNMENT_BOTTOM: 154 if (bounds.bottom() >= (launcher_bounds.y() - 155 kPanelSnapToLauncherDistance)) { 156 should_attach = true; 157 offset->set_y(launcher_bounds.y() - bounds.height() - bounds.y()); 158 } 159 break; 160 case SHELF_ALIGNMENT_LEFT: 161 if (bounds.x() <= (launcher_bounds.right() + 162 kPanelSnapToLauncherDistance)) { 163 should_attach = true; 164 offset->set_x(launcher_bounds.right() - bounds.x()); 165 } 166 break; 167 case SHELF_ALIGNMENT_RIGHT: 168 if (bounds.right() >= (launcher_bounds.x() - 169 kPanelSnapToLauncherDistance)) { 170 should_attach = true; 171 offset->set_x(launcher_bounds.x() - bounds.width() - bounds.x()); 172 } 173 break; 174 case SHELF_ALIGNMENT_TOP: 175 if (bounds.y() <= (launcher_bounds.bottom() + 176 kPanelSnapToLauncherDistance)) { 177 should_attach = true; 178 offset->set_y(launcher_bounds.bottom() - bounds.y()); 179 } 180 break; 181 } 182 } 183 return should_attach; 184} 185 186void PanelWindowResizer::StartedDragging() { 187 // Tell the panel layout manager that we are dragging this panel before 188 // attaching it so that it does not get repositioned. 189 if (panel_container_) 190 GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget()); 191 if (!was_attached_) { 192 // Attach the panel while dragging placing it in front of other panels. 193 GetTarget()->SetProperty(internal::kContinueDragAfterReparent, true); 194 GetTarget()->SetProperty(internal::kPanelAttachedKey, true); 195 GetTarget()->SetDefaultParentByRootWindow( 196 GetTarget()->GetRootWindow(), 197 GetTarget()->GetBoundsInScreen()); 198 } 199} 200 201void PanelWindowResizer::FinishDragging() { 202 if (!did_move_or_resize_) 203 return; 204 if (GetTarget()->GetProperty(internal::kPanelAttachedKey) != 205 should_attach_) { 206 GetTarget()->SetProperty(internal::kPanelAttachedKey, should_attach_); 207 GetTarget()->SetDefaultParentByRootWindow( 208 GetTarget()->GetRootWindow(), 209 GetTarget()->GetBoundsInScreen()); 210 } 211 if (panel_container_) 212 GetPanelLayoutManager(panel_container_)->FinishDragging(); 213} 214 215void PanelWindowResizer::UpdateLauncherPosition() { 216 if (panel_container_) { 217 GetPanelLayoutManager(panel_container_)->launcher()-> 218 UpdateIconPositionForWindow(GetTarget()); 219 } 220} 221 222} // namespace aura 223