| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |