1 // Copyright (c) 2013 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/mirror_window_controller.h" 6 7 #if defined(USE_X11) 8 #include <X11/Xlib.h> 9 10 // Xlib.h defines RootWindow. 11 #undef RootWindow 12 #endif 13 14 #include "ash/display/display_controller.h" 15 #include "ash/display/display_info.h" 16 #include "ash/display/display_manager.h" 17 #include "ash/display/root_window_transformers.h" 18 #include "ash/host/root_window_host_factory.h" 19 #include "ash/shell.h" 20 #include "ash/wm/window_properties.h" 21 #include "base/strings/stringprintf.h" 22 #include "ui/aura/client/capture_client.h" 23 #include "ui/aura/env.h" 24 #include "ui/aura/root_window.h" 25 #include "ui/aura/root_window_transformer.h" 26 #include "ui/aura/window_delegate.h" 27 #include "ui/base/cursor/cursors_aura.h" 28 #include "ui/base/hit_test.h" 29 #include "ui/base/layout.h" 30 #include "ui/base/resource/resource_bundle.h" 31 #include "ui/compositor/reflector.h" 32 #include "ui/gfx/canvas.h" 33 #include "ui/gfx/image/image_skia.h" 34 #include "ui/gfx/image/image_skia_operations.h" 35 #include "ui/gfx/native_widget_types.h" 36 37 namespace ash { 38 namespace internal { 39 namespace { 40 41 #if defined(USE_X11) 42 // Mirror window shouldn't handle input events. 43 void DisableInput(XID window) { 44 long event_mask = ExposureMask | VisibilityChangeMask | 45 StructureNotifyMask | PropertyChangeMask; 46 XSelectInput(base::MessagePumpAuraX11::GetDefaultXDisplay(), 47 window, event_mask); 48 } 49 #endif 50 51 class NoneCaptureClient : public aura::client::CaptureClient { 52 public: 53 NoneCaptureClient() {} 54 virtual ~NoneCaptureClient() {} 55 56 private: 57 // Does a capture on the |window|. 58 virtual void SetCapture(aura::Window* window) OVERRIDE {} 59 60 // Releases a capture from the |window|. 61 virtual void ReleaseCapture(aura::Window* window) OVERRIDE {} 62 63 // Returns the current capture window. 64 virtual aura::Window* GetCaptureWindow() OVERRIDE { 65 return NULL; 66 } 67 68 DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient); 69 }; 70 71 } // namespace 72 73 class CursorWindowDelegate : public aura::WindowDelegate { 74 public: 75 CursorWindowDelegate() {} 76 virtual ~CursorWindowDelegate() {} 77 78 // aura::WindowDelegate overrides: 79 virtual gfx::Size GetMinimumSize() const OVERRIDE { 80 return size_; 81 } 82 virtual gfx::Size GetMaximumSize() const OVERRIDE { 83 return size_; 84 } 85 virtual void OnBoundsChanged(const gfx::Rect& old_bounds, 86 const gfx::Rect& new_bounds) OVERRIDE { 87 } 88 virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE { 89 return gfx::kNullCursor; 90 } 91 virtual int GetNonClientComponent( 92 const gfx::Point& point) const OVERRIDE { 93 return HTNOWHERE; 94 } 95 virtual bool ShouldDescendIntoChildForEventHandling( 96 aura::Window* child, 97 const gfx::Point& location) OVERRIDE { 98 return false; 99 } 100 virtual bool CanFocus() OVERRIDE { 101 return false; 102 } 103 virtual void OnCaptureLost() OVERRIDE { 104 } 105 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 106 canvas->DrawImageInt(cursor_image_, 0, 0); 107 } 108 virtual void OnDeviceScaleFactorChanged( 109 float device_scale_factor) OVERRIDE { 110 } 111 virtual void OnWindowDestroying() OVERRIDE {} 112 virtual void OnWindowDestroyed() OVERRIDE {} 113 virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE { 114 } 115 virtual bool HasHitTestMask() const OVERRIDE { 116 return false; 117 } 118 virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} 119 virtual scoped_refptr<ui::Texture> CopyTexture() OVERRIDE { 120 NOTREACHED(); 121 return scoped_refptr<ui::Texture>(); 122 } 123 124 // Set the cursor image for the |display|'s scale factor. Note that 125 // mirror window's scale factor is always 1.0f, therefore we need to 126 // take 2x's image and paint as if it's 1x image. 127 void SetCursorImage(const gfx::ImageSkia& image, 128 const gfx::Display& display) { 129 device_scale_factor_ = 130 ui::GetScaleFactorFromScale(display.device_scale_factor()); 131 const gfx::ImageSkiaRep& image_rep = 132 image.GetRepresentation(device_scale_factor_); 133 size_ = image_rep.pixel_size(); 134 cursor_image_ = gfx::ImageSkia::CreateFrom1xBitmap(image_rep.sk_bitmap()); 135 } 136 137 const gfx::Size size() const { return size_; } 138 139 private: 140 gfx::ImageSkia cursor_image_; 141 ui::ScaleFactor device_scale_factor_; 142 gfx::Size size_; 143 144 DISALLOW_COPY_AND_ASSIGN(CursorWindowDelegate); 145 }; 146 147 MirrorWindowController::MirrorWindowController() 148 : current_cursor_type_(ui::kCursorNone), 149 current_cursor_rotation_(gfx::Display::ROTATE_0), 150 cursor_window_(NULL), 151 cursor_window_delegate_(new CursorWindowDelegate) { 152 } 153 154 MirrorWindowController::~MirrorWindowController() { 155 // Make sure the root window gets deleted before cursor_window_delegate. 156 Close(); 157 } 158 159 void MirrorWindowController::UpdateWindow(const DisplayInfo& display_info) { 160 static int mirror_root_window_count = 0; 161 162 if (!root_window_.get()) { 163 const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel(); 164 aura::RootWindow::CreateParams params(bounds_in_pixel); 165 params.host = Shell::GetInstance()->root_window_host_factory()-> 166 CreateRootWindowHost(bounds_in_pixel); 167 root_window_.reset(new aura::RootWindow(params)); 168 root_window_->SetName( 169 base::StringPrintf("MirrorRootWindow-%d", mirror_root_window_count++)); 170 root_window_->compositor()->SetBackgroundColor(SK_ColorBLACK); 171 // No need to remove RootWindowObserver because 172 // the DisplayController object outlives RootWindow objects. 173 root_window_->AddRootWindowObserver( 174 Shell::GetInstance()->display_controller()); 175 root_window_->AddRootWindowObserver(this); 176 // TODO(oshima): TouchHUD is using idkey. 177 root_window_->SetProperty(internal::kDisplayIdKey, display_info.id()); 178 root_window_->Init(); 179 #if defined(USE_X11) 180 DisableInput(root_window_->GetAcceleratedWidget()); 181 #endif 182 183 aura::client::SetCaptureClient(root_window_.get(), new NoneCaptureClient()); 184 root_window_->ShowRootWindow(); 185 186 // TODO(oshima): Start mirroring. 187 aura::Window* mirror_window = new aura::Window(NULL); 188 mirror_window->Init(ui::LAYER_TEXTURED); 189 root_window_->AddChild(mirror_window); 190 mirror_window->SetBounds(root_window_->bounds()); 191 mirror_window->Show(); 192 reflector_ = ui::ContextFactory::GetInstance()-> 193 CreateReflector(Shell::GetPrimaryRootWindow()->compositor(), 194 mirror_window->layer()); 195 196 cursor_window_ = new aura::Window(cursor_window_delegate_.get()); 197 cursor_window_->SetTransparent(true); 198 cursor_window_->Init(ui::LAYER_TEXTURED); 199 root_window_->AddChild(cursor_window_); 200 cursor_window_->Show(); 201 } else { 202 root_window_->SetProperty(internal::kDisplayIdKey, display_info.id()); 203 root_window_->SetHostBounds(display_info.bounds_in_pixel()); 204 } 205 206 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 207 const DisplayInfo& source_display_info = display_manager->GetDisplayInfo( 208 Shell::GetScreen()->GetPrimaryDisplay().id()); 209 DCHECK(display_manager->mirrored_display().is_valid()); 210 scoped_ptr<aura::RootWindowTransformer> transformer( 211 internal::CreateRootWindowTransformerForMirroredDisplay( 212 source_display_info, 213 display_info)); 214 root_window_->SetRootWindowTransformer(transformer.Pass()); 215 216 UpdateCursorLocation(); 217 } 218 219 void MirrorWindowController::UpdateWindow() { 220 if (root_window_.get()) { 221 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 222 const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo( 223 display_manager->mirrored_display().id()); 224 UpdateWindow(mirror_display_info); 225 } 226 } 227 228 void MirrorWindowController::Close() { 229 if (root_window_.get()) { 230 ui::ContextFactory::GetInstance()->RemoveReflector(reflector_); 231 reflector_ = NULL; 232 NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>( 233 aura::client::GetCaptureClient(root_window_.get())); 234 delete capture_client; 235 236 root_window_->RemoveRootWindowObserver( 237 Shell::GetInstance()->display_controller()); 238 root_window_->RemoveRootWindowObserver(this); 239 root_window_.reset(); 240 cursor_window_ = NULL; 241 } 242 } 243 244 void MirrorWindowController::UpdateCursorLocation() { 245 if (cursor_window_) { 246 // TODO(oshima): Rotate cursor image (including hotpoint). 247 gfx::Point point = aura::Env::GetInstance()->last_mouse_location(); 248 Shell::GetPrimaryRootWindow()->ConvertPointToHost(&point); 249 point.Offset(-hot_point_.x(), -hot_point_.y()); 250 gfx::Rect bounds = cursor_window_->bounds(); 251 bounds.set_origin(point); 252 cursor_window_->SetBounds(bounds); 253 } 254 } 255 256 void MirrorWindowController::SetMirroredCursor(gfx::NativeCursor cursor) { 257 const gfx::Display& display = Shell::GetScreen()->GetPrimaryDisplay(); 258 if (current_cursor_type_ == cursor.native_type() && 259 current_cursor_rotation_ == display.rotation()) 260 return; 261 current_cursor_type_ = cursor.native_type(); 262 current_cursor_rotation_ = display.rotation(); 263 int resource_id; 264 bool success = ui::GetCursorDataFor( 265 current_cursor_type_, 266 display.device_scale_factor(), 267 &resource_id, 268 &hot_point_); 269 if (!success) 270 return; 271 const gfx::ImageSkia* image = 272 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); 273 gfx::ImageSkia rotated = *image; 274 switch (current_cursor_rotation_) { 275 case gfx::Display::ROTATE_0: 276 break; 277 case gfx::Display::ROTATE_90: 278 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 279 *image, SkBitmapOperations::ROTATION_90_CW); 280 hot_point_.SetPoint( 281 rotated.width() - hot_point_.y(), 282 hot_point_.x()); 283 break; 284 case gfx::Display::ROTATE_180: 285 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 286 *image, SkBitmapOperations::ROTATION_180_CW); 287 hot_point_.SetPoint( 288 rotated.height() - hot_point_.x(), 289 rotated.width() - hot_point_.y()); 290 break; 291 case gfx::Display::ROTATE_270: 292 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 293 *image, SkBitmapOperations::ROTATION_270_CW); 294 hot_point_.SetPoint( 295 hot_point_.y(), 296 rotated.height() - hot_point_.x()); 297 break; 298 } 299 cursor_window_delegate_->SetCursorImage(rotated, display); 300 301 if (cursor_window_) { 302 cursor_window_->SetBounds(gfx::Rect(cursor_window_delegate_->size())); 303 cursor_window_->SchedulePaintInRect( 304 gfx::Rect(cursor_window_->bounds().size())); 305 UpdateCursorLocation(); 306 } 307 } 308 309 void MirrorWindowController::SetMirroredCursorVisibility(bool visible) { 310 if (cursor_window_) 311 visible ? cursor_window_->Show() : cursor_window_->Hide(); 312 } 313 314 void MirrorWindowController::OnRootWindowHostResized( 315 const aura::RootWindow* root) { 316 // Do not use |old_size| as it contains RootWindow's (but not host's) size, 317 // and this parameter wil be removed soon. 318 if (mirror_window_host_size_ == root->GetHostSize()) 319 return; 320 mirror_window_host_size_ = root->GetHostSize(); 321 reflector_->OnMirroringCompositorResized(); 322 root_window_->SetRootWindowTransformer( 323 CreateRootWindowTransformer().Pass()); 324 UpdateCursorLocation(); 325 } 326 327 328 scoped_ptr<aura::RootWindowTransformer> 329 MirrorWindowController::CreateRootWindowTransformer() const { 330 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 331 const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo( 332 display_manager->mirrored_display().id()); 333 const DisplayInfo& source_display_info = display_manager->GetDisplayInfo( 334 Shell::GetScreen()->GetPrimaryDisplay().id()); 335 DCHECK(display_manager->mirrored_display().is_valid()); 336 return scoped_ptr<aura::RootWindowTransformer>( 337 internal::CreateRootWindowTransformerForMirroredDisplay( 338 source_display_info, 339 mirror_display_info)); 340 } 341 342 } // namespace internal 343 } // namespace ash 344