on xenial help sign in
Add a plugin to take screenshots on vol up + vol down

The screenshots are saved into <Pictures dir>/Screenshots/ Fixes: 1369644 Approved by: Albert Astals Cid

commit4565c0c06389a4de44d63b1b7cd662db89078cb0 authorAlberto Aguirre <alberto.aguirre@canonical.com> dateTue 4 Nov 2014, 12:51 (12 years ago) parent262de1a5c43cb6
12 files changed+381−4
debian/unity8-private.install+1 plugins/CMakeLists.txt+1 plugins/ScreenGrabber/CMakeLists.txt+13 plugins/ScreenGrabber/ScreenGrabber.qmltypes+17 plugins/ScreenGrabber/plugin.cpp+28 plugins/ScreenGrabber/plugin.h+33 plugins/ScreenGrabber/qmldir+3 plugins/ScreenGrabber/screengrabber.cpp+94 plugins/ScreenGrabber/screengrabber.h+42 qml/Components/ScreenGrabber.qml+72 qml/Components/VolumeKeyFilter.qml+63 qml/Shell.qml+14−4
debian/unity8-private.install+1
@@ -6,6 +6,7 @@ usr/lib/*/unity8/qml/LightDM
66usr/lib/*/unity8/qml/Lights
77usr/lib/*/unity8/qml/Powerd
88usr/lib/*/unity8/qml/SessionBroadcast
9+usr/lib/*/unity8/qml/ScreenGrabber
910usr/lib/*/unity8/qml/Ubuntu
1011usr/lib/*/unity8/qml/Unity
1112usr/lib/*/unity8/qml/Utils
plugins/CMakeLists.txt+1
@@ -18,6 +18,7 @@ add_subdirectory(Lights)
1818add_subdirectory(Dash)
1919add_subdirectory(Powerd)
2020add_subdirectory(SessionBroadcast)
21+add_subdirectory(ScreenGrabber)
2122add_subdirectory(Ubuntu)
2223add_subdirectory(Unity)
2324add_subdirectory(Utils)
plugins/ScreenGrabber/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include_directories(
2+ ${CMAKE_CURRENT_BINARY_DIR}
3+)
4+
5+set(SCREENGRABBERSOURCES
6+ screengrabber.cpp
7+ plugin.cpp
8+)
9+
10+add_library(ScreenGrabber-qml MODULE ${SCREENGRABBERSOURCES})
11+qt5_use_modules(ScreenGrabber-qml Qml Gui Quick Concurrent)
12+
13+add_unity8_plugin(ScreenGrabber 0.1 ScreenGrabber TARGETS ScreenGrabber-qml)
plugins/ScreenGrabber/ScreenGrabber.qmltypesnew file+17
@@ -0,0 +1,17 @@
1+import QtQuick.tooling 1.1
2+
3+// This file describes the plugin-supplied types contained in the library.
4+// It is used for QML tooling purposes only.
5+//
6+// This file was auto-generated by:
7+// 'qmlplugindump -nonrelocatable ScreenGrabber 0.1 plugins'
8+
9+Module {
10+ Component {
11+ name: "ScreenGrabber"
12+ prototype: "QObject"
13+ exports: ["ScreenGrabber/ScreenGrabber 0.1"]
14+ exportMetaObjectRevisions: [0]
15+ Method { name: "captureAndSave" }
16+ }
17+}
plugins/ScreenGrabber/plugin.cppnew file+28
@@ -0,0 +1,28 @@
1+/*
2+ * Copyright (C) 2014 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+ * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "screengrabber.h"
21+
22+#include <QtQml/qqml.h>
23+
24+void ScreenGrabberPlugin::registerTypes(const char *uri)
25+{
26+ Q_ASSERT(uri == QLatin1String("ScreenGrabber"));
27+ qmlRegisterType<ScreenGrabber>(uri, 0, 1, "ScreenGrabber");
28+}
plugins/ScreenGrabber/plugin.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2014 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+ * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
17+ */
18+
19+#ifndef SCREENGRABBER_PLUGIN_H
20+#define SCREENGRABBER_PLUGIN_H
21+
22+#include <QtQml/QQmlExtensionPlugin>
23+
24+class ScreenGrabberPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif // SCREENGRABBER_PLUGIN_H
plugins/ScreenGrabber/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module ScreenGrabber
2+plugin ScreenGrabber-qml
3+typeinfo ScreenGrabber.qmltypes
plugins/ScreenGrabber/screengrabber.cppnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (C) 2014 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+ * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
17+ */
18+
19+#include "screengrabber.h"
20+
21+#include <QDir>
22+#include <QDateTime>
23+#include <QStandardPaths>
24+#include <QtGui/QImage>
25+#include <QtGui/QGuiApplication>
26+#include <QtQuick/QQuickWindow>
27+#include <QtConcurrent/QtConcurrentRun>
28+
29+#include <QDebug>
30+
31+void saveScreenshot(QImage screenshot, QString filename, QString format, int quality)
32+{
33+ if (!screenshot.save(filename, format.toLatin1().data(), quality))
34+ qWarning() << "ScreenShotter: failed to save snapshot!";
35+}
36+
37+ScreenGrabber::ScreenGrabber(QObject *parent)
38+ : QObject(parent),
39+ screenshotQuality(0)
40+{
41+ QDir screenshotsDir(QStandardPaths::displayName(QStandardPaths::PicturesLocation));
42+ screenshotsDir.mkdir("Screenshots");
43+ screenshotsDir.cd("Screenshots");
44+ if (screenshotsDir.exists())
45+ {
46+ fileNamePrefix = screenshotsDir.absolutePath();
47+ fileNamePrefix.append("/screenshot");
48+ }
49+ else
50+ {
51+ qWarning() << "ScreenShotter: failed to create directory at: " << screenshotsDir.absolutePath();
52+ }
53+}
54+
55+void ScreenGrabber::captureAndSave()
56+{
57+ if (fileNamePrefix.isEmpty())
58+ {
59+ qWarning() << "ScreenShotter: no directory to save screenshot";
60+ return;
61+ }
62+
63+ const QWindowList windows = QGuiApplication::topLevelWindows();
64+ if (windows.empty())
65+ {
66+ qWarning() << "ScreenShotter: no top level windows found!";
67+ return;
68+ }
69+
70+ QQuickWindow *main_window = qobject_cast<QQuickWindow *>(windows[0]);
71+ if (!main_window)
72+ {
73+ qWarning() << "ScreenShotter: can only take screenshots of QQuickWindows";
74+ return;
75+ }
76+
77+ QImage screenshot = main_window->grabWindow();
78+ QtConcurrent::run(saveScreenshot, screenshot, makeFileName(), getFormat(), screenshotQuality);
79+}
80+
81+QString ScreenGrabber::makeFileName()
82+{
83+ QString fileName(fileNamePrefix);
84+ fileName.append(QDateTime::currentDateTime().toString("yyyymmdd_hhmmsszzz"));
85+ fileName.append(".");
86+ fileName.append(getFormat());
87+ return fileName;
88+}
89+
90+QString ScreenGrabber::getFormat()
91+{
92+ //TODO: This should be configurable (perhaps through gsettings?)
93+ return "png";
94+}
plugins/ScreenGrabber/screengrabber.hnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 2014 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+ * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
17+ */
18+
19+#ifndef SNAPSHOTTER_H
20+#define SNAPSHOTTER_H
21+
22+#include <QObject>
23+#include <QString>
24+
25+class ScreenGrabber: public QObject
26+{
27+ Q_OBJECT
28+
29+public:
30+ explicit ScreenGrabber(QObject *parent = 0);
31+
32+public Q_SLOTS:
33+ void captureAndSave();
34+
35+private:
36+ QString makeFileName();
37+ QString getFormat();
38+ QString fileNamePrefix;
39+ int screenshotQuality;
40+};
41+
42+#endif
qml/Components/ScreenGrabber.qmlnew file+72
@@ -0,0 +1,72 @@
1+/*
2+ * Copyright (C) 2014 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+import QtQuick 2.0
18+import QtMultimedia 5.0
19+import ScreenGrabber 0.1
20+
21+Rectangle {
22+ id: root
23+ enabled: true
24+ visible: false
25+ color: "white"
26+ anchors.fill: parent
27+ opacity: 0.0
28+
29+ ScreenGrabber {
30+ id: screenGrabber
31+ objectName: "screenGrabber"
32+ }
33+
34+ Audio {
35+ id: shutterSound
36+ audioRole: MediaPlayer.alert
37+ source: "/system/media/audio/ui/camera_click.ogg"
38+ }
39+
40+ function capture() {
41+ if (!enabled)
42+ return;
43+
44+ visible = true;
45+ shutterSound.stop();
46+ shutterSound.play();
47+ fadeIn.start();
48+ }
49+
50+ NumberAnimation on opacity {
51+ id: fadeIn
52+ from: 0.0
53+ to: 1.0
54+ onStopped: {
55+ if (visible) {
56+ fadeOut.start();
57+ }
58+ }
59+ }
60+
61+ NumberAnimation on opacity {
62+ id: fadeOut
63+ from: 1.0
64+ to: 0.0
65+ onStopped: {
66+ if (visible) {
67+ screenGrabber.captureAndSave();
68+ visible = false;
69+ }
70+ }
71+ }
72+}
qml/Components/VolumeKeyFilter.qmlnew file+63
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (C) 2014 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+import QtQuick 2.0
18+/*!
19+ \brief A filter for volume keys
20+
21+A filter which treats volume keys as single tri-state key with the states:
22+VolumeUp Pressed, VolumeDown Pressed or Volume Up+Down pressed
23+*/
24+QtObject {
25+ id: root
26+
27+ signal volumeUpPressed()
28+ signal volumeDownPressed()
29+ signal bothVolumeKeysPressed()
30+
31+ property bool volumeUpKeyPressed: false
32+ property bool volumeDownKeyPressed: false
33+ property bool aVolumeKeyWasReleased: true
34+
35+ function onKeyPressed(key) {
36+ if (key == Qt.Key_VolumeUp)
37+ volumeUpKeyPressed = true;
38+ else if (key == Qt.Key_VolumeDown)
39+ volumeDownKeyPressed = true;
40+
41+ if (volumeDownKeyPressed && volumeUpKeyPressed) {
42+ //avoids sending a signal repeatedly if both keys are held
43+ //instead one of the keys must have been previously released
44+ if (aVolumeKeyWasReleased)
45+ bothVolumeKeysPressed();
46+ aVolumeKeyWasReleased = false;
47+ } else if (volumeDownKeyPressed) {
48+ volumeDownPressed();
49+ } else if (volumeUpKeyPressed) {
50+ volumeUpPressed();
51+ }
52+ }
53+
54+ function onKeyReleased(key) {
55+ if (key == Qt.Key_VolumeUp) {
56+ volumeUpKeyPressed = false;
57+ aVolumeKeyWasReleased = true;
58+ } else if (key == Qt.Key_VolumeDown) {
59+ volumeDownKeyPressed = false;
60+ aVolumeKeyWasReleased = true;
61+ }
62+ }
63+}
qml/Shell.qml+14−4
@@ -133,23 +133,32 @@ Item {
133133 objectName: "dashCommunicator"
134134 }
135135
136+ ScreenGrabber {
137+ id: screenGrabber
138+ z: edgeDemo.z + 10
139+ enabled: Powerd.status === Powerd.On
140+ }
141+
136142 Binding {
137143 target: ApplicationManager
138144 property: "forceDashActive"
139145 value: launcher.shown || launcher.dashSwipe
140146 }
141147
148+ VolumeKeyFilter {
149+ id: volumeKeyFilter
150+ onVolumeDownPressed: volumeControl.volumeDown()
151+ onVolumeUpPressed: volumeControl.volumeUp()
152+ onBothVolumeKeysPressed: screenGrabber.capture()
153+ }
142154
143155 WindowKeysFilter {
144− // Handle but do not filter out volume keys
145− Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
146− Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
147−
148156 Keys.onPressed: {
149157 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
150158 dialogs.onPowerKeyPressed();
151159 event.accepted = true;
152160 } else {
161+ volumeKeyFilter.onKeyPressed(event.key);
153162 event.accepted = false;
154163 }
155164 }
@@ -159,6 +168,7 @@ Item {
159168 dialogs.onPowerKeyReleased();
160169 event.accepted = true;
161170 } else {
171+ volumeKeyFilter.onKeyReleased(event.key);
162172 event.accepted = false;
163173 }
164174 }