Home | History | Annotate | Download | only in cursor
      1 // Copyright (c) 2012 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 "ui/base/cursor/cursor_loader_x11.h"
      6 
      7 #include <float.h>
      8 #include <X11/Xlib.h>
      9 #include <X11/cursorfont.h>
     10 
     11 #include "base/logging.h"
     12 #include "skia/ext/image_operations.h"
     13 #include "ui/base/cursor/cursor.h"
     14 #include "ui/base/cursor/cursor_util.h"
     15 #include "ui/base/x/x11_util.h"
     16 #include "ui/gfx/image/image.h"
     17 #include "ui/gfx/point_conversions.h"
     18 #include "ui/gfx/size_conversions.h"
     19 #include "ui/gfx/skbitmap_operations.h"
     20 #include "ui/gfx/skia_util.h"
     21 
     22 namespace {
     23 
     24 // Returns X font cursor shape from an Aura cursor.
     25 int CursorShapeFromNative(const gfx::NativeCursor& native_cursor) {
     26   switch (native_cursor.native_type()) {
     27     case ui::kCursorMiddlePanning:
     28       return XC_fleur;
     29     case ui::kCursorEastPanning:
     30       return XC_sb_right_arrow;
     31     case ui::kCursorNorthPanning:
     32       return XC_sb_up_arrow;
     33     case ui::kCursorNorthEastPanning:
     34       return XC_top_right_corner;
     35     case ui::kCursorNorthWestPanning:
     36       return XC_top_left_corner;
     37     case ui::kCursorSouthPanning:
     38       return XC_sb_down_arrow;
     39     case ui::kCursorSouthEastPanning:
     40       return XC_bottom_right_corner;
     41     case ui::kCursorSouthWestPanning:
     42       return XC_bottom_left_corner;
     43     case ui::kCursorWestPanning:
     44       return XC_sb_left_arrow;
     45     case ui::kCursorNone:
     46     case ui::kCursorGrab:
     47     case ui::kCursorGrabbing:
     48       // TODO(jamescook): Need cursors for these.  crbug.com/111650
     49       return XC_left_ptr;
     50 
     51 #if defined(OS_CHROMEOS)
     52     case ui::kCursorNull:
     53     case ui::kCursorPointer:
     54     case ui::kCursorNoDrop:
     55     case ui::kCursorNotAllowed:
     56     case ui::kCursorCopy:
     57     case ui::kCursorMove:
     58     case ui::kCursorEastResize:
     59     case ui::kCursorNorthResize:
     60     case ui::kCursorSouthResize:
     61     case ui::kCursorWestResize:
     62     case ui::kCursorNorthEastResize:
     63     case ui::kCursorNorthWestResize:
     64     case ui::kCursorSouthWestResize:
     65     case ui::kCursorSouthEastResize:
     66     case ui::kCursorIBeam:
     67     case ui::kCursorAlias:
     68     case ui::kCursorCell:
     69     case ui::kCursorContextMenu:
     70     case ui::kCursorCross:
     71     case ui::kCursorHelp:
     72     case ui::kCursorWait:
     73     case ui::kCursorNorthSouthResize:
     74     case ui::kCursorEastWestResize:
     75     case ui::kCursorNorthEastSouthWestResize:
     76     case ui::kCursorNorthWestSouthEastResize:
     77     case ui::kCursorProgress:
     78     case ui::kCursorColumnResize:
     79     case ui::kCursorRowResize:
     80     case ui::kCursorVerticalText:
     81     case ui::kCursorZoomIn:
     82     case ui::kCursorZoomOut:
     83     case ui::kCursorHand:
     84       // In some environments, the image assets are not set (e.g. in
     85       // content-browsertests, content-shell etc.).
     86       return XC_left_ptr;
     87 #else  // defined(OS_CHROMEOS)
     88     case ui::kCursorNull:
     89       return XC_left_ptr;
     90     case ui::kCursorPointer:
     91       return XC_left_ptr;
     92     case ui::kCursorMove:
     93       return XC_fleur;
     94     case ui::kCursorCross:
     95       return XC_crosshair;
     96     case ui::kCursorHand:
     97       return XC_hand2;
     98     case ui::kCursorIBeam:
     99       return XC_xterm;
    100     case ui::kCursorProgress:
    101     case ui::kCursorWait:
    102       return XC_watch;
    103     case ui::kCursorHelp:
    104       return XC_question_arrow;
    105     case ui::kCursorEastResize:
    106       return XC_right_side;
    107     case ui::kCursorNorthResize:
    108       return XC_top_side;
    109     case ui::kCursorNorthEastResize:
    110       return XC_top_right_corner;
    111     case ui::kCursorNorthWestResize:
    112       return XC_top_left_corner;
    113     case ui::kCursorSouthResize:
    114       return XC_bottom_side;
    115     case ui::kCursorSouthEastResize:
    116       return XC_bottom_right_corner;
    117     case ui::kCursorSouthWestResize:
    118       return XC_bottom_left_corner;
    119     case ui::kCursorWestResize:
    120       return XC_left_side;
    121     case ui::kCursorNorthSouthResize:
    122       return XC_sb_v_double_arrow;
    123     case ui::kCursorEastWestResize:
    124       return XC_sb_h_double_arrow;
    125     case ui::kCursorColumnResize:
    126       return XC_sb_h_double_arrow;
    127     case ui::kCursorRowResize:
    128       return XC_sb_v_double_arrow;
    129 #endif  // defined(OS_CHROMEOS)
    130     case ui::kCursorCustom:
    131       NOTREACHED();
    132       return XC_left_ptr;
    133   }
    134   NOTREACHED() << "Case not handled for " << native_cursor.native_type();
    135   return XC_left_ptr;
    136 }
    137 
    138 }  // namespace
    139 
    140 namespace ui {
    141 
    142 CursorLoader* CursorLoader::Create() {
    143   return new CursorLoaderX11;
    144 }
    145 
    146 CursorLoaderX11::CursorLoaderX11()
    147     : invisible_cursor_(CreateInvisibleCursor(), gfx::GetXDisplay()) {
    148 }
    149 
    150 CursorLoaderX11::~CursorLoaderX11() {
    151   UnloadAll();
    152 }
    153 
    154 void CursorLoaderX11::LoadImageCursor(int id,
    155                                       int resource_id,
    156                                       const gfx::Point& hot) {
    157   SkBitmap bitmap;
    158   gfx::Point hotspot = hot;
    159 
    160   GetImageCursorBitmap(resource_id, scale(), rotation(), &hotspot, &bitmap);
    161   XcursorImage* x_image = SkBitmapToXcursorImage(&bitmap, hotspot);
    162   cursors_[id] = CreateReffedCustomXCursor(x_image);
    163 }
    164 
    165 void CursorLoaderX11::LoadAnimatedCursor(int id,
    166                                          int resource_id,
    167                                          const gfx::Point& hot,
    168                                          int frame_delay_ms) {
    169   std::vector<SkBitmap> bitmaps;
    170   gfx::Point hotspot = hot;
    171 
    172   GetAnimatedCursorBitmaps(
    173       resource_id, scale(), rotation(), &hotspot, &bitmaps);
    174 
    175   XcursorImages* x_images = XcursorImagesCreate(bitmaps.size());
    176   x_images->nimage = bitmaps.size();
    177 
    178   for (unsigned int frame = 0; frame < bitmaps.size(); ++frame) {
    179     XcursorImage* x_image = SkBitmapToXcursorImage(&bitmaps[frame], hotspot);
    180     x_image->delay = frame_delay_ms;
    181     x_images->images[frame] = x_image;
    182   }
    183 
    184   animated_cursors_[id] = std::make_pair(
    185       XcursorImagesLoadCursor(gfx::GetXDisplay(), x_images), x_images);
    186 }
    187 
    188 void CursorLoaderX11::UnloadAll() {
    189   for (ImageCursorMap::const_iterator it = cursors_.begin();
    190        it != cursors_.end(); ++it)
    191     UnrefCustomXCursor(it->second);
    192 
    193   // Free animated cursors and images.
    194   for (AnimatedCursorMap::iterator it = animated_cursors_.begin();
    195        it != animated_cursors_.end(); ++it) {
    196     XcursorImagesDestroy(it->second.second);  // also frees individual frames.
    197     XFreeCursor(gfx::GetXDisplay(), it->second.first);
    198   }
    199 }
    200 
    201 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) {
    202   DCHECK(cursor);
    203 
    204   ::Cursor xcursor;
    205   if (IsImageCursor(*cursor))
    206     xcursor = ImageCursorFromNative(*cursor);
    207   else if (*cursor == kCursorNone)
    208     xcursor =  invisible_cursor_.get();
    209   else if (*cursor == kCursorCustom)
    210     xcursor = cursor->platform();
    211   else if (scale() == 1.0f && rotation() == gfx::Display::ROTATE_0) {
    212     xcursor = GetXCursor(CursorShapeFromNative(*cursor));
    213   } else {
    214     xcursor = ImageCursorFromNative(kCursorPointer);
    215   }
    216 
    217   cursor->SetPlatformCursor(xcursor);
    218 }
    219 
    220 const XcursorImage* CursorLoaderX11::GetXcursorImageForTest(int id) {
    221   return test::GetCachedXcursorImage(cursors_[id]);
    222 }
    223 
    224 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
    225   int type = native_cursor.native_type();
    226   return cursors_.count(type) || animated_cursors_.count(type);
    227 }
    228 
    229 ::Cursor CursorLoaderX11::ImageCursorFromNative(
    230     gfx::NativeCursor native_cursor) {
    231   int type = native_cursor.native_type();
    232   if (animated_cursors_.count(type))
    233     return animated_cursors_[type].first;
    234 
    235   ImageCursorMap::iterator find = cursors_.find(type);
    236   if (find != cursors_.end())
    237     return cursors_[type];
    238   return GetXCursor(CursorShapeFromNative(native_cursor));
    239 }
    240 
    241 }  // namespace ui
    242