2 * Copyright (C) 2015 Canonical, Ltd.
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17#include "CursorImageProvider.h"
23#include <QSvgRenderer>
25CursorImageProvider *CursorImageProvider::m_instance = nullptr;
30BuiltInCursorImage::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 QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
50 svgRenderer->render(&imagePainter);
58BlankCursorImage::BlankCursorImage()
60 qimage = QImage(1, 1, QImage::Format_ARGB32);
61 qimage.fill(Qt::transparent);
68CustomCursorImage::CustomCursorImage(const QCursor &cursor)
70 qimage = cursor.pixmap().toImage();
71 hotspot = cursor.hotSpot();
77XCursorImage::XCursorImage(const QString &theme, const QString &file)
78 : xcursorImages(nullptr)
80 xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), 32);
86 for (int i = 0; i < xcursorImages->nimage && !loaded; ++i) {
87 XcursorImage *xcursorImage = xcursorImages->images[i];
88 if (xcursorImage->size == 32) {
90 qimage = QImage((uchar*)xcursorImage->pixels,
91 xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
93 hotspot.setX(xcursorImage->xhot);
94 hotspot.setY(xcursorImage->yhot);
101XCursorImage::~XCursorImage()
103 XcursorImagesDestroy(xcursorImages);
107// CursorImageProvider
109CursorImageProvider::CursorImageProvider()
110 : QQuickImageProvider(QQuickImageProvider::Image)
113 qFatal("Cannot have multiple CursorImageProvider instances");
117 m_fallbackNames[QStringLiteral("closedhand")].append(QStringLiteral("grabbing"));
118 m_fallbackNames[QStringLiteral("closedhand")].append(QStringLiteral("dnd-none"));
120 m_fallbackNames[QStringLiteral("dnd-copy")].append(QStringLiteral("dnd-none"));
121 m_fallbackNames[QStringLiteral("dnd-copy")].append(QStringLiteral("grabbing"));
122 m_fallbackNames[QStringLiteral("dnd-copy")].append(QStringLiteral("closedhand"));
124 m_fallbackNames[QStringLiteral("dnd-move")].append(QStringLiteral("dnd-none"));
125 m_fallbackNames[QStringLiteral("dnd-move")].append(QStringLiteral("grabbing"));
126 m_fallbackNames[QStringLiteral("dnd-move")].append(QStringLiteral("closedhand"));
128 m_fallbackNames[QStringLiteral("dnd-link")].append(QStringLiteral("dnd-none"));
129 m_fallbackNames[QStringLiteral("dnd-link")].append(QStringLiteral("grabbing"));
130 m_fallbackNames[QStringLiteral("dnd-link")].append(QStringLiteral("closedhand"));
132 m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("crossed_circle")); // DMZ-White and DMZ-Black themes
133 m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("not-allowed"));
134 m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("circle"));
136 m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointing_hand"));
137 m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointer"));
139 m_fallbackNames[QStringLiteral("ibeam")].append(QStringLiteral("xterm"));
140 m_fallbackNames[QStringLiteral("ibeam")].append(QStringLiteral("text"));
142 m_fallbackNames[QStringLiteral("left_ptr")].append(QStringLiteral("default"));
143 m_fallbackNames[QStringLiteral("left_ptr")].append(QStringLiteral("top_left_arrow"));
144 m_fallbackNames[QStringLiteral("left_ptr")].append(QStringLiteral("left_arrow"));
146 m_fallbackNames[QStringLiteral("left_ptr_watch")].append(QStringLiteral("half-busy"));
147 m_fallbackNames[QStringLiteral("left_ptr_watch")].append(QStringLiteral("progress"));
149 m_fallbackNames[QStringLiteral("size_bdiag")].append(QStringLiteral("fd_double_arrow"));
150 m_fallbackNames[QStringLiteral("size_bdiag")].append(QStringLiteral("nesw-resize"));
152 m_fallbackNames[QStringLiteral("size_fdiag")].append(QStringLiteral("bd_double_arrow")); // DMZ-White and DMZ-Black themes
153 m_fallbackNames[QStringLiteral("size_fdiag")].append(QStringLiteral("nwse-resize"));
155 m_fallbackNames[QStringLiteral("size_hor")].append(QStringLiteral("sb_h_double_arrow")); // DMZ-White and DMZ-Black themes
156 m_fallbackNames[QStringLiteral("size_hor")].append(QStringLiteral("ew-resize"));
157 m_fallbackNames[QStringLiteral("size_hor")].append(QStringLiteral("h_double_arrow"));
159 m_fallbackNames[QStringLiteral("size_ver")].append(QStringLiteral("sb_v_double_arrow")); // DMZ-White and DMZ-Black themes
160 m_fallbackNames[QStringLiteral("size_ver")].append(QStringLiteral("ns-resize"));
161 m_fallbackNames[QStringLiteral("size_ver")].append(QStringLiteral("v_double_arrow"));
163 m_fallbackNames[QStringLiteral("split_h")].append(QStringLiteral("sb_h_double_arrow")); // DMZ-White and DMZ-Black themes
164 m_fallbackNames[QStringLiteral("split_h")].append(QStringLiteral("col-resize"));
166 m_fallbackNames[QStringLiteral("split_v")].append(QStringLiteral("sb_v_double_arrow")); // DMZ-White and DMZ-Black themes
167 m_fallbackNames[QStringLiteral("split_v")].append(QStringLiteral("row-resize"));
169 m_fallbackNames[QStringLiteral("up_arrow")].append(QStringLiteral("sb_up_arrow")); // DMZ-White and DMZ-Black themes
171 m_fallbackNames[QStringLiteral("watch")].append(QStringLiteral("wait"));
173 m_fallbackNames[QStringLiteral("whats_this")].append(QStringLiteral("left_ptr_help"));
174 m_fallbackNames[QStringLiteral("whats_this")].append(QStringLiteral("help"));
175 m_fallbackNames[QStringLiteral("whats_this")].append(QStringLiteral("question_arrow"));
177 m_fallbackNames[QStringLiteral("xterm")].append(QStringLiteral("ibeam"));
180CursorImageProvider::~CursorImageProvider()
183 QList< QMap<QString, CursorImage*> > cursorList = m_cursors.values();
185 for (int i = 0; i < cursorList.count(); ++i) {
186 QList<CursorImage*> cursorImageList = cursorList[i].values();
187 for (int j = 0; j < cursorImageList.count(); ++j) {
188 delete cursorImageList[j];
194 m_instance = nullptr;
197QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/)
199 CursorImage *cursorImage = fetchCursor(cursorThemeAndName);
200 size->setWidth(cursorImage->qimage.width());
201 size->setHeight(cursorImage->qimage.height());
203 return cursorImage->qimage;
206QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
208 CursorImage *cursorImage = fetchCursor(themeName, cursorName);
210 return cursorImage->hotspot;
216CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
221 QStringList themeAndNameList = cursorThemeAndName.split('/');
222 if (themeAndNameList.size() != 2) {
225 themeName = themeAndNameList[0];
226 cursorName = themeAndNameList[1];
229 return fetchCursor(themeName, cursorName);
232CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName)
234 CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName);
236 // Try some fallbacks
237 if (cursorImage->qimage.isNull()) {
238 if (m_fallbackNames.contains(cursorName)) {
239 const QStringList &fallbackNames = m_fallbackNames[cursorName];
241 while (cursorImage->qimage.isNull() && i < fallbackNames.count()) {
242 qDebug().nospace() << "CursorImageProvider: "<< cursorName <<" not found, trying " << fallbackNames.at(i);
243 cursorImage = fetchCursorHelper(themeName, fallbackNames.at(i));
249 // if it all fails, there must be at least a left_ptr
250 if (cursorImage->qimage.isNull() && cursorName != QLatin1String("left_ptr")) {
251 qDebug() << "CursorImageProvider:" << cursorName
252 << "not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort.";
253 cursorImage = fetchCursorHelper(themeName, QStringLiteral("left_ptr"));
256 if (cursorImage->qimage.isNull()) {
257 // finally, go for the built-in cursor
258 qWarning() << "CursorImageProvider: couldn't find any cursors. Using the built-in one";
259 if (!m_builtInCursorImage) {
260 m_builtInCursorImage.reset(new BuiltInCursorImage);
262 cursorImage = m_builtInCursorImage.data();
268CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName)
270 if (cursorName == QLatin1String("blank")) {
271 return &m_blankCursorImage;
272 } else if (cursorName == QLatin1String("custom")) {
273 return m_customCursorImage.data();
275 QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName];
277 if (!themeCursors.contains(cursorName)) {
278 themeCursors[cursorName] = new XCursorImage(themeName, cursorName);
281 return themeCursors[cursorName];
285void CursorImageProvider::setCustomCursor(const QCursor &customCursor)
287 if (customCursor.pixmap().isNull()) {
288 m_customCursorImage.reset();
290 m_customCursorImage.reset(new CustomCursorImage(customCursor));
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list