1 /*
2 * SPDX-FileCopyrightText: 2013 Giorgos Tsiapaliokas <terietor@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "view.h"
8
9 #include <QDBusInterface>
10 #include <QDBusReply>
11 #include <QDebug>
12 #include <QFileDialog>
13 #include <QQmlContext>
14 #include <QQmlEngine>
15 #include <QQuickItem>
16
17 #include <KDesktopFile>
18 #include <KLocalizedString>
19
20 #include <KPackage/Package>
21 #include <KPackage/PackageLoader>
22
23 class ViewerCorona : public Plasma::Corona
24 {
25 public:
ViewerCorona()26 ViewerCorona()
27 : Plasma::Corona()
28 , m_view(nullptr)
29 {
30 }
31
setView(View * view)32 void setView(View *view)
33 {
34 m_view = view;
35 }
36
screenGeometry(int id) const37 QRect screenGeometry(int id) const override
38 {
39 Q_UNUSED(id);
40 if (m_view) {
41 return m_view->geometry();
42 } else {
43 return QRect();
44 }
45 }
46
screenForContainment(const Plasma::Containment * containment) const47 int screenForContainment(const Plasma::Containment *containment) const override
48 {
49 return 0;
50 }
51
52 private:
53 View *m_view;
54 };
55
View(ViewerCorona * cor,bool konsoleVisible,QWindow * parent)56 View::View(ViewerCorona *cor, bool konsoleVisible, QWindow *parent)
57 : PlasmaQuick::ContainmentView(cor, parent)
58 {
59 cor->setView(this);
60 m_konsoleVisible = konsoleVisible;
61 engine()->rootContext()->setContextProperty("desktop", this);
62 setSource(QUrl::fromLocalFile(cor->kPackage().filePath("views", "Desktop.qml")));
63 }
64
~View()65 View::~View()
66 {
67 }
68
resizeEvent(QResizeEvent * event)69 void View::resizeEvent(QResizeEvent *event)
70 {
71 emit corona()->screenGeometryChanged(0);
72 emit corona()->availableScreenRectChanged();
73 emit corona()->availableScreenRegionChanged();
74 PlasmaQuick::ContainmentView::resizeEvent(event);
75 }
76
pluginFromPath(const QString & path) const77 QString View::pluginFromPath(const QString &path) const
78 {
79 QDir dir(path);
80 if (!dir.exists()) {
81 return QString();
82 }
83
84 QString metadataPath = dir.absolutePath();
85 if (!QFile(metadataPath).exists()) {
86 return QString();
87 } else {
88 return metadataPath;
89 }
90 }
91
addApplet(const QString & applet)92 void View::addApplet(const QString &applet)
93 {
94 QString metadataPath = pluginFromPath(applet);
95
96 Plasma::Containment *c = containment();
97
98 if (!c) {
99 qCritical("Containment doesn't exist");
100 return;
101 }
102
103 Plasma::Applet *a = nullptr;
104 if (metadataPath.isEmpty()) {
105 a = containment()->createApplet(applet);
106 } else {
107 a = Plasma::Applet::loadPlasmoid(metadataPath);
108
109 // Load translations from KPackage files if bundled
110 const QString localePath = a->kPackage().filePath("translations");
111 if (!localePath.isEmpty()) {
112 const QString localeDomain = QByteArray("plasma_applet_") + a->pluginMetaData().pluginId();
113 KLocalizedString::addDomainLocaleDir(localeDomain.toLatin1(), localePath);
114 }
115
116 containment()->addApplet(a);
117 }
118
119 if (!a->pluginMetaData().isValid()) {
120 // xgettext:no-c-format
121 qCritical() << i18n("Applet %1 does not exist.", applet);
122 return;
123 }
124 m_lastAppletName = applet;
125 }
126
addContainment(const QString & cont)127 void View::addContainment(const QString &cont)
128 {
129 QString actualCont = pluginFromPath(cont);
130 if (actualCont.isEmpty()) {
131 actualCont = cont;
132 }
133
134 Plasma::Containment *c = corona()->createContainment(actualCont);
135
136 if (!c->pluginMetaData().isValid()) {
137 // xgettext:no-c-format
138 qCritical() << i18n("Containment %1 does not exist.", actualCont);
139 return;
140 }
141
142 setContainment(c);
143
144 connect(containment(), &Plasma::Containment::appletRemoved, [=](Plasma::Applet *applet) {
145 if (applet && applet->pluginMetaData().isValid()) {
146 addApplet(applet->pluginMetaData().pluginId());
147 }
148 });
149 }
150
addFormFactor(const QString & formFactor)151 void View::addFormFactor(const QString &formFactor)
152 {
153 Plasma::Types::FormFactor formFactorType = Plasma::Types::Planar;
154 const QString ff = formFactor.toLower();
155
156 if (ff.isEmpty() || ff == QStringLiteral("planar")) {
157 formFactorType = Plasma::Types::Planar;
158 } else if (ff == QStringLiteral("vertical")) {
159 formFactorType = Plasma::Types::Vertical;
160 } else if (ff == QStringLiteral("horizontal")) {
161 formFactorType = Plasma::Types::Horizontal;
162 } else if (ff == QStringLiteral("mediacenter")) {
163 formFactorType = Plasma::Types::MediaCenter;
164 } else if (ff == QStringLiteral("application")) {
165 formFactorType = Plasma::Types::Application;
166 } else {
167 qWarning() << "FormFactor " << ff << "doesn't exist. Planar formFactor has been used!!";
168 }
169
170 Plasma::Containment *c = containment();
171 if (!c) {
172 qCritical("Containment doesn't exist!");
173 return;
174 }
175
176 c->setFormFactor(formFactorType);
177 }
178
changeFormFactor(int formFactor)179 void View::changeFormFactor(int formFactor)
180 {
181 QString formFactorType = "planar";
182 switch (formFactor) {
183 case Plasma::Types::Planar:
184 formFactorType = "planar";
185 break;
186 case Plasma::Types::Vertical:
187 formFactorType = "vertical";
188 break;
189 case Plasma::Types::Horizontal:
190 formFactorType = "horizontal";
191 break;
192 case Plasma::Types::MediaCenter:
193 formFactorType = "mediacenter";
194 break;
195 case Plasma::Types::Application:
196 formFactorType = "application";
197 break;
198 }
199
200 addFormFactor(formFactorType);
201 }
202
addLocation(const QString & location)203 void View::addLocation(const QString &location)
204 {
205 Plasma::Types::Location locationType = Plasma::Types::Floating;
206
207 const QString l = location.toLower();
208
209 if (l.isEmpty() || l == QStringLiteral("floating")) {
210 locationType = Plasma::Types::Floating;
211 } else if (l == QStringLiteral("desktop")) {
212 locationType = Plasma::Types::Desktop;
213 } else if (l == QStringLiteral("fullscreen")) {
214 locationType = Plasma::Types::FullScreen;
215 } else if (l == QStringLiteral("topedge")) {
216 locationType = Plasma::Types::TopEdge;
217 } else if (l == QStringLiteral("bottomedge")) {
218 locationType = Plasma::Types::BottomEdge;
219 } else if (l == QStringLiteral("rightedge")) {
220 locationType = Plasma::Types::RightEdge;
221 } else if (l == QStringLiteral("leftedge")) {
222 locationType = Plasma::Types::LeftEdge;
223 } else {
224 qWarning() << "Location " << l << "doesn't exist. Floating location has been used!!";
225 }
226
227 Plasma::Containment *c = containment();
228 if (!c) {
229 qCritical("Containment doesn't exist!");
230 return;
231 }
232
233 setLocation(locationType);
234 }
235
emitExternalData(const QString & data)236 void View::emitExternalData(const QString &data)
237 {
238 if (data.isEmpty()) {
239 return;
240 }
241
242 Plasma::Applet *applet = containment()->applets().constFirst();
243
244 QObject *graphicsObject = qobject_cast<QQuickItem *>(applet->property("_plasma_graphicObject").value<QObject *>());
245 if (!graphicsObject) {
246 return;
247 }
248
249 QMetaObject::invokeMethod(graphicsObject, "externalData", Q_ARG(QString, QString()), Q_ARG(QVariant, data));
250 }
251
konsoleVisible()252 bool View::konsoleVisible()
253 {
254 return m_konsoleVisible;
255 }
256
changeLocation(int location)257 void View::changeLocation(int location)
258 {
259 QString locationType = "floating";
260 switch (location) {
261 case Plasma::Types::Floating:
262 locationType = "floating";
263 break;
264 case Plasma::Types::Desktop:
265 locationType = "desktop";
266 break;
267 case Plasma::Types::FullScreen:
268 locationType = "fullscreen";
269 break;
270 case Plasma::Types::TopEdge:
271 locationType = "topedge";
272 break;
273 case Plasma::Types::BottomEdge:
274 locationType = "bottomedge";
275 break;
276 case Plasma::Types::RightEdge:
277 locationType = "rightedge";
278 break;
279 case Plasma::Types::LeftEdge:
280 locationType = "leftedge";
281 break;
282 }
283
284 addLocation(locationType);
285 }
286
createCorona()287 ViewerCorona *View::createCorona()
288 {
289 KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("Plasma/Shell");
290 package.setPath("org.kde.plasma.plasmoidviewershell");
291
292 ViewerCorona *cor = new ViewerCorona();
293 cor->setKPackage(package);
294
295 return cor;
296 }
297
takeScreenShot()298 void View::takeScreenShot()
299 {
300 QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot"));
301
302 QDBusPendingCall async = interface.asyncCall(QStringLiteral("screenshotArea"), x(), y(), width(), height());
303
304 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this);
305
306 connect(watcher, &QDBusPendingCallWatcher::finished, [](QDBusPendingCallWatcher *call) {
307 QDBusPendingReply<QString> reply = *call;
308 call->deleteLater();
309
310 if (!reply.isValid()) {
311 qDebug() << "The screenshot has failed, the reply is invalid with error" << reply.error().message();
312 return;
313 }
314
315 QString dest = QFileDialog::getSaveFileName(nullptr, i18nc("@title:window", "Save Screenshot"), QDir::homePath(), QStringLiteral("Images (*.png)"));
316
317 if (dest.isEmpty()) {
318 return;
319 }
320
321 if (!dest.endsWith(QStringLiteral(".png"))) {
322 dest.append(QStringLiteral(".png"));
323 }
324
325 QFile f(reply.value());
326 f.rename(dest);
327 });
328 }
329
330 #include "moc_view.cpp"
331