cursor_window_controller.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
1// Copyright 2014 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/display/cursor_window_controller.h" 6 7#include "ash/display/display_controller.h" 8#include "ash/display/mirror_window_controller.h" 9#include "ash/root_window_controller.h" 10#include "ash/shell.h" 11#include "ash/shell_window_ids.h" 12#include "ui/aura/env.h" 13#include "ui/aura/window_delegate.h" 14#include "ui/aura/window_event_dispatcher.h" 15#include "ui/base/cursor/cursors_aura.h" 16#include "ui/base/hit_test.h" 17#include "ui/base/resource/resource_bundle.h" 18#include "ui/compositor/dip_util.h" 19#include "ui/gfx/canvas.h" 20#include "ui/gfx/display.h" 21#include "ui/gfx/image/image_skia.h" 22#include "ui/gfx/image/image_skia_operations.h" 23 24namespace ash { 25 26class CursorWindowDelegate : public aura::WindowDelegate { 27 public: 28 CursorWindowDelegate() : is_cursor_compositing_enabled_(false) {} 29 virtual ~CursorWindowDelegate() {} 30 31 // aura::WindowDelegate overrides: 32 virtual gfx::Size GetMinimumSize() const OVERRIDE { return size_; } 33 virtual gfx::Size GetMaximumSize() const OVERRIDE { return size_; } 34 virtual void OnBoundsChanged(const gfx::Rect& old_bounds, 35 const gfx::Rect& new_bounds) OVERRIDE {} 36 virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE { 37 return gfx::kNullCursor; 38 } 39 virtual int GetNonClientComponent( 40 const gfx::Point& point) const OVERRIDE { 41 return HTNOWHERE; 42 } 43 virtual bool ShouldDescendIntoChildForEventHandling( 44 aura::Window* child, 45 const gfx::Point& location) OVERRIDE { 46 return false; 47 } 48 virtual bool CanFocus() OVERRIDE { return false; } 49 virtual void OnCaptureLost() OVERRIDE {} 50 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 51 canvas->DrawImageInt(cursor_image_, 0, 0); 52 } 53 virtual void OnDeviceScaleFactorChanged( 54 float device_scale_factor) OVERRIDE {} 55 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {} 56 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {} 57 virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {} 58 virtual bool HasHitTestMask() const OVERRIDE { return false; } 59 virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} 60 61 // Sets cursor compositing mode on/off. 62 void SetCursorCompositingEnabled(bool enabled) { 63 is_cursor_compositing_enabled_ = enabled; 64 } 65 66 // Sets the cursor image for the |display|'s scale factor. 67 void SetCursorImage(const gfx::ImageSkia& image, 68 const gfx::Display& display) { 69 float scale_factor = display.device_scale_factor(); 70 const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(scale_factor); 71 if (!is_cursor_compositing_enabled_) { 72 // Note that mirror window's scale factor is always 1.0f, therefore we 73 // need to take 2x's image and paint as if it's 1x image. 74 size_ = image_rep.pixel_size(); 75 cursor_image_ = gfx::ImageSkia::CreateFrom1xBitmap(image_rep.sk_bitmap()); 76 } else { 77 size_ = image.size(); 78 cursor_image_ = gfx::ImageSkia( 79 gfx::ImageSkiaRep(image_rep.sk_bitmap(), scale_factor)); 80 } 81 } 82 83 const gfx::Size size() const { return size_; } 84 85 private: 86 bool is_cursor_compositing_enabled_; 87 gfx::ImageSkia cursor_image_; 88 gfx::Size size_; 89 90 DISALLOW_COPY_AND_ASSIGN(CursorWindowDelegate); 91}; 92 93CursorWindowController::CursorWindowController() 94 : is_cursor_compositing_enabled_(false), 95 container_(NULL), 96 cursor_type_(ui::kCursorNone), 97 cursor_set_(ui::CURSOR_SET_NORMAL), 98 cursor_rotation_(gfx::Display::ROTATE_0), 99 delegate_(new CursorWindowDelegate()) { 100} 101 102CursorWindowController::~CursorWindowController() { 103 SetContainer(NULL); 104} 105 106void CursorWindowController::SetCursorCompositingEnabled(bool enabled) { 107 if (is_cursor_compositing_enabled_ != enabled) { 108 is_cursor_compositing_enabled_ = enabled; 109 delegate_->SetCursorCompositingEnabled(enabled); 110 UpdateCursorImage(); 111 UpdateContainer(); 112 } 113} 114 115void CursorWindowController::UpdateContainer() { 116 display_ = Shell::GetScreen()->GetPrimaryDisplay(); 117 if (is_cursor_compositing_enabled_) { 118 SetDisplay(display_); 119 } else { 120 SetContainer(Shell::GetInstance()-> 121 display_controller()-> 122 mirror_window_controller()-> 123 GetWindow()); 124 } 125} 126 127void CursorWindowController::SetDisplay(const gfx::Display& display) { 128 if (!is_cursor_compositing_enabled_) 129 return; 130 131 display_ = display; 132 aura::Window* root_window = Shell::GetInstance()->display_controller()-> 133 GetRootWindowForDisplayId(display.id()); 134 if (!root_window) 135 return; 136 137 SetContainer(GetRootWindowController(root_window)->GetContainer( 138 kShellWindowId_MouseCursorContainer)); 139 SetBoundsInScreen(display.bounds()); 140} 141 142void CursorWindowController::UpdateLocation() { 143 if (!cursor_window_) 144 return; 145 146 gfx::Point point = aura::Env::GetInstance()->last_mouse_location(); 147 if (!is_cursor_compositing_enabled_) { 148 Shell::GetPrimaryRootWindow()->GetHost()->ConvertPointToHost(&point); 149 } else { 150 point.Offset(-bounds_in_screen_.x(), -bounds_in_screen_.y()); 151 } 152 point.Offset(-hot_point_.x(), -hot_point_.y()); 153 gfx::Rect bounds = cursor_window_->bounds(); 154 bounds.set_origin(point); 155 cursor_window_->SetBounds(bounds); 156} 157 158void CursorWindowController::SetCursor(gfx::NativeCursor cursor) { 159 if (cursor_type_ == cursor.native_type() && 160 cursor_rotation_ == display_.rotation()) 161 return; 162 cursor_type_ = cursor.native_type(); 163 cursor_rotation_ = display_.rotation(); 164 UpdateCursorImage(); 165} 166 167void CursorWindowController::SetCursorSet(ui::CursorSetType cursor_set) { 168 cursor_set_ = cursor_set; 169 UpdateCursorImage(); 170} 171 172void CursorWindowController::SetVisibility(bool visible) { 173 if (!cursor_window_) 174 return; 175 if (visible) 176 cursor_window_->Show(); 177 else 178 cursor_window_->Hide(); 179} 180 181void CursorWindowController::SetContainer(aura::Window* container) { 182 if (container_ == container) 183 return; 184 185 container_ = container; 186 if (!container) { 187 cursor_window_.reset(); 188 return; 189 } 190 191 if (!cursor_window_) { 192 cursor_window_.reset(new aura::Window(delegate_.get())); 193 cursor_window_->SetTransparent(true); 194 cursor_window_->Init(aura::WINDOW_LAYER_TEXTURED); 195 cursor_window_->set_ignore_events(true); 196 cursor_window_->set_owned_by_parent(false); 197 } 198 199 container->AddChild(cursor_window_.get()); 200 cursor_window_->Show(); 201 SetBoundsInScreen(container->bounds()); 202} 203 204void CursorWindowController::SetBoundsInScreen(const gfx::Rect& bounds) { 205 bounds_in_screen_ = bounds; 206 UpdateLocation(); 207} 208 209void CursorWindowController::UpdateCursorImage() { 210 int resource_id; 211 // TODO(hshi): support custom cursor set. 212 if (!ui::GetCursorDataFor(cursor_set_, 213 cursor_type_, 214 display_.device_scale_factor(), 215 &resource_id, 216 &hot_point_)) { 217 return; 218 } 219 const gfx::ImageSkia* image = 220 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); 221 gfx::ImageSkia rotated = *image; 222 if (!is_cursor_compositing_enabled_) { 223 switch (cursor_rotation_) { 224 case gfx::Display::ROTATE_0: 225 break; 226 case gfx::Display::ROTATE_90: 227 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 228 *image, SkBitmapOperations::ROTATION_90_CW); 229 hot_point_.SetPoint( 230 rotated.width() - hot_point_.y(), 231 hot_point_.x()); 232 break; 233 case gfx::Display::ROTATE_180: 234 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 235 *image, SkBitmapOperations::ROTATION_180_CW); 236 hot_point_.SetPoint( 237 rotated.height() - hot_point_.x(), 238 rotated.width() - hot_point_.y()); 239 break; 240 case gfx::Display::ROTATE_270: 241 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 242 *image, SkBitmapOperations::ROTATION_270_CW); 243 hot_point_.SetPoint( 244 hot_point_.y(), 245 rotated.height() - hot_point_.x()); 246 break; 247 } 248 } else { 249 hot_point_ = ui::ConvertPointToDIP(Shell::GetPrimaryRootWindow()->layer(), 250 hot_point_); 251 } 252 delegate_->SetCursorImage(rotated, display_); 253 if (cursor_window_) { 254 cursor_window_->SetBounds(gfx::Rect(delegate_->size())); 255 cursor_window_->SchedulePaintInRect( 256 gfx::Rect(cursor_window_->bounds().size())); 257 UpdateLocation(); 258 } 259} 260 261} // namespace ash 262