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