panel_window_resizer.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/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" 27 28namespace ash { 29 30namespace { 31const int kPanelSnapToLauncherDistance = 30; 32 33internal::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()); 38} 39 40} // namespace 41 42PanelWindowResizer::~PanelWindowResizer() { 43 if (destroyed_) 44 *destroyed_ = true; 45} 46 47// static 48PanelWindowResizer* 49PanelWindowResizer::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 59void 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(); 66 } 67 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); 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 127const gfx::Point& PanelWindowResizer::GetInitialLocation() const { 128 return details_.initial_location_in_parent; 129} 130 131PanelWindowResizer::PanelWindowResizer(WindowResizer* next_window_resizer, 132 const Details& details) 133 : details_(details), 134 next_window_resizer_(next_window_resizer), 135 panel_container_(NULL), 136 did_move_or_resize_(false), 137 was_attached_(GetTarget()->GetProperty(internal::kPanelAttachedKey)), 138 should_attach_(was_attached_), 139 destroyed_(NULL) { 140 DCHECK(details_.is_resizable); 141 panel_container_ = Shell::GetContainer( 142 details.window->GetRootWindow(), 143 internal::kShellWindowId_PanelContainer); 144} 145 146bool PanelWindowResizer::AttachToLauncher(const gfx::Rect& bounds, 147 gfx::Point* offset) { 148 bool should_attach = false; 149 if (panel_container_) { 150 internal::PanelLayoutManager* panel_layout_manager = 151 GetPanelLayoutManager(panel_container_); 152 gfx::Rect launcher_bounds = ScreenAsh::ConvertRectFromScreen( 153 GetTarget()->parent(), 154 panel_layout_manager->launcher()-> 155 shelf_widget()->GetWindowBoundsInScreen()); 156 switch (panel_layout_manager->launcher()->alignment()) { 157 case SHELF_ALIGNMENT_BOTTOM: 158 if (bounds.bottom() >= (launcher_bounds.y() - 159 kPanelSnapToLauncherDistance)) { 160 should_attach = true; 161 offset->set_y(launcher_bounds.y() - bounds.height() - bounds.y()); 162 } 163 break; 164 case SHELF_ALIGNMENT_LEFT: 165 if (bounds.x() <= (launcher_bounds.right() + 166 kPanelSnapToLauncherDistance)) { 167 should_attach = true; 168 offset->set_x(launcher_bounds.right() - bounds.x()); 169 } 170 break; 171 case SHELF_ALIGNMENT_RIGHT: 172 if (bounds.right() >= (launcher_bounds.x() - 173 kPanelSnapToLauncherDistance)) { 174 should_attach = true; 175 offset->set_x(launcher_bounds.x() - bounds.width() - bounds.x()); 176 } 177 break; 178 case SHELF_ALIGNMENT_TOP: 179 if (bounds.y() <= (launcher_bounds.bottom() + 180 kPanelSnapToLauncherDistance)) { 181 should_attach = true; 182 offset->set_y(launcher_bounds.bottom() - bounds.y()); 183 } 184 break; 185 } 186 } 187 return should_attach; 188} 189 190void PanelWindowResizer::StartedDragging() { 191 // Tell the panel layout manager that we are dragging this panel before 192 // attaching it so that it does not get repositioned. 193 if (panel_container_) 194 GetPanelLayoutManager(panel_container_)->StartDragging(GetTarget()); 195 if (!was_attached_) { 196 // Attach the panel while dragging placing it in front of other panels. 197 GetTarget()->SetProperty(internal::kContinueDragAfterReparent, true); 198 GetTarget()->SetProperty(internal::kPanelAttachedKey, true); 199 // We use root window coordinates to ensure that during the drag the panel 200 // is reparented to a container in the root window that has that window. 201 GetTarget()->SetDefaultParentByRootWindow( 202 GetTarget()->GetRootWindow(), 203 GetTarget()->GetRootWindow()->GetBoundsInScreen()); 204 } 205} 206 207void PanelWindowResizer::FinishDragging() { 208 if (!did_move_or_resize_) 209 return; 210 if (GetTarget()->GetProperty(internal::kPanelAttachedKey) != 211 should_attach_) { 212 GetTarget()->SetProperty(internal::kPanelAttachedKey, should_attach_); 213 // We use last known location to ensure that after the drag the panel 214 // is reparented to a container in the root window that has that location. 215 GetTarget()->SetDefaultParentByRootWindow( 216 GetTarget()->GetRootWindow(), 217 gfx::Rect(last_location_, gfx::Size())); 218 } 219 if (panel_container_) 220 GetPanelLayoutManager(panel_container_)->FinishDragging(); 221} 222 223void PanelWindowResizer::UpdateLauncherPosition() { 224 if (panel_container_) { 225 GetPanelLayoutManager(panel_container_)->launcher()-> 226 UpdateIconPositionForWindow(GetTarget()); 227 } 228} 229 230} // namespace aura 231