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.
5 #include "ui/base/cursor/cursor_loader_x11.h"
8 #include <X11/cursorfont.h>
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/geometry/point_conversions.h"
17 #include "ui/gfx/geometry/size_conversions.h"
18 #include "ui/gfx/image/image.h"
19 #include "ui/gfx/skbitmap_operations.h"
20 #include "ui/gfx/skia_util.h"
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
:
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
;
47 case ui::kCursorGrabbing
:
48 // TODO(jamescook): Need cursors for these. crbug.com/111650
51 #if defined(OS_CHROMEOS)
53 case ui::kCursorPointer
:
54 case ui::kCursorNoDrop
:
55 case ui::kCursorNotAllowed
:
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
:
69 case ui::kCursorContextMenu
:
70 case ui::kCursorCross
:
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
:
84 // In some environments, the image assets are not set (e.g. in
85 // content-browsertests, content-shell etc.).
87 #else // defined(OS_CHROMEOS)
90 case ui::kCursorPointer
:
94 case ui::kCursorCross
:
98 case ui::kCursorIBeam
:
100 case ui::kCursorProgress
:
101 case ui::kCursorWait
:
103 case ui::kCursorHelp
:
104 return XC_question_arrow
;
105 case ui::kCursorEastResize
:
106 return XC_right_side
;
107 case ui::kCursorNorthResize
:
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
:
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
:
134 NOTREACHED() << "Case not handled for " << native_cursor
.native_type();
142 CursorLoader
* CursorLoader::Create() {
143 return new CursorLoaderX11
;
146 CursorLoaderX11::CursorLoaderX11()
147 : invisible_cursor_(CreateInvisibleCursor(), gfx::GetXDisplay()) {
150 CursorLoaderX11::~CursorLoaderX11() {
154 void CursorLoaderX11::LoadImageCursor(int id
,
156 const gfx::Point
& hot
) {
158 gfx::Point hotspot
= hot
;
160 GetImageCursorBitmap(resource_id
, scale(), rotation(), &hotspot
, &bitmap
);
161 XcursorImage
* x_image
= SkBitmapToXcursorImage(&bitmap
, hotspot
);
162 cursors_
[id
] = CreateReffedCustomXCursor(x_image
);
165 void CursorLoaderX11::LoadAnimatedCursor(int id
,
167 const gfx::Point
& hot
,
168 int frame_delay_ms
) {
169 std::vector
<SkBitmap
> bitmaps
;
170 gfx::Point hotspot
= hot
;
172 GetAnimatedCursorBitmaps(
173 resource_id
, scale(), rotation(), &hotspot
, &bitmaps
);
175 XcursorImages
* x_images
= XcursorImagesCreate(bitmaps
.size());
176 x_images
->nimage
= bitmaps
.size();
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
;
184 animated_cursors_
[id
] = std::make_pair(
185 XcursorImagesLoadCursor(gfx::GetXDisplay(), x_images
), x_images
);
188 void CursorLoaderX11::UnloadAll() {
189 for (ImageCursorMap::const_iterator it
= cursors_
.begin();
190 it
!= cursors_
.end(); ++it
)
191 UnrefCustomXCursor(it
->second
);
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
);
201 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor
* cursor
) {
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
));
214 xcursor
= ImageCursorFromNative(kCursorPointer
);
217 cursor
->SetPlatformCursor(xcursor
);
220 const XcursorImage
* CursorLoaderX11::GetXcursorImageForTest(int id
) {
221 return test::GetCachedXcursorImage(cursors_
[id
]);
224 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor
) {
225 int type
= native_cursor
.native_type();
226 return cursors_
.count(type
) || animated_cursors_
.count(type
);
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
;
235 ImageCursorMap::iterator find
= cursors_
.find(type
);
236 if (find
!= cursors_
.end())
237 return cursors_
[type
];
238 return GetXCursor(CursorShapeFromNative(native_cursor
));