@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
33 *
44 * This program is free software: you can redistribute it and/or modify it under
55 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -46,6 +46,9 @@ BuiltInCursorImage::BuiltInCursorImage()
4646 qimage.fill(Qt::transparent);
4747 QPainter imagePainter(&qimage);
4848
49+ frameWidth = qimage.width();
50+ frameHeight = qimage.height();
51+
4952 QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
5053 svgRenderer->render(&imagePainter);
5154 delete svgRenderer;
@@ -59,6 +62,8 @@ BlankCursorImage::BlankCursorImage()
5962{
6063 qimage = QImage(1, 1, QImage::Format_ARGB32);
6164 qimage.fill(Qt::transparent);
65+ frameWidth = qimage.width();
66+ frameHeight = qimage.height();
6267}
6368
6469/////
@@ -69,40 +74,74 @@ CustomCursorImage::CustomCursorImage(const QCursor &cursor)
6974{
7075 qimage = cursor.pixmap().toImage();
7176 hotspot = cursor.hotSpot();
77+ frameWidth = qimage.width();
78+ frameHeight = qimage.height();
7279}
7380
7481/////
7582// XCursorImage
7683
7784XCursorImage::XCursorImage(const QString &theme, const QString &file)
78− : xcursorImages(nullptr)
7985{
8086 // TODO: Consider grid unit value
8187 // Hardcoding to a medium size for now
8288 int preferredCursorHeightPx = 32;
8389
84− xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),
90+ XcursorImages *xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),
8591 preferredCursorHeightPx);
86− if (!xcursorImages) {
92+ if (!xcursorImages || xcursorImages->nimage == 0) {
8793 return;
8894 }
8995
90− // Just take the first one. It will have multiple images in case of an animated cursor.
91− // TODO: Support animated cursors
92− if ( xcursorImages->nimage > 0) {
93− XcursorImage *xcursorImage = xcursorImages->images[0];
96+ frameCount = xcursorImages->nimage;
9497
95− qimage = QImage((uchar*)xcursorImage->pixels,
96− xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
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;
102+ }
103+ if (frameHeight < (int)xcursorImage->height) {
104+ frameHeight = xcursorImage->height;
105+ }
106+ if (i == 0) {
107+ frameDuration = (int)xcursorImage->delay;
108+ } else {
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.";
112+ }
113+ }
114+ }
97115
116+ {
117+ // Assume that the hotspot position does not animate
118+ XcursorImage *xcursorImage = xcursorImages->images[0];
98119 hotspot.setX(xcursorImage->xhot);
99120 hotspot.setY(xcursorImage->yhot);
100121 }
122+
123+ // Build the sprite as a single row of frames
124+ qimage = QImage(frameWidth*frameCount, frameHeight, QImage::Format_ARGB32);
125+ qimage.fill(Qt::transparent);
126+
127+ {
128+ QPainter painter(&qimage);
129+
130+ for (int i = 0; i < xcursorImages->nimage; ++i) {
131+ XcursorImage *xcursorImage = xcursorImages->images[i];
132+
133+ auto frameImage = QImage((uchar*)xcursorImage->pixels,
134+ xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
135+
136+ painter.drawImage(QPoint(i*frameWidth, 0), frameImage);
137+ }
138+ }
139+
140+ XcursorImagesDestroy(xcursorImages);
101141}
102142
103143XCursorImage::~XCursorImage()
104144{
105− XcursorImagesDestroy(xcursorImages);
106145}
107146
108147/////
@@ -205,16 +244,6 @@ QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSiz
205244 return cursorImage->qimage;
206245}
207246
208−QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
209−{
210− CursorImage *cursorImage = fetchCursor(themeName, cursorName);
211− if (cursorImage) {
212− return cursorImage->hotspot;
213− } else {
214− return QPoint(0,0);
215− }
216−}
217−
218247CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
219248{
220249 QString themeName;