Libplasma

wallpaperitem.cpp
1/*
2 SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "wallpaperitem.h"
8#include "appletcontext_p.h"
9
10#include "containmentitem.h"
11#include "sharedqmlengine.h"
12
13#include <KConfigLoader>
14#include <KConfigPropertyMap>
15#include <KDesktopFile>
16
17#include <QDebug>
18#include <QFile>
19#include <QLoggingCategory>
20#include <QQmlContext>
21#include <QQmlExpression>
22#include <QQmlProperty>
23
24#include <Plasma/Corona>
25#include <Plasma/PluginLoader>
26#include <kpackage/packageloader.h>
27#include <qabstractitemmodel.h>
28#include <qtmetamacros.h>
29
30#include "debug_p.h"
31
32WallpaperItem::WallpaperItem(QQuickItem *parent)
33 : QQuickItem(parent)
34{
35 // resize at the beginning to avoid as much resize events as possible
36 if (parent) {
37 setSize(QSizeF(parent->width(), parent->height()));
38 }
39}
40
41WallpaperItem::~WallpaperItem()
42{
43}
44
45void WallpaperItem::classBegin()
46{
48 PlasmaQuick::AppletContext *ac = qobject_cast<PlasmaQuick::AppletContext *>(QQmlEngine::contextForObject(this)->parentContext());
49 Q_ASSERT(ac);
50 m_containment = ac->applet()->containment();
51 m_wallpaperPlugin = m_containment->wallpaperPlugin();
52 m_qmlObject = ac->sharedQmlEngine();
53 m_qmlObject->setParent(this);
54
55 m_pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Wallpaper"));
56 m_pkg.setPath(m_wallpaperPlugin);
57
58 if (configScheme()) {
59 m_configuration = new KConfigPropertyMap(configScheme(), this);
60 }
61
62 connect(m_containment->corona(), &Plasma::Corona::startupCompleted, this, &WallpaperItem::accentColorChanged);
63}
64
65void WallpaperItem::componentComplete()
66{
68
69 m_loading = false;
70 Q_EMIT isLoadingChanged();
71}
72
74{
75 auto filter = [&mimetype, &formFactor](const KPluginMetaData &md) -> bool {
76 if (!formFactor.isEmpty() && !md.value(u"X-Plasma-FormFactors").contains(formFactor)) {
77 return false;
78 }
79 return md.value(u"X-Plasma-DropMimeTypes", QStringList()).contains(mimetype);
80 };
81 return KPackage::PackageLoader::self()->findPackages(QStringLiteral("Plasma/Wallpaper"), QString(), filter);
82}
83
84KPackage::Package WallpaperItem::kPackage() const
85{
86 return m_pkg;
87}
88
89QString WallpaperItem::pluginName() const
90{
91 return m_wallpaperPlugin;
92}
93
94KConfigPropertyMap *WallpaperItem::configuration() const
95{
96 return m_configuration;
97}
98
99KConfigLoader *WallpaperItem::configScheme()
100{
101 if (!m_configLoader) {
102 // FIXME: do we need "mainconfigxml" in wallpaper packagestructures?
103 const QString xmlPath = m_pkg.filePath("config", QStringLiteral("main.xml"));
104
105 KConfigGroup cfg = m_containment->config();
106 cfg = KConfigGroup(&cfg, QStringLiteral("Wallpaper"));
107 cfg = KConfigGroup(&cfg, m_wallpaperPlugin);
108
109 if (xmlPath.isEmpty()) {
110 m_configLoader = new KConfigLoader(cfg, nullptr, this);
111 } else {
112 QFile file(xmlPath);
113 m_configLoader = new KConfigLoader(cfg, &file, this);
114 }
115 }
116
117 return m_configLoader;
118}
119
120void WallpaperItem::requestOpenUrl(const QUrl &url)
121{
122 Q_EMIT openUrlRequested(url);
123}
124
125WallpaperItem *WallpaperItem::loadWallpaper(ContainmentItem *containmentItem)
126{
127 if (containmentItem->containment()->wallpaperPlugin().isEmpty()) {
128 return nullptr;
129 }
130 KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Wallpaper"));
131 pkg.setPath(containmentItem->containment()->wallpaperPlugin());
132 if (!pkg.isValid()) {
133 qCWarning(LOG_PLASMAQUICK) << "Error loading the wallpaper, no valid package loaded";
134 return nullptr;
135 }
136
137 PlasmaQuick::SharedQmlEngine *qmlObject = new PlasmaQuick::SharedQmlEngine(containmentItem->containment());
138 qmlObject->setInitializationDelayed(true);
139
140 const QString rootPath = pkg.metadata().value(u"X-Plasma-RootPath");
141 if (!rootPath.isEmpty()) {
142 qmlObject->setTranslationDomain(QLatin1String("plasma_wallpaper_") + rootPath);
143 } else {
144 qmlObject->setTranslationDomain(QLatin1String("plasma_wallpaper_") + pkg.metadata().pluginId());
145 }
146
147 /*
148 * The initialization is delayed, so it's fine to setSource first.
149 * This also prevents many undefined wallpaper warnings caused by "wallpaper" being set
150 * when the old wallpaper plugin still exists.
151 */
152 qmlObject->setSource(pkg.fileUrl("mainscript"));
153 WallpaperItem *wallpaper = qobject_cast<WallpaperItem *>(qmlObject->rootObject());
154 if (!wallpaper) {
155 if (qmlObject->mainComponent() && qmlObject->mainComponent()->isError()) {
156 qCWarning(LOG_PLASMAQUICK) << "Error loading the wallpaper" << qmlObject->mainComponent()->errors();
157 } else if (qmlObject->rootObject()) {
158 qCWarning(LOG_PLASMAQUICK) << "Root item of wallpaper" << containmentItem->containment()->wallpaperPlugin()
159 << "not a WallpaperItem instance, instead is" << qmlObject->rootObject();
160 }
161 qmlObject->completeInitialization();
162 delete qmlObject->rootObject();
163 return nullptr;
164 }
165
166 if (!qEnvironmentVariableIntValue("PLASMA_NO_CONTEXTPROPERTIES")) {
167 qmlObject->rootContext()->setContextProperty(QStringLiteral("wallpaper"), wallpaper);
168 }
169
170 // initialize with our size to avoid as much resize events as possible
171 QVariantHash props;
172 props[QStringLiteral("parent")] = QVariant::fromValue(containmentItem);
173 props[QStringLiteral("width")] = containmentItem->width();
174 props[QStringLiteral("height")] = containmentItem->height();
175 qmlObject->completeInitialization(props);
176 return wallpaper;
177}
178
180{
181 return m_contextualActions;
182}
183
184QQmlListProperty<QAction> WallpaperItem::qmlContextualActions()
185{
186 return QQmlListProperty<QAction>(this,
187 nullptr,
188 WallpaperItem::contextualActions_append,
189 WallpaperItem::contextualActions_count,
190 WallpaperItem::contextualActions_at,
191 WallpaperItem::contextualActions_clear,
192 WallpaperItem::contextualActions_replace,
193 WallpaperItem::contextualActions_removeLast);
194}
195
196bool WallpaperItem::supportsMimetype(const QString &mimetype) const
197{
198 return m_pkg.metadata().value(u"X-Plasma-DropMimeTypes", QStringList()).contains(mimetype);
199}
200
201bool WallpaperItem::isLoading() const
202{
203 return m_loading;
204}
205
206QColor WallpaperItem::accentColor() const
207{
208 return m_accentColor.value_or(QColor(Qt::transparent));
209}
210
211void WallpaperItem::setAccentColor(const QColor &newColor)
212{
213 if (m_accentColor.has_value() && m_accentColor == newColor) {
214 return;
215 }
216
217 m_accentColor = newColor;
218 Q_EMIT accentColorChanged();
219}
220
221void WallpaperItem::resetAccentColor()
222{
223 if (!m_accentColor.has_value()) {
224 return;
225 }
226
227 m_accentColor.reset();
228 Q_EMIT accentColorChanged();
229}
230
231void WallpaperItem::contextualActions_append(QQmlListProperty<QAction> *prop, QAction *action)
232{
233 WallpaperItem *w = static_cast<WallpaperItem *>(prop->object);
234 w->m_contextualActions.append(action);
235 QObject::connect(action, &QObject::destroyed, w, [w, action]() {
236 w->m_contextualActions.removeAll(action);
237 Q_EMIT w->contextualActionsChanged(w->m_contextualActions);
238 });
239 Q_EMIT w->contextualActionsChanged(w->m_contextualActions);
240};
241
242qsizetype WallpaperItem::contextualActions_count(QQmlListProperty<QAction> *prop)
243{
244 WallpaperItem *w = static_cast<WallpaperItem *>(prop->object);
245 return w->m_contextualActions.count();
246}
247
248QAction *WallpaperItem::contextualActions_at(QQmlListProperty<QAction> *prop, qsizetype idx)
249{
250 WallpaperItem *w = static_cast<WallpaperItem *>(prop->object);
251 return w->m_contextualActions.value(idx);
252}
253
254void WallpaperItem::contextualActions_clear(QQmlListProperty<QAction> *prop)
255{
256 WallpaperItem *w = static_cast<WallpaperItem *>(prop->object);
257 w->m_contextualActions.clear();
258 Q_EMIT w->contextualActionsChanged(w->m_contextualActions);
259}
260
261void WallpaperItem::contextualActions_replace(QQmlListProperty<QAction> *prop, qsizetype idx, QAction *action)
262{
263 WallpaperItem *w = static_cast<WallpaperItem *>(prop->object);
264 w->m_contextualActions.replace(idx, action);
265 Q_EMIT w->contextualActionsChanged(w->m_contextualActions);
266}
267
268void WallpaperItem::contextualActions_removeLast(QQmlListProperty<QAction> *prop)
269{
270 WallpaperItem *w = static_cast<WallpaperItem *>(prop->object);
271 w->m_contextualActions.pop_back();
272 Q_EMIT w->contextualActionsChanged(w->m_contextualActions);
273}
274
275#include "moc_wallpaperitem.cpp"
This class is exposed to containments QML as the attached property Plasmoid.
QList< KPluginMetaData > findPackages(const QString &packageFormat, const QString &packageRoot=QString(), std::function< bool(const KPluginMetaData &)> filter=std::function< bool(const KPluginMetaData &)>())
Package loadPackage(const QString &packageFormat, const QString &packagePath=QString())
static PackageLoader * self()
void setPath(const QString &path)
QUrl fileUrl(const QByteArray &key, const QString &filename=QString()) const
bool isValid() const
KPluginMetaData metadata() const
QString pluginId() const
bool value(QStringView key, bool defaultValue) const
An object that instantiates an entire QML context, with its own declarative engine.
QQmlContext * rootContext() const
The components's creation context.
void setInitializationDelayed(const bool delay)
Sets whether the execution of the QML file has to be delayed later in the event loop.
void setSource(const QUrl &source)
Sets the path of the QML file to parse and execute.
QQmlComponent * mainComponent() const
void setTranslationDomain(const QString &translationDomain)
Call this method before calling setupBindings to install a translation domain for all i18n global fun...
void completeInitialization(const QVariantHash &initialProperties=QVariantHash())
Finishes the process of initialization.
void startupCompleted()
Emitted when the startup phase has been completed.
QQmlListProperty< QAction > contextualActions
Actions to be added in the desktop context menu.
static WallpaperItem * loadWallpaper(ContainmentItem *ContainmentItem)
Instantiate the WallpaperItem for a given containment, using the proper plugin.
static QList< KPluginMetaData > listWallpaperMetadataForMimetype(const QString &mimetype, const QString &formFactor=QString())
Returns a list of all known wallpapers that can accept the given mimetype.
void append(QList< T > &&value)
void clear()
qsizetype count() const const
void pop_back()
qsizetype removeAll(const AT &t)
void replace(qsizetype i, parameter_type value)
T value(qsizetype i) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
T qobject_cast(QObject *object)
QList< QQmlError > errors() const const
bool isError() const const
void setContextProperty(const QString &name, QObject *value)
QQmlContext * contextForObject(const QObject *object)
virtual void classBegin() override
virtual void componentComplete() override
bool isEmpty() const const
transparent
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 11 2025 11:56:56 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.