Home | History | Annotate | Download | only in display
      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