From 75af9fbb873836ec9334479533b6a4f7de15c0c1 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Wed, 9 Mar 2016 15:32:10 +0000 Subject: [PATCH] plasma: move wallpaper rendering to main thread Signed-off-by: Ivailo Monev --- plasma/CMakeLists.txt | 1 - plasma/private/wallpaper_p.h | 2 - plasma/private/wallpaperrenderthread.cpp | 269 ----------------------- plasma/private/wallpaperrenderthread_p.h | 83 ------- plasma/wallpaper.cpp | 160 +++++++++++--- plasma/wallpaper.h | 2 - 6 files changed, 134 insertions(+), 383 deletions(-) delete mode 100644 plasma/private/wallpaperrenderthread.cpp delete mode 100644 plasma/private/wallpaperrenderthread_p.h diff --git a/plasma/CMakeLists.txt b/plasma/CMakeLists.txt index d8f2b8c5..16a84131 100644 --- a/plasma/CMakeLists.txt +++ b/plasma/CMakeLists.txt @@ -126,7 +126,6 @@ set(plasma_LIB_SRCS private/style.cpp private/themedwidgetinterface.cpp private/tooltip.cpp - private/wallpaperrenderthread.cpp private/windowpreview.cpp private/kineticscroll.cpp private/declarative/declarativenetworkaccessmanagerfactory.cpp diff --git a/plasma/private/wallpaper_p.h b/plasma/private/wallpaper_p.h index 3e62db67..bb0ab8e6 100644 --- a/plasma/private/wallpaper_p.h +++ b/plasma/private/wallpaper_p.h @@ -27,7 +27,6 @@ #include "plasma/scripting/wallpaperscript.h" #include "plasma/private/dataengineconsumer_p.h" -#include "plasma/private/wallpaperrenderthread_p.h" namespace Plasma { @@ -44,7 +43,6 @@ public: bool findInCache(const QString &key, unsigned int lastModified = 0); - void newRenderCompleted(const WallpaperRenderRequest &render, const QImage &image); void setupScriptSupport(); void renderWallpaper(const QString &sourceImagePath, const QImage &image, const QSize &size, Wallpaper::ResizeMethod resizeMethod, const QColor &color); diff --git a/plasma/private/wallpaperrenderthread.cpp b/plasma/private/wallpaperrenderthread.cpp deleted file mode 100644 index 4ff3ccf7..00000000 --- a/plasma/private/wallpaperrenderthread.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2007 Paolo Capriotti - * Copyright (c) 2009 Aaron Seigo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "plasma/private/wallpaperrenderthread_p.h" - -#include -#include -#include -#include - -#include "config-plasma.h" -#ifndef PLASMA_NO_SOLID -#include -#include -#endif - -#include - -namespace Plasma -{ - -int WallpaperRenderRequest::s_token = 0; -int WallpaperRenderThread::s_rendererCount = 0; -QQueue WallpaperRenderThread::s_renderQueue; - -WallpaperRenderThread::WallpaperRenderThread(const WallpaperRenderRequest &request, QObject *parent) - : QThread(parent), - m_request(request), - m_abort(false) -{ - qRegisterMetaType("WallpaperRenderRequest"); - if (!request.requester) { - deleteLater(); - return; - } - - ++s_rendererCount; - connect(this, SIGNAL(done(WallpaperRenderRequest,QImage)), - request.requester.data(), SLOT(newRenderCompleted(WallpaperRenderRequest,QImage))); -} - -WallpaperRenderThread::~WallpaperRenderThread() -{ - kDebug() << "rendering done"; - m_abort = true; - wait(); - --s_rendererCount; - checkQueue(); -} - -void WallpaperRenderThread::render(const WallpaperRenderRequest &request) -{ - QObject *requester = request.requester.data(); - if (!requester) { - return; - } - - // remove all dead requests and requests previously made for the same parent - QMutableListIterator it(s_renderQueue); - while (it.hasNext()) { - const WallpaperRenderRequest &request = it.next(); - - if (!request.requester || request.requester.data() == requester) { - it.remove(); - } - } - - s_renderQueue.append(request); - checkQueue(); -} - -void WallpaperRenderThread::checkQueue() -{ - if (s_renderQueue.isEmpty()) { - return; - } - - if (QCoreApplication::closingDown()) { - s_renderQueue.clear(); - return; - } - -#ifndef PLASMA_NO_SOLID - const int numProcs = qMax(1, Solid::Device::listFromType(Solid::DeviceInterface::Processor).count()); -#else - const int numProcs = 1; -#endif - kDebug() << "checking rendering against" << s_rendererCount << numProcs; - if (s_rendererCount < numProcs) { - WallpaperRenderThread *renderThread = new WallpaperRenderThread(s_renderQueue.dequeue()); - renderThread->start(); - } -} - -void WallpaperRenderThread::run() -{ - kDebug() << "rendering wallpaper" << m_request.file; - QImage result(m_request.size, QImage::Format_ARGB32_Premultiplied); - result.fill(m_request.color.rgba()); - - if (m_request.file.isEmpty() && m_request.providedImage.isNull() && !QFile::exists(m_request.file)) { - if (!m_abort) { - emit done(m_request, result); - } - - kDebug() << "wrong request or file does not exist"; - deleteLater(); - return; - } - - QPoint pos(0, 0); - //const float ratio = qMax(float(1), m_request.size.width() / float(m_request.size.height())); - const bool scalable = m_request.file.endsWith(QLatin1String("svg")) || m_request.file.endsWith(QLatin1String("svgz")); - bool tiled = false; - QSize scaledSize; - QImage img; - - // set image size - QSize imgSize(1, 1); - if (!m_request.providedImage.isNull()) { - img = m_request.providedImage; - kDebug() << "going to resize the img" << img.size(); - imgSize = imgSize.expandedTo(img.size()); - } else if (scalable) { - // scalable: image can be of any size - imgSize = imgSize.expandedTo(m_request.size); - } else { - // otherwise, use the natural size of the loaded image - img = QImage(m_request.file); - imgSize = imgSize.expandedTo(img.size()); - //kDebug() << "loaded with" << imgSize << ratio; - } - - // set render parameters according to resize mode - switch (m_request.resizeMethod) - { - case Wallpaper::ScaledResize: - scaledSize = m_request.size; - break; - case Wallpaper::CenteredResize: - scaledSize = imgSize; - pos = QPoint((m_request.size.width() - scaledSize.width()) / 2, - (m_request.size.height() - scaledSize.height()) / 2); - - //If the picture is bigger than the screen, shrink it - if (m_request.size.width() < imgSize.width() && imgSize.width() > imgSize.height()) { - int width = m_request.size.width(); - int height = width * scaledSize.height() / imgSize.width(); - scaledSize = QSize(width, height); - pos = QPoint((m_request.size.width() - scaledSize.width()) / 2, - (m_request.size.height() - scaledSize.height()) / 2); - } else if (m_request.size.height() < imgSize.height()) { - int height = m_request.size.height(); - int width = height * imgSize.width() / imgSize.height(); - scaledSize = QSize(width, height); - pos = QPoint((m_request.size.width() - scaledSize.width()) / 2, - (m_request.size.height() - scaledSize.height()) / 2); - } - - break; - case Wallpaper::MaxpectResize: { - float xratio = (float) m_request.size.width() / imgSize.width(); - float yratio = (float) m_request.size.height() / imgSize.height(); - if (xratio > yratio) { - int height = m_request.size.height(); - int width = height * imgSize.width() / imgSize.height(); - scaledSize = QSize(width, height); - } else { - int width = m_request.size.width(); - int height = width * imgSize.height() / imgSize.width(); - scaledSize = QSize(width, height); - } - - pos = QPoint((m_request.size.width() - scaledSize.width()) / 2, - (m_request.size.height() - scaledSize.height()) / 2); - break; - } - case Wallpaper::ScaledAndCroppedResize: { - float xratio = (float) m_request.size.width() / imgSize.width(); - float yratio = (float) m_request.size.height() / imgSize.height(); - if (xratio > yratio) { - int width = m_request.size.width(); - int height = width * imgSize.height() / imgSize.width(); - scaledSize = QSize(width, height); - } else { - int height = m_request.size.height(); - int width = height * imgSize.width() / imgSize.height(); - scaledSize = QSize(width, height); - } - pos = QPoint((m_request.size.width() - scaledSize.width()) / 2, - (m_request.size.height() - scaledSize.height()) / 2); - break; - } - case Wallpaper::TiledResize: - scaledSize = imgSize; - tiled = true; - break; - case Wallpaper::CenterTiledResize: - scaledSize = imgSize; - pos = QPoint(-scaledSize.width() + ((m_request.size.width() - scaledSize.width()) / 2) % scaledSize.width(), - -scaledSize.height() + ((m_request.size.height() - scaledSize.height()) / 2) % scaledSize.height()); - tiled = true; - break; - } - - QPainter p(&result); - //kDebug() << token << scalable << scaledSize << imgSize; - if (scalable) { - // tiling is ignored for scalable wallpapers - QSvgRenderer svg(m_request.file); - if (m_abort) { - deleteLater(); - return; - } - svg.render(&p); - } else { - if (scaledSize != imgSize) { - img = img.scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - } - - if (m_abort) { - deleteLater(); - return; - } - - if (tiled) { - for (int x = pos.x(); x < m_request.size.width(); x += scaledSize.width()) { - for (int y = pos.y(); y < m_request.size.height(); y += scaledSize.height()) { - p.drawImage(QPoint(x, y), img); - if (m_abort) { - deleteLater(); - return; - } - } - } - } else { - p.drawImage(pos, img); - } - } - - // signal we're done - if (!m_abort) { - emit done(m_request, result); - } - - deleteLater(); -} - -} // namespace Plasma - -#include "moc_wallpaperrenderthread_p.cpp" - diff --git a/plasma/private/wallpaperrenderthread_p.h b/plasma/private/wallpaperrenderthread_p.h deleted file mode 100644 index 677c0273..00000000 --- a/plasma/private/wallpaperrenderthread_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2007 Paolo Capriotti - * Copyright (c) 2009 Aaron Seigo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef PLASMA_WALLPAPERRENDERTHREAD_P_H -#define PLASMA_WALLPAPERRENDERTHREAD_P_H - -#include -#include -#include -#include -#include -#include - -#include "plasma/wallpaper.h" - -namespace Plasma -{ - -class WallpaperRenderRequest -{ -public: - WallpaperRenderRequest() - : token(++s_token) - { - - } - QWeakPointer requester; - QImage providedImage; - QString file; - QSize size; - Wallpaper::ResizeMethod resizeMethod; - QColor color; - int token; - - static int s_token; -}; - -class WallpaperRenderThread : public QThread -{ - Q_OBJECT - -public: - WallpaperRenderThread(const WallpaperRenderRequest &request, QObject *parent = 0); - virtual ~WallpaperRenderThread(); - - static void render(const WallpaperRenderRequest &request); - -Q_SIGNALS: - void done(const WallpaperRenderRequest &request, const QImage &image); - -protected: - virtual void run(); - -private: - static void checkQueue(); - WallpaperRenderRequest m_request; - - bool m_abort; - static int s_rendererCount; - static QQueue s_renderQueue; -}; - -} // namespace Plasma - -Q_DECLARE_METATYPE(Plasma::WallpaperRenderRequest) -#endif // PLASMA_WALLPAPERRENDERTHREAD_P_H diff --git a/plasma/wallpaper.cpp b/plasma/wallpaper.cpp index c69a5647..eb9d72de 100644 --- a/plasma/wallpaper.cpp +++ b/plasma/wallpaper.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -480,16 +482,138 @@ void WallpaperPrivate::renderWallpaper(const QString &sourceImagePath, const QIm } } - WallpaperRenderRequest request; - renderToken = request.token; - request.requester = q; - request.providedImage = image; - request.file = sourceImagePath; - request.size = size; - request.resizeMethod = resizeMethod; - request.color = color; - WallpaperRenderThread::render(request); - //kDebug() << "rendering" << sourceImagePath << ", token is" << d->renderToken; + kDebug() << "rendering wallpaper" << sourceImagePath; + QImage result(size, QImage::Format_ARGB32_Premultiplied); + result.fill(color.rgba()); + + if (sourceImagePath.isEmpty() && image.isNull() && !QFile::exists(sourceImagePath)) { + kDebug() << "wrong request or file does not exist"; + return; + } + + QPoint pos(0, 0); + //const float ratio = qMax(float(1), size.width() / float(size.height())); + const bool scalable = sourceImagePath.endsWith(QLatin1String("svg")) || sourceImagePath.endsWith(QLatin1String("svgz")); + bool tiled = false; + QSize scaledSize; + QImage img; + + // set image size + QSize imgSize(1, 1); + if (!image.isNull()) { + img = image; + kDebug() << "going to resize the img" << img.size(); + imgSize = imgSize.expandedTo(img.size()); + } else if (scalable) { + // scalable: image can be of any size + imgSize = imgSize.expandedTo(size); + } else { + // otherwise, use the natural size of the loaded image + img = QImage(sourceImagePath); + imgSize = imgSize.expandedTo(img.size()); + //kDebug() << "loaded with" << imgSize << ratio; + } + + // set render parameters according to resize mode + switch (resizeMethod) + { + case Wallpaper::ScaledResize: + scaledSize = size; + break; + case Wallpaper::CenteredResize: + scaledSize = imgSize; + pos = QPoint((size.width() - scaledSize.width()) / 2, + (size.height() - scaledSize.height()) / 2); + + //If the picture is bigger than the screen, shrink it + if (size.width() < imgSize.width() && imgSize.width() > imgSize.height()) { + int width = size.width(); + int height = width * scaledSize.height() / imgSize.width(); + scaledSize = QSize(width, height); + pos = QPoint((size.width() - scaledSize.width()) / 2, + (size.height() - scaledSize.height()) / 2); + } else if (size.height() < imgSize.height()) { + int height = size.height(); + int width = height * imgSize.width() / imgSize.height(); + scaledSize = QSize(width, height); + pos = QPoint((size.width() - scaledSize.width()) / 2, + (size.height() - scaledSize.height()) / 2); + } + + break; + case Wallpaper::MaxpectResize: { + float xratio = (float) size.width() / imgSize.width(); + float yratio = (float) size.height() / imgSize.height(); + if (xratio > yratio) { + int height = size.height(); + int width = height * imgSize.width() / imgSize.height(); + scaledSize = QSize(width, height); + } else { + int width = size.width(); + int height = width * imgSize.height() / imgSize.width(); + scaledSize = QSize(width, height); + } + + pos = QPoint((size.width() - scaledSize.width()) / 2, + (size.height() - scaledSize.height()) / 2); + break; + } + case Wallpaper::ScaledAndCroppedResize: { + float xratio = (float) size.width() / imgSize.width(); + float yratio = (float) size.height() / imgSize.height(); + if (xratio > yratio) { + int width = size.width(); + int height = width * imgSize.height() / imgSize.width(); + scaledSize = QSize(width, height); + } else { + int height = size.height(); + int width = height * imgSize.width() / imgSize.height(); + scaledSize = QSize(width, height); + } + pos = QPoint((size.width() - scaledSize.width()) / 2, + (size.height() - scaledSize.height()) / 2); + break; + } + case Wallpaper::TiledResize: + scaledSize = imgSize; + tiled = true; + break; + case Wallpaper::CenterTiledResize: + scaledSize = imgSize; + pos = QPoint(-scaledSize.width() + ((size.width() - scaledSize.width()) / 2) % scaledSize.width(), + -scaledSize.height() + ((size.height() - scaledSize.height()) / 2) % scaledSize.height()); + tiled = true; + break; + } + + QPainter p(&result); + //kDebug() << token << scalable << scaledSize << imgSize; + if (scalable) { + // tiling is ignored for scalable wallpapers + QSvgRenderer svg(sourceImagePath); + svg.render(&p); + } else { + if (scaledSize != imgSize) { + img = img.scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + + if (tiled) { + for (int x = pos.x(); x < size.width(); x += scaledSize.width()) { + for (int y = pos.y(); y < size.height(); y += scaledSize.height()) { + p.drawImage(QPoint(x, y), img); + } + } + } else { + p.drawImage(pos, img); + } + } + + if (cacheRendering) { + q->insertIntoCache(cacheKey(sourceImagePath, size, resizeMethod, color), result); + } + + //kDebug() << "rendering complete!"; + emit q->renderCompleted(result); } WallpaperPrivate::WallpaperPrivate(KService::Ptr service, Wallpaper *wallpaper) : @@ -542,22 +666,6 @@ QString WallpaperPrivate::cachePath(const QString &key) const return KGlobal::dirs()->locateLocal("cache", "plasma-wallpapers/" + key + ".png"); } -void WallpaperPrivate::newRenderCompleted(const WallpaperRenderRequest &request, const QImage &image) -{ - kDebug() << request.token << renderToken; - if (request.token != renderToken) { - //kDebug() << "render token mismatch" << token << renderToken; - return; - } - - if (cacheRendering) { - q->insertIntoCache(cacheKey(request.file, request.size, request.resizeMethod, request.color), image); - } - - //kDebug() << "rendering complete!"; - emit q->renderCompleted(image); -} - // put all setup routines for script here. at this point we can assume that // package exists and that we have a script engine void WallpaperPrivate::setupScriptSupport() diff --git a/plasma/wallpaper.h b/plasma/wallpaper.h index ecc08be6..ad494b3c 100644 --- a/plasma/wallpaper.h +++ b/plasma/wallpaper.h @@ -565,8 +565,6 @@ class PLASMA_EXPORT Wallpaper : public QObject void setPreviewDuringConfiguration(const bool preview); private: - Q_PRIVATE_SLOT(d, void newRenderCompleted(const WallpaperRenderRequest &request, - const QImage &image)) Q_PRIVATE_SLOT(d, void initScript()) friend class WallpaperPackage;