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