on xenial help sign in
Merge from trunk
commitf5ee18441b0a1761b7337c3c88e120090e811950 authorMichael Terry <michael.terry@canonical.com> dateWed 4 May 2016, 16:11 (10 years ago) parentc08d1bb491724e
47 files changed+355−513
debian/changelog+23 debian/unity8-private.install+1−1 plugins/CMakeLists.txt+1−1 plugins/ScreenGrabber/CMakeLists.txt−13 plugins/ScreenGrabber/qmldir−3 plugins/ScreenGrabber/screengrabber.cpp−115 plugins/ScreenGrabber/screengrabber.h−49 plugins/ScreenshotDirectory/CMakeLists.txt+9 plugins/ScreenGrabber/ScreenGrabber.qmltypes → plugins/ScreenshotDirectory/ScreenGrabber.qmltypes plugins/ScreenshotDirectory/ScreenshotDirectory.cpp+64 plugins/Utils/windowscreenshotprovider.h → plugins/ScreenshotDirectory/ScreenshotDirectory.h+17−9 plugins/ScreenGrabber/plugin.cpp → plugins/ScreenshotDirectory/plugin.cpp+5−7 plugins/ScreenGrabber/plugin.h → plugins/ScreenshotDirectory/plugin.h+5−7 plugins/ScreenshotDirectory/qmldir+2 plugins/Utils/CMakeLists.txt−1 plugins/Utils/plugin.cpp−8 plugins/Utils/plugin.h−1 plugins/Utils/windowscreenshotprovider.cpp−59 po/unity8.pot+4−4 qml/Components/ScreenGrabber.qml → qml/Components/ItemGrabber.qml+27−17 qml/Components/WindowScreenshot.qml → qml/Components/ItemSnapshot.qml+13−3 qml/Components/NotificationAudio.qml+7−3 qml/Components/VirtualTouchPad.qml+1−1 qml/Dash/GenericScopeView.qml+5 qml/DisabledScreenNotice.qml+4−4 qml/OrientedShell.qml+7−7 qml/Panel/IndicatorsMenu.qml+20−10 qml/Rotation/HalfLoopRotationAnimation.qml+2−1 qml/Rotation/ImmediateRotationAction.qml+11−22 qml/Rotation/NinetyRotationAnimation.qml+14−16 qml/Rotation/RotationStates.qml+25−5 qml/Rotation/UpdateShellTransformations.qml+42 qml/Shell.qml+11−5 qml/Stages/AbstractStage.qml+8−7 qml/Stages/DesktopStage.qml+7 qml/Stages/PhoneStage.qml+2 qml/Stages/ShimStage.qml−1 qml/Stages/TabletStage.qml+3 src/SecondaryWindow.cpp+9 src/ShellApplication.cpp+6 tests/mocks/Utils/CMakeLists.txt−1 tests/mocks/Utils/plugin.cpp−8 tests/mocks/Utils/plugin.h−1 tests/plugins/CMakeLists.txt−1 tests/plugins/ScreenGrabber/CMakeLists.txt−14 tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp−77 tests/plugins/ScreenGrabber/grabber.qml−31
debian/changelog+23
@@ -1,3 +1,26 @@
1+unity8 (8.12+16.04.20160429.2-0ubuntu1) xenial; urgency=medium
2+
3+ [ CI Train Bot ]
4+ * Resync trunk.
5+
6+ [ Daniel d'Andrada ]
7+ * Ensure shell transformations use bindings as OrientedShell can get
8+ resized
9+ * Make shell rotation animation work on multimonitor scenarios.
10+ * Refactor screenshotting code and make it work in multimonitor
11+ scenarios
12+
13+ [ Gerry Boland, Nick Dedekind ]
14+ * Indicators: set menu height binding while fully open/closed, fixes
15+ dynamic grid unit bug.
16+
17+ [ Michael Zanetti ]
18+ * Call the dash sizing hack when units.gu changes
19+ * Temporary means to override GUs on the internal screen
20+ * reduce some paint layers.
21+
22+ -- Michał Sawicz <michal.sawicz@canonical.com> Fri, 29 Apr 2016 20:07:37 +0000
23+
124unity8 (8.12+16.04.20160427.3-0ubuntu1) xenial; urgency=medium
225
326 [ Albert Astals Cid ]
debian/unity8-private.install+1−1
@@ -8,7 +8,7 @@ usr/lib/*/unity8/qml/Greeter
88usr/lib/*/unity8/qml/IntegratedLightDM
99usr/lib/*/unity8/qml/Lights
1010usr/lib/*/unity8/qml/Powerd
11−usr/lib/*/unity8/qml/ScreenGrabber
11+usr/lib/*/unity8/qml/ScreenshotDirectory
1212usr/lib/*/unity8/qml/SessionBroadcast
1313usr/lib/*/unity8/qml/Ubuntu
1414usr/lib/*/unity8/qml/Unity
plugins/CMakeLists.txt+1−1
@@ -19,8 +19,8 @@ add_subdirectory(IntegratedLightDM)
1919add_subdirectory(Lights)
2020add_subdirectory(Dash)
2121add_subdirectory(Powerd)
22+add_subdirectory(ScreenshotDirectory)
2223add_subdirectory(SessionBroadcast)
23−add_subdirectory(ScreenGrabber)
2424add_subdirectory(Ubuntu)
2525add_subdirectory(UInput)
2626add_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+}
plugins/Utils/windowscreenshotprovider.h → plugins/ScreenshotDirectory/ScreenshotDirectory.hrenamed+17−9
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -14,18 +14,26 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#ifndef WINDOW_SCREENSHOT_PROVIDER_H_
18−#define WINDOW_SCREENSHOT_PROVIDER_H_
17+#ifndef SCREENSHOTDIRECTORY_H
18+#define SCREENSHOTDIRECTORY_H
1919
20−#include <QQuickImageProvider>
20+#include <QObject>
21+#include <QString>
2122
22−class WindowScreenshotProvider : public QQuickImageProvider
23+class ScreenshotDirectory: public QObject
2324{
25+ Q_OBJECT
26+
2427public:
25− WindowScreenshotProvider();
28+ explicit ScreenshotDirectory(QObject *parent = 0);
29+ ~ScreenshotDirectory() = default;
30+
31+public Q_SLOTS:
32+ QString makeFileName() const;
2633
27− // id is ignored for now
28− QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
34+private:
35+ QString format() const;
36+ QString m_fileNamePrefix;
2937};
3038
31−#endif // WINDOW_SCREENSHOT_PROVIDER_H_
39+#endif // SCREENSHOTDIRECTORY_H
plugins/ScreenGrabber/plugin.cpp → plugins/ScreenshotDirectory/plugin.cpprenamed+5−7
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014,2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -12,17 +12,15 @@
1212 *
1313 * You should have received a copy of the GNU General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
1715 */
1816
1917#include "plugin.h"
20−#include "screengrabber.h"
18+#include "ScreenshotDirectory.h"
2119
2220#include <QtQml/qqml.h>
2321
24−void ScreenGrabberPlugin::registerTypes(const char *uri)
22+void ScreenshotDirectoryPlugin::registerTypes(const char *uri)
2523{
26− Q_ASSERT(uri == QLatin1String("ScreenGrabber"));
27− qmlRegisterType<ScreenGrabber>(uri, 0, 1, "ScreenGrabber");
24+ Q_ASSERT(uri == QLatin1String("ScreenshotDirectory"));
25+ qmlRegisterType<ScreenshotDirectory>(uri, 0, 1, "ScreenshotDirectory");
2826}
plugins/ScreenGrabber/plugin.h → plugins/ScreenshotDirectory/plugin.hrenamed+5−7
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014,2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -12,16 +12,14 @@
1212 *
1313 * You should have received a copy of the GNU General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Alberto Aguirre <alberto.aguirre@canonical.com>
1715 */
1816
19−#ifndef SCREENGRABBER_PLUGIN_H
20−#define SCREENGRABBER_PLUGIN_H
17+#ifndef SCREENSHOTDIRECTORY_PLUGIN_H
18+#define SCREENSHOTDIRECTORY_PLUGIN_H
2119
2220#include <QtQml/QQmlExtensionPlugin>
2321
24−class ScreenGrabberPlugin : public QQmlExtensionPlugin
22+class ScreenshotDirectoryPlugin : public QQmlExtensionPlugin
2523{
2624 Q_OBJECT
2725 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
@@ -30,4 +28,4 @@ public:
3028 void registerTypes(const char *uri) override;
3129};
3230
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
plugins/Utils/CMakeLists.txt−1
@@ -18,7 +18,6 @@ set(QMLPLUGIN_SRC
1818 Timer.cpp
1919 unitymenumodelpaths.cpp
2020 windowinputfilter.cpp
21− windowscreenshotprovider.cpp
2221 easingcurve.cpp
2322 windowstatestorage.cpp
2423 timezoneFormatter.cpp
plugins/Utils/plugin.cpp−8
@@ -31,7 +31,6 @@
3131#include "unitysortfilterproxymodelqml.h"
3232#include "unitymenumodelpaths.h"
3333#include "windowinputfilter.h"
34−#include "windowscreenshotprovider.h"
3534#include "windowstatestorage.h"
3635#include "constants.h"
3736#include "timezoneFormatter.h"
@@ -82,10 +81,3 @@ void UtilsPlugin::registerTypes(const char *uri)
8281 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
8382 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
8483}
85−
86−void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
87−{
88− QQmlExtensionPlugin::initializeEngine(engine, uri);
89−
90− engine->addImageProvider(QStringLiteral("window"), new WindowScreenshotProvider);
91−}
plugins/Utils/plugin.h−1
@@ -29,7 +29,6 @@ class UtilsPlugin : public QQmlExtensionPlugin
2929
3030public:
3131 void registerTypes(const char *uri) override;
32− void initializeEngine(QQmlEngine *engine, const char *uri) override;
3332};
3433
3534#endif
plugins/Utils/windowscreenshotprovider.cppdeleted−59
@@ -1,59 +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 "windowscreenshotprovider.h"
18−
19−#include <QGuiApplication>
20−#include <QQuickWindow>
21−
22−WindowScreenshotProvider::WindowScreenshotProvider()
23− : QQuickImageProvider(QQmlImageProviderBase::Image, 0)
24−{
25−}
26−
27−// A very simple implementation where we assume that there's only one window and that it's a
28−// QQuickWindow. Thus the id parameter is irrelevant.
29−//
30−// Idea: Make the id contain the objectName of the QQuickWindow once we care about a multi-display
31−// compositor?
32−// Strictly speaking that could be the actual QWindow::winId(), but that's mostly a
33−// meaningless arbitrary number.
34−QImage WindowScreenshotProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
35−{
36− Q_UNUSED(id);
37− Q_UNUSED(requestedSize);
38−
39− QWindowList windows = QGuiApplication::topLevelWindows();
40−
41− if (windows.count() != 1) {
42− size->rwidth() = 0;
43− size->rheight() = 0;
44− return QImage();
45− }
46−
47− QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(windows[0]);
48−
49− if (!quickWindow) {
50− size->rwidth() = 0;
51− size->rheight() = 0;
52− return QImage();
53− }
54−
55− QImage image = quickWindow->grabWindow();
56− size->rwidth() = image.width();
57− size->rheight() = image.height();
58− return image;
59−}
po/unity8.pot+4−4
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2016-04-27 15:01+0000\n"
11+"POT-Creation-Date: 2016-04-29 20:07+0000\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -186,15 +186,15 @@ msgstr ""
186186msgid "Reset"
187187msgstr ""
188188
189−#: qml/Dash/GenericScopeView.qml:570 qml/Dash/GenericScopeView.qml:755
189+#: qml/Dash/GenericScopeView.qml:575 qml/Dash/GenericScopeView.qml:760
190190msgid "Show less"
191191msgstr ""
192192
193−#: qml/Dash/GenericScopeView.qml:570
193+#: qml/Dash/GenericScopeView.qml:575
194194msgid "Show all"
195195msgstr ""
196196
197−#: qml/Dash/GenericScopeView.qml:627
197+#: qml/Dash/GenericScopeView.qml:632
198198msgctxt "Label: Hint for dash search line edit"
199199msgid "Search"
200200msgstr ""
qml/Components/ScreenGrabber.qml → qml/Components/ItemGrabber.qmlrenamed+27−17
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -15,36 +15,31 @@
1515 */
1616
1717import QtQuick 2.4
18−import ScreenGrabber 0.1
19−import GlobalShortcut 1.0
18+import ScreenshotDirectory 0.1
2019
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+ */
2125Rectangle {
2226 id: root
2327 visible: false
2428 color: "white"
25− anchors.fill: parent
2629 opacity: 0.0
2730
28− // to be set from outside
29− property int rotationAngle: 0
30−
31− ScreenGrabber {
32− id: screenGrabber
31+ ScreenshotDirectory {
32+ id: screenshotDirectory
3333 objectName: "screenGrabber"
3434 }
3535
36− GlobalShortcut {
37− id: screenshotShortcut
38− shortcut: Qt.Key_Print
39− onTriggered: capture()
40− }
41−
4236 NotificationAudio {
4337 id: shutterSound
4438 source: "/system/media/audio/ui/camera_click.ogg"
4539 }
4640
47− function capture() {
41+ function capture(item) {
42+ d.target = item;
4843 visible = true;
4944 shutterSound.stop();
5045 shutterSound.play();
@@ -62,13 +57,28 @@ Rectangle {
6257 }
6358 }
6459
60+ QtObject {
61+ id: d
62+ property Item target
63+ }
64+
6565 NumberAnimation on opacity {
6666 id: fadeOut
6767 from: 1.0
6868 to: 0.0
6969 onStopped: {
7070 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+
7282 visible = false;
7383 }
7484 }
qml/Components/WindowScreenshot.qml → qml/Components/ItemSnapshot.qmlrenamed+13−3
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -19,9 +19,19 @@ import QtQuick 2.4
1919Item {
2020 id: root
2121
22+ property Item target
23+
24+ property bool ready: image.status === Image.Ready
25+
2226 function take() {
23− var timeNow = new Date().getTime();
24− image.source = "image://window/" + timeNow;
27+ if (!target) {
28+ console.warn("ItemSnapshot.take(): no target set");
29+ return;
30+ }
31+
32+ target.grabToImage(function(result) {
33+ image.source = result.url;
34+ });
2535 }
2636
2737 // Unload the image to free up memory
qml/Components/NotificationAudio.qml+7−3
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -23,10 +23,14 @@ Item {
2323 readonly property var playbackState: priv.audio ? priv.audio.playbackState : 0
2424
2525 function play() {
26− priv.audio.play();
26+ if (priv.audio) {
27+ priv.audio.play();
28+ }
2729 }
2830 function stop() {
29− priv.audio.stop();
31+ if (priv.audio) {
32+ priv.audio.stop();
33+ }
3034 }
3135
3236 QtObject {
qml/Components/VirtualTouchPad.qml+1−1
@@ -31,7 +31,7 @@ Item {
3131 anchors.fill: parent
3232
3333 // FIXME: Once we have Qt DPR support, this should be Qt.styleHints.startDragDistance
34− readonly property int clickThreshold: units.gu(1.5)
34+ readonly property int clickThreshold: internalGu * 1.5
3535 property bool isClick: false
3636 property bool isDoubleClick: false
3737 property bool isDrag: false
qml/Dash/GenericScopeView.qml+5
@@ -360,6 +360,11 @@ FocusScope {
360360 scopeView.enableHeightBehaviorOnNextCreation = item.enableHeightBehaviorOnNextCreation;
361361 }
362362 }
363+ // FIXME: directly connecting to onUnitsChanged cause a compile error:
364+ // Cannot assign to non-existent property "onUnitsChanged"
365+ // Until the units object is reworked to properly do all we need, let's go through a intermediate property
366+ property int pxpgu: units.gu(1);
367+ onPxpguChanged: clickScopeSizingHacks();
363368
364369 function clickScopeSizingHacks() {
365370 if (scope && scope.id === "clickscope" &&
qml/DisabledScreenNotice.qml+4−4
@@ -96,19 +96,19 @@ Item {
9696
9797 Column {
9898 anchors.centerIn: parent
99− width: parent.width - units.gu(8)
100− spacing: units.gu(4)
99+ width: parent.width - (internalGu * 8)
100+ spacing: internalGu * 4
101101
102102 Label {
103103 id: text
104104 text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.")
105105 color: "white"
106106 width: parent.width
107− fontSize: "large"
107+ font.pixelSize: 2.5 * internalGu
108108 wrapMode: Text.Wrap
109109 }
110110 Icon {
111− height: units.gu(8)
111+ height: internalGu * 8
112112 width: height
113113 name: "input-touchpad-symbolic"
114114 color: "white"
qml/OrientedShell.qml+7−7
@@ -26,9 +26,8 @@ import "Rotation"
2626// Workaround https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473471
2727import Ubuntu.Components 1.3
2828
29−Rectangle {
29+Item {
3030 id: root
31− color: "black"
3231
3332 implicitWidth: units.gu(40)
3433 implicitHeight: units.gu(71)
@@ -241,7 +240,7 @@ Rectangle {
241240 orientedShell: root
242241 shell: shell
243242 shellCover: shellCover
244− windowScreenshot: windowScreenshot
243+ shellSnapshot: shellSnapshot
245244 }
246245
247246 Shell {
@@ -291,8 +290,9 @@ Rectangle {
291290 visible: false
292291 }
293292
294− WindowScreenshot {
295− id: windowScreenshot
293+ ItemSnapshot {
294+ id: shellSnapshot
295+ target: shell
296296 visible: false
297297 width: root.width
298298 height: root.height
@@ -302,9 +302,9 @@ Rectangle {
302302 property real transformOriginY
303303
304304 transform: Rotation {
305− origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
305+ origin.x: shellSnapshot.transformOriginX; origin.y: shellSnapshot.transformOriginY;
306306 axis { x: 0; y: 0; z: 1 }
307− angle: windowScreenshot.transformRotationAngle
307+ angle: shellSnapshot.transformRotationAngle
308308 }
309309 }
310310}
qml/Panel/IndicatorsMenu.qml+20−10
@@ -43,18 +43,28 @@ Showable {
4343
4444 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
4545 // use its own values. Need to ask design about this.
46− showAnimation: StandardAnimation {
47− property: "height"
48− to: openedHeight
49− duration: UbuntuAnimation.BriskDuration
50− easing.type: Easing.OutCubic
46+ showAnimation: SequentialAnimation {
47+ StandardAnimation {
48+ target: root
49+ property: "height"
50+ to: openedHeight
51+ duration: UbuntuAnimation.BriskDuration
52+ easing.type: Easing.OutCubic
53+ }
54+ // set binding in case units.gu changes while menu open, so height correctly adjusted to fit
55+ ScriptAction { script: root.height = Qt.binding( function(){ return root.openedHeight; } ) }
5156 }
5257
53− hideAnimation: StandardAnimation {
54− property: "height"
55− to: minimizedPanelHeight
56− duration: UbuntuAnimation.BriskDuration
57− easing.type: Easing.OutCubic
58+ hideAnimation: SequentialAnimation {
59+ StandardAnimation {
60+ target: root
61+ property: "height"
62+ to: minimizedPanelHeight
63+ duration: UbuntuAnimation.BriskDuration
64+ easing.type: Easing.OutCubic
65+ }
66+ // set binding in case units.gu changes while menu closed, so menu adjusts to fit
67+ ScriptAction { script: root.height = Qt.binding( function(){ return root.minimizedPanelHeight; } ) }
5868 }
5969
6070 height: minimizedPanelHeight
qml/Rotation/HalfLoopRotationAnimation.qml+2−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -42,5 +42,6 @@ SequentialAnimation {
4242 from: root.fromAngle; to: root.toAngle
4343 duration: rotationDuration; easing.type: rotationEasing
4444 }
45+ UpdateShellTransformations { info: root.info; shell: root.shell }
4546 ScriptAction { script: { info.transitioning = false; } }
4647}
qml/Rotation/ImmediateRotationAction.qml+11−22
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -16,30 +16,19 @@
1616
1717import QtQuick 2.4
1818
19−ScriptAction {
19+SequentialAnimation {
20+ id: root
2021 property var info
2122 property var shell
2223
23− script: {
24− info.transitioning = true;
25− shell.orientationAngle = info.requestedOrientationAngle;
26− shell.transformRotationAngle = info.requestedOrientationAngle;
24+ ScriptAction { script: {
25+ root.info.transitioning = true;
26+ } }
2727
28− // Making bindings as orientedShell's dimensions might wiggle during startup.
29− if (info.requestedOrientationAngle === 90 || info.requestedOrientationAngle === 270) {
30− shell.width = Qt.binding(function() { return orientedShell.height; });
31− shell.height = Qt.binding(function() { return orientedShell.width; });
32− } else {
33− shell.width = Qt.binding(function() { return orientedShell.width; });
34− shell.height = Qt.binding(function() { return orientedShell.height; });
35− }
28+ UpdateShellTransformations { info: root.info; shell: root.shell }
3629
37− shell.x = Qt.binding(function() { return (orientedShell.width - shell.width) / 2; });
38− shell.y = Qt.binding(function() { return (orientedShell.height - shell.height) / 2; });
39− shell.transformOriginX = Qt.binding(function() { return shell.width / 2; });
40− shell.transformOriginY = Qt.binding(function() { return shell.height / 2; });
41−
42− shell.updateFocusedAppOrientation();
43− info.transitioning = false;
44− }
30+ ScriptAction { script: {
31+ root.shell.updateFocusedAppOrientation();
32+ root.info.transitioning = false;
33+ } }
4534}
qml/Rotation/NinetyRotationAnimation.qml+14−16
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -30,8 +30,7 @@ SequentialAnimation {
3030
3131 ScriptAction { script: {
3232 info.transitioning = true;
33− windowScreenshot.take();
34− windowScreenshot.visible = true;
33+
3534 shell.orientationAngle = root.toAngle;
3635 shell.x = 0;
3736 shell.width = flipShellDimensions ? orientedShell.height : orientedShell.width;
@@ -41,12 +40,10 @@ SequentialAnimation {
4140 shell.updateFocusedAppOrientation();
4241 shellCover.visible = true;
4342
44− windowScreenshot.transformOriginX = orientedShell.width / 2;
45− if (fromAngle == 180 || fromAngle == 270) {
46− windowScreenshot.transformOriginY = orientedShell.height - (orientedShell.width / 2);
47− } else {
48− windowScreenshot.transformOriginY = orientedShell.width / 2;
49− }
43+ shellSnapshot.transformOriginX = shell.transformOriginX;
44+ shellSnapshot.transformOriginY = shell.transformOriginY;
45+ shellSnapshot.transformRotationAngle = shell.transformRotationAngle;
46+ shellSnapshot.visible = true;
5047 } }
5148 ParallelAnimation {
5249 NumberAnimation {
@@ -66,24 +63,25 @@ SequentialAnimation {
6663 }
6764
6865 NumberAnimation {
69− target: windowScreenshot; property: "opacity"; from: 1; to: 0;
66+ target: shellSnapshot; property: "opacity"; from: 1; to: 0;
7067 duration: rotationDuration; easing.type: rotationEasing
7168 }
7269 RotationAnimation {
73− target: windowScreenshot; property: "transformRotationAngle";
74− from: 0; to: root.toAngle - root.fromAngle
70+ target: shellSnapshot; property: "transformRotationAngle";
71+ from: root.fromAngle; to: root.toAngle
7572 direction: RotationAnimation.Shortest
7673 duration: rotationDuration; easing.type: rotationEasing
7774 }
7875 NumberAnimation {
79− target: windowScreenshot; property: "y"
80− from: 0; to: root.toY - root.fromY
76+ target: shellSnapshot; property: "y"
77+ from: root.fromY; to: root.toY
8178 duration: rotationDuration; easing.type: rotationEasing
8279 }
8380 }
81+ UpdateShellTransformations { info: root.info; shell: root.shell }
8482 ScriptAction { script: {
85− windowScreenshot.visible = false;
86− windowScreenshot.discard();
83+ shellSnapshot.visible = false;
84+ shellSnapshot.discard();
8785 shellCover.visible = false;
8886 info.transitioning = false;
8987 } }
qml/Rotation/RotationStates.qml+25−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015,2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ StateGroup {
3030 property Item orientedShell
3131 property Item shell
3232 property Item shellCover
33− property Item windowScreenshot
33+ property Item shellSnapshot
3434
3535 property int rotationDuration: 450
3636 property int rotationEasing: Easing.InOutCubic
@@ -88,12 +88,32 @@ StateGroup {
8888 }
8989
9090 var requestedState = d.requestedOrientationAngle.toString();
91− if (requestedState !== root.state) {
92− d.resolveAnimationType();
93− root.state = requestedState;
91+ if (requestedState === root.state) {
92+ return;
93+ }
94+
95+ d.resolveAnimationType();
96+
97+ var angleDiff = Math.abs(root.shell.orientationAngle - d.requestedOrientationAngle);
98+ var isNinetyRotationAnimation = angleDiff == 90 || angleDiff == 270;
99+ var needsShellSnapshot = d.animationType == d.fullAnimation && isNinetyRotationAnimation;
100+
101+ if (needsShellSnapshot && !shellSnapshotReady) {
102+ root.shellSnapshot.take();
103+ // try again once we have a shell snapshot ready for use. Snapshot taking is async.
104+ return;
105+ }
106+
107+ if (!needsShellSnapshot && shellSnapshotReady) {
108+ root.shellSnapshot.discard();
94109 }
110+
111+ root.state = requestedState;
95112 }
96113
114+ property bool shellSnapshotReady: root.shellSnapshot && root.shellSnapshot.ready
115+ onShellSnapshotReadyChanged: tryUpdateState();
116+
97117 property Connections shellConnections: Connections {
98118 target: root.orientedShell
99119 onOrientationChangesEnabledChanged: {
qml/Rotation/UpdateShellTransformations.qmlnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 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+import QtQuick 2.4
18+
19+ScriptAction {
20+ property var info
21+ property var shell
22+
23+ script: {
24+ shell.orientationAngle = info.requestedOrientationAngle;
25+ shell.transformRotationAngle = info.requestedOrientationAngle;
26+
27+ // They must all be bindings as orientedShell's size can change
28+
29+ if (info.requestedOrientationAngle === 90 || info.requestedOrientationAngle === 270) {
30+ shell.width = Qt.binding(function() { return orientedShell.height; });
31+ shell.height = Qt.binding(function() { return orientedShell.width; });
32+ } else {
33+ shell.width = Qt.binding(function() { return orientedShell.width; });
34+ shell.height = Qt.binding(function() { return orientedShell.height; });
35+ }
36+
37+ shell.x = Qt.binding(function() { return (orientedShell.width - shell.width) / 2; });
38+ shell.y = Qt.binding(function() { return (orientedShell.height - shell.height) / 2; });
39+ shell.transformOriginX = Qt.binding(function() { return shell.width / 2; });
40+ shell.transformOriginY = Qt.binding(function() { return shell.height / 2; });
41+ }
42+}
qml/Shell.qml+11−5
@@ -193,7 +193,7 @@ Item {
193193 onPowerKeyLongPressed: dialogs.showPowerDialog();
194194 onVolumeDownTriggered: volumeControl.volumeDown();
195195 onVolumeUpTriggered: volumeControl.volumeUp();
196− onScreenshotTriggered: screenGrabber.capture();
196+ onScreenshotTriggered: itemGrabber.capture(shell);
197197 }
198198
199199 GlobalShortcut {
@@ -705,16 +705,22 @@ Item {
705705 onShowHome: showHome()
706706 }
707707
708− ScreenGrabber {
709− id: screenGrabber
710− rotationAngle: -shell.orientationAngle
708+ ItemGrabber {
709+ id: itemGrabber
710+ anchors.fill: parent
711711 z: dialogs.z + 10
712+ GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
713+ Connections {
714+ target: applicationsDisplayLoader.item
715+ ignoreUnknownSignals: true
716+ onItemSnapshotRequested: itemGrabber.capture(item)
717+ }
712718 }
713719
714720 Cursor {
715721 id: cursor
716722 visible: shell.hasMouse
717− z: screenGrabber.z + 1
723+ z: itemGrabber.z + 1
718724
719725 onPushedLeftBoundary: {
720726 if (buttons === Qt.NoButton) {
qml/Stages/AbstractStage.qml+8−7
@@ -21,13 +21,6 @@ import GSettings 1.0
2121FocusScope {
2222 id: root
2323
24− property alias color: backRect.color
25− Rectangle {
26− id: backRect
27− color: "#060606"
28− anchors.fill: parent
29− }
30−
3124 // Controls to be set from outside
3225 property QtObject applicationManager
3326 property QtObject topLevelSurfaceList
@@ -49,6 +42,7 @@ FocusScope {
4942 property bool suspended
5043 // A Stage should paint a wallpaper etc over its full size but not use the margins for window placement
5144 property int leftMargin: 0
45+ property alias paintBackground: background.visible
5246
5347 // To be read from outside
5448 property var mainApp: null
@@ -60,6 +54,7 @@ FocusScope {
6054 | Qt.InvertedLandscapeOrientation
6155
6256 signal stageAboutToBeUnloaded
57+ signal itemSnapshotRequested(Item item)
6358
6459 // Shared code for use in stage implementations
6560 GSettings {
@@ -76,4 +71,10 @@ FocusScope {
7671 }
7772 return false;
7873 }
74+
75+ Rectangle {
76+ id: background
77+ color: "#060606"
78+ anchors.fill: parent
79+ }
7980}
qml/Stages/DesktopStage.qml+7
@@ -26,6 +26,7 @@ import GlobalShortcut 1.0
2626AbstractStage {
2727 id: root
2828 anchors.fill: parent
29+ paintBackground: false
2930
3031 // functions to be called from outside
3132 function updateFocusedAppOrientation() { /* TODO */ }
@@ -94,6 +95,12 @@ AbstractStage {
9495 active: priv.focusedAppDelegate !== null
9596 }
9697
98+ GlobalShortcut {
99+ shortcut: Qt.AltModifier|Qt.Key_Print
100+ onTriggered: root.itemSnapshotRequested(priv.focusedAppDelegate)
101+ active: priv.focusedAppDelegate !== null
102+ }
103+
97104 Connections {
98105 target: root.topLevelSurfaceList
99106 onCountChanged: {
qml/Stages/PhoneStage.qml+2
@@ -31,6 +31,8 @@ AbstractStage {
3131 property real startScale: 1.1
3232 property real endScale: 0.7
3333
34+ paintBackground: spreadView.shiftedContentX !== 0
35+
3436 onBeingResizedChanged: {
3537 if (beingResized) {
3638 // Brace yourselves for impact!
qml/Stages/ShimStage.qml−1
@@ -21,7 +21,6 @@ AbstractStage {
2121 id: shimStage
2222
2323 anchors.fill: parent
24− color: UbuntuColors.lightAubergine
2524
2625 Text {
2726 id: greeterModeText
qml/Stages/TabletStage.qml+3
@@ -34,6 +34,8 @@ AbstractStage {
3434 property int stageFocusedSurface: priv.focusedAppDelegate ? priv.focusedAppDelegate.stage : ApplicationInfoInterface.MainStage
3535 // </tutorial-hacks>
3636
37+ paintBackground: spreadView.shiftedContentX !== 0
38+
3739 // Functions to be called from outside
3840 function updateFocusedAppOrientation() {
3941 var mainStageIndex = root.topLevelSurfaceList.indexForId(priv.mainStageItemId);
@@ -746,6 +748,7 @@ AbstractStage {
746748 surface: model.surface
747749 closeable: !isDash
748750 highlightShown: root.altTabPressed && priv.highlightIndex == zIndex
751+ dropShadow: spreadView.active || priv.focusedAppDelegateIsDislocated
749752
750753 readonly property bool wantsMainStage: stage == ApplicationInfoInterface.MainStage
751754
src/SecondaryWindow.cpp+9
@@ -19,9 +19,18 @@
1919// local
2020#include <paths.h>
2121
22+#include <QQmlContext>
23+
2224SecondaryWindow::SecondaryWindow(QQmlEngine *engine)
2325 : QQuickView(engine, nullptr)
2426{
27+ QByteArray pxpguEnv = qgetenv("GRID_UNIT_PX");
28+ bool ok;
29+ int pxpgu = pxpguEnv.toInt(&ok);
30+ if (!ok) {
31+ pxpgu = 8;
32+ }
33+ engine->rootContext()->setContextProperty("internalGu", pxpgu);
2534 setResizeMode(QQuickView::SizeRootObjectToView);
2635 setColor("black");
2736 setTitle(QStringLiteral("Unity8 Shell - Secondary Screen"));
src/ShellApplication.cpp+6
@@ -168,6 +168,9 @@ void ShellApplication::onScreenAdded(QScreen * /*screen*/)
168168 // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
169169 // its backing QPlatformWindow recreated). So lets refocus it.
170170 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);
171174
172175 m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
173176 m_secondaryWindow->setScreen(screens().at(0));
@@ -194,5 +197,8 @@ void ShellApplication::onScreenAboutToBeRemoved(QScreen *screen)
194197 // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
195198 // its backing QPlatformWindow recreated). So lets refocus it.
196199 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);
197203 }
198204}
tests/mocks/Utils/CMakeLists.txt−1
@@ -13,7 +13,6 @@ set(QMLPLUGIN_SRC
1313 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
1414 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp
1515 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowinputfilter.cpp
16− ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
1716 ${CMAKE_SOURCE_DIR}/plugins/Utils/easingcurve.cpp
1817 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
1918 ${CMAKE_SOURCE_DIR}/plugins/Utils/timezoneFormatter.cpp
tests/mocks/Utils/plugin.cpp−8
@@ -33,7 +33,6 @@
3333#include <unitysortfilterproxymodelqml.h>
3434#include <unitymenumodelpaths.h>
3535#include <windowinputfilter.h>
36−#include <windowscreenshotprovider.h>
3736#include <easingcurve.h>
3837#include <timezoneFormatter.h>
3938#include <applicationsfiltermodel.h>
@@ -82,10 +81,3 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
8281 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
8382 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
8483}
85−
86−void FakeUtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
87−{
88− QQmlExtensionPlugin::initializeEngine(engine, uri);
89−
90− engine->addImageProvider(QLatin1String("window"), new WindowScreenshotProvider);
91−}
tests/mocks/Utils/plugin.h−1
@@ -27,7 +27,6 @@ class FakeUtilsPlugin : public QQmlExtensionPlugin
2727
2828public:
2929 void registerTypes(const char *uri);
30− void initializeEngine(QQmlEngine *engine, const char *uri);
3130};
3231
3332#endif
tests/plugins/CMakeLists.txt−1
@@ -3,7 +3,6 @@ add_subdirectory(GlobalShortcut)
33add_subdirectory(Greeter)
44add_subdirectory(IntegratedLightDM)
55add_subdirectory(Dash)
6−add_subdirectory(ScreenGrabber)
76add_subdirectory(Ubuntu)
87add_subdirectory(Unity)
98add_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"
tests/plugins/ScreenGrabber/grabber.qmldeleted−31
@@ -1,31 +0,0 @@
1−/*
2− * Copyright 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−import QtQuick 2.4
18−import ScreenGrabber 0.1
19−
20−Rectangle {
21− property var grabber: screenGrabber
22−
23− width: 101 // width intentionally bigger than height to test rotation
24− height: 100
25− color: "green"
26−
27− ScreenGrabber {
28− id: screenGrabber
29− objectName: "screenGrabber"
30− }
31−}