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/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/gfx/x/x11_types.h"
     39 #endif
     40 
     41 namespace ash {
     42 namespace internal {
     43 namespace {
     44 
     45 #if defined(USE_X11)
     46 // Mirror window shouldn't handle input events.
     47 void DisableInput(XID window) {
     48   long event_mask = ExposureMask | VisibilityChangeMask |
     49       StructureNotifyMask | PropertyChangeMask;
     50   XSelectInput(gfx::GetXDisplay(), window, event_mask);
     51 }
     52 #endif
     53 
     54 class 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   virtual aura::Window* GetGlobalCaptureWindow() OVERRIDE {
     71     return NULL;
     72   }
     73 
     74   DISALLOW_COPY_AND_ASSIGN(NoneCaptureClient);
     75 };
     76 
     77 }  // namespace
     78 
     79 class CursorWindowDelegate : public aura::WindowDelegate {
     80  public:
     81   CursorWindowDelegate() {}
     82   virtual ~CursorWindowDelegate() {}
     83 
     84   // aura::WindowDelegate overrides:
     85   virtual gfx::Size GetMinimumSize() const OVERRIDE {
     86     return size_;
     87   }
     88   virtual gfx::Size GetMaximumSize() const OVERRIDE {
     89     return size_;
     90   }
     91   virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
     92                                const gfx::Rect& new_bounds) OVERRIDE {
     93   }
     94   virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
     95     return gfx::kNullCursor;
     96   }
     97   virtual int GetNonClientComponent(
     98       const gfx::Point& point) const OVERRIDE {
     99     return HTNOWHERE;
    100   }
    101   virtual bool ShouldDescendIntoChildForEventHandling(
    102       aura::Window* child,
    103       const gfx::Point& location) OVERRIDE {
    104     return false;
    105   }
    106   virtual bool CanFocus() OVERRIDE {
    107     return false;
    108   }
    109   virtual void OnCaptureLost() OVERRIDE {
    110   }
    111   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    112     canvas->DrawImageInt(cursor_image_, 0, 0);
    113   }
    114   virtual void OnDeviceScaleFactorChanged(
    115       float device_scale_factor) OVERRIDE {
    116   }
    117   virtual void OnWindowDestroying() OVERRIDE {}
    118   virtual void OnWindowDestroyed() OVERRIDE {}
    119   virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {
    120   }
    121   virtual bool HasHitTestMask() const OVERRIDE {
    122     return false;
    123   }
    124   virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}
    125   virtual void DidRecreateLayer(ui::Layer* old_layer,
    126                                 ui::Layer* new_layer) OVERRIDE {}
    127 
    128   // Set the cursor image for the |display|'s scale factor.  Note that
    129   // mirror window's scale factor is always 1.0f, therefore we need to
    130   // take 2x's image and paint as if it's 1x image.
    131   void SetCursorImage(const gfx::ImageSkia& image,
    132                       const gfx::Display& display) {
    133     const gfx::ImageSkiaRep& image_rep =
    134         image.GetRepresentation(display.device_scale_factor());
    135     size_ = image_rep.pixel_size();
    136     cursor_image_ = gfx::ImageSkia::CreateFrom1xBitmap(image_rep.sk_bitmap());
    137   }
    138 
    139   const gfx::Size size() const { return size_; }
    140 
    141  private:
    142   gfx::ImageSkia cursor_image_;
    143   gfx::Size size_;
    144 
    145   DISALLOW_COPY_AND_ASSIGN(CursorWindowDelegate);
    146 };
    147 
    148 MirrorWindowController::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 
    155 MirrorWindowController::~MirrorWindowController() {
    156   // Make sure the root window gets deleted before cursor_window_delegate.
    157   Close();
    158 }
    159 
    160 void 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_native = display_info.bounds_in_native();
    165     aura::RootWindow::CreateParams params(bounds_in_native);
    166     params.host = Shell::GetInstance()->root_window_host_factory()->
    167         CreateRootWindowHost(bounds_in_native);
    168     root_window_.reset(new aura::RootWindow(params));
    169     root_window_->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_->window())->display_id =
    179         display_info.id();
    180     root_window_->Init();
    181 #if defined(USE_X11)
    182     DisableInput(root_window_->host()->GetAcceleratedWidget());
    183 #endif
    184 
    185     aura::client::SetCaptureClient(root_window_->window(),
    186                                    new NoneCaptureClient());
    187     root_window_->host()->Show();
    188 
    189     // TODO(oshima): Start mirroring.
    190     aura::Window* mirror_window = new aura::Window(NULL);
    191     mirror_window->Init(ui::LAYER_TEXTURED);
    192     root_window_->window()->AddChild(mirror_window);
    193     mirror_window->SetBounds(root_window_->window()->bounds());
    194     mirror_window->Show();
    195     reflector_ = ui::ContextFactory::GetInstance()->CreateReflector(
    196         Shell::GetPrimaryRootWindow()->GetDispatcher()->compositor(),
    197         mirror_window->layer());
    198 
    199     cursor_window_ = new aura::Window(cursor_window_delegate_.get());
    200     cursor_window_->SetTransparent(true);
    201     cursor_window_->Init(ui::LAYER_TEXTURED);
    202     root_window_->window()->AddChild(cursor_window_);
    203     cursor_window_->Show();
    204   } else {
    205     GetRootWindowSettings(root_window_->window())->display_id =
    206         display_info.id();
    207     root_window_->SetHostBounds(display_info.bounds_in_native());
    208   }
    209 
    210   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
    211   const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
    212       Shell::GetScreen()->GetPrimaryDisplay().id());
    213   DCHECK(display_manager->IsMirrored());
    214   scoped_ptr<aura::RootWindowTransformer> transformer(
    215       internal::CreateRootWindowTransformerForMirroredDisplay(
    216           source_display_info,
    217           display_info));
    218   root_window_->SetRootWindowTransformer(transformer.Pass());
    219 
    220   UpdateCursorLocation();
    221 }
    222 
    223 void MirrorWindowController::UpdateWindow() {
    224   if (root_window_.get()) {
    225     DisplayManager* display_manager = Shell::GetInstance()->display_manager();
    226     const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo(
    227         display_manager->mirrored_display_id());
    228     UpdateWindow(mirror_display_info);
    229   }
    230 }
    231 
    232 void MirrorWindowController::Close() {
    233   if (root_window_.get()) {
    234     ui::ContextFactory::GetInstance()->RemoveReflector(reflector_);
    235     reflector_ = NULL;
    236     NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>(
    237         aura::client::GetCaptureClient(root_window_->window()));
    238     aura::client::SetCaptureClient(root_window_->window(), NULL);
    239     delete capture_client;
    240 
    241     root_window_->RemoveRootWindowObserver(
    242         Shell::GetInstance()->display_controller());
    243     root_window_->RemoveRootWindowObserver(this);
    244     root_window_.reset();
    245     cursor_window_ = NULL;
    246   }
    247 }
    248 
    249 void MirrorWindowController::UpdateCursorLocation() {
    250   if (cursor_window_) {
    251     // TODO(oshima): Rotate cursor image (including hotpoint).
    252     gfx::Point point = aura::Env::GetInstance()->last_mouse_location();
    253     Shell::GetPrimaryRootWindow()->GetDispatcher()->ConvertPointToHost(&point);
    254     point.Offset(-hot_point_.x(), -hot_point_.y());
    255     gfx::Rect bounds = cursor_window_->bounds();
    256     bounds.set_origin(point);
    257     cursor_window_->SetBounds(bounds);
    258   }
    259 }
    260 
    261 void MirrorWindowController::SetMirroredCursor(gfx::NativeCursor cursor) {
    262   const gfx::Display& display = Shell::GetScreen()->GetPrimaryDisplay();
    263   if (current_cursor_type_ == cursor.native_type() &&
    264       current_cursor_rotation_ == display.rotation())
    265     return;
    266   current_cursor_type_ = cursor.native_type();
    267   current_cursor_rotation_ = display.rotation();
    268   int resource_id;
    269   bool success = ui::GetCursorDataFor(
    270       ui::CURSOR_SET_NORMAL,  // Not support custom cursor set.
    271       current_cursor_type_,
    272       display.device_scale_factor(),
    273       &resource_id,
    274       &hot_point_);
    275   if (!success)
    276     return;
    277   const gfx::ImageSkia* image =
    278       ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
    279   gfx::ImageSkia rotated = *image;
    280   switch (current_cursor_rotation_) {
    281     case gfx::Display::ROTATE_0:
    282       break;
    283     case gfx::Display::ROTATE_90:
    284       rotated = gfx::ImageSkiaOperations::CreateRotatedImage(
    285           *image, SkBitmapOperations::ROTATION_90_CW);
    286       hot_point_.SetPoint(
    287           rotated.width() - hot_point_.y(),
    288           hot_point_.x());
    289       break;
    290     case gfx::Display::ROTATE_180:
    291       rotated = gfx::ImageSkiaOperations::CreateRotatedImage(
    292           *image, SkBitmapOperations::ROTATION_180_CW);
    293       hot_point_.SetPoint(
    294           rotated.height() - hot_point_.x(),
    295           rotated.width() - hot_point_.y());
    296       break;
    297     case gfx::Display::ROTATE_270:
    298       rotated = gfx::ImageSkiaOperations::CreateRotatedImage(
    299           *image, SkBitmapOperations::ROTATION_270_CW);
    300       hot_point_.SetPoint(
    301           hot_point_.y(),
    302           rotated.height() - hot_point_.x());
    303       break;
    304   }
    305   cursor_window_delegate_->SetCursorImage(rotated, display);
    306 
    307   if (cursor_window_) {
    308     cursor_window_->SetBounds(gfx::Rect(cursor_window_delegate_->size()));
    309     cursor_window_->SchedulePaintInRect(
    310         gfx::Rect(cursor_window_->bounds().size()));
    311     UpdateCursorLocation();
    312   }
    313 }
    314 
    315 void MirrorWindowController::SetMirroredCursorVisibility(bool visible) {
    316   if (cursor_window_)
    317     visible ? cursor_window_->Show() : cursor_window_->Hide();
    318 }
    319 
    320 void MirrorWindowController::OnRootWindowHostResized(
    321     const aura::RootWindow* root) {
    322   // Do not use |old_size| as it contains RootWindow's (but not host's) size,
    323   // and this parameter wil be removed soon.
    324   if (mirror_window_host_size_ == root->host()->GetBounds().size())
    325     return;
    326   mirror_window_host_size_ = root->host()->GetBounds().size();
    327   reflector_->OnMirroringCompositorResized();
    328   root_window_->SetRootWindowTransformer(
    329       CreateRootWindowTransformer().Pass());
    330   UpdateCursorLocation();
    331 }
    332 
    333 
    334 scoped_ptr<aura::RootWindowTransformer>
    335 MirrorWindowController::CreateRootWindowTransformer() const {
    336   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
    337   const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo(
    338       display_manager->mirrored_display_id());
    339   const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
    340       Shell::GetScreen()->GetPrimaryDisplay().id());
    341   DCHECK(display_manager->IsMirrored());
    342   return scoped_ptr<aura::RootWindowTransformer>(
    343       internal::CreateRootWindowTransformerForMirroredDisplay(
    344           source_display_info,
    345           mirror_display_info));
    346 }
    347 
    348 }  // namespace internal
    349 }  // namespace ash
    350