/*
* Copyright (C) 2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
* SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#include "CursorImageProvider.h"
#include
#include
#include
#include
#include
CursorImageProvider *CursorImageProvider::m_instance = nullptr;
/////
// BuiltInCursorImage
BuiltInCursorImage::BuiltInCursorImage()
{
const char *svgString =
""
"";
qimage = QImage(20, 32, QImage::Format_ARGB32);
qimage.fill(Qt::transparent);
QPainter imagePainter(&qimage);
QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
svgRenderer->render(&imagePainter);
delete svgRenderer;
}
/////
// BlankCursorImage
BlankCursorImage::BlankCursorImage()
{
qimage = QImage(1, 1, QImage::Format_ARGB32);
qimage.fill(Qt::transparent);
}
/////
// CustomCursorImage
CustomCursorImage::CustomCursorImage(const QCursor &cursor)
{
qimage = cursor.pixmap().toImage();
hotspot = cursor.hotSpot();
}
/////
// XCursorImage
XCursorImage::XCursorImage(const QString &theme, const QString &file)
: xcursorImages(nullptr)
{
xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), 32);
if (!xcursorImages) {
return;
}
bool loaded = false;
for (int i = 0; i < xcursorImages->nimage && !loaded; ++i) {
XcursorImage *xcursorImage = xcursorImages->images[i];
if (xcursorImage->size == 32) {
qimage = QImage((uchar*)xcursorImage->pixels,
xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
hotspot.setX(xcursorImage->xhot);
hotspot.setY(xcursorImage->yhot);
loaded = true;
}
}
}
XCursorImage::~XCursorImage()
{
XcursorImagesDestroy(xcursorImages);
}
/////
// CursorImageProvider
CursorImageProvider::CursorImageProvider()
: QQuickImageProvider(QQuickImageProvider::Image)
{
if (m_instance) {
qFatal("Cannot have multiple CursorImageProvider instances");
}
m_instance = this;
m_fallbackNames[QStringLiteral("closedhand")].append(QStringLiteral("grabbing"));
m_fallbackNames[QStringLiteral("closedhand")].append(QStringLiteral("dnd-none"));
m_fallbackNames[QStringLiteral("dnd-copy")].append(QStringLiteral("dnd-none"));
m_fallbackNames[QStringLiteral("dnd-copy")].append(QStringLiteral("grabbing"));
m_fallbackNames[QStringLiteral("dnd-copy")].append(QStringLiteral("closedhand"));
m_fallbackNames[QStringLiteral("dnd-move")].append(QStringLiteral("dnd-none"));
m_fallbackNames[QStringLiteral("dnd-move")].append(QStringLiteral("grabbing"));
m_fallbackNames[QStringLiteral("dnd-move")].append(QStringLiteral("closedhand"));
m_fallbackNames[QStringLiteral("dnd-link")].append(QStringLiteral("dnd-none"));
m_fallbackNames[QStringLiteral("dnd-link")].append(QStringLiteral("grabbing"));
m_fallbackNames[QStringLiteral("dnd-link")].append(QStringLiteral("closedhand"));
m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("crossed_circle")); // DMZ-White and DMZ-Black themes
m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("not-allowed"));
m_fallbackNames[QStringLiteral("forbidden")].append(QStringLiteral("circle"));
m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointing_hand"));
m_fallbackNames[QStringLiteral("hand")].append(QStringLiteral("pointer"));
m_fallbackNames[QStringLiteral("ibeam")].append(QStringLiteral("xterm"));
m_fallbackNames[QStringLiteral("ibeam")].append(QStringLiteral("text"));
m_fallbackNames[QStringLiteral("left_ptr")].append(QStringLiteral("default"));
m_fallbackNames[QStringLiteral("left_ptr")].append(QStringLiteral("top_left_arrow"));
m_fallbackNames[QStringLiteral("left_ptr")].append(QStringLiteral("left_arrow"));
m_fallbackNames[QStringLiteral("left_ptr_watch")].append(QStringLiteral("half-busy"));
m_fallbackNames[QStringLiteral("left_ptr_watch")].append(QStringLiteral("progress"));
m_fallbackNames[QStringLiteral("size_bdiag")].append(QStringLiteral("fd_double_arrow"));
m_fallbackNames[QStringLiteral("size_bdiag")].append(QStringLiteral("nesw-resize"));
m_fallbackNames[QStringLiteral("size_fdiag")].append(QStringLiteral("bd_double_arrow")); // DMZ-White and DMZ-Black themes
m_fallbackNames[QStringLiteral("size_fdiag")].append(QStringLiteral("nwse-resize"));
m_fallbackNames[QStringLiteral("size_hor")].append(QStringLiteral("sb_h_double_arrow")); // DMZ-White and DMZ-Black themes
m_fallbackNames[QStringLiteral("size_hor")].append(QStringLiteral("ew-resize"));
m_fallbackNames[QStringLiteral("size_hor")].append(QStringLiteral("h_double_arrow"));
m_fallbackNames[QStringLiteral("size_ver")].append(QStringLiteral("sb_v_double_arrow")); // DMZ-White and DMZ-Black themes
m_fallbackNames[QStringLiteral("size_ver")].append(QStringLiteral("ns-resize"));
m_fallbackNames[QStringLiteral("size_ver")].append(QStringLiteral("v_double_arrow"));
m_fallbackNames[QStringLiteral("split_h")].append(QStringLiteral("sb_h_double_arrow")); // DMZ-White and DMZ-Black themes
m_fallbackNames[QStringLiteral("split_h")].append(QStringLiteral("col-resize"));
m_fallbackNames[QStringLiteral("split_v")].append(QStringLiteral("sb_v_double_arrow")); // DMZ-White and DMZ-Black themes
m_fallbackNames[QStringLiteral("split_v")].append(QStringLiteral("row-resize"));
m_fallbackNames[QStringLiteral("up_arrow")].append(QStringLiteral("sb_up_arrow")); // DMZ-White and DMZ-Black themes
m_fallbackNames[QStringLiteral("watch")].append(QStringLiteral("wait"));
m_fallbackNames[QStringLiteral("whats_this")].append(QStringLiteral("left_ptr_help"));
m_fallbackNames[QStringLiteral("whats_this")].append(QStringLiteral("help"));
m_fallbackNames[QStringLiteral("whats_this")].append(QStringLiteral("question_arrow"));
m_fallbackNames[QStringLiteral("xterm")].append(QStringLiteral("ibeam"));
}
CursorImageProvider::~CursorImageProvider()
{
{
QList< QMap > cursorList = m_cursors.values();
for (int i = 0; i < cursorList.count(); ++i) {
QList cursorImageList = cursorList[i].values();
for (int j = 0; j < cursorImageList.count(); ++j) {
delete cursorImageList[j];
}
}
}
m_cursors.clear();
m_instance = nullptr;
}
QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/)
{
CursorImage *cursorImage = fetchCursor(cursorThemeAndName);
size->setWidth(cursorImage->qimage.width());
size->setHeight(cursorImage->qimage.height());
return cursorImage->qimage;
}
QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
{
CursorImage *cursorImage = fetchCursor(themeName, cursorName);
if (cursorImage) {
return cursorImage->hotspot;
} else {
return QPoint(0,0);
}
}
CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
{
QString themeName;
QString cursorName;
{
QStringList themeAndNameList = cursorThemeAndName.split('/');
if (themeAndNameList.size() != 2) {
return nullptr;
}
themeName = themeAndNameList[0];
cursorName = themeAndNameList[1];
}
return fetchCursor(themeName, cursorName);
}
CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName)
{
CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName);
// Try some fallbacks
if (cursorImage->qimage.isNull()) {
if (m_fallbackNames.contains(cursorName)) {
const QStringList &fallbackNames = m_fallbackNames[cursorName];
int i = 0;
while (cursorImage->qimage.isNull() && i < fallbackNames.count()) {
qDebug().nospace() << "CursorImageProvider: "<< cursorName <<" not found, trying " << fallbackNames.at(i);
cursorImage = fetchCursorHelper(themeName, fallbackNames.at(i));
++i;
}
}
}
// if it all fails, there must be at least a left_ptr
if (cursorImage->qimage.isNull() && cursorName != QLatin1String("left_ptr")) {
qDebug() << "CursorImageProvider:" << cursorName
<< "not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort.";
cursorImage = fetchCursorHelper(themeName, QStringLiteral("left_ptr"));
}
if (cursorImage->qimage.isNull()) {
// finally, go for the built-in cursor
qWarning() << "CursorImageProvider: couldn't find any cursors. Using the built-in one";
if (!m_builtInCursorImage) {
m_builtInCursorImage.reset(new BuiltInCursorImage);
}
cursorImage = m_builtInCursorImage.data();
}
return cursorImage;
}
CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName)
{
if (cursorName == QLatin1String("blank")) {
return &m_blankCursorImage;
} else if (cursorName == QLatin1String("custom")) {
return m_customCursorImage.data();
} else {
QMap &themeCursors = m_cursors[themeName];
if (!themeCursors.contains(cursorName)) {
themeCursors[cursorName] = new XCursorImage(themeName, cursorName);
}
return themeCursors[cursorName];
}
}
void CursorImageProvider::setCustomCursor(const QCursor &customCursor)
{
if (customCursor.pixmap().isNull()) {
m_customCursorImage.reset();
} else {
m_customCursorImage.reset(new CustomCursorImage(customCursor));
}
}