OLD | NEW |
(Empty) | |
| 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/drag_window_resizer.h" |
| 6 |
| 7 #include "ash/display/mouse_cursor_event_filter.h" |
| 8 #include "ash/screen_ash.h" |
| 9 #include "ash/shell.h" |
| 10 #include "ash/wm/coordinate_conversion.h" |
| 11 #include "ash/wm/cursor_manager.h" |
| 12 #include "ash/wm/drag_window_controller.h" |
| 13 #include "ash/wm/property_util.h" |
| 14 #include "ui/aura/client/aura_constants.h" |
| 15 #include "ui/aura/env.h" |
| 16 #include "ui/aura/root_window.h" |
| 17 #include "ui/aura/window.h" |
| 18 #include "ui/aura/window_delegate.h" |
| 19 #include "ui/base/hit_test.h" |
| 20 #include "ui/base/ui_base_types.h" |
| 21 #include "ui/gfx/screen.h" |
| 22 |
| 23 namespace ash { |
| 24 namespace internal { |
| 25 |
| 26 namespace { |
| 27 |
| 28 // The maximum opacity of the drag phantom window. |
| 29 const float kMaxOpacity = 0.8f; |
| 30 |
| 31 // Returns true if Ash has more than one root window. |
| 32 bool HasSecondaryRootWindow() { |
| 33 return Shell::GetAllRootWindows().size() > 1; |
| 34 } |
| 35 |
| 36 // When there are two root windows, returns one of the root windows which is not |
| 37 // |root_window|. Returns NULL if only one root window exists. |
| 38 aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) { |
| 39 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); |
| 40 if (root_windows.size() < 2) |
| 41 return NULL; |
| 42 DCHECK_EQ(2U, root_windows.size()); |
| 43 if (root_windows[0] == root_window) |
| 44 return root_windows[1]; |
| 45 return root_windows[0]; |
| 46 } |
| 47 |
| 48 } |
| 49 |
| 50 DragWindowResizer::~DragWindowResizer() { |
| 51 Shell* shell = Shell::GetInstance(); |
| 52 shell->mouse_cursor_filter()->set_mouse_warp_mode( |
| 53 MouseCursorEventFilter::WARP_ALWAYS); |
| 54 shell->mouse_cursor_filter()->HideSharedEdgeIndicator(); |
| 55 |
| 56 if (destroyed_) |
| 57 *destroyed_ = true; |
| 58 } |
| 59 |
| 60 // static |
| 61 DragWindowResizer* DragWindowResizer::Create(WindowResizer* window_resizer, |
| 62 aura::Window* window, |
| 63 const gfx::Point& location, |
| 64 int window_component) { |
| 65 Details details(window, location, window_component); |
| 66 return details.is_resizable ? |
| 67 new DragWindowResizer(window_resizer, details) : NULL; |
| 68 } |
| 69 |
| 70 void DragWindowResizer::Drag(const gfx::Point& location, int event_flags) { |
| 71 bool destroyed = false; |
| 72 destroyed_ = &destroyed; |
| 73 window_resizer_->Drag(location, event_flags); |
| 74 if (destroyed) |
| 75 return; |
| 76 destroyed_ = NULL; |
| 77 last_mouse_location_ = location; |
| 78 |
| 79 // Show a phantom window for dragging in another root window. |
| 80 if (HasSecondaryRootWindow()) { |
| 81 gfx::Point location_in_screen = location; |
| 82 wm::ConvertPointToScreen(GetTarget()->parent(), &location_in_screen); |
| 83 const bool in_original_root = |
| 84 wm::GetRootWindowAt(location_in_screen) == GetTarget()->GetRootWindow(); |
| 85 UpdateDragWindow(GetTarget()->bounds(), in_original_root); |
| 86 } else { |
| 87 drag_window_controller_.reset(); |
| 88 } |
| 89 } |
| 90 |
| 91 void DragWindowResizer::CompleteDrag(int event_flags) { |
| 92 window_resizer_->CompleteDrag(event_flags); |
| 93 |
| 94 GetTarget()->layer()->SetOpacity(details_.initial_opacity); |
| 95 drag_window_controller_.reset(); |
| 96 |
| 97 // Check if the destination is another display. |
| 98 gfx::Point last_mouse_location_in_screen = last_mouse_location_; |
| 99 wm::ConvertPointToScreen(GetTarget()->parent(), |
| 100 &last_mouse_location_in_screen); |
| 101 gfx::Screen* screen = Shell::GetScreen(); |
| 102 const gfx::Display dst_display = |
| 103 screen->GetDisplayNearestPoint(last_mouse_location_in_screen); |
| 104 |
| 105 if (dst_display.id() != |
| 106 screen->GetDisplayNearestWindow(GetTarget()->GetRootWindow()).id()) { |
| 107 const gfx::Rect dst_bounds = |
| 108 ScreenAsh::ConvertRectToScreen(GetTarget()->parent(), |
| 109 GetTarget()->bounds()); |
| 110 GetTarget()->SetBoundsInScreen(dst_bounds, dst_display); |
| 111 } |
| 112 } |
| 113 |
| 114 void DragWindowResizer::RevertDrag() { |
| 115 window_resizer_->RevertDrag(); |
| 116 |
| 117 drag_window_controller_.reset(); |
| 118 GetTarget()->layer()->SetOpacity(details_.initial_opacity); |
| 119 } |
| 120 |
| 121 aura::Window* DragWindowResizer::GetTarget() { |
| 122 return window_resizer_->GetTarget(); |
| 123 } |
| 124 |
| 125 DragWindowResizer::DragWindowResizer(WindowResizer* window_resizer, |
| 126 const Details& details) |
| 127 : window_resizer_(window_resizer), |
| 128 details_(details), |
| 129 destroyed_(NULL) { |
| 130 // The pointer should be confined in one display during resizing a window |
| 131 // because the window cannot span two displays at the same time anyway. The |
| 132 // exception is window/tab dragging operation. During that operation, |
| 133 // |mouse_warp_mode_| should be set to WARP_DRAG so that the user could move a |
| 134 // window/tab to another display. |
| 135 MouseCursorEventFilter* mouse_cursor_filter = |
| 136 Shell::GetInstance()->mouse_cursor_filter(); |
| 137 mouse_cursor_filter->set_mouse_warp_mode( |
| 138 ShouldAllowMouseWarp() ? |
| 139 MouseCursorEventFilter::WARP_DRAG : MouseCursorEventFilter::WARP_NONE); |
| 140 if (ShouldAllowMouseWarp()) { |
| 141 mouse_cursor_filter->ShowSharedEdgeIndicator( |
| 142 details.window->GetRootWindow()); |
| 143 } |
| 144 } |
| 145 |
| 146 void DragWindowResizer::UpdateDragWindow(const gfx::Rect& bounds, |
| 147 bool in_original_root) { |
| 148 if (details_.window_component != HTCAPTION || !ShouldAllowMouseWarp()) |
| 149 return; |
| 150 |
| 151 // It's available. Show a phantom window on the display if needed. |
| 152 aura::RootWindow* another_root = |
| 153 GetAnotherRootWindow(GetTarget()->GetRootWindow()); |
| 154 const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen()); |
| 155 const gfx::Rect bounds_in_screen = |
| 156 ScreenAsh::ConvertRectToScreen(GetTarget()->parent(), bounds); |
| 157 gfx::Rect bounds_in_another_root = |
| 158 gfx::IntersectRects(root_bounds_in_screen, bounds_in_screen); |
| 159 const float fraction_in_another_window = |
| 160 (bounds_in_another_root.width() * bounds_in_another_root.height()) / |
| 161 static_cast<float>(bounds.width() * bounds.height()); |
| 162 |
| 163 if (fraction_in_another_window > 0) { |
| 164 if (!drag_window_controller_.get()) { |
| 165 drag_window_controller_.reset( |
| 166 new DragWindowController(GetTarget())); |
| 167 // Always show the drag phantom on the |another_root| window. |
| 168 drag_window_controller_->SetDestinationDisplay( |
| 169 Shell::GetScreen()->GetDisplayMatching( |
| 170 another_root->GetBoundsInScreen())); |
| 171 drag_window_controller_->Show(); |
| 172 } else { |
| 173 // No animation. |
| 174 drag_window_controller_->SetBounds(bounds_in_screen); |
| 175 } |
| 176 const float phantom_opacity = |
| 177 !in_original_root ? 1 : (kMaxOpacity * fraction_in_another_window); |
| 178 const float window_opacity = |
| 179 in_original_root ? 1 : (kMaxOpacity * (1 - fraction_in_another_window)); |
| 180 drag_window_controller_->SetOpacity(phantom_opacity); |
| 181 GetTarget()->layer()->SetOpacity(window_opacity); |
| 182 } else { |
| 183 drag_window_controller_.reset(); |
| 184 GetTarget()->layer()->SetOpacity(1.0f); |
| 185 } |
| 186 } |
| 187 |
| 188 bool DragWindowResizer::ShouldAllowMouseWarp() { |
| 189 return (details_.window_component == HTCAPTION) && |
| 190 (GetTarget()->GetProperty(aura::client::kModalKey) == |
| 191 ui::MODAL_TYPE_NONE) && |
| 192 (GetTarget()->type() == aura::client::WINDOW_TYPE_NORMAL); |
| 193 } |
| 194 |
| 195 } // namespace internal |
| 196 } // namespace ash |
OLD | NEW |