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