on xenial help sign in
Refactor screenshotting code and make it work in multimonitor scenarios
e407b3cDaniel d'Andrada
debian/unity8-private.install+1−1
@@ -8,7 +8,7 @@ usr/lib/*/unity8/qml/Greeter
8usr/lib/*/unity8/qml/IntegratedLightDM
8usr/lib/*/unity8/qml/IntegratedLightDM
9usr/lib/*/unity8/qml/Lights
9usr/lib/*/unity8/qml/Lights
10usr/lib/*/unity8/qml/Powerd
10usr/lib/*/unity8/qml/Powerd
11−usr/lib/*/unity8/qml/ScreenGrabber
11+usr/lib/*/unity8/qml/ScreenshotDirectory
12usr/lib/*/unity8/qml/SessionBroadcast
12usr/lib/*/unity8/qml/SessionBroadcast
13usr/lib/*/unity8/qml/Ubuntu
13usr/lib/*/unity8/qml/Ubuntu
14usr/lib/*/unity8/qml/Unity
14usr/lib/*/unity8/qml/Unity
plugins/CMakeLists.txt+1−1
@@ -19,8 +19,8 @@ add_subdirectory(IntegratedLightDM)
19add_subdirectory(Lights)
19add_subdirectory(Lights)
20add_subdirectory(Dash)
20add_subdirectory(Dash)
21add_subdirectory(Powerd)
21add_subdirectory(Powerd)
22+add_subdirectory(ScreenshotDirectory)
22add_subdirectory(SessionBroadcast)
23add_subdirectory(SessionBroadcast)
23−add_subdirectory(ScreenGrabber)
24add_subdirectory(Ubuntu)
24add_subdirectory(Ubuntu)
25add_subdirectory(UInput)
25add_subdirectory(UInput)
26add_subdirectory(Unity)
26add_subdirectory(Unity)
plugins/ScreenGrabber/CMakeLists.txtdeleted−13
@@ -1,13 +0,0 @@
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/qmldirdeleted−3
@@ -1,3 +0,0 @@
1−module ScreenGrabber
2−plugin ScreenGrabber-qml
3−typeinfo ScreenGrabber.qmltypes
plugins/ScreenGrabber/screengrabber.cppdeleted−115
@@ -1,115 +0,0 @@
1−/*
2− * Copyright (C) 2014-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−#include "screengrabber.h"
18−
19−#include <QDir>
20−#include <QDateTime>
21−#include <QStandardPaths>
22−#include <QTemporaryDir>
23−#include <QtGui/QImage>
24−#include <QtGui/QGuiApplication>
25−#include <QtQuick/QQuickWindow>
26−
27−#include <QDebug>
28−
29−QString saveScreenshot(const QImage &screenshot, const QString &filename, const QString &format, int quality)
30−{
31− if (screenshot.save(filename, format.toLatin1().data(), quality)) {
32− return filename;
33− } else {
34− qWarning() << "ScreenGrabber: failed to save snapshot!";
35− }
36− return QString();
37−}
38−
39−ScreenGrabber::ScreenGrabber(QObject *parent)
40− : QObject(parent)
41−{
42− QObject::connect(&m_watcher,
43− &QFutureWatcher<QString>::finished,
44− this,
45− &ScreenGrabber::onScreenshotSaved);
46−
47− QDir screenshotsDir;
48− if (qEnvironmentVariableIsSet("UNITY_TESTING")) {
49− QTemporaryDir tDir;
50− tDir.setAutoRemove(false);
51− screenshotsDir = tDir.path();
52− } else {
53− screenshotsDir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
54− }
55− screenshotsDir.mkpath(QStringLiteral("Screenshots"));
56− screenshotsDir.cd(QStringLiteral("Screenshots"));
57− if (screenshotsDir.exists()) {
58− fileNamePrefix = screenshotsDir.absolutePath();
59− fileNamePrefix.append("/screenshot");
60− } else {
61− qWarning() << "ScreenGrabber: failed to create directory at: " << screenshotsDir.absolutePath();
62− }
63−}
64−
65−void ScreenGrabber::captureAndSave(int angle)
66−{
67− if (fileNamePrefix.isEmpty())
68− {
69− qWarning() << "ScreenShotter: no directory to save screenshot";
70− return;
71− }
72−
73− const QWindowList windows = QGuiApplication::topLevelWindows();
74− if (windows.empty())
75− {
76− qWarning() << "ScreenShotter: no top level windows found!";
77− return;
78− }
79−
80− QQuickWindow *main_window = qobject_cast<QQuickWindow *>(windows[0]);
81− if (!main_window)
82− {
83− qWarning() << "ScreenShotter: can only take screenshots of QQuickWindows";
84− return;
85− }
86−
87− const QImage screenshot = main_window->grabWindow().transformed(QTransform().rotate(angle));
88− const QString filename = makeFileName();
89− qDebug() << "Saving screenshot to" << filename;
90− QFuture<QString> saveFuture(QtConcurrent::run(saveScreenshot, screenshot, filename, getFormat(), screenshotQuality));
91− m_watcher.setFuture(saveFuture);
92−}
93−
94−void ScreenGrabber::onScreenshotSaved()
95−{
96− const QString filename = m_watcher.future().result();
97− if (!filename.isEmpty()) {
98− Q_EMIT screenshotSaved(filename);
99− }
100−}
101−
102−QString ScreenGrabber::makeFileName() const
103−{
104− QString fileName(fileNamePrefix);
105− fileName.append(QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd_hhmmsszzz")));
106− fileName.append(".");
107− fileName.append(getFormat());
108− return fileName;
109−}
110−
111−QString ScreenGrabber::getFormat() const
112−{
113− //TODO: This should be configurable (perhaps through gsettings?)
114− return QStringLiteral("png");
115−}
plugins/ScreenGrabber/screengrabber.hdeleted−49
@@ -1,49 +0,0 @@
1−/*
2− * Copyright (C) 2014-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−#ifndef SNAPSHOTTER_H
18−#define SNAPSHOTTER_H
19−
20−#include <QObject>
21−#include <QString>
22−#include <QtConcurrent>
23−
24−class ScreenGrabber: public QObject
25−{
26− Q_OBJECT
27−
28−public:
29− explicit ScreenGrabber(QObject *parent = 0);
30− ~ScreenGrabber() = default;
31−
32−public Q_SLOTS:
33− void captureAndSave(int angle = 0);
34−
35−Q_SIGNALS:
36− void screenshotSaved(const QString &filename);
37−
38−private Q_SLOTS:
39− void onScreenshotSaved();
40−
41−private:
42− QString makeFileName() const;
43− QString getFormat() const;
44− QString fileNamePrefix;
45− int screenshotQuality = -1; // default quality for the format
46− QFutureWatcher<QString> m_watcher;
47−};
48−
49−#endif
plugins/ScreenshotDirectory/CMakeLists.txtnew file+9
@@ -0,0 +1,9 @@
1+set(PLUGIN_SOURCES
2+ ScreenshotDirectory.cpp
3+ plugin.cpp
4+)
5+
6+add_library(ScreenshotDirectory-qml MODULE ${PLUGIN_SOURCES})
7+qt5_use_modules(ScreenshotDirectory-qml Qml Gui Quick)
8+
9+add_unity8_plugin(ScreenshotDirectory 0.1 ScreenshotDirectory TARGETS ScreenshotDirectory-qml)
plugins/ScreenGrabber/ScreenGrabber.qmltypes → plugins/ScreenshotDirectory/ScreenGrabber.qmltypesrenamed

The content is the same.

plugins/ScreenshotDirectory/ScreenshotDirectory.cppnew file+64
@@ -0,0 +1,64 @@
1+/*
2+ * Copyright (C) 2014-2016 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+#include "ScreenshotDirectory.h"
18+
19+#include <QDir>
20+#include <QDateTime>
21+#include <QStandardPaths>
22+#include <QTemporaryDir>
23+
24+#include <QDebug>
25+
26+ScreenshotDirectory::ScreenshotDirectory(QObject *parent)
27+ : QObject(parent)
28+{
29+ QDir screenshotsDir;
30+ if (qEnvironmentVariableIsSet("UNITY_TESTING")) {
31+ QTemporaryDir tDir;
32+ tDir.setAutoRemove(false);
33+ screenshotsDir = tDir.path();
34+ } else {
35+ screenshotsDir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
36+ }
37+ screenshotsDir.mkpath(QStringLiteral("Screenshots"));
38+ screenshotsDir.cd(QStringLiteral("Screenshots"));
39+ if (screenshotsDir.exists()) {
40+ m_fileNamePrefix = screenshotsDir.absolutePath();
41+ m_fileNamePrefix.append("/screenshot");
42+ } else {
43+ qWarning() << "ScreenshotDirectory: failed to create directory at:" << screenshotsDir.absolutePath();
44+ }
45+}
46+
47+QString ScreenshotDirectory::makeFileName() const
48+{
49+ if (m_fileNamePrefix.isEmpty()) {
50+ return QString();
51+ }
52+
53+ QString fileName(m_fileNamePrefix);
54+ fileName.append(QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd_hhmmsszzz")));
55+ fileName.append(".");
56+ fileName.append(format());
57+ return fileName;
58+}
59+
60+QString ScreenshotDirectory::format() const
61+{
62+ //TODO: This should be configurable (perhaps through gsettings?)
63+ return QStringLiteral("png");
64+}
tests/plugins/ScreenGrabber/grabber.qml → plugins/ScreenshotDirectory/ScreenshotDirectory.hrenamed+21−13
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2015 Canonical Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -14,18 +14,26 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−import QtQuick 2.4
17+#ifndef SCREENSHOTDIRECTORY_H
18−import ScreenGrabber 0.1
18+#define SCREENSHOTDIRECTORY_H
19
19
20−Rectangle {
20+#include <QObject>
21− property var grabber: screenGrabber
21+#include <QString>
22
22
23− width: 101 // width intentionally bigger than height to test rotation
23+class ScreenshotDirectory: public QObject
24− height: 100
24+{
25− color: "green"
25+ Q_OBJECT
26
26
27− ScreenGrabber {
27+public:
28− id: screenGrabber
28+ explicit ScreenshotDirectory(QObject *parent = 0);
29− objectName: "screenGrabber"
29+ ~ScreenshotDirectory() = default;
30+
31+public Q_SLOTS:
32+ QString makeFileName() const;
33+
34+private:
35+ QString format() const;
36+ QString m_fileNamePrefix;
30− }
37+};
31−}
38+
39+#endif // SCREENSHOTDIRECTORY_H
plugins/ScreenGrabber/plugin.cpp → plugins/ScreenshotDirectory/plugin.cpprenamed+5−7
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014,2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -12,17 +12,15 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
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/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
17 */
15 */
18
16
19#include "plugin.h"
17#include "plugin.h"
20−#include "screengrabber.h"
18+#include "ScreenshotDirectory.h"
21
19
22#include <QtQml/qqml.h>
20#include <QtQml/qqml.h>
23
21
24−void ScreenGrabberPlugin::registerTypes(const char *uri)
22+void ScreenshotDirectoryPlugin::registerTypes(const char *uri)
25{
23{
26− Q_ASSERT(uri == QLatin1String("ScreenGrabber"));
24+ Q_ASSERT(uri == QLatin1String("ScreenshotDirectory"));
27− qmlRegisterType<ScreenGrabber>(uri, 0, 1, "ScreenGrabber");
25+ qmlRegisterType<ScreenshotDirectory>(uri, 0, 1, "ScreenshotDirectory");
28}
26}
plugins/ScreenGrabber/plugin.h → plugins/ScreenshotDirectory/plugin.hrenamed+5−7
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014,2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -12,16 +12,14 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
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/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
17 */
15 */
18
16
19−#ifndef SCREENGRABBER_PLUGIN_H
17+#ifndef SCREENSHOTDIRECTORY_PLUGIN_H
20−#define SCREENGRABBER_PLUGIN_H
18+#define SCREENSHOTDIRECTORY_PLUGIN_H
21
19
22#include <QtQml/QQmlExtensionPlugin>
20#include <QtQml/QQmlExtensionPlugin>
23
21
24−class ScreenGrabberPlugin : public QQmlExtensionPlugin
22+class ScreenshotDirectoryPlugin : public QQmlExtensionPlugin
25{
23{
26 Q_OBJECT
24 Q_OBJECT
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
@@ -30,4 +28,4 @@ public:
30 void registerTypes(const char *uri) override;
28 void registerTypes(const char *uri) override;
31};
29};
32
30
33−#endif // SCREENGRABBER_PLUGIN_H
31+#endif // SCREENSHOTDIRECTORY_PLUGIN_H
plugins/ScreenshotDirectory/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module ScreenshotDirectory
2+plugin ScreenshotDirectory-qml
qml/Components/ScreenGrabber.qml → qml/Components/ItemGrabber.qmlrenamed+27−17
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -15,36 +15,31 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18−import ScreenGrabber 0.1
18+import ScreenshotDirectory 0.1
19−import GlobalShortcut 1.0
20
19
20+/*
21+ Captures an image of the given item and saves it in a screenshots directory.
22+ It also displays a flash visual effect and camera shutter sound, as feedback
23+ to the user to hint that a screenshot was taken.
24+ */
21Rectangle {
25Rectangle {
22 id: root
26 id: root
23 visible: false
27 visible: false
24 color: "white"
28 color: "white"
25− anchors.fill: parent
26 opacity: 0.0
29 opacity: 0.0
27
30
28− // to be set from outside
31+ ScreenshotDirectory {
29− property int rotationAngle: 0
32+ id: screenshotDirectory
30−
31− ScreenGrabber {
32− id: screenGrabber
33 objectName: "screenGrabber"
33 objectName: "screenGrabber"
34 }
34 }
35
35
36− GlobalShortcut {
37− id: screenshotShortcut
38− shortcut: Qt.Key_Print
39− onTriggered: capture()
40− }
41−
42 NotificationAudio {
36 NotificationAudio {
43 id: shutterSound
37 id: shutterSound
44 source: "/system/media/audio/ui/camera_click.ogg"
38 source: "/system/media/audio/ui/camera_click.ogg"
45 }
39 }
46
40
47− function capture() {
41+ function capture(item) {
42+ d.target = item;
48 visible = true;
43 visible = true;
49 shutterSound.stop();
44 shutterSound.stop();
50 shutterSound.play();
45 shutterSound.play();
@@ -62,13 +57,28 @@ Rectangle {
62 }
57 }
63 }
58 }
64
59
60+ QtObject {
61+ id: d
62+ property Item target
63+ }
64+
65 NumberAnimation on opacity {
65 NumberAnimation on opacity {
66 id: fadeOut
66 id: fadeOut
67 from: 1.0
67 from: 1.0
68 to: 0.0
68 to: 0.0
69 onStopped: {
69 onStopped: {
70 if (visible) {
70 if (visible) {
71− screenGrabber.captureAndSave(root.rotationAngle);
71+ d.target.grabToImage(function(result)
72+ {
73+ var fileName = screenshotDirectory.makeFileName();
74+ if (fileName.length === 0) {
75+ console.warn("ItemGrabber: No fileName to save image to");
76+ } else {
77+ console.log("ItemGrabber: Saving image to " + fileName);
78+ result.saveToFile(fileName);
79+ }
80+ });
81+
72 visible = false;
82 visible = false;
73 }
83 }
74 }
84 }
qml/Components/NotificationAudio.qml+7−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -22,10 +22,14 @@ Item {
22 readonly property var playbackState: priv.audio ? priv.audio.playbackState : 0
22 readonly property var playbackState: priv.audio ? priv.audio.playbackState : 0
23
23
24 function play() {
24 function play() {
25+ if (priv.audio) {
25− priv.audio.play();
26+ priv.audio.play();
27+ }
26 }
28 }
27 function stop() {
29 function stop() {
30+ if (priv.audio) {
28− priv.audio.stop();
31+ priv.audio.stop();
32+ }
29 }
33 }
30
34
31 QtObject {
35 QtObject {
qml/Shell.qml+11−5
@@ -193,7 +193,7 @@ Item {
193 onPowerKeyLongPressed: dialogs.showPowerDialog();
193 onPowerKeyLongPressed: dialogs.showPowerDialog();
194 onVolumeDownTriggered: volumeControl.volumeDown();
194 onVolumeDownTriggered: volumeControl.volumeDown();
195 onVolumeUpTriggered: volumeControl.volumeUp();
195 onVolumeUpTriggered: volumeControl.volumeUp();
196− onScreenshotTriggered: screenGrabber.capture();
196+ onScreenshotTriggered: itemGrabber.capture(shell);
197 }
197 }
198
198
199 GlobalShortcut {
199 GlobalShortcut {
@@ -706,16 +706,22 @@ Item {
706 onShowHome: showHome()
706 onShowHome: showHome()
707 }
707 }
708
708
709− ScreenGrabber {
709+ ItemGrabber {
710− id: screenGrabber
710+ id: itemGrabber
711− rotationAngle: -shell.orientationAngle
711+ anchors.fill: parent
712 z: dialogs.z + 10
712 z: dialogs.z + 10
713+ GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
714+ Connections {
715+ target: applicationsDisplayLoader.item
716+ ignoreUnknownSignals: true
717+ onItemSnapshotRequested: itemGrabber.capture(item)
718+ }
713 }
719 }
714
720
715 Cursor {
721 Cursor {
716 id: cursor
722 id: cursor
717 visible: shell.hasMouse
723 visible: shell.hasMouse
718− z: screenGrabber.z + 1
724+ z: itemGrabber.z + 1
719
725
720 onPushedLeftBoundary: {
726 onPushedLeftBoundary: {
721 if (buttons === Qt.NoButton) {
727 if (buttons === Qt.NoButton) {
qml/Stages/AbstractStage.qml+1
@@ -60,6 +60,7 @@ FocusScope {
60 | Qt.InvertedLandscapeOrientation
60 | Qt.InvertedLandscapeOrientation
61
61
62 signal stageAboutToBeUnloaded
62 signal stageAboutToBeUnloaded
63+ signal itemSnapshotRequested(Item item)
63
64
64 // Shared code for use in stage implementations
65 // Shared code for use in stage implementations
65 GSettings {
66 GSettings {
qml/Stages/DesktopStage.qml+6
@@ -94,6 +94,12 @@ AbstractStage {
94 active: priv.focusedAppDelegate !== null
94 active: priv.focusedAppDelegate !== null
95 }
95 }
96
96
97+ GlobalShortcut {
98+ shortcut: Qt.ControlModifier|Qt.Key_Print
99+ onTriggered: root.itemSnapshotRequested(priv.focusedAppDelegate)
100+ active: priv.focusedAppDelegate !== null
101+ }
102+
97 Connections {
103 Connections {
98 target: root.topLevelSurfaceList
104 target: root.topLevelSurfaceList
99 onCountChanged: {
105 onCountChanged: {
src/ShellApplication.cpp+6
@@ -168,6 +168,9 @@ void ShellApplication::onScreenAdded(QScreen * /*screen*/)
168 // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
168 // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
169 // its backing QPlatformWindow recreated). So lets refocus it.
169 // its backing QPlatformWindow recreated). So lets refocus it.
170 m_shellView->requestActivate();
170 m_shellView->requestActivate();
171+ // QWindow::destroy() is called when it changes between screens. We have to manually make it visible again
172+ // <dandrader> This bug is supposedly fixed in Qt 5.5.1, although I can still reproduce it there. :-/
173+ m_shellView->setVisible(true);
171
174
172 m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
175 m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
173 m_secondaryWindow->setScreen(screens().at(0));
176 m_secondaryWindow->setScreen(screens().at(0));
@@ -194,5 +197,8 @@ void ShellApplication::onScreenAboutToBeRemoved(QScreen *screen)
194 // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
197 // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
195 // its backing QPlatformWindow recreated). So lets refocus it.
198 // its backing QPlatformWindow recreated). So lets refocus it.
196 m_shellView->requestActivate();
199 m_shellView->requestActivate();
200+ // QWindow::destroy() is called when it changes between screens. We have to manually make it visible again
201+ // <dandrader> This bug is supposedly fixed in Qt 5.5.1, although I can still reproduce it there. :-/
202+ m_shellView->setVisible(true);
197 }
203 }
198}
204}
tests/plugins/CMakeLists.txt−1
@@ -3,7 +3,6 @@ add_subdirectory(GlobalShortcut)
3add_subdirectory(Greeter)
3add_subdirectory(Greeter)
4add_subdirectory(IntegratedLightDM)
4add_subdirectory(IntegratedLightDM)
5add_subdirectory(Dash)
5add_subdirectory(Dash)
6−add_subdirectory(ScreenGrabber)
7add_subdirectory(Ubuntu)
6add_subdirectory(Ubuntu)
8add_subdirectory(Unity)
7add_subdirectory(Unity)
9add_subdirectory(Utils)
8add_subdirectory(Utils)
tests/plugins/ScreenGrabber/CMakeLists.txtdeleted−14
@@ -1,14 +0,0 @@
1−include_directories(
2− ${CMAKE_SOURCE_DIR}/plugins/ScreenGrabber
3− ${CMAKE_CURRENT_BINARY_DIR}
4− )
5−
6−add_definitions(
7− -DCURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
8− )
9−add_definitions(-DBUILT_PLUGINS_DIR="${CMAKE_BINARY_DIR}/plugins")
10−
11−add_executable(ScreenGrabberTestExec ScreenGrabberTest.cpp ${CMAKE_SOURCE_DIR}/plugins/ScreenGrabber/screengrabber.cpp)
12−qt5_use_modules(ScreenGrabberTestExec Test Quick Concurrent)
13−target_link_libraries(ScreenGrabberTestExec ${Qt5Quick_LIBRARIES} ScreenGrabber-qml)
14−add_unity8_uitest(ScreenGrabber ScreenGrabberTestExec DEPENDS ScreenGrabber-qml)
tests/plugins/ScreenGrabber/ScreenGrabberTest.cppdeleted−77
@@ -1,77 +0,0 @@
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−#include "screengrabber.h"
18−
19−#include <QtTest>
20−#include <QtQuick/QQuickView>
21−#include <QtQuick/QQuickItem>
22−#include <QQmlEngine>
23−
24−class ScreenGrabberTest: public QObject
25−{
26− Q_OBJECT
27−
28−private Q_SLOTS:
29−
30− void initTestCase()
31− {
32− m_view = new QQuickView();
33− m_view->engine()->addImportPath(BUILT_PLUGINS_DIR);
34− m_view->setSource(QUrl::fromLocalFile(CURRENT_SOURCE_DIR "/grabber.qml"));
35− m_grabber = dynamic_cast<ScreenGrabber*>(m_view->rootObject()->property("grabber").value<QObject*>());
36− QVERIFY(m_grabber);
37− m_view->show();
38− QTest::qWaitForWindowExposed(m_view);
39− }
40−
41− void cleanupTestCase()
42− {
43− delete m_view;
44− m_view = nullptr;
45− QTRY_COMPARE(QThreadPool::globalInstance()->activeThreadCount(), 0);
46− }
47−
48− void testGrabScreenshot()
49− {
50− QSignalSpy grabberSpy(m_grabber, &ScreenGrabber::screenshotSaved);
51− m_grabber->captureAndSave();
52− QTRY_VERIFY(grabberSpy.count() == 1);
53− const QVariantList args = grabberSpy.takeFirst();
54− QVERIFY(args.count() == 1); // verify we got a non-empty filename where the screenshot has been saved
55− QVERIFY(!args.first().toString().isEmpty());
56− }
57−
58− void testRotatedScreenshot()
59− {
60− QSignalSpy grabberSpy(m_grabber, &ScreenGrabber::screenshotSaved);
61− m_grabber->captureAndSave(90); // rotate by 90°
62− QTRY_VERIFY(grabberSpy.count() == 1);
63− const QVariantList args = grabberSpy.takeFirst();
64− const QString filename = args.first().toString();
65− QVERIFY(!filename.isEmpty());
66− QImage img(filename);
67− QVERIFY(img.height() > img.width()); // verify that the image got rotated by 90° (height > width)
68− }
69−
70−private:
71− QQuickView *m_view;
72− ScreenGrabber *m_grabber = nullptr;
73−};
74−
75−QTEST_MAIN(ScreenGrabberTest)
76−
77−#include "ScreenGrabberTest.moc"