mirror_window_controller.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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/root_window_settings.h" 20#include "ash/shell.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#if defined(USE_X11) 38#include "ui/base/x/x11_util.h" 39#endif 40 41namespace ash { 42namespace internal { 43namespace { 44 45#if defined(USE_X11) 46// Mirror window shouldn't handle input events. 47void DisableInput(XID window) { 48 long event_mask = ExposureMask | VisibilityChangeMask | 49 StructureNotifyMask | PropertyChangeMask; 50 XSelectInput(ui::GetXDisplay(), window, event_mask); 51} 52#endif 53 54class NoneCaptureClient : public aura::client::CaptureClient { 55 public: 56 NoneCaptureClient() {} 57 virtual ~NoneCaptureClient() {} 58 59 private: 60 // Does a capture on the |window|. 61 virtual void SetCapture(aura::Window* window) OVERRIDE {} 62 63 // Releases a capture from the |window|. 64 virtual void ReleaseCapture(aura::Window* window) OVERRIDE {} 65 66 // Returns the current capture window. 67 virtual aura::Window* GetCaptureWindow() OVERRIDE { 68 return NULL; 69 } 70 71 DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient); 72}; 73 74} // namespace 75 76class CursorWindowDelegate : public aura::WindowDelegate { 77 public: 78 CursorWindowDelegate() {} 79 virtual ~CursorWindowDelegate() {} 80 81 // aura::WindowDelegate overrides: 82 virtual gfx::Size GetMinimumSize() const OVERRIDE { 83 return size_; 84 } 85 virtual gfx::Size GetMaximumSize() const OVERRIDE { 86 return size_; 87 } 88 virtual void OnBoundsChanged(const gfx::Rect& old_bounds, 89 const gfx::Rect& new_bounds) OVERRIDE { 90 } 91 virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE { 92 return gfx::kNullCursor; 93 } 94 virtual int GetNonClientComponent( 95 const gfx::Point& point) const OVERRIDE { 96 return HTNOWHERE; 97 } 98 virtual bool ShouldDescendIntoChildForEventHandling( 99 aura::Window* child, 100 const gfx::Point& location) OVERRIDE { 101 return false; 102 } 103 virtual bool CanFocus() OVERRIDE { 104 return false; 105 } 106 virtual void OnCaptureLost() OVERRIDE { 107 } 108 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 109 canvas->DrawImageInt(cursor_image_, 0, 0); 110 } 111 virtual void OnDeviceScaleFactorChanged( 112 float device_scale_factor) OVERRIDE { 113 } 114 virtual void OnWindowDestroying() OVERRIDE {} 115 virtual void OnWindowDestroyed() OVERRIDE {} 116 virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE { 117 } 118 virtual bool HasHitTestMask() const OVERRIDE { 119 return false; 120 } 121 virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} 122 virtual void DidRecreateLayer(ui::Layer* old_layer, 123 ui::Layer* new_layer) OVERRIDE {} 124 125 // Set the cursor image for the |display|'s scale factor. Note that 126 // mirror window's scale factor is always 1.0f, therefore we need to 127 // take 2x's image and paint as if it's 1x image. 128 void SetCursorImage(const gfx::ImageSkia& image, 129 const gfx::Display& display) { 130 device_scale_factor_ = 131 ui::GetScaleFactorFromScale(display.device_scale_factor()); 132 const gfx::ImageSkiaRep& image_rep = 133 image.GetRepresentation(device_scale_factor_); 134 size_ = image_rep.pixel_size(); 135 cursor_image_ = gfx::ImageSkia::CreateFrom1xBitmap(image_rep.sk_bitmap()); 136 } 137 138 const gfx::Size size() const { return size_; } 139 140 private: 141 gfx::ImageSkia cursor_image_; 142 ui::ScaleFactor device_scale_factor_; 143 gfx::Size size_; 144 145 DISALLOW_COPY_AND_ASSIGN(CursorWindowDelegate); 146}; 147 148MirrorWindowController::MirrorWindowController() 149 : current_cursor_type_(ui::kCursorNone), 150 current_cursor_rotation_(gfx::Display::ROTATE_0), 151 cursor_window_(NULL), 152 cursor_window_delegate_(new CursorWindowDelegate) { 153} 154 155MirrorWindowController::~MirrorWindowController() { 156 // Make sure the root window gets deleted before cursor_window_delegate. 157 Close(); 158} 159 160void MirrorWindowController::UpdateWindow(const DisplayInfo& display_info) { 161 static int mirror_root_window_count = 0; 162 163 if (!root_window_.get()) { 164 const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel(); 165 aura::RootWindow::CreateParams params(bounds_in_pixel); 166 params.host = Shell::GetInstance()->root_window_host_factory()-> 167 CreateRootWindowHost(bounds_in_pixel); 168 root_window_.reset(new aura::RootWindow(params)); 169 root_window_->SetName( 170 base::StringPrintf("MirrorRootWindow-%d", mirror_root_window_count++)); 171 root_window_->compositor()->SetBackgroundColor(SK_ColorBLACK); 172 // No need to remove RootWindowObserver because 173 // the DisplayController object outlives RootWindow objects. 174 root_window_->AddRootWindowObserver( 175 Shell::GetInstance()->display_controller()); 176 root_window_->AddRootWindowObserver(this); 177 // TODO(oshima): TouchHUD is using idkey. 178 InitRootWindowSettings(root_window_.get())->display_id = display_info.id(); 179 root_window_->Init(); 180#if defined(USE_X11) 181 DisableInput(root_window_->GetAcceleratedWidget()); 182#endif 183 184 aura::client::SetCaptureClient(root_window_.get(), new NoneCaptureClient()); 185 root_window_->ShowRootWindow(); 186 187 // TODO(oshima): Start mirroring. 188 aura::Window* mirror_window = new aura::Window(NULL); 189 mirror_window->Init(ui::LAYER_TEXTURED); 190 root_window_->AddChild(mirror_window); 191 mirror_window->SetBounds(root_window_->bounds()); 192 mirror_window->Show(); 193 reflector_ = ui::ContextFactory::GetInstance()-> 194 CreateReflector(Shell::GetPrimaryRootWindow()->compositor(), 195 mirror_window->layer()); 196 197 cursor_window_ = new aura::Window(cursor_window_delegate_.get()); 198 cursor_window_->SetTransparent(true); 199 cursor_window_->Init(ui::LAYER_TEXTURED); 200 root_window_->AddChild(cursor_window_); 201 cursor_window_->Show(); 202 } else { 203 GetRootWindowSettings(root_window_.get())->display_id = display_info.id(); 204 root_window_->SetHostBounds(display_info.bounds_in_pixel()); 205 } 206 207 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 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_controller()); 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 ui::CURSOR_SET_NORMAL, // Not support custom cursor set. 267 current_cursor_type_, 268 display.device_scale_factor(), 269 &resource_id, 270 &hot_point_); 271 if (!success) 272 return; 273 const gfx::ImageSkia* image = 274 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); 275 gfx::ImageSkia rotated = *image; 276 switch (current_cursor_rotation_) { 277 case gfx::Display::ROTATE_0: 278 break; 279 case gfx::Display::ROTATE_90: 280 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 281 *image, SkBitmapOperations::ROTATION_90_CW); 282 hot_point_.SetPoint( 283 rotated.width() - hot_point_.y(), 284 hot_point_.x()); 285 break; 286 case gfx::Display::ROTATE_180: 287 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 288 *image, SkBitmapOperations::ROTATION_180_CW); 289 hot_point_.SetPoint( 290 rotated.height() - hot_point_.x(), 291 rotated.width() - hot_point_.y()); 292 break; 293 case gfx::Display::ROTATE_270: 294 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 295 *image, SkBitmapOperations::ROTATION_270_CW); 296 hot_point_.SetPoint( 297 hot_point_.y(), 298 rotated.height() - hot_point_.x()); 299 break; 300 } 301 cursor_window_delegate_->SetCursorImage(rotated, display); 302 303 if (cursor_window_) { 304 cursor_window_->SetBounds(gfx::Rect(cursor_window_delegate_->size())); 305 cursor_window_->SchedulePaintInRect( 306 gfx::Rect(cursor_window_->bounds().size())); 307 UpdateCursorLocation(); 308 } 309} 310 311void MirrorWindowController::SetMirroredCursorVisibility(bool visible) { 312 if (cursor_window_) 313 visible ? cursor_window_->Show() : cursor_window_->Hide(); 314} 315 316void MirrorWindowController::OnRootWindowHostResized( 317 const aura::RootWindow* root) { 318 // Do not use |old_size| as it contains RootWindow's (but not host's) size, 319 // and this parameter wil be removed soon. 320 if (mirror_window_host_size_ == root->GetHostSize()) 321 return; 322 mirror_window_host_size_ = root->GetHostSize(); 323 reflector_->OnMirroringCompositorResized(); 324 root_window_->SetRootWindowTransformer( 325 CreateRootWindowTransformer().Pass()); 326 UpdateCursorLocation(); 327} 328 329 330scoped_ptr<aura::RootWindowTransformer> 331MirrorWindowController::CreateRootWindowTransformer() const { 332 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 333 const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo( 334 display_manager->mirrored_display().id()); 335 const DisplayInfo& source_display_info = display_manager->GetDisplayInfo( 336 Shell::GetScreen()->GetPrimaryDisplay().id()); 337 DCHECK(display_manager->mirrored_display().is_valid()); 338 return scoped_ptr<aura::RootWindowTransformer>( 339 internal::CreateRootWindowTransformerForMirroredDisplay( 340 source_display_info, 341 mirror_display_info)); 342} 343 344} // namespace internal 345} // namespace ash 346