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 <X11/Xlib.h> | |
8 #include <X11/cursorfont.h> | |
9 | |
10 #include "base/logging.h" | |
11 #include "grit/ui_resources.h" | |
12 #include "ui/base/cursor/cursor.h" | |
13 #include "ui/base/resource/resource_bundle.h" | |
14 #include "ui/base/x/x11_util.h" | |
15 #include "ui/gfx/image/image.h" | |
16 #include "ui/gfx/image/image_skia.h" | |
17 | |
18 namespace { | |
19 | |
20 // Returns X font cursor shape from an Aura cursor. | |
21 int CursorShapeFromNative(gfx::NativeCursor native_cursor) { | |
22 switch (native_cursor.native_type()) { | |
23 case ui::kCursorMiddlePanning: | |
24 return XC_fleur; | |
25 case ui::kCursorEastPanning: | |
26 return XC_sb_right_arrow; | |
27 case ui::kCursorNorthPanning: | |
28 return XC_sb_up_arrow; | |
29 case ui::kCursorNorthEastPanning: | |
30 return XC_top_right_corner; | |
31 case ui::kCursorNorthWestPanning: | |
32 return XC_top_left_corner; | |
33 case ui::kCursorSouthPanning: | |
34 return XC_sb_down_arrow; | |
35 case ui::kCursorSouthEastPanning: | |
36 return XC_bottom_right_corner; | |
37 case ui::kCursorSouthWestPanning: | |
38 return XC_bottom_left_corner; | |
39 case ui::kCursorWestPanning: | |
40 return XC_sb_left_arrow; | |
41 case ui::kCursorNone: | |
42 case ui::kCursorGrab: | |
43 case ui::kCursorGrabbing: | |
44 // TODO(jamescook): Need cursors for these. crbug.com/111650 | |
45 return XC_left_ptr; | |
46 | |
47 case ui::kCursorNull: | |
48 case ui::kCursorPointer: | |
49 case ui::kCursorNoDrop: | |
50 case ui::kCursorNotAllowed: | |
51 case ui::kCursorCopy: | |
52 case ui::kCursorMove: | |
53 case ui::kCursorEastResize: | |
54 case ui::kCursorNorthResize: | |
55 case ui::kCursorSouthResize: | |
56 case ui::kCursorWestResize: | |
57 case ui::kCursorNorthEastResize: | |
58 case ui::kCursorNorthWestResize: | |
59 case ui::kCursorSouthWestResize: | |
60 case ui::kCursorSouthEastResize: | |
61 case ui::kCursorIBeam: | |
62 case ui::kCursorAlias: | |
63 case ui::kCursorCell: | |
64 case ui::kCursorContextMenu: | |
65 case ui::kCursorCross: | |
66 case ui::kCursorHelp: | |
67 case ui::kCursorWait: | |
68 case ui::kCursorNorthSouthResize: | |
69 case ui::kCursorEastWestResize: | |
70 case ui::kCursorNorthEastSouthWestResize: | |
71 case ui::kCursorNorthWestSouthEastResize: | |
72 case ui::kCursorProgress: | |
73 case ui::kCursorColumnResize: | |
74 case ui::kCursorRowResize: | |
75 case ui::kCursorVerticalText: | |
76 case ui::kCursorZoomIn: | |
77 case ui::kCursorZoomOut: | |
78 NOTREACHED() << "Cursor (" << native_cursor.native_type() << ") should " | |
79 << "have an image asset."; | |
80 return XC_left_ptr; | |
81 case ui::kCursorCustom: | |
82 NOTREACHED(); | |
83 return XC_left_ptr; | |
84 } | |
85 NOTREACHED(); | |
86 return XC_left_ptr; | |
87 } | |
88 | |
89 } // namespace | |
90 | |
91 namespace ui { | |
92 | |
93 CursorLoader* CursorLoader::Create() { | |
94 return new CursorLoaderX11; | |
95 } | |
96 | |
97 CursorLoaderX11::CursorLoaderX11() | |
98 : invisible_cursor_(0U) { | |
99 Display* xdisplay = ui::GetXDisplay(); | |
100 // Initialize invisible cursor. | |
101 char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
102 XColor black; | |
103 black.red = black.green = black.blue = 0; | |
104 Pixmap blank = XCreateBitmapFromData(xdisplay, DefaultRootWindow(xdisplay), | |
105 nodata, 8, 8); | |
106 invisible_cursor_ = XCreatePixmapCursor(xdisplay, blank, blank, | |
107 &black, &black, 0, 0); | |
108 XFreePixmap(xdisplay, blank); | |
oshima
2012/09/07 19:52:01
There is a leak inside pixmap, so you probably hav
mazda
2012/09/07 22:38:14
Thanks. I'll do it.
| |
109 } | |
110 | |
111 CursorLoaderX11::~CursorLoaderX11() { | |
112 UnloadAll(); | |
113 // Clears XCursorCache. | |
114 ui::GetXCursor(ui::kCursorClearXCursorCache); | |
115 | |
116 XFreeCursor(ui::GetXDisplay(), invisible_cursor_); | |
117 } | |
118 | |
119 void CursorLoaderX11::LoadImageCursor( | |
120 int id, int resource_id, int hot_x, int hot_y) { | |
121 const gfx::ImageSkia* image = | |
122 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); | |
123 const gfx::ImageSkiaRep& image_rep = image->GetRepresentation( | |
124 ui::GetScaleFactorFromScale(device_scale_factor())); | |
125 gfx::Point hot(hot_x * device_scale_factor(), hot_y * device_scale_factor()); | |
126 XcursorImage* x_image = | |
127 ui::SkBitmapToXcursorImage(&image_rep.sk_bitmap(), hot); | |
128 cursors_[id] = ui::CreateReffedCustomXCursor(x_image); | |
129 // |bitmap| is owned by the resource bundle. So we do not need to free it. | |
130 } | |
131 | |
132 void CursorLoaderX11::LoadAnimatedCursor( | |
133 int id, int resource_id, int hot_x, int hot_y, int frame_delay_ms) { | |
134 const gfx::ImageSkia* image = | |
135 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); | |
136 const gfx::ImageSkiaRep& image_rep = image->GetRepresentation( | |
137 ui::GetScaleFactorFromScale(device_scale_factor())); | |
138 const SkBitmap bitmap = image_rep.sk_bitmap(); | |
139 DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config); | |
140 int frame_width = bitmap.height(); | |
141 int frame_height = frame_width; | |
142 int total_width = bitmap.width(); | |
143 DCHECK_EQ(total_width % frame_width, 0); | |
144 int frame_count = total_width / frame_width; | |
145 DCHECK_GT(frame_count, 0); | |
146 XcursorImages* x_images = XcursorImagesCreate(frame_count); | |
147 x_images->nimage = frame_count; | |
148 bitmap.lockPixels(); | |
149 unsigned int* pixels = bitmap.getAddr32(0, 0); | |
150 // Create each frame. | |
151 for (int i = 0; i < frame_count; ++i) { | |
152 XcursorImage* x_image = XcursorImageCreate(frame_width, frame_height); | |
153 for (int j = 0; j < frame_height; ++j) { | |
154 // Copy j'th row of i'th frame. | |
155 memcpy(x_image->pixels + j * frame_width, | |
156 pixels + i * frame_width + j * total_width, | |
157 frame_width * 4); | |
158 } | |
159 x_image->xhot = hot_x * device_scale_factor(); | |
160 x_image->yhot = hot_y * device_scale_factor(); | |
161 x_image->delay = frame_delay_ms; | |
162 x_images->images[i] = x_image; | |
163 } | |
164 bitmap.unlockPixels(); | |
165 | |
166 animated_cursors_[id] = std::make_pair( | |
167 XcursorImagesLoadCursor(ui::GetXDisplay(), x_images), x_images); | |
168 // |bitmap| is owned by the resource bundle. So we do not need to free it. | |
169 } | |
170 | |
171 void CursorLoaderX11::UnloadAll() { | |
172 for (ImageCursorMap::const_iterator it = cursors_.begin(); | |
173 it != cursors_.end(); ++it) | |
174 ui::UnrefCustomXCursor(it->second); | |
175 | |
176 // Free animated cursors and images. | |
177 for (AnimatedCursorMap::iterator it = animated_cursors_.begin(); | |
178 it != animated_cursors_.end(); ++it) { | |
179 XcursorImagesDestroy(it->second.second); // also frees individual frames. | |
180 XFreeCursor(ui::GetXDisplay(), it->second.first); | |
181 } | |
182 } | |
183 | |
184 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) { | |
185 DCHECK(cursor); | |
186 | |
187 ::Cursor xcursor; | |
188 if (IsImageCursor(*cursor)) | |
189 xcursor = ImageCursorFromNative(*cursor); | |
190 else if (*cursor == ui::kCursorNone) | |
191 xcursor = invisible_cursor_; | |
192 else if (*cursor == ui::kCursorCustom) | |
193 xcursor = cursor->platform(); | |
194 else if (device_scale_factor() == 1.0f) | |
195 xcursor = ui::GetXCursor(CursorShapeFromNative(*cursor)); | |
196 else | |
197 xcursor = ImageCursorFromNative(ui::kCursorPointer); | |
198 | |
199 cursor->SetPlatformCursor(xcursor); | |
200 } | |
201 | |
202 void CursorLoaderX11::HideHostCursor() { | |
203 XDefineCursor(ui::GetXDisplay(), DefaultRootWindow(ui::GetXDisplay()), | |
204 invisible_cursor_); | |
205 } | |
206 | |
207 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) { | |
208 int type = native_cursor.native_type(); | |
209 return cursors_.find(type) != cursors_.end() || | |
210 animated_cursors_.find(type) != animated_cursors_.end(); | |
211 } | |
212 | |
213 ::Cursor CursorLoaderX11::ImageCursorFromNative( | |
214 gfx::NativeCursor native_cursor) { | |
215 int type = native_cursor.native_type(); | |
216 if (animated_cursors_.count(type)) | |
217 return animated_cursors_[type].first; | |
218 DCHECK(cursors_.find(type) != cursors_.end()); | |
219 return cursors_[type]; | |
220 } | |
221 | |
222 } | |
OLD | NEW |