@@ -0,0 +1,130 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#include "sessionscreenshoter.h"
19+
20+#include <QDebug>
21+#include <QQuickItem>
22+#include <QQuickItemGrabResult>
23+#include <QtConcurrent>
24+
25+static QString cachePath()
26+{
27+ return QDir::homePath() + "/.cache/app_shots/";
28+}
29+
30+SessionScreenshoter::SessionScreenshoter(QObject *parent)
31+ : QObject(parent),
32+ m_target(nullptr)
33+{
34+ // TODO tests
35+}
36+
37+QString SessionScreenshoter::appId() const
38+{
39+ return m_appId;
40+}
41+
42+void SessionScreenshoter::setAppdId(const QString &appId)
43+{
44+ if (appId != m_appId) {
45+ m_appId = appId;
46+ const QString path = cachePath() + appId + ".png";
47+ if (QFile::exists(path)) {
48+ setPath(path);
49+ }
50+ }
51+}
52+
53+QQuickItem *SessionScreenshoter::target() const
54+{
55+ return m_target;
56+}
57+
58+void SessionScreenshoter::setTarget(QQuickItem *target)
59+{
60+ if (target != m_target) {
61+ m_target = target;
62+ Q_EMIT targetChanged();
63+ }
64+}
65+
66+QString SessionScreenshoter::path() const
67+{
68+ return m_path;
69+}
70+
71+void SessionScreenshoter::setPath(const QString &path)
72+{
73+ if (path != m_path) {
74+ m_path = path;
75+ Q_EMIT pathChanged();
76+ }
77+}
78+
79+static QString saveScreenshot(const QString &appId, const QSharedPointer<QQuickItemGrabResult> grabResult)
80+{
81+ const QImage image = grabResult->image();
82+ const QString cPath = cachePath();
83+ QDir d;
84+ d.mkpath(cPath);
85+ const QString path = cPath + appId + ".png";
86+ bool b = image.save(path);
87+ if (b) {
88+ return path;
89+ } else {
90+ return QString();
91+ }
92+}
93+
94+void SessionScreenshoter::take()
95+{
96+ if (!m_grabResult.isNull()) {
97+ qWarning() << "Asked to take a screenshot when there's one already being taken, ignoring";
98+ return;
99+ }
100+
101+ if (m_target && !m_appId.isEmpty()) {
102+ // grabToImage runs in a separate thread
103+ m_grabResult = m_target->grabToImage();
104+ connect(m_grabResult.data(), &QQuickItemGrabResult::ready, this, &SessionScreenshoter::grabReady);
105+ } else {
106+ qWarning() << "Can't take screnshot: appId:" << m_appId << " target:" << m_target;
107+ }
108+}
109+
110+void SessionScreenshoter::removeScreenshot()
111+{
112+ const QString path = cachePath() + m_appId + ".png";
113+ QFile::remove(path);
114+}
115+
116+void SessionScreenshoter::grabReady()
117+{
118+ QFuture<QString> f = QtConcurrent::run(saveScreenshot, m_appId, m_grabResult);
119+ m_watcher.reset(new QFutureWatcher<QString>(this));
120+ m_watcher->setFuture(f);
121+ connect(m_watcher.data(), &QFutureWatcher<QString>::finished, this, &SessionScreenshoter::saveFinished);
122+}
123+
124+void SessionScreenshoter::saveFinished()
125+{
126+ setPath(m_watcher->future().result());
127+ m_watcher.clear();
128+ m_grabResult.clear();
129+ Q_EMIT screenshotTaken();
130+}