on xenial help sign in
Make shell rotation animation work on multimonitor scenarios
commitfa119b376371de3b316e2c5776177db9efdbd8f2 authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateFri 29 Apr 2016, 09:52 (10 years ago) parentaea3ad1
12 files changed+57−139
plugins/Utils/CMakeLists.txt−1 plugins/Utils/plugin.cpp−8 plugins/Utils/plugin.h−1 plugins/Utils/windowscreenshotprovider.cpp−59 plugins/Utils/windowscreenshotprovider.h−31 qml/Components/WindowScreenshot.qml → qml/Components/ItemSnapshot.qml+13−3 qml/OrientedShell.qml+6−5 qml/Rotation/NinetyRotationAnimation.qml+13−16 qml/Rotation/RotationStates.qml+25−5 tests/mocks/Utils/CMakeLists.txt−1 tests/mocks/Utils/plugin.cpp−8 tests/mocks/Utils/plugin.h−1
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−}
plugins/Utils/windowscreenshotprovider.hdeleted−31
@@ -1,31 +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−#ifndef WINDOW_SCREENSHOT_PROVIDER_H_
18−#define WINDOW_SCREENSHOT_PROVIDER_H_
19−
20−#include <QQuickImageProvider>
21−
22−class WindowScreenshotProvider : public QQuickImageProvider
23−{
24−public:
25− WindowScreenshotProvider();
26−
27− // id is ignored for now
28− QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
29−};
30−
31−#endif // WINDOW_SCREENSHOT_PROVIDER_H_
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/OrientedShell.qml+6−5
@@ -241,7 +241,7 @@ Rectangle {
241241 orientedShell: root
242242 shell: shell
243243 shellCover: shellCover
244− windowScreenshot: windowScreenshot
244+ shellSnapshot: shellSnapshot
245245 }
246246
247247 Shell {
@@ -291,8 +291,9 @@ Rectangle {
291291 visible: false
292292 }
293293
294− WindowScreenshot {
295− id: windowScreenshot
294+ ItemSnapshot {
295+ id: shellSnapshot
296+ target: shell
296297 visible: false
297298 width: root.width
298299 height: root.height
@@ -302,9 +303,9 @@ Rectangle {
302303 property real transformOriginY
303304
304305 transform: Rotation {
305− origin.x: windowScreenshot.transformOriginX; origin.y: windowScreenshot.transformOriginY;
306+ origin.x: shellSnapshot.transformOriginX; origin.y: shellSnapshot.transformOriginY;
306307 axis { x: 0; y: 0; z: 1 }
307− angle: windowScreenshot.transformRotationAngle
308+ angle: shellSnapshot.transformRotationAngle
308309 }
309310 }
310311}
qml/Rotation/NinetyRotationAnimation.qml+13−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,24 @@ 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 }
8481 ScriptAction { script: {
85− windowScreenshot.visible = false;
86− windowScreenshot.discard();
82+ shellSnapshot.visible = false;
83+ shellSnapshot.discard();
8784 shellCover.visible = false;
8885 info.transitioning = false;
8986 } }
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: {
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