Merge lp:~gerboland/unity8/orientationLock into lp:unity8
- orientationLock
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Daniel d'Andrada | ||||||||
Approved revision: | 1222 | ||||||||
Merged at revision: | 1264 | ||||||||
Proposed branch: | lp:~gerboland/unity8/orientationLock | ||||||||
Merge into: | lp:unity8 | ||||||||
Diff against target: |
741 lines (+382/-6) 17 files modified
plugins/Unity/Session/CMakeLists.txt (+7/-0) plugins/Unity/Session/orientationlock.cpp (+74/-0) plugins/Unity/Session/orientationlock.h (+62/-0) plugins/Unity/Session/plugin.cpp (+8/-4) qml/Shell.qml (+25/-0) qml/Stages/ApplicationWindow.qml (+2/-0) qml/Stages/PhoneStage.qml (+9/-0) qml/Stages/SessionContainer.qml (+7/-0) qml/Stages/SpreadDelegate.qml (+2/-0) qml/Stages/SurfaceContainer.qml (+5/-0) qml/Stages/TabletStage.qml (+8/-0) tests/mocks/Unity/Application/MirSurfaceItem.cpp (+14/-0) tests/mocks/Unity/Application/MirSurfaceItem.h (+7/-0) tests/mocks/Unity/Application/MirSurfaceItem.qml (+12/-2) tests/qmltests/Stages/tst_ApplicationWindow.qml (+19/-0) tests/qmltests/Stages/tst_PhoneStage.qml (+58/-0) tests/qmltests/Stages/tst_SessionContainer.qml (+63/-0) |
||||||||
To merge this branch: | bzr merge lp:~gerboland/unity8/orientationLock | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel d'Andrada (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Review via email: mp+232484@code.launchpad.net |
Commit message
Shell-controlled orientation support with orientation lock ability
Description of the change
Shell-controlled orientation support with orientation lock ability
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Y
* Did you make sure that your branch does not contain spurious tags?
Y
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
* If you changed the UI, has there been a design review?
N
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1211
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
OrientationLock
-------
In plugins/
"""
-static QObject *dbusunitysessi
+static QObject *dbusunitysessi
{
- Q_UNUSED(engine)
- Q_UNUSED(
-
"""
Why? Is using Q_UNUSED() bad form?
-------
In qml/Shell.qml
"""
+ readonly property int deviceOrientation: Screen.
"""
Please call it "orientation angle" or "rotation" instead of "orientation" as it's not a Qt.ScreenOrient
-------
In qml/Stages/
"""
+ onInteractiveCh
+ if (interactive) {
+ appDelegate.
+ } else {
+ appDelegate.
+ }
+ }
"""
Could it use the same approach as qml/Stages/
-------
Run "make tryShell", "make tryApplicationW
-------
Please rotate the whole MirSurfaceItem mock and not just its text. Like this:
http://
-------
Add a test in SessionContainer that verifies that child sessions rotate along with the root one.
In qml/Stages/
"""
"""
Please make it a Binding{} and put it alongside other similar bindings in SessionContaine
Then ApplicationWind
Daniel d'Andrada (dandrader) wrote : | # |
> [...]
> Please call it "orientation angle" or "rotation" instead of "orientation" as
> it's not a Qt.ScreenOrient
> [...]
Actually "rotation" would clash with Item.rotation.
Daniel d'Andrada (dandrader) wrote : | # |
By the way, have you checked how does that work with the virtual keyboard? eg: if you lock the app orientation, will the vkb keep rotating?
- 1212. By Gerry Boland
-
Merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1212
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1213. By Gerry Boland
-
Use OrientationLock
.savedOrientati on. Rename deviceOrientation to deviceOrientati onAngle - 1214. By Gerry Boland
-
TabletStage: Use Binding instead of JS settings a binding
- 1215. By Gerry Boland
-
MockMirSurfaceItem: Rotate whole thing, even if image looks weird
- 1216. By Gerry Boland
-
Use Binding instead JS establised binding
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1214
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1216
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1217. By Gerry Boland
-
Propagate orientation to all child surfaces, update tests to suit
- 1218. By Gerry Boland
-
Oopsie, orientation will work now
- 1219. By Gerry Boland
-
Add test for SurfaceContainer
Gerry Boland (gerboland) wrote : | # |
> OrientationLock
I added code to use it, but it's not persistent over logout/in yet so is a touch pointless. I wanted to implement the persistence in a separate MR, but I can do it now if you like.
> -------
>
> In plugins/
>
> """
> -static QObject *dbusunitysessi
> QJSEngine *scriptEngine)
> +static QObject *dbusunitysessi
> QJSEngine */*jsEngine*/)
> {
> - Q_UNUSED(engine)
> - Q_UNUSED(
> -
> """
>
> Why? Is using Q_UNUSED() bad form?
I recall Saviq saying he preferred this to Q_UNUSED. Depends on how clever the compiler is really - if we don't name the argument then the compiler definitely knows not to bother with it. But if we use Q_UNUSED it depends on if the compiler is smart enough to guess our intentions. I prefer this way too really.
> -------
>
> In qml/Shell.qml
>
> """
> + readonly property int deviceOrientation:
> Screen.
> """
>
> Please call it "orientation angle" or "rotation" instead of "orientation" as
> it's not a Qt.ScreenOrient
Done.
> -------
>
> In qml/Stages/
>
> """
> + onInteractiveCh
> + if (interactive) {
> + appDelegate.
> { return root.orientation; } );
> + } else {
> + appDelegate.
> breaks the binding intentionally
> + }
> + }
> """
>
> Could it use the same approach as qml/Stages/
Done
>
> -------
>
> Run "make tryShell", "make tryApplicationW
> The "SURFACE" word is rotated.
>
> -------
>
> Please rotate the whole MirSurfaceItem mock and not just its text. Like this:
> http://
The orientation of the word was my hint to tester the orientation of the mock surface - I thought rotating the image and scaling it was more ugly. But I did it your way, and yeah it's more clear what's going on.
> -------
>
> Add a test in SessionContainer that verifies that child sessions rotate along
> with the root one.
Done
> In qml/Stages/
>
> """
> surface.orientation = Qt.binding( function() { return
> root.orientation; } );
> """
>
> Please make it a Binding{} and put it alongside other similar bindings in
> SessionContaine
> Then ApplicationWind
> SessionContaine
Done
Gerry Boland (gerboland) wrote : | # |
> By the way, have you checked how does that work with the virtual keyboard? eg:
> if you lock the app orientation, will the vkb keep rotating?
Application tells the keyboard what geometry to be, so it always suits what orientation the app is in. If orientation locked, app orientation does not change, and so keyboard doesn't either.
- 1220. By Gerry Boland
-
Bad copy/paste, fix orientation on tablet
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1217
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1220
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
In tests/qmltests/
"""
"""
Huh!? You're comparing sessionContaine
You probably meant:
tryCompare(
Calling it rootSessionCont
-------
In tests/qmltests/
"""
/* Text orientation changes are propagated to all children immediately */
"""
typo. s/Text/Test
-------
"""
--- qml/Stages/
+++ qml/Stages/
@@ -27,6 +27,7 @@ Item {
// to be set from outside
property QtObject application
+ property int orientation
QtObject {
id: d
@@ -111,6 +112,7 @@ Item {
id: sessionContainer
session: application ? application.session : null
+ orientation: root.orientation
if (sessionContain
"""
Just a suggestion (feel free to change it or not):
I think it's better to use property aliases in such cases as they seem to be more efficient (besides being more concise) than property bindings. But who knows, maybe they boil down to the same in the qml engine...
Daniel d'Andrada (dandrader) wrote : | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes. Works fine.
* Did CI run pass? If not, please explain why.
No but due to an unrelated failure.
Gerry Boland (gerboland) wrote : | # |
> In tests/qmltests/
>
> """
> tryCompare(
> sessionContaine
> """
>
> Huh!? You're comparing sessionContaine
> You probably meant:
> tryCompare(
Yep silly me. Thanks for catching that.
> Calling it rootSessionCont
> help to clarify things. But that's just a suggestion.
Done. And used childSessionCon
> -------
>
> In tests/qmltests/
>
> """
> /* Text orientation changes are propagated to all children immediately */
> """
>
> typo. s/Text/Test
Done
> -------
>
> """
> --- qml/Stages/
> +++ qml/Stages/
> @@ -27,6 +27,7 @@ Item {
>
> // to be set from outside
> property QtObject application
> + property int orientation
>
> QtObject {
> id: d
> @@ -111,6 +112,7 @@ Item {
> id: sessionContainer
> session: application ? application.session : null
> anchors.fill: parent
> + orientation: root.orientation
>
> onSurfaceChanged: {
> if (sessionContain
> """
>
> Just a suggestion (feel free to change it or not):
> I think it's better to use property aliases in such cases as they seem to be
> more efficient (besides being more concise) than property bindings. But who
> knows, maybe they boil down to the same in the qml engine...
I've no idea how aliases work. I suppose they must be more efficient, but I also heard from a Qt developer (working on the QtQuickComponents) that they're expensive. So I don't know! I tend not to use them as (in this instance) it's harder to see immediately that SessionContainer has an orientation property, and you need to scroll around to figure out what sets that property. Personal taste I guess :) Mind if I leave it alone? If we learn it is indeed an optimization, I'll switch it.
- 1221. By Gerry Boland
-
test_SessionCon
tainer: stupid compare statements fixed. Using root & child prefixes to clarify things - 1222. By Gerry Boland
-
Typo
Daniel d'Andrada (dandrader) wrote : | # |
Thumbs up.
-------
"""
tryCompare(
"""
Nitpick:
You should swap rootSessionCont
Ie, you expect childSessionCon
Preview Diff
1 | === modified file 'plugins/Unity/Session/CMakeLists.txt' |
2 | --- plugins/Unity/Session/CMakeLists.txt 2014-06-13 13:13:16 +0000 |
3 | +++ plugins/Unity/Session/CMakeLists.txt 2014-09-12 19:54:38 +0000 |
4 | @@ -1,10 +1,16 @@ |
5 | +include(FindPkgConfig) |
6 | + |
7 | +pkg_search_module(GIO REQUIRED gio-2.0) |
8 | + |
9 | include_directories( |
10 | ${CMAKE_CURRENT_SOURCE_DIR} |
11 | + ${GIO_INCLUDE_DIRS} |
12 | ) |
13 | |
14 | set(QMLSESSIONPLUGIN_SRC |
15 | plugin.cpp |
16 | dbusunitysessionservice.cpp |
17 | + orientationlock.cpp |
18 | ) |
19 | |
20 | add_library(UnitySession-qml MODULE |
21 | @@ -12,6 +18,7 @@ |
22 | ) |
23 | |
24 | qt5_use_modules(UnitySession-qml DBus Qml) |
25 | +target_link_libraries(UnitySession-qml ${GIO_LDFLAGS}) |
26 | |
27 | # export the qmldir and qmltypes files |
28 | add_unity8_plugin(Unity.Session 0.1 Unity/Session TARGETS UnitySession-qml) |
29 | |
30 | === added file 'plugins/Unity/Session/orientationlock.cpp' |
31 | --- plugins/Unity/Session/orientationlock.cpp 1970-01-01 00:00:00 +0000 |
32 | +++ plugins/Unity/Session/orientationlock.cpp 2014-09-12 19:54:38 +0000 |
33 | @@ -0,0 +1,74 @@ |
34 | +/* |
35 | + * Copyright (C) 2014 Canonical, Ltd. |
36 | + * |
37 | + * This program is free software: you can redistribute it and/or modify it under |
38 | + * the terms of the GNU Lesser General Public License version 3, as published by |
39 | + * the Free Software Foundation. |
40 | + * |
41 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
42 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
43 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
44 | + * Lesser General Public License for more details. |
45 | + * |
46 | + * You should have received a copy of the GNU Lesser General Public License |
47 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
48 | + */ |
49 | + |
50 | +#include "orientationlock.h" |
51 | + |
52 | +#include <QDBusConnection> |
53 | +#include <QDBusInterface> |
54 | + |
55 | +OrientationLock::OrientationLock(QObject *parent) |
56 | + : QObject(parent) |
57 | + , m_enabled(false) |
58 | + , m_savedOrientation(Qt::PortraitOrientation) |
59 | +{ |
60 | + systemSettings = g_settings_new("com.ubuntu.touch.system"); |
61 | + g_signal_connect(systemSettings, "changed::rotation-lock", |
62 | + G_CALLBACK(OrientationLock::onEnabledChangedProxy), this); |
63 | + m_enabled = g_settings_get_boolean(systemSettings, "rotation-lock"); |
64 | +} |
65 | + |
66 | +OrientationLock::~OrientationLock() |
67 | +{ |
68 | + g_signal_handlers_disconnect_by_data(systemSettings, this); |
69 | + g_object_unref(systemSettings); |
70 | +} |
71 | + |
72 | +bool OrientationLock::enabled() const |
73 | +{ |
74 | + return m_enabled; |
75 | +} |
76 | + |
77 | +Qt::ScreenOrientation OrientationLock::savedOrientation() const |
78 | +{ |
79 | + return m_savedOrientation; |
80 | +} |
81 | + |
82 | +void OrientationLock::onEnabledChangedProxy(GSettings */*settings*/, const gchar */*key*/, gpointer data) |
83 | +{ |
84 | + OrientationLock* _this = static_cast<OrientationLock*>(data); |
85 | + _this->onEnabledChanged(); |
86 | +} |
87 | + |
88 | +void OrientationLock::onEnabledChanged() |
89 | +{ |
90 | + const bool enabled = g_settings_get_boolean(systemSettings, "rotation-lock"); |
91 | + if (m_enabled != enabled) { |
92 | + m_enabled = enabled; |
93 | + Q_EMIT enabledChanged(); |
94 | + } |
95 | +} |
96 | + |
97 | +void OrientationLock::setSavedOrientation(const Qt::ScreenOrientation orientation) |
98 | +{ |
99 | + if (orientation == m_savedOrientation) { |
100 | + return; |
101 | + } |
102 | + |
103 | + m_savedOrientation = orientation; |
104 | + |
105 | + //TODO - save value with dbus to persist over sessions |
106 | + Q_EMIT savedOrientationChanged(); |
107 | +} |
108 | |
109 | === added file 'plugins/Unity/Session/orientationlock.h' |
110 | --- plugins/Unity/Session/orientationlock.h 1970-01-01 00:00:00 +0000 |
111 | +++ plugins/Unity/Session/orientationlock.h 2014-09-12 19:54:38 +0000 |
112 | @@ -0,0 +1,62 @@ |
113 | +/* |
114 | + * Copyright (C) 2014 Canonical, Ltd. |
115 | + * |
116 | + * This program is free software: you can redistribute it and/or modify it under |
117 | + * the terms of the GNU Lesser General Public License version 3, as published by |
118 | + * the Free Software Foundation. |
119 | + * |
120 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
121 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
122 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
123 | + * Lesser General Public License for more details. |
124 | + * |
125 | + * You should have received a copy of the GNU Lesser General Public License |
126 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
127 | + */ |
128 | + |
129 | +#ifndef ORIENTATIONLOCK_H |
130 | +#define ORIENTATIONLOCK_H |
131 | + |
132 | +#include <gio/gio.h> |
133 | +#include <QtCore/QObject> |
134 | +#include <QtDBus/QDBusInterface> |
135 | + |
136 | +/** |
137 | + * @brief The OrientationLock class exports orientation lock related properties to QML |
138 | + * It has two properties: |
139 | + * - readonly boolean with the Orientation lock property state |
140 | + * - Qt::ScreenOrientation to save the locked orientation state across Sessions (only relevant if lock is true) |
141 | + */ |
142 | +class OrientationLock : public QObject |
143 | +{ |
144 | + Q_OBJECT |
145 | + |
146 | + Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged) |
147 | + Q_PROPERTY(Qt::ScreenOrientation savedOrientation READ savedOrientation WRITE setSavedOrientation |
148 | + NOTIFY savedOrientationChanged) |
149 | + |
150 | +public: |
151 | + explicit OrientationLock(QObject *parent = 0); |
152 | + ~OrientationLock(); |
153 | + |
154 | + bool enabled() const; |
155 | + Qt::ScreenOrientation savedOrientation() const; |
156 | + void setSavedOrientation(const Qt::ScreenOrientation orientation); |
157 | + |
158 | +Q_SIGNALS: |
159 | + void enabledChanged(); |
160 | + void savedOrientationChanged(); |
161 | + |
162 | +private Q_SLOTS: |
163 | + static void onEnabledChangedProxy(GSettings *settings, const gchar *key, gpointer data); |
164 | + void onEnabledChanged(); |
165 | + |
166 | +private: |
167 | + QDBusInterface *dbusInterface; |
168 | + GSettings *systemSettings; |
169 | + |
170 | + bool m_enabled; |
171 | + Qt::ScreenOrientation m_savedOrientation; |
172 | +}; |
173 | + |
174 | +#endif // ORIENTATIONLOCK_H |
175 | |
176 | === modified file 'plugins/Unity/Session/plugin.cpp' |
177 | --- plugins/Unity/Session/plugin.cpp 2014-05-07 15:21:51 +0000 |
178 | +++ plugins/Unity/Session/plugin.cpp 2014-09-12 19:54:38 +0000 |
179 | @@ -18,23 +18,27 @@ |
180 | |
181 | #include "plugin.h" |
182 | #include "dbusunitysessionservice.h" |
183 | +#include "orientationlock.h" |
184 | |
185 | #include <QAbstractItemModel> |
186 | #include <QDBusConnection> |
187 | #include <QtQml/qqml.h> |
188 | |
189 | -static QObject *dbusunitysessionservice_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
190 | +static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/) |
191 | { |
192 | - Q_UNUSED(engine) |
193 | - Q_UNUSED(scriptEngine) |
194 | - |
195 | return new DBusUnitySessionService(); |
196 | } |
197 | |
198 | +static QObject *orientationlock_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/) |
199 | +{ |
200 | + return new OrientationLock(); |
201 | +} |
202 | + |
203 | void SessionPlugin::registerTypes(const char *uri) |
204 | { |
205 | qmlRegisterType<QAbstractItemModel>(); |
206 | |
207 | Q_ASSERT(uri == QLatin1String("Unity.Session")); |
208 | qmlRegisterSingletonType<DBusUnitySessionService>(uri, 0, 1, "DBusUnitySessionService", dbusunitysessionservice_provider); |
209 | + qmlRegisterSingletonType<OrientationLock>(uri, 0, 1, "OrientationLock", orientationlock_provider); |
210 | } |
211 | |
212 | === modified file 'qml/Shell.qml' |
213 | --- qml/Shell.qml 2014-09-08 14:15:51 +0000 |
214 | +++ qml/Shell.qml 2014-09-12 19:54:38 +0000 |
215 | @@ -15,6 +15,7 @@ |
216 | */ |
217 | |
218 | import QtQuick 2.0 |
219 | +import QtQuick.Window 2.0 |
220 | import AccountsService 0.1 |
221 | import GSettings 1.0 |
222 | import Unity.Application 0.1 |
223 | @@ -61,6 +62,22 @@ |
224 | property int failedLoginsDelayAttempts: 7 // number of failed logins |
225 | property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting |
226 | |
227 | + property int orientation |
228 | + readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) |
229 | + onDeviceOrientationAngleChanged: { |
230 | + if (!OrientationLock.enabled) { |
231 | + orientation = Screen.orientation; |
232 | + } |
233 | + } |
234 | + readonly property bool orientationLockEnabled: OrientationLock.enabled |
235 | + onOrientationLockEnabledChanged: { |
236 | + if (orientationLockEnabled) { |
237 | + OrientationLock.savedOrientation = Screen.orientation; |
238 | + } else { |
239 | + orientation = Screen.orientation; |
240 | + } |
241 | + } |
242 | + |
243 | function activateApplication(appId) { |
244 | if (ApplicationManager.findApplication(appId)) { |
245 | ApplicationManager.requestFocusApplication(appId); |
246 | @@ -85,6 +102,9 @@ |
247 | |
248 | Component.onCompleted: { |
249 | Theme.name = "Ubuntu.Components.Themes.SuruGradient" |
250 | + if (orientationLockEnabled) { |
251 | + orientation = OrientationLock.savedOrientation; |
252 | + } |
253 | } |
254 | |
255 | GSettings { |
256 | @@ -207,6 +227,11 @@ |
257 | property: "inverseProgress" |
258 | value: launcher.progress |
259 | } |
260 | + Binding { |
261 | + target: applicationsDisplayLoader.item |
262 | + property: "orientation" |
263 | + value: shell.orientation |
264 | + } |
265 | } |
266 | } |
267 | |
268 | |
269 | === modified file 'qml/Stages/ApplicationWindow.qml' |
270 | --- qml/Stages/ApplicationWindow.qml 2014-09-03 16:38:10 +0000 |
271 | +++ qml/Stages/ApplicationWindow.qml 2014-09-12 19:54:38 +0000 |
272 | @@ -27,6 +27,7 @@ |
273 | |
274 | // to be set from outside |
275 | property QtObject application |
276 | + property int orientation |
277 | |
278 | QtObject { |
279 | id: d |
280 | @@ -111,6 +112,7 @@ |
281 | id: sessionContainer |
282 | session: application ? application.session : null |
283 | anchors.fill: parent |
284 | + orientation: root.orientation |
285 | |
286 | onSurfaceChanged: { |
287 | if (sessionContainer.surface) { |
288 | |
289 | === modified file 'qml/Stages/PhoneStage.qml' |
290 | --- qml/Stages/PhoneStage.qml 2014-09-02 14:57:05 +0000 |
291 | +++ qml/Stages/PhoneStage.qml 2014-09-12 19:54:38 +0000 |
292 | @@ -18,6 +18,7 @@ |
293 | import Ubuntu.Components 0.1 |
294 | import Ubuntu.Gestures 0.1 |
295 | import Unity.Application 0.1 |
296 | +import Unity.Session 0.1 |
297 | import Utils 0.1 |
298 | import "../Components" |
299 | |
300 | @@ -30,6 +31,7 @@ |
301 | property bool interactive |
302 | property bool spreadEnabled: true // If false, animations and right edge will be disabled |
303 | property real inverseProgress: 0 // This is the progress for left edge drags, in pixels. |
304 | + property int orientation: Qt.PortraitOrientation |
305 | |
306 | color: "black" |
307 | |
308 | @@ -372,6 +374,13 @@ |
309 | progress: appDelegate.progress - spreadView.positionMarker1 |
310 | } |
311 | |
312 | + Binding { |
313 | + target: appDelegate |
314 | + property: "orientation" |
315 | + when: appDelegate.interactive |
316 | + value: root.orientation |
317 | + } |
318 | + |
319 | onClicked: { |
320 | if (spreadView.phase == 2) { |
321 | if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) { |
322 | |
323 | === modified file 'qml/Stages/SessionContainer.qml' |
324 | --- qml/Stages/SessionContainer.qml 2014-09-02 15:51:04 +0000 |
325 | +++ qml/Stages/SessionContainer.qml 2014-09-12 19:54:38 +0000 |
326 | @@ -24,12 +24,14 @@ |
327 | readonly property var childSessions: session ? session.childSessions : null |
328 | readonly property alias surface: _surfaceContainer.surface |
329 | property bool interactive: true |
330 | + property int orientation |
331 | |
332 | readonly property alias surfaceContainer: _surfaceContainer |
333 | SurfaceContainer { |
334 | id: _surfaceContainer |
335 | anchors.fill: parent |
336 | surface: session ? session.surface : null |
337 | + orientation: root.orientation |
338 | } |
339 | |
340 | Binding { |
341 | @@ -74,6 +76,11 @@ |
342 | target: item; when: item |
343 | property: "height"; value: root.height |
344 | } |
345 | + |
346 | + Binding { |
347 | + target: item; when: item |
348 | + property: "orientation"; value: root.orientation |
349 | + } |
350 | } |
351 | } |
352 | |
353 | |
354 | === modified file 'qml/Stages/SpreadDelegate.qml' |
355 | --- qml/Stages/SpreadDelegate.qml 2014-08-27 20:58:10 +0000 |
356 | +++ qml/Stages/SpreadDelegate.qml 2014-09-12 19:54:38 +0000 |
357 | @@ -36,6 +36,7 @@ |
358 | property alias swipeToCloseEnabled: dragArea.enabled |
359 | property bool closeable |
360 | property alias application: appWindow.application |
361 | + property int orientation |
362 | |
363 | Item { |
364 | objectName: "appWindowWithShadow" |
365 | @@ -62,6 +63,7 @@ |
366 | } |
367 | |
368 | interactive: root.interactive |
369 | + orientation: root.orientation |
370 | } |
371 | } |
372 | |
373 | |
374 | === modified file 'qml/Stages/SurfaceContainer.qml' |
375 | --- qml/Stages/SurfaceContainer.qml 2014-09-01 12:48:57 +0000 |
376 | +++ qml/Stages/SurfaceContainer.qml 2014-09-12 19:54:38 +0000 |
377 | @@ -22,6 +22,7 @@ |
378 | objectName: "surfaceContainer" |
379 | property Item surface: null |
380 | property bool hadSurface: false |
381 | + property int orientation |
382 | |
383 | onSurfaceChanged: { |
384 | if (surface) { |
385 | @@ -34,6 +35,10 @@ |
386 | target: surface |
387 | property: "anchors.fill"; value: root |
388 | } |
389 | + Binding { |
390 | + target: surface |
391 | + property: "orientation"; value: root.orientation |
392 | + } |
393 | |
394 | states: [ |
395 | State { |
396 | |
397 | === modified file 'qml/Stages/TabletStage.qml' |
398 | --- qml/Stages/TabletStage.qml 2014-09-02 18:10:49 +0000 |
399 | +++ qml/Stages/TabletStage.qml 2014-09-12 19:54:38 +0000 |
400 | @@ -34,6 +34,7 @@ |
401 | property real maximizedAppTopMargin |
402 | property bool interactive |
403 | property real inverseProgress: 0 // This is the progress for left edge drags, in pixels. |
404 | + property int orientation: Qt.PortraitOrientation |
405 | |
406 | onInverseProgressChanged: { |
407 | // This can't be a simple binding because that would be triggered after this handler |
408 | @@ -535,6 +536,13 @@ |
409 | return progress; |
410 | } |
411 | |
412 | + Binding { |
413 | + target: spreadTile |
414 | + property: "orientation" |
415 | + when: spreadTile.interactive |
416 | + value: root.orientation |
417 | + } |
418 | + |
419 | onClicked: { |
420 | if (spreadView.phase == 2) { |
421 | spreadView.snapTo(index); |
422 | |
423 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp' |
424 | --- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-08-29 14:50:49 +0000 |
425 | +++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-09-12 19:54:38 +0000 |
426 | @@ -39,6 +39,7 @@ |
427 | , m_type(type) |
428 | , m_state(state) |
429 | , m_live(true) |
430 | + , m_orientation(Qt::PortraitOrientation) |
431 | , m_qmlItem(nullptr) |
432 | , m_screenshotUrl(screenshot) |
433 | { |
434 | @@ -108,6 +109,19 @@ |
435 | } |
436 | } |
437 | |
438 | +void MirSurfaceItem::setOrientation(const Qt::ScreenOrientation orientation) |
439 | +{ |
440 | + if (m_orientation == orientation) |
441 | + return; |
442 | + |
443 | + m_orientation = orientation; |
444 | + |
445 | + QQmlProperty orientationProp(m_qmlItem, "orientation"); |
446 | + orientationProp.write(QVariant::fromValue(orientation)); |
447 | + |
448 | + Q_EMIT orientationChanged(); |
449 | +} |
450 | + |
451 | void MirSurfaceItem::setSession(Session* session) |
452 | { |
453 | m_session = session; |
454 | |
455 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h' |
456 | --- tests/mocks/Unity/Application/MirSurfaceItem.h 2014-09-01 12:24:06 +0000 |
457 | +++ tests/mocks/Unity/Application/MirSurfaceItem.h 2014-09-12 19:54:38 +0000 |
458 | @@ -34,6 +34,7 @@ |
459 | Q_PROPERTY(State state READ state NOTIFY stateChanged) |
460 | Q_PROPERTY(QString name READ name CONSTANT) |
461 | Q_PROPERTY(bool live READ live NOTIFY liveChanged) |
462 | + Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged DESIGNABLE false) |
463 | |
464 | public: |
465 | enum Type { |
466 | @@ -64,6 +65,9 @@ |
467 | State state() const { return m_state; } |
468 | QString name() const { return m_name; } |
469 | bool live() const { return m_live; } |
470 | + Qt::ScreenOrientation orientation() const { return m_orientation; } |
471 | + |
472 | + void setOrientation(const Qt::ScreenOrientation orientation); |
473 | |
474 | void setSession(Session* item); |
475 | void setScreenshot(const QUrl& screenshot); |
476 | @@ -76,6 +80,7 @@ |
477 | void typeChanged(Type); |
478 | void stateChanged(State); |
479 | void liveChanged(bool live); |
480 | + void orientationChanged(); |
481 | |
482 | void inputMethodRequested(); |
483 | void inputMethodDismissed(); |
484 | @@ -104,6 +109,7 @@ |
485 | const Type m_type; |
486 | State m_state; |
487 | bool m_live; |
488 | + Qt::ScreenOrientation m_orientation; |
489 | |
490 | QQmlComponent *m_qmlContentComponent; |
491 | QQuickItem *m_qmlItem; |
492 | @@ -114,5 +120,6 @@ |
493 | |
494 | Q_DECLARE_METATYPE(MirSurfaceItem*) |
495 | Q_DECLARE_METATYPE(QList<MirSurfaceItem*>) |
496 | +Q_DECLARE_METATYPE(Qt::ScreenOrientation) |
497 | |
498 | #endif // MIRSURFACEITEM_H |
499 | |
500 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.qml' |
501 | --- tests/mocks/Unity/Application/MirSurfaceItem.qml 2014-08-18 16:59:08 +0000 |
502 | +++ tests/mocks/Unity/Application/MirSurfaceItem.qml 2014-09-12 19:54:38 +0000 |
503 | @@ -21,12 +21,22 @@ |
504 | id: root |
505 | color: "pink" |
506 | |
507 | - anchors.fill: parent |
508 | - |
509 | implicitWidth: units.gu(40) |
510 | implicitHeight: units.gu(70) |
511 | |
512 | + rotation: { |
513 | + if (orientation == Qt.PortraitOrientation) return 0; |
514 | + else if (orientation == Qt.LandscapeOrientation) return 90; |
515 | + else if (orientation == Qt.InvertedPortraitOrientation) return 180; |
516 | + else return 270; |
517 | + } |
518 | + x: parent ? (parent.width - width) / 2 : 0 |
519 | + y: parent ? (parent.height - height) / 2 : 0 |
520 | + width: parent ? (rotation == 0 || rotation == 180 ? parent.width : parent.height) : implicitWidth |
521 | + height: parent ? (rotation == 0 || rotation == 180 ? parent.height : parent.width) : implicitHeight |
522 | + |
523 | property alias screenshotSource: screenshotImage.source |
524 | + property int orientation: Qt.PortraitOrientation |
525 | |
526 | property bool wantInputMethod: false |
527 | |
528 | |
529 | === modified file 'tests/qmltests/Stages/tst_ApplicationWindow.qml' |
530 | --- tests/qmltests/Stages/tst_ApplicationWindow.qml 2014-09-02 23:25:33 +0000 |
531 | +++ tests/qmltests/Stages/tst_ApplicationWindow.qml 2014-09-12 19:54:38 +0000 |
532 | @@ -50,6 +50,7 @@ |
533 | ApplicationWindow { |
534 | anchors.fill: parent |
535 | application: fakeApplication |
536 | + orientation: Qt.PortraitOrientation |
537 | } |
538 | } |
539 | FocusScope { |
540 | @@ -147,6 +148,24 @@ |
541 | } |
542 | } |
543 | |
544 | + Button { |
545 | + anchors { left: parent.left; right: parent.right } |
546 | + text: "Rotate device \u27F3" |
547 | + onClicked: { |
548 | + var orientation = applicationWindowLoader.item.orientation |
549 | + if (orientation == Qt.PortraitOrientation) { |
550 | + orientation = Qt.LandscapeOrientation; |
551 | + } else if (orientation == Qt.LandscapeOrientation) { |
552 | + orientation = Qt.InvertedPortraitOrientation; |
553 | + } else if (orientation == Qt.InvertedPortraitOrientation) { |
554 | + orientation = Qt.InvertedLandscapeOrientation; |
555 | + } else { |
556 | + orientation = Qt.PortraitOrientation; |
557 | + } |
558 | + applicationWindowLoader.item.orientation = orientation; |
559 | + } |
560 | + } |
561 | + |
562 | } |
563 | } |
564 | |
565 | |
566 | === modified file 'tests/qmltests/Stages/tst_PhoneStage.qml' |
567 | --- tests/qmltests/Stages/tst_PhoneStage.qml 2014-08-27 21:39:17 +0000 |
568 | +++ tests/qmltests/Stages/tst_PhoneStage.qml 2014-09-12 19:54:38 +0000 |
569 | @@ -31,6 +31,8 @@ |
570 | anchors { fill: parent; rightMargin: units.gu(30) } |
571 | dragAreaWidth: units.gu(2) |
572 | maximizedAppTopMargin: units.gu(3) + units.dp(2) |
573 | + interactive: true |
574 | + orientation: Qt.PortraitOrientation |
575 | } |
576 | |
577 | Binding { |
578 | @@ -67,6 +69,21 @@ |
579 | ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfoInterface.Stopped); |
580 | } |
581 | } |
582 | + Button { |
583 | + anchors { left: parent.left; right: parent.right } |
584 | + text: "Rotate device \u27F3" |
585 | + onClicked: { |
586 | + if (phoneStage.orientation == Qt.PortraitOrientation) { |
587 | + phoneStage.orientation = Qt.LandscapeOrientation; |
588 | + } else if (phoneStage.orientation == Qt.LandscapeOrientation) { |
589 | + phoneStage.orientation = Qt.InvertedPortraitOrientation; |
590 | + } else if (phoneStage.orientation == Qt.InvertedPortraitOrientation) { |
591 | + phoneStage.orientation = Qt.InvertedLandscapeOrientation; |
592 | + } else { |
593 | + phoneStage.orientation = Qt.PortraitOrientation; |
594 | + } |
595 | + } |
596 | + } |
597 | } |
598 | ListView { |
599 | id: appList |
600 | @@ -256,6 +273,46 @@ |
601 | compare(ApplicationManager.focusedApplicationId, selectedApp.appId); |
602 | } |
603 | |
604 | + function test_orientation_change_sent_to_focused_app() { |
605 | + phoneStage.orientation = Qt.PortraitOrientation; |
606 | + addApps(1); |
607 | + |
608 | + var spreadView = findChild(phoneStage, "spreadView"); |
609 | + var app = findChild(spreadView, "appDelegate0"); |
610 | + tryCompare(app, "orientation", Qt.PortraitOrientation); |
611 | + |
612 | + phoneStage.orientation = Qt.LandscapeOrientation; |
613 | + tryCompare(app, "orientation", Qt.LandscapeOrientation); |
614 | + } |
615 | + |
616 | + function test_orientation_change_not_sent_to_apps_while_spread_open() { |
617 | + phoneStage.orientation = Qt.PortraitOrientation; |
618 | + addApps(1); |
619 | + |
620 | + var spreadView = findChild(phoneStage, "spreadView"); |
621 | + var app = findChild(spreadView, "appDelegate0"); |
622 | + tryCompare(app, "orientation", Qt.PortraitOrientation); |
623 | + |
624 | + goToSpread(); |
625 | + phoneStage.orientation = Qt.LandscapeOrientation; |
626 | + tryCompare(app, "orientation", Qt.PortraitOrientation); |
627 | + } |
628 | + |
629 | + function test_orientation_change_not_sent_to_unfocused_app_until_it_focused() { |
630 | + phoneStage.orientation = Qt.PortraitOrientation; |
631 | + addApps(1); |
632 | + |
633 | + var spreadView = findChild(phoneStage, "spreadView"); |
634 | + var app = findChild(spreadView, "appDelegate0"); |
635 | + |
636 | + goToSpread(); |
637 | + phoneStage.orientation = Qt.LandscapeOrientation; |
638 | + tryCompare(app, "orientation", Qt.PortraitOrientation); |
639 | + |
640 | + phoneStage.select(app.application.appId); |
641 | + tryCompare(app, "orientation", Qt.LandscapeOrientation); |
642 | + } |
643 | + |
644 | function cleanup() { |
645 | while (ApplicationManager.count > 1) { |
646 | var oldCount = ApplicationManager.count; |
647 | @@ -263,6 +320,7 @@ |
648 | ApplicationManager.stopApplication(ApplicationManager.get(closingIndex).appId) |
649 | tryCompare(ApplicationManager, "count", oldCount - 1) |
650 | } |
651 | + phoneStage.orientation = Qt.PortraitOrientation; |
652 | } |
653 | } |
654 | } |
655 | |
656 | === modified file 'tests/qmltests/Stages/tst_SessionContainer.qml' |
657 | --- tests/qmltests/Stages/tst_SessionContainer.qml 2014-09-02 15:51:20 +0000 |
658 | +++ tests/qmltests/Stages/tst_SessionContainer.qml 2014-09-12 19:54:38 +0000 |
659 | @@ -41,6 +41,7 @@ |
660 | SessionContainer { |
661 | id: sessionContainer |
662 | anchors.fill: parent |
663 | + orientation: Qt.PortraitOrientation |
664 | } |
665 | } |
666 | |
667 | @@ -112,6 +113,24 @@ |
668 | session: sessionContainerLoader.item ? sessionContainerLoader.item.session : null |
669 | } |
670 | } |
671 | + |
672 | + Button { |
673 | + anchors { left: parent.left; right: parent.right } |
674 | + text: "Rotate device \u27F3" |
675 | + onClicked: { |
676 | + var orientation = sessionContainerLoader.item.orientation |
677 | + if (orientation == Qt.PortraitOrientation) { |
678 | + orientation = Qt.LandscapeOrientation; |
679 | + } else if (orientation == Qt.LandscapeOrientation) { |
680 | + orientation = Qt.InvertedPortraitOrientation; |
681 | + } else if (orientation == Qt.InvertedPortraitOrientation) { |
682 | + orientation = Qt.InvertedLandscapeOrientation; |
683 | + } else { |
684 | + orientation = Qt.PortraitOrientation; |
685 | + } |
686 | + sessionContainerLoader.item.orientation = orientation; |
687 | + } |
688 | + } |
689 | } |
690 | } |
691 | |
692 | @@ -263,5 +282,49 @@ |
693 | // wait for animation to end |
694 | tryCompareFunction(function() { return isContainerAnimating(childContainer); }, false); |
695 | } |
696 | + |
697 | + function test_orientationPropagatedToChildren_data() { |
698 | + return [ { tag: "count=1", count: 1 }, |
699 | + { tag: "count=4", count: 4 } ]; |
700 | + } |
701 | + |
702 | + /* Test orientation changes are propagated to all children immediately */ |
703 | + function test_orientationPropagatedToChildren(data) { |
704 | + sessionCheckbox.checked = true; |
705 | + var rootSessionContainer = sessionContainerLoader.item; |
706 | + compare(rootSessionContainer.childSessions.count(), 0); |
707 | + |
708 | + var i; |
709 | + var sessions = []; |
710 | + for (i = 0; i < data.count; i++) { |
711 | + var session = ApplicationTest.addChildSession(rootSessionContainer.session, |
712 | + "gallery"); |
713 | + session.createSurface(); |
714 | + rootSessionContainer.session.addChildSession(session); |
715 | + |
716 | + // Check child SessionContainer has orientation matching the parent |
717 | + var delegate = findChild(rootSessionContainer, "childDelegate" + i); |
718 | + var childSessionContainer = findChild(delegate, "sessionContainer"); |
719 | + |
720 | + tryCompare(rootSessionContainer, "orientation", childSessionContainer.orientation); |
721 | + |
722 | + sessions.push(session); |
723 | + } |
724 | + |
725 | + // Change orientation and verify all children updated |
726 | + rootSessionContainer.orientation = Qt.LandscapeOrientation; |
727 | + |
728 | + for (i = 0; i < data.count; i++) { |
729 | + var delegate = findChild(rootSessionContainer, "childDelegate" + i); |
730 | + var childSessionContainer = findChild(delegate, "sessionContainer"); |
731 | + |
732 | + tryCompare(rootSessionContainer, "orientation", childSessionContainer.orientation); |
733 | + } |
734 | + |
735 | + // Clean up |
736 | + for (i = data.count-1; i >= 0; i--) { |
737 | + ApplicationTest.removeSession(sessions[i]); |
738 | + } |
739 | + } |
740 | } |
741 | } |
270 + surface.orientation = Qt.binding( function() { return root.orientation; } );
Use a Binding component instead, like it's already done for surface.enabled and surface. interactive.