on eaebd92 help sign in
unity8/plugins/Cursor/CursorImageProvider.cpp
191 lines 6.2 kB history raw
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
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.
7 *
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.
12 *
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/>.
15 */
17#include "CursorImageProvider.h"
19#include <QDebug>
20#include <QFile>
21#include <QPainter>
22#include <QSvgRenderer>
24CursorImageProvider *CursorImageProvider::m_instance = nullptr;
26/////
27// BuiltInCursorImage
29BuiltInCursorImage::BuiltInCursorImage()
31 const char *svgString =
32 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
33 "<svg"
34 " xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
35 " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\""
36 " xmlns:svg=\"http://www.w3.org/2000/svg\""
37 " xmlns=\"http://www.w3.org/2000/svg\""
38 " version=\"1.1\">"
39 " <path"
40 " 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\""
41 " 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\" />"
42 "</svg>";
44 qimage = QImage(20, 32, QImage::Format_ARGB32);
45 QPainter imagePainter(&qimage);
47 QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
48 svgRenderer->render(&imagePainter);
49 delete svgRenderer;
52/////
53// XCursorImage
55XCursorImage::XCursorImage(const QString &theme, const QString &file)
56 : xcursorImages(nullptr)
58 xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), 32);
59 if (!xcursorImages) {
60 return;
61 }
63 bool loaded = false;
64 for (int i = 0; i < xcursorImages->nimage && !loaded; ++i) {
65 XcursorImage *xcursorImage = xcursorImages->images[i];
66 if (xcursorImage->size == 32) {
68 qimage = QImage((uchar*)xcursorImage->pixels,
69 xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
71 hotspot.setX(xcursorImage->xhot);
72 hotspot.setY(xcursorImage->yhot);
74 loaded = true;
75 }
76 }
79XCursorImage::~XCursorImage()
81 XcursorImagesDestroy(xcursorImages);
84/////
85// CursorImageProvider
87CursorImageProvider::CursorImageProvider()
88 : QQuickImageProvider(QQuickImageProvider::Image)
90 if (m_instance) {
91 qFatal("Cannot have multiple CursorImageProvider instances");
92 }
93 m_instance = this;
96CursorImageProvider::~CursorImageProvider()
98 {
99 QList< QMap<QString, CursorImage*> > cursorList = m_cursors.values();
101 for (int i = 0; i < cursorList.count(); ++i) {
102 QList<CursorImage*> cursorImageList = cursorList[i].values();
103 for (int j = 0; j < cursorImageList.count(); ++j) {
104 delete cursorImageList[j];
105 }
106 }
107 }
109 m_cursors.clear();
110 m_instance = nullptr;
113QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/)
115 CursorImage *cursorImage = fetchCursor(cursorThemeAndName);
116 size->setWidth(cursorImage->qimage.width());
117 size->setHeight(cursorImage->qimage.height());
119 return cursorImage->qimage;
122QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
124 CursorImage *cursorImage = fetchCursor(themeName, cursorName);
125 if (cursorImage) {
126 return cursorImage->hotspot;
127 } else {
128 return QPoint(0,0);
129 }
132CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
134 QString themeName;
135 QString cursorName;
136 {
137 QStringList themeAndNameList = cursorThemeAndName.split("/");
138 if (themeAndNameList.size() != 2) {
139 return nullptr;
140 }
141 themeName = themeAndNameList[0];
142 cursorName = themeAndNameList[1];
143 }
145 return fetchCursor(themeName, cursorName);
148CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName)
150 CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName);
152 // Try some fallbacks
153 if (cursorImage->qimage.isNull()) {
154 if (cursorName == "ibeam") {
155 qDebug() << "CursorImageProvider: \"ibeam\" not found, falling back to \"xterm\"";
156 cursorImage = fetchCursorHelper(themeName, "xterm");
157 } else if (cursorName == "xterm") {
158 qDebug() << "CursorImageProvider: \"xterm\" not found, falling back to \"ibeam\"";
159 cursorImage = fetchCursorHelper(themeName, "ibeam");
160 }
161 }
163 // if it all fails, there must be at least a left_ptr
164 if (cursorImage->qimage.isNull() && cursorName != "left_ptr") {
165 qDebug() << "CursorImageProvider:" << cursorName
166 << "not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort.";
167 cursorImage = fetchCursorHelper(themeName, "left_ptr");
168 }
170 if (cursorImage->qimage.isNull()) {
171 // finally, go for the built-in cursor
172 qWarning() << "CursorImageProvider: couldn't find any cursors. Using the built-in one";
173 if (!m_builtInCursorImage) {
174 m_builtInCursorImage.reset(new BuiltInCursorImage);
175 }
176 cursorImage = m_builtInCursorImage.data();
177 }
179 return cursorImage;
182CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName)
184 QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName];
186 if (!themeCursors.contains(cursorName)) {
187 themeCursors[cursorName] = new XCursorImage(themeName, cursorName);
188 }
190 return themeCursors[cursorName];