17 #include "CursorImageProvider.h" 23 #include <QSvgRenderer> 25 CursorImageProvider *CursorImageProvider::m_instance =
nullptr;
30 BuiltInCursorImage::BuiltInCursorImage()
32 const char *svgString =
33 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" 35 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" 36 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" 37 " xmlns:svg=\"http://www.w3.org/2000/svg\"" 38 " xmlns=\"http://www.w3.org/2000/svg\"" 41 " style=\"fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:40;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1\"" 42 " d=\"M 20.504,50.94931 460.42533,518.14486 266.47603,515.61948 366.48114,719.16522 274.05218,770.68296 172.53185,559.56112 20.504,716.13476 Z\" />" 45 qimage = QImage(20, 32, QImage::Format_ARGB32);
46 qimage.fill(Qt::transparent);
47 QPainter imagePainter(&qimage);
49 frameWidth = qimage.width();
50 frameHeight = qimage.height();
52 QSvgRenderer *svgRenderer =
new QSvgRenderer(QByteArray(svgString));
53 svgRenderer->render(&imagePainter);
61 BlankCursorImage::BlankCursorImage()
63 qimage = QImage(1, 1, QImage::Format_ARGB32);
64 qimage.fill(Qt::transparent);
65 frameWidth = qimage.width();
66 frameHeight = qimage.height();
73 CustomCursorImage::CustomCursorImage(
const QCursor &cursor)
75 qimage = cursor.pixmap().toImage();
76 hotspot = cursor.hotSpot();
77 frameWidth = qimage.width();
78 frameHeight = qimage.height();
84 XCursorImage::XCursorImage(
const QString &theme,
const QString &file)
88 int preferredCursorHeightPx = 32;
90 XcursorImages *xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),
91 preferredCursorHeightPx);
92 if (!xcursorImages || xcursorImages->nimage == 0) {
96 frameCount = xcursorImages->nimage;
98 for (
int i = 0; i < xcursorImages->nimage; ++i) {
99 XcursorImage *xcursorImage = xcursorImages->images[0];
100 if (frameWidth < (
int)xcursorImage->width) {
101 frameWidth = xcursorImage->width;
103 if (frameHeight < (
int)xcursorImage->height) {
104 frameHeight = xcursorImage->height;
107 frameDuration = (int)xcursorImage->delay;
109 if (frameDuration != (
int)xcursorImage->delay) {
110 qWarning().nospace() <<
"CursorImageProvider: XCursorImage("<<theme<<
","<<file<<
") has" 111 " varying delays in its animation. Animation won't look right.";
118 XcursorImage *xcursorImage = xcursorImages->images[0];
119 hotspot.setX(xcursorImage->xhot);
120 hotspot.setY(xcursorImage->yhot);
124 qimage = QImage(frameWidth*frameCount, frameHeight, QImage::Format_ARGB32);
125 qimage.fill(Qt::transparent);
128 QPainter painter(&qimage);
130 for (
int i = 0; i < xcursorImages->nimage; ++i) {
131 XcursorImage *xcursorImage = xcursorImages->images[i];
133 auto frameImage = QImage((uchar*)xcursorImage->pixels,
134 xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
136 painter.drawImage(QPoint(i*frameWidth, 0), frameImage);
140 XcursorImagesDestroy(xcursorImages);
143 XCursorImage::~XCursorImage()
150 CursorImageProvider::CursorImageProvider()
151 : QQuickImageProvider(QQuickImageProvider::Image)
154 qFatal(
"Cannot have multiple CursorImageProvider instances");
158 m_fallbackNames[QStringLiteral(
"closedhand")].append(QStringLiteral(
"grabbing"));
159 m_fallbackNames[QStringLiteral(
"closedhand")].append(QStringLiteral(
"dnd-none"));
161 m_fallbackNames[QStringLiteral(
"dnd-copy")].append(QStringLiteral(
"dnd-none"));
162 m_fallbackNames[QStringLiteral(
"dnd-copy")].append(QStringLiteral(
"grabbing"));
163 m_fallbackNames[QStringLiteral(
"dnd-copy")].append(QStringLiteral(
"closedhand"));
165 m_fallbackNames[QStringLiteral(
"dnd-move")].append(QStringLiteral(
"dnd-none"));
166 m_fallbackNames[QStringLiteral(
"dnd-move")].append(QStringLiteral(
"grabbing"));
167 m_fallbackNames[QStringLiteral(
"dnd-move")].append(QStringLiteral(
"closedhand"));
169 m_fallbackNames[QStringLiteral(
"dnd-link")].append(QStringLiteral(
"dnd-none"));
170 m_fallbackNames[QStringLiteral(
"dnd-link")].append(QStringLiteral(
"grabbing"));
171 m_fallbackNames[QStringLiteral(
"dnd-link")].append(QStringLiteral(
"closedhand"));
173 m_fallbackNames[QStringLiteral(
"forbidden")].append(QStringLiteral(
"crossed_circle"));
174 m_fallbackNames[QStringLiteral(
"forbidden")].append(QStringLiteral(
"not-allowed"));
175 m_fallbackNames[QStringLiteral(
"forbidden")].append(QStringLiteral(
"circle"));
177 m_fallbackNames[QStringLiteral(
"hand")].append(QStringLiteral(
"pointing_hand"));
178 m_fallbackNames[QStringLiteral(
"hand")].append(QStringLiteral(
"pointer"));
180 m_fallbackNames[QStringLiteral(
"ibeam")].append(QStringLiteral(
"xterm"));
181 m_fallbackNames[QStringLiteral(
"ibeam")].append(QStringLiteral(
"text"));
183 m_fallbackNames[QStringLiteral(
"left_ptr")].append(QStringLiteral(
"default"));
184 m_fallbackNames[QStringLiteral(
"left_ptr")].append(QStringLiteral(
"top_left_arrow"));
185 m_fallbackNames[QStringLiteral(
"left_ptr")].append(QStringLiteral(
"left_arrow"));
187 m_fallbackNames[QStringLiteral(
"left_ptr_watch")].append(QStringLiteral(
"half-busy"));
188 m_fallbackNames[QStringLiteral(
"left_ptr_watch")].append(QStringLiteral(
"progress"));
190 m_fallbackNames[QStringLiteral(
"size_bdiag")].append(QStringLiteral(
"fd_double_arrow"));
191 m_fallbackNames[QStringLiteral(
"size_bdiag")].append(QStringLiteral(
"nesw-resize"));
193 m_fallbackNames[QStringLiteral(
"size_fdiag")].append(QStringLiteral(
"bd_double_arrow"));
194 m_fallbackNames[QStringLiteral(
"size_fdiag")].append(QStringLiteral(
"nwse-resize"));
196 m_fallbackNames[QStringLiteral(
"size_hor")].append(QStringLiteral(
"sb_h_double_arrow"));
197 m_fallbackNames[QStringLiteral(
"size_hor")].append(QStringLiteral(
"ew-resize"));
198 m_fallbackNames[QStringLiteral(
"size_hor")].append(QStringLiteral(
"h_double_arrow"));
200 m_fallbackNames[QStringLiteral(
"size_ver")].append(QStringLiteral(
"sb_v_double_arrow"));
201 m_fallbackNames[QStringLiteral(
"size_ver")].append(QStringLiteral(
"ns-resize"));
202 m_fallbackNames[QStringLiteral(
"size_ver")].append(QStringLiteral(
"v_double_arrow"));
204 m_fallbackNames[QStringLiteral(
"split_h")].append(QStringLiteral(
"sb_h_double_arrow"));
205 m_fallbackNames[QStringLiteral(
"split_h")].append(QStringLiteral(
"col-resize"));
207 m_fallbackNames[QStringLiteral(
"split_v")].append(QStringLiteral(
"sb_v_double_arrow"));
208 m_fallbackNames[QStringLiteral(
"split_v")].append(QStringLiteral(
"row-resize"));
210 m_fallbackNames[QStringLiteral(
"up_arrow")].append(QStringLiteral(
"sb_up_arrow"));
212 m_fallbackNames[QStringLiteral(
"watch")].append(QStringLiteral(
"wait"));
214 m_fallbackNames[QStringLiteral(
"whats_this")].append(QStringLiteral(
"left_ptr_help"));
215 m_fallbackNames[QStringLiteral(
"whats_this")].append(QStringLiteral(
"help"));
216 m_fallbackNames[QStringLiteral(
"whats_this")].append(QStringLiteral(
"question_arrow"));
218 m_fallbackNames[QStringLiteral(
"xterm")].append(QStringLiteral(
"ibeam"));
221 CursorImageProvider::~CursorImageProvider()
224 QList< QMap<QString, CursorImage*> > cursorList = m_cursors.values();
226 for (
int i = 0; i < cursorList.count(); ++i) {
227 QList<CursorImage*> cursorImageList = cursorList[i].values();
228 for (
int j = 0; j < cursorImageList.count(); ++j) {
229 delete cursorImageList[j];
235 m_instance =
nullptr;
238 QImage CursorImageProvider::requestImage(
const QString &cursorThemeAndName, QSize *size,
const QSize & )
240 CursorImage *cursorImage = fetchCursor(cursorThemeAndName);
241 size->setWidth(cursorImage->qimage.width());
242 size->setHeight(cursorImage->qimage.height());
244 return cursorImage->qimage;
247 CursorImage *CursorImageProvider::fetchCursor(
const QString &cursorThemeAndName)
252 QStringList themeAndNameList = cursorThemeAndName.split(
'/');
253 if (themeAndNameList.size() != 2) {
256 themeName = themeAndNameList[0];
257 cursorName = themeAndNameList[1];
260 return fetchCursor(themeName, cursorName);
263 CursorImage *CursorImageProvider::fetchCursor(
const QString &themeName,
const QString &cursorName)
265 CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName);
268 if (cursorImage->qimage.isNull()) {
269 if (m_fallbackNames.contains(cursorName)) {
270 const QStringList &fallbackNames = m_fallbackNames[cursorName];
272 while (cursorImage->qimage.isNull() && i < fallbackNames.count()) {
273 qDebug().nospace() <<
"CursorImageProvider: "<< cursorName <<
" not found, trying " << fallbackNames.at(i);
274 cursorImage = fetchCursorHelper(themeName, fallbackNames.at(i));
281 if (cursorImage->qimage.isNull() && cursorName != QLatin1String(
"left_ptr")) {
282 qDebug() <<
"CursorImageProvider:" << cursorName
283 <<
"not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort.";
284 cursorImage = fetchCursorHelper(themeName, QStringLiteral(
"left_ptr"));
287 if (cursorImage->qimage.isNull()) {
289 qWarning() <<
"CursorImageProvider: couldn't find any cursors. Using the built-in one";
290 if (!m_builtInCursorImage) {
291 m_builtInCursorImage.reset(
new BuiltInCursorImage);
293 cursorImage = m_builtInCursorImage.data();
299 CursorImage *CursorImageProvider::fetchCursorHelper(
const QString &themeName,
const QString &cursorName)
301 if (cursorName == QLatin1String(
"blank")) {
302 return &m_blankCursorImage;
303 }
else if (cursorName == QLatin1String(
"custom")) {
304 return m_customCursorImage.data();
306 QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName];
308 if (!themeCursors.contains(cursorName)) {
309 themeCursors[cursorName] =
new XCursorImage(themeName, cursorName);
312 return themeCursors[cursorName];
316 void CursorImageProvider::setCustomCursor(
const QCursor &customCursor)
318 if (customCursor.pixmap().isNull()) {
319 m_customCursorImage.reset();
321 m_customCursorImage.reset(
new CustomCursorImage(customCursor));