• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
CursorShapeFromNative(const gfx::NativeCursor & native_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 
Create()142 CursorLoader* CursorLoader::Create() {
143   return new CursorLoaderX11;
144 }
145 
CursorLoaderX11()146 CursorLoaderX11::CursorLoaderX11()
147     : invisible_cursor_(CreateInvisibleCursor(), gfx::GetXDisplay()) {
148 }
149 
~CursorLoaderX11()150 CursorLoaderX11::~CursorLoaderX11() {
151   UnloadAll();
152 }
153 
LoadImageCursor(int id,int resource_id,const gfx::Point & hot)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 
LoadAnimatedCursor(int id,int resource_id,const gfx::Point & hot,int frame_delay_ms)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 
UnloadAll()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 
SetPlatformCursor(gfx::NativeCursor * cursor)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 
GetXcursorImageForTest(int id)220 const XcursorImage* CursorLoaderX11::GetXcursorImageForTest(int id) {
221   return test::GetCachedXcursorImage(cursors_[id]);
222 }
223 
IsImageCursor(gfx::NativeCursor native_cursor)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 
ImageCursorFromNative(gfx::NativeCursor native_cursor)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