Merge lp:~gerboland/unity8/orientationLock into lp:unity8

Proposed by Gerry Boland
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
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://code.launchpad.net/~gerboland/qtmir/exposeOrientation/+merge/232485
https://code.launchpad.net/~gerboland/qtubuntu/exposeOrientation/+merge/232252
https://code.launchpad.net/~gerboland/platform-api/exposeOrientation/+merge/232250
 * 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

To post a comment you must log in.
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

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.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

OrientationLock::savedOrientation is not being used anywhere.

----------------------------------------------------------------

In plugins/Unity/Session/plugin.cpp:

"""
-static QObject *dbusunitysessionservice_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
+static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
 {
- Q_UNUSED(engine)
- Q_UNUSED(scriptEngine)
-
"""

Why? Is using Q_UNUSED() bad form?

---------------------------------------------------------------------

In qml/Shell.qml

"""
+ readonly property int deviceOrientation: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
"""

Please call it "orientation angle" or "rotation" instead of "orientation" as it's not a Qt.ScreenOrientation type.

---------------------------------------------------------------------

In qml/Stages/TabletStage.qml:

"""
+ onInteractiveChanged: {
+ if (interactive) {
+ appDelegate.orientation = Qt.binding( function() { return root.orientation; } );
+ } else {
+ appDelegate.orientation = root.orientation; // breaks the binding intentionally
+ }
+ }
"""

Could it use the same approach as qml/Stages/PhoneStage.qml?

---------------------------------------------------------------------

Run "make tryShell", "make tryApplicationWindow" or "make trySpreadDelegate". The "SURFACE" word is rotated.

---------------------------------------------------------------------

Please rotate the whole MirSurfaceItem mock and not just its text. Like this:
http://paste.ubuntu.com/8292833/

-----------------------------------------------------------------------

Add a test in SessionContainer that verifies that child sessions rotate along with the root one.

In qml/Stages/ApplicationWindow.qml:

"""
                surface.orientation = Qt.binding( function() { return root.orientation; } );
"""

Please make it a Binding{} and put it alongside other similar bindings in SessionContainer.qml
Then ApplicationWindow.orientation would be just an alias to its internal SessionContainer.orientation.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> [...]
> Please call it "orientation angle" or "rotation" instead of "orientation" as
> it's not a Qt.ScreenOrientation type.
> [...]

Actually "rotation" would clash with Item.rotation.

Revision history for this message
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?

lp:~gerboland/unity8/orientationLock updated
1212. By Gerry Boland

Merge trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~gerboland/unity8/orientationLock updated
1213. By Gerry Boland

Use OrientationLock.savedOrientation. Rename deviceOrientation to deviceOrientationAngle

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~gerboland/unity8/orientationLock updated
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

Revision history for this message
Gerry Boland (gerboland) wrote :

> OrientationLock::savedOrientation is not being used anywhere.
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/Unity/Session/plugin.cpp:
>
> """
> -static QObject *dbusunitysessionservice_provider(QQmlEngine *engine,
> QJSEngine *scriptEngine)
> +static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/,
> QJSEngine */*jsEngine*/)
> {
> - Q_UNUSED(engine)
> - Q_UNUSED(scriptEngine)
> -
> """
>
> 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.angleBetween(Screen.primaryOrientation, Screen.orientation)
> """
>
> Please call it "orientation angle" or "rotation" instead of "orientation" as
> it's not a Qt.ScreenOrientation type.

Done.

> ---------------------------------------------------------------------
>
> In qml/Stages/TabletStage.qml:
>
> """
> + onInteractiveChanged: {
> + if (interactive) {
> + appDelegate.orientation = Qt.binding( function()
> { return root.orientation; } );
> + } else {
> + appDelegate.orientation = root.orientation; //
> breaks the binding intentionally
> + }
> + }
> """
>
> Could it use the same approach as qml/Stages/PhoneStage.qml?

Done

>
> ---------------------------------------------------------------------
>
> Run "make tryShell", "make tryApplicationWindow" or "make trySpreadDelegate".
> The "SURFACE" word is rotated.
>
> ---------------------------------------------------------------------
>
> Please rotate the whole MirSurfaceItem mock and not just its text. Like this:
> http://paste.ubuntu.com/8292833/

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/ApplicationWindow.qml:
>
> """
> surface.orientation = Qt.binding( function() { return
> root.orientation; } );
> """
>
> Please make it a Binding{} and put it alongside other similar bindings in
> SessionContainer.qml
> Then ApplicationWindow.orientation would be just an alias to its internal
> SessionContainer.orientation.

Done

Revision history for this message
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.

lp:~gerboland/unity8/orientationLock updated
1220. By Gerry Boland

Bad copy/paste, fix orientation on tablet

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

In tests/qmltests/Stages/tst_SessionContainer.qml

"""
                tryCompare(sessionContainer, "orientation", sessionContainer.orientation);
"""

Huh!? You're comparing sessionContainer.orientation to itself?
You probably meant:
tryCompare(childContainer, "orientation", sessionContainer.orientation);

Calling it rootSessionContainer instead of just sessionContainer would also help to clarify things. But that's just a suggestion.

-----------------------------------------------------

In tests/qmltests/Stages/tst_SessionContainer.qml

"""
/* Text orientation changes are propagated to all children immediately */
"""

typo. s/Text/Test

------------------------------------------------------

"""
--- qml/Stages/ApplicationWindow.qml 2014-09-03 16:38:10 +0000
+++ qml/Stages/ApplicationWindow.qml 2014-09-11 10:41:11 +0000
@@ -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 (sessionContainer.surface) {
"""

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...

review: Needs Fixing
Revision history for this message
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.

Revision history for this message
Gerry Boland (gerboland) wrote :

> In tests/qmltests/Stages/tst_SessionContainer.qml
>
> """
> tryCompare(sessionContainer, "orientation",
> sessionContainer.orientation);
> """
>
> Huh!? You're comparing sessionContainer.orientation to itself?
> You probably meant:
> tryCompare(childContainer, "orientation", sessionContainer.orientation);

Yep silly me. Thanks for catching that.

> Calling it rootSessionContainer instead of just sessionContainer would also
> help to clarify things. But that's just a suggestion.

Done. And used childSessionContainer while I was at it.

> -----------------------------------------------------
>
> In tests/qmltests/Stages/tst_SessionContainer.qml
>
> """
> /* Text orientation changes are propagated to all children immediately */
> """
>
> typo. s/Text/Test

Done

> ------------------------------------------------------
>
> """
> --- qml/Stages/ApplicationWindow.qml 2014-09-03 16:38:10 +0000
> +++ qml/Stages/ApplicationWindow.qml 2014-09-11 10:41:11 +0000
> @@ -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 (sessionContainer.surface) {
> """
>
> 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.

lp:~gerboland/unity8/orientationLock updated
1221. By Gerry Boland

test_SessionContainer: stupid compare statements fixed. Using root & child prefixes to clarify things

1222. By Gerry Boland

Typo

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Thumbs up.

--------------------

"""
tryCompare(rootSessionContainer, "orientation", childSessionContainer.orientation);
"""

Nitpick:
You should swap rootSessionContainer with childSessionContainer, as the last parameter is the expected value.
Ie, you expect childSessionContainer.orientation (the property whose value should change) to eventually be rootSessionContainer.orientation (the value that you've manually set), not the other way round.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/Unity/Session/CMakeLists.txt'
--- plugins/Unity/Session/CMakeLists.txt 2014-06-13 13:13:16 +0000
+++ plugins/Unity/Session/CMakeLists.txt 2014-09-12 19:54:38 +0000
@@ -1,10 +1,16 @@
1include(FindPkgConfig)
2
3pkg_search_module(GIO REQUIRED gio-2.0)
4
1include_directories(5include_directories(
2 ${CMAKE_CURRENT_SOURCE_DIR}6 ${CMAKE_CURRENT_SOURCE_DIR}
7 ${GIO_INCLUDE_DIRS}
3)8)
49
5set(QMLSESSIONPLUGIN_SRC10set(QMLSESSIONPLUGIN_SRC
6 plugin.cpp11 plugin.cpp
7 dbusunitysessionservice.cpp12 dbusunitysessionservice.cpp
13 orientationlock.cpp
8 )14 )
915
10add_library(UnitySession-qml MODULE16add_library(UnitySession-qml MODULE
@@ -12,6 +18,7 @@
12 )18 )
1319
14qt5_use_modules(UnitySession-qml DBus Qml)20qt5_use_modules(UnitySession-qml DBus Qml)
21target_link_libraries(UnitySession-qml ${GIO_LDFLAGS})
1522
16# export the qmldir and qmltypes files23# export the qmldir and qmltypes files
17add_unity8_plugin(Unity.Session 0.1 Unity/Session TARGETS UnitySession-qml)24add_unity8_plugin(Unity.Session 0.1 Unity/Session TARGETS UnitySession-qml)
1825
=== added file 'plugins/Unity/Session/orientationlock.cpp'
--- plugins/Unity/Session/orientationlock.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Unity/Session/orientationlock.cpp 2014-09-12 19:54:38 +0000
@@ -0,0 +1,74 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "orientationlock.h"
18
19#include <QDBusConnection>
20#include <QDBusInterface>
21
22OrientationLock::OrientationLock(QObject *parent)
23 : QObject(parent)
24 , m_enabled(false)
25 , m_savedOrientation(Qt::PortraitOrientation)
26{
27 systemSettings = g_settings_new("com.ubuntu.touch.system");
28 g_signal_connect(systemSettings, "changed::rotation-lock",
29 G_CALLBACK(OrientationLock::onEnabledChangedProxy), this);
30 m_enabled = g_settings_get_boolean(systemSettings, "rotation-lock");
31}
32
33OrientationLock::~OrientationLock()
34{
35 g_signal_handlers_disconnect_by_data(systemSettings, this);
36 g_object_unref(systemSettings);
37}
38
39bool OrientationLock::enabled() const
40{
41 return m_enabled;
42}
43
44Qt::ScreenOrientation OrientationLock::savedOrientation() const
45{
46 return m_savedOrientation;
47}
48
49void OrientationLock::onEnabledChangedProxy(GSettings */*settings*/, const gchar */*key*/, gpointer data)
50{
51 OrientationLock* _this = static_cast<OrientationLock*>(data);
52 _this->onEnabledChanged();
53}
54
55void OrientationLock::onEnabledChanged()
56{
57 const bool enabled = g_settings_get_boolean(systemSettings, "rotation-lock");
58 if (m_enabled != enabled) {
59 m_enabled = enabled;
60 Q_EMIT enabledChanged();
61 }
62}
63
64void OrientationLock::setSavedOrientation(const Qt::ScreenOrientation orientation)
65{
66 if (orientation == m_savedOrientation) {
67 return;
68 }
69
70 m_savedOrientation = orientation;
71
72 //TODO - save value with dbus to persist over sessions
73 Q_EMIT savedOrientationChanged();
74}
075
=== added file 'plugins/Unity/Session/orientationlock.h'
--- plugins/Unity/Session/orientationlock.h 1970-01-01 00:00:00 +0000
+++ plugins/Unity/Session/orientationlock.h 2014-09-12 19:54:38 +0000
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef ORIENTATIONLOCK_H
18#define ORIENTATIONLOCK_H
19
20#include <gio/gio.h>
21#include <QtCore/QObject>
22#include <QtDBus/QDBusInterface>
23
24/**
25 * @brief The OrientationLock class exports orientation lock related properties to QML
26 * It has two properties:
27 * - readonly boolean with the Orientation lock property state
28 * - Qt::ScreenOrientation to save the locked orientation state across Sessions (only relevant if lock is true)
29 */
30class OrientationLock : public QObject
31{
32 Q_OBJECT
33
34 Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged)
35 Q_PROPERTY(Qt::ScreenOrientation savedOrientation READ savedOrientation WRITE setSavedOrientation
36 NOTIFY savedOrientationChanged)
37
38public:
39 explicit OrientationLock(QObject *parent = 0);
40 ~OrientationLock();
41
42 bool enabled() const;
43 Qt::ScreenOrientation savedOrientation() const;
44 void setSavedOrientation(const Qt::ScreenOrientation orientation);
45
46Q_SIGNALS:
47 void enabledChanged();
48 void savedOrientationChanged();
49
50private Q_SLOTS:
51 static void onEnabledChangedProxy(GSettings *settings, const gchar *key, gpointer data);
52 void onEnabledChanged();
53
54private:
55 QDBusInterface *dbusInterface;
56 GSettings *systemSettings;
57
58 bool m_enabled;
59 Qt::ScreenOrientation m_savedOrientation;
60};
61
62#endif // ORIENTATIONLOCK_H
063
=== modified file 'plugins/Unity/Session/plugin.cpp'
--- plugins/Unity/Session/plugin.cpp 2014-05-07 15:21:51 +0000
+++ plugins/Unity/Session/plugin.cpp 2014-09-12 19:54:38 +0000
@@ -18,23 +18,27 @@
1818
19#include "plugin.h"19#include "plugin.h"
20#include "dbusunitysessionservice.h"20#include "dbusunitysessionservice.h"
21#include "orientationlock.h"
2122
22#include <QAbstractItemModel>23#include <QAbstractItemModel>
23#include <QDBusConnection>24#include <QDBusConnection>
24#include <QtQml/qqml.h>25#include <QtQml/qqml.h>
2526
26static QObject *dbusunitysessionservice_provider(QQmlEngine *engine, QJSEngine *scriptEngine)27static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
27{28{
28 Q_UNUSED(engine)
29 Q_UNUSED(scriptEngine)
30
31 return new DBusUnitySessionService();29 return new DBusUnitySessionService();
32}30}
3331
32static QObject *orientationlock_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
33{
34 return new OrientationLock();
35}
36
34void SessionPlugin::registerTypes(const char *uri)37void SessionPlugin::registerTypes(const char *uri)
35{38{
36 qmlRegisterType<QAbstractItemModel>();39 qmlRegisterType<QAbstractItemModel>();
3740
38 Q_ASSERT(uri == QLatin1String("Unity.Session"));41 Q_ASSERT(uri == QLatin1String("Unity.Session"));
39 qmlRegisterSingletonType<DBusUnitySessionService>(uri, 0, 1, "DBusUnitySessionService", dbusunitysessionservice_provider);42 qmlRegisterSingletonType<DBusUnitySessionService>(uri, 0, 1, "DBusUnitySessionService", dbusunitysessionservice_provider);
43 qmlRegisterSingletonType<OrientationLock>(uri, 0, 1, "OrientationLock", orientationlock_provider);
40}44}
4145
=== modified file 'qml/Shell.qml'
--- qml/Shell.qml 2014-09-08 14:15:51 +0000
+++ qml/Shell.qml 2014-09-12 19:54:38 +0000
@@ -15,6 +15,7 @@
15 */15 */
1616
17import QtQuick 2.017import QtQuick 2.0
18import QtQuick.Window 2.0
18import AccountsService 0.119import AccountsService 0.1
19import GSettings 1.020import GSettings 1.0
20import Unity.Application 0.121import Unity.Application 0.1
@@ -61,6 +62,22 @@
61 property int failedLoginsDelayAttempts: 7 // number of failed logins62 property int failedLoginsDelayAttempts: 7 // number of failed logins
62 property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting63 property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting
6364
65 property int orientation
66 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
67 onDeviceOrientationAngleChanged: {
68 if (!OrientationLock.enabled) {
69 orientation = Screen.orientation;
70 }
71 }
72 readonly property bool orientationLockEnabled: OrientationLock.enabled
73 onOrientationLockEnabledChanged: {
74 if (orientationLockEnabled) {
75 OrientationLock.savedOrientation = Screen.orientation;
76 } else {
77 orientation = Screen.orientation;
78 }
79 }
80
64 function activateApplication(appId) {81 function activateApplication(appId) {
65 if (ApplicationManager.findApplication(appId)) {82 if (ApplicationManager.findApplication(appId)) {
66 ApplicationManager.requestFocusApplication(appId);83 ApplicationManager.requestFocusApplication(appId);
@@ -85,6 +102,9 @@
85102
86 Component.onCompleted: {103 Component.onCompleted: {
87 Theme.name = "Ubuntu.Components.Themes.SuruGradient"104 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
105 if (orientationLockEnabled) {
106 orientation = OrientationLock.savedOrientation;
107 }
88 }108 }
89109
90 GSettings {110 GSettings {
@@ -207,6 +227,11 @@
207 property: "inverseProgress"227 property: "inverseProgress"
208 value: launcher.progress228 value: launcher.progress
209 }229 }
230 Binding {
231 target: applicationsDisplayLoader.item
232 property: "orientation"
233 value: shell.orientation
234 }
210 }235 }
211 }236 }
212237
213238
=== modified file 'qml/Stages/ApplicationWindow.qml'
--- qml/Stages/ApplicationWindow.qml 2014-09-03 16:38:10 +0000
+++ qml/Stages/ApplicationWindow.qml 2014-09-12 19:54:38 +0000
@@ -27,6 +27,7 @@
2727
28 // to be set from outside28 // to be set from outside
29 property QtObject application29 property QtObject application
30 property int orientation
3031
31 QtObject {32 QtObject {
32 id: d33 id: d
@@ -111,6 +112,7 @@
111 id: sessionContainer112 id: sessionContainer
112 session: application ? application.session : null113 session: application ? application.session : null
113 anchors.fill: parent114 anchors.fill: parent
115 orientation: root.orientation
114116
115 onSurfaceChanged: {117 onSurfaceChanged: {
116 if (sessionContainer.surface) {118 if (sessionContainer.surface) {
117119
=== modified file 'qml/Stages/PhoneStage.qml'
--- qml/Stages/PhoneStage.qml 2014-09-02 14:57:05 +0000
+++ qml/Stages/PhoneStage.qml 2014-09-12 19:54:38 +0000
@@ -18,6 +18,7 @@
18import Ubuntu.Components 0.118import Ubuntu.Components 0.1
19import Ubuntu.Gestures 0.119import Ubuntu.Gestures 0.1
20import Unity.Application 0.120import Unity.Application 0.1
21import Unity.Session 0.1
21import Utils 0.122import Utils 0.1
22import "../Components"23import "../Components"
2324
@@ -30,6 +31,7 @@
30 property bool interactive31 property bool interactive
31 property bool spreadEnabled: true // If false, animations and right edge will be disabled32 property bool spreadEnabled: true // If false, animations and right edge will be disabled
32 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.33 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
34 property int orientation: Qt.PortraitOrientation
3335
34 color: "black"36 color: "black"
3537
@@ -372,6 +374,13 @@
372 progress: appDelegate.progress - spreadView.positionMarker1374 progress: appDelegate.progress - spreadView.positionMarker1
373 }375 }
374376
377 Binding {
378 target: appDelegate
379 property: "orientation"
380 when: appDelegate.interactive
381 value: root.orientation
382 }
383
375 onClicked: {384 onClicked: {
376 if (spreadView.phase == 2) {385 if (spreadView.phase == 2) {
377 if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) {386 if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) {
378387
=== modified file 'qml/Stages/SessionContainer.qml'
--- qml/Stages/SessionContainer.qml 2014-09-02 15:51:04 +0000
+++ qml/Stages/SessionContainer.qml 2014-09-12 19:54:38 +0000
@@ -24,12 +24,14 @@
24 readonly property var childSessions: session ? session.childSessions : null24 readonly property var childSessions: session ? session.childSessions : null
25 readonly property alias surface: _surfaceContainer.surface25 readonly property alias surface: _surfaceContainer.surface
26 property bool interactive: true26 property bool interactive: true
27 property int orientation
2728
28 readonly property alias surfaceContainer: _surfaceContainer29 readonly property alias surfaceContainer: _surfaceContainer
29 SurfaceContainer {30 SurfaceContainer {
30 id: _surfaceContainer31 id: _surfaceContainer
31 anchors.fill: parent32 anchors.fill: parent
32 surface: session ? session.surface : null33 surface: session ? session.surface : null
34 orientation: root.orientation
33 }35 }
3436
35 Binding {37 Binding {
@@ -74,6 +76,11 @@
74 target: item; when: item76 target: item; when: item
75 property: "height"; value: root.height77 property: "height"; value: root.height
76 }78 }
79
80 Binding {
81 target: item; when: item
82 property: "orientation"; value: root.orientation
83 }
77 }84 }
78 }85 }
7986
8087
=== modified file 'qml/Stages/SpreadDelegate.qml'
--- qml/Stages/SpreadDelegate.qml 2014-08-27 20:58:10 +0000
+++ qml/Stages/SpreadDelegate.qml 2014-09-12 19:54:38 +0000
@@ -36,6 +36,7 @@
36 property alias swipeToCloseEnabled: dragArea.enabled36 property alias swipeToCloseEnabled: dragArea.enabled
37 property bool closeable37 property bool closeable
38 property alias application: appWindow.application38 property alias application: appWindow.application
39 property int orientation
3940
40 Item {41 Item {
41 objectName: "appWindowWithShadow"42 objectName: "appWindowWithShadow"
@@ -62,6 +63,7 @@
62 }63 }
6364
64 interactive: root.interactive65 interactive: root.interactive
66 orientation: root.orientation
65 }67 }
66 }68 }
6769
6870
=== modified file 'qml/Stages/SurfaceContainer.qml'
--- qml/Stages/SurfaceContainer.qml 2014-09-01 12:48:57 +0000
+++ qml/Stages/SurfaceContainer.qml 2014-09-12 19:54:38 +0000
@@ -22,6 +22,7 @@
22 objectName: "surfaceContainer"22 objectName: "surfaceContainer"
23 property Item surface: null23 property Item surface: null
24 property bool hadSurface: false24 property bool hadSurface: false
25 property int orientation
2526
26 onSurfaceChanged: {27 onSurfaceChanged: {
27 if (surface) {28 if (surface) {
@@ -34,6 +35,10 @@
34 target: surface35 target: surface
35 property: "anchors.fill"; value: root36 property: "anchors.fill"; value: root
36 }37 }
38 Binding {
39 target: surface
40 property: "orientation"; value: root.orientation
41 }
3742
38 states: [43 states: [
39 State {44 State {
4045
=== modified file 'qml/Stages/TabletStage.qml'
--- qml/Stages/TabletStage.qml 2014-09-02 18:10:49 +0000
+++ qml/Stages/TabletStage.qml 2014-09-12 19:54:38 +0000
@@ -34,6 +34,7 @@
34 property real maximizedAppTopMargin34 property real maximizedAppTopMargin
35 property bool interactive35 property bool interactive
36 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.36 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
37 property int orientation: Qt.PortraitOrientation
3738
38 onInverseProgressChanged: {39 onInverseProgressChanged: {
39 // This can't be a simple binding because that would be triggered after this handler40 // This can't be a simple binding because that would be triggered after this handler
@@ -535,6 +536,13 @@
535 return progress;536 return progress;
536 }537 }
537538
539 Binding {
540 target: spreadTile
541 property: "orientation"
542 when: spreadTile.interactive
543 value: root.orientation
544 }
545
538 onClicked: {546 onClicked: {
539 if (spreadView.phase == 2) {547 if (spreadView.phase == 2) {
540 spreadView.snapTo(index);548 spreadView.snapTo(index);
541549
=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp'
--- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-08-29 14:50:49 +0000
+++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-09-12 19:54:38 +0000
@@ -39,6 +39,7 @@
39 , m_type(type)39 , m_type(type)
40 , m_state(state)40 , m_state(state)
41 , m_live(true)41 , m_live(true)
42 , m_orientation(Qt::PortraitOrientation)
42 , m_qmlItem(nullptr)43 , m_qmlItem(nullptr)
43 , m_screenshotUrl(screenshot)44 , m_screenshotUrl(screenshot)
44{45{
@@ -108,6 +109,19 @@
108 }109 }
109}110}
110111
112void MirSurfaceItem::setOrientation(const Qt::ScreenOrientation orientation)
113{
114 if (m_orientation == orientation)
115 return;
116
117 m_orientation = orientation;
118
119 QQmlProperty orientationProp(m_qmlItem, "orientation");
120 orientationProp.write(QVariant::fromValue(orientation));
121
122 Q_EMIT orientationChanged();
123}
124
111void MirSurfaceItem::setSession(Session* session)125void MirSurfaceItem::setSession(Session* session)
112{126{
113 m_session = session;127 m_session = session;
114128
=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h'
--- tests/mocks/Unity/Application/MirSurfaceItem.h 2014-09-01 12:24:06 +0000
+++ tests/mocks/Unity/Application/MirSurfaceItem.h 2014-09-12 19:54:38 +0000
@@ -34,6 +34,7 @@
34 Q_PROPERTY(State state READ state NOTIFY stateChanged)34 Q_PROPERTY(State state READ state NOTIFY stateChanged)
35 Q_PROPERTY(QString name READ name CONSTANT)35 Q_PROPERTY(QString name READ name CONSTANT)
36 Q_PROPERTY(bool live READ live NOTIFY liveChanged)36 Q_PROPERTY(bool live READ live NOTIFY liveChanged)
37 Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged DESIGNABLE false)
3738
38public:39public:
39 enum Type {40 enum Type {
@@ -64,6 +65,9 @@
64 State state() const { return m_state; }65 State state() const { return m_state; }
65 QString name() const { return m_name; }66 QString name() const { return m_name; }
66 bool live() const { return m_live; }67 bool live() const { return m_live; }
68 Qt::ScreenOrientation orientation() const { return m_orientation; }
69
70 void setOrientation(const Qt::ScreenOrientation orientation);
6771
68 void setSession(Session* item);72 void setSession(Session* item);
69 void setScreenshot(const QUrl& screenshot);73 void setScreenshot(const QUrl& screenshot);
@@ -76,6 +80,7 @@
76 void typeChanged(Type);80 void typeChanged(Type);
77 void stateChanged(State);81 void stateChanged(State);
78 void liveChanged(bool live);82 void liveChanged(bool live);
83 void orientationChanged();
7984
80 void inputMethodRequested();85 void inputMethodRequested();
81 void inputMethodDismissed();86 void inputMethodDismissed();
@@ -104,6 +109,7 @@
104 const Type m_type;109 const Type m_type;
105 State m_state;110 State m_state;
106 bool m_live;111 bool m_live;
112 Qt::ScreenOrientation m_orientation;
107113
108 QQmlComponent *m_qmlContentComponent;114 QQmlComponent *m_qmlContentComponent;
109 QQuickItem *m_qmlItem;115 QQuickItem *m_qmlItem;
@@ -114,5 +120,6 @@
114120
115Q_DECLARE_METATYPE(MirSurfaceItem*)121Q_DECLARE_METATYPE(MirSurfaceItem*)
116Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)122Q_DECLARE_METATYPE(QList<MirSurfaceItem*>)
123Q_DECLARE_METATYPE(Qt::ScreenOrientation)
117124
118#endif // MIRSURFACEITEM_H125#endif // MIRSURFACEITEM_H
119126
=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.qml'
--- tests/mocks/Unity/Application/MirSurfaceItem.qml 2014-08-18 16:59:08 +0000
+++ tests/mocks/Unity/Application/MirSurfaceItem.qml 2014-09-12 19:54:38 +0000
@@ -21,12 +21,22 @@
21 id: root21 id: root
22 color: "pink"22 color: "pink"
2323
24 anchors.fill: parent
25
26 implicitWidth: units.gu(40)24 implicitWidth: units.gu(40)
27 implicitHeight: units.gu(70)25 implicitHeight: units.gu(70)
2826
27 rotation: {
28 if (orientation == Qt.PortraitOrientation) return 0;
29 else if (orientation == Qt.LandscapeOrientation) return 90;
30 else if (orientation == Qt.InvertedPortraitOrientation) return 180;
31 else return 270;
32 }
33 x: parent ? (parent.width - width) / 2 : 0
34 y: parent ? (parent.height - height) / 2 : 0
35 width: parent ? (rotation == 0 || rotation == 180 ? parent.width : parent.height) : implicitWidth
36 height: parent ? (rotation == 0 || rotation == 180 ? parent.height : parent.width) : implicitHeight
37
29 property alias screenshotSource: screenshotImage.source38 property alias screenshotSource: screenshotImage.source
39 property int orientation: Qt.PortraitOrientation
3040
31 property bool wantInputMethod: false41 property bool wantInputMethod: false
3242
3343
=== modified file 'tests/qmltests/Stages/tst_ApplicationWindow.qml'
--- tests/qmltests/Stages/tst_ApplicationWindow.qml 2014-09-02 23:25:33 +0000
+++ tests/qmltests/Stages/tst_ApplicationWindow.qml 2014-09-12 19:54:38 +0000
@@ -50,6 +50,7 @@
50 ApplicationWindow {50 ApplicationWindow {
51 anchors.fill: parent51 anchors.fill: parent
52 application: fakeApplication52 application: fakeApplication
53 orientation: Qt.PortraitOrientation
53 }54 }
54 }55 }
55 FocusScope {56 FocusScope {
@@ -147,6 +148,24 @@
147 }148 }
148 }149 }
149150
151 Button {
152 anchors { left: parent.left; right: parent.right }
153 text: "Rotate device \u27F3"
154 onClicked: {
155 var orientation = applicationWindowLoader.item.orientation
156 if (orientation == Qt.PortraitOrientation) {
157 orientation = Qt.LandscapeOrientation;
158 } else if (orientation == Qt.LandscapeOrientation) {
159 orientation = Qt.InvertedPortraitOrientation;
160 } else if (orientation == Qt.InvertedPortraitOrientation) {
161 orientation = Qt.InvertedLandscapeOrientation;
162 } else {
163 orientation = Qt.PortraitOrientation;
164 }
165 applicationWindowLoader.item.orientation = orientation;
166 }
167 }
168
150 }169 }
151 }170 }
152171
153172
=== modified file 'tests/qmltests/Stages/tst_PhoneStage.qml'
--- tests/qmltests/Stages/tst_PhoneStage.qml 2014-08-27 21:39:17 +0000
+++ tests/qmltests/Stages/tst_PhoneStage.qml 2014-09-12 19:54:38 +0000
@@ -31,6 +31,8 @@
31 anchors { fill: parent; rightMargin: units.gu(30) }31 anchors { fill: parent; rightMargin: units.gu(30) }
32 dragAreaWidth: units.gu(2)32 dragAreaWidth: units.gu(2)
33 maximizedAppTopMargin: units.gu(3) + units.dp(2)33 maximizedAppTopMargin: units.gu(3) + units.dp(2)
34 interactive: true
35 orientation: Qt.PortraitOrientation
34 }36 }
3537
36 Binding {38 Binding {
@@ -67,6 +69,21 @@
67 ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfoInterface.Stopped);69 ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfoInterface.Stopped);
68 }70 }
69 }71 }
72 Button {
73 anchors { left: parent.left; right: parent.right }
74 text: "Rotate device \u27F3"
75 onClicked: {
76 if (phoneStage.orientation == Qt.PortraitOrientation) {
77 phoneStage.orientation = Qt.LandscapeOrientation;
78 } else if (phoneStage.orientation == Qt.LandscapeOrientation) {
79 phoneStage.orientation = Qt.InvertedPortraitOrientation;
80 } else if (phoneStage.orientation == Qt.InvertedPortraitOrientation) {
81 phoneStage.orientation = Qt.InvertedLandscapeOrientation;
82 } else {
83 phoneStage.orientation = Qt.PortraitOrientation;
84 }
85 }
86 }
70 }87 }
71 ListView {88 ListView {
72 id: appList89 id: appList
@@ -256,6 +273,46 @@
256 compare(ApplicationManager.focusedApplicationId, selectedApp.appId);273 compare(ApplicationManager.focusedApplicationId, selectedApp.appId);
257 }274 }
258275
276 function test_orientation_change_sent_to_focused_app() {
277 phoneStage.orientation = Qt.PortraitOrientation;
278 addApps(1);
279
280 var spreadView = findChild(phoneStage, "spreadView");
281 var app = findChild(spreadView, "appDelegate0");
282 tryCompare(app, "orientation", Qt.PortraitOrientation);
283
284 phoneStage.orientation = Qt.LandscapeOrientation;
285 tryCompare(app, "orientation", Qt.LandscapeOrientation);
286 }
287
288 function test_orientation_change_not_sent_to_apps_while_spread_open() {
289 phoneStage.orientation = Qt.PortraitOrientation;
290 addApps(1);
291
292 var spreadView = findChild(phoneStage, "spreadView");
293 var app = findChild(spreadView, "appDelegate0");
294 tryCompare(app, "orientation", Qt.PortraitOrientation);
295
296 goToSpread();
297 phoneStage.orientation = Qt.LandscapeOrientation;
298 tryCompare(app, "orientation", Qt.PortraitOrientation);
299 }
300
301 function test_orientation_change_not_sent_to_unfocused_app_until_it_focused() {
302 phoneStage.orientation = Qt.PortraitOrientation;
303 addApps(1);
304
305 var spreadView = findChild(phoneStage, "spreadView");
306 var app = findChild(spreadView, "appDelegate0");
307
308 goToSpread();
309 phoneStage.orientation = Qt.LandscapeOrientation;
310 tryCompare(app, "orientation", Qt.PortraitOrientation);
311
312 phoneStage.select(app.application.appId);
313 tryCompare(app, "orientation", Qt.LandscapeOrientation);
314 }
315
259 function cleanup() {316 function cleanup() {
260 while (ApplicationManager.count > 1) {317 while (ApplicationManager.count > 1) {
261 var oldCount = ApplicationManager.count;318 var oldCount = ApplicationManager.count;
@@ -263,6 +320,7 @@
263 ApplicationManager.stopApplication(ApplicationManager.get(closingIndex).appId)320 ApplicationManager.stopApplication(ApplicationManager.get(closingIndex).appId)
264 tryCompare(ApplicationManager, "count", oldCount - 1)321 tryCompare(ApplicationManager, "count", oldCount - 1)
265 }322 }
323 phoneStage.orientation = Qt.PortraitOrientation;
266 }324 }
267 }325 }
268}326}
269327
=== modified file 'tests/qmltests/Stages/tst_SessionContainer.qml'
--- tests/qmltests/Stages/tst_SessionContainer.qml 2014-09-02 15:51:20 +0000
+++ tests/qmltests/Stages/tst_SessionContainer.qml 2014-09-12 19:54:38 +0000
@@ -41,6 +41,7 @@
41 SessionContainer {41 SessionContainer {
42 id: sessionContainer42 id: sessionContainer
43 anchors.fill: parent43 anchors.fill: parent
44 orientation: Qt.PortraitOrientation
44 }45 }
45 }46 }
4647
@@ -112,6 +113,24 @@
112 session: sessionContainerLoader.item ? sessionContainerLoader.item.session : null113 session: sessionContainerLoader.item ? sessionContainerLoader.item.session : null
113 }114 }
114 }115 }
116
117 Button {
118 anchors { left: parent.left; right: parent.right }
119 text: "Rotate device \u27F3"
120 onClicked: {
121 var orientation = sessionContainerLoader.item.orientation
122 if (orientation == Qt.PortraitOrientation) {
123 orientation = Qt.LandscapeOrientation;
124 } else if (orientation == Qt.LandscapeOrientation) {
125 orientation = Qt.InvertedPortraitOrientation;
126 } else if (orientation == Qt.InvertedPortraitOrientation) {
127 orientation = Qt.InvertedLandscapeOrientation;
128 } else {
129 orientation = Qt.PortraitOrientation;
130 }
131 sessionContainerLoader.item.orientation = orientation;
132 }
133 }
115 }134 }
116 }135 }
117136
@@ -263,5 +282,49 @@
263 // wait for animation to end282 // wait for animation to end
264 tryCompareFunction(function() { return isContainerAnimating(childContainer); }, false);283 tryCompareFunction(function() { return isContainerAnimating(childContainer); }, false);
265 }284 }
285
286 function test_orientationPropagatedToChildren_data() {
287 return [ { tag: "count=1", count: 1 },
288 { tag: "count=4", count: 4 } ];
289 }
290
291 /* Test orientation changes are propagated to all children immediately */
292 function test_orientationPropagatedToChildren(data) {
293 sessionCheckbox.checked = true;
294 var rootSessionContainer = sessionContainerLoader.item;
295 compare(rootSessionContainer.childSessions.count(), 0);
296
297 var i;
298 var sessions = [];
299 for (i = 0; i < data.count; i++) {
300 var session = ApplicationTest.addChildSession(rootSessionContainer.session,
301 "gallery");
302 session.createSurface();
303 rootSessionContainer.session.addChildSession(session);
304
305 // Check child SessionContainer has orientation matching the parent
306 var delegate = findChild(rootSessionContainer, "childDelegate" + i);
307 var childSessionContainer = findChild(delegate, "sessionContainer");
308
309 tryCompare(rootSessionContainer, "orientation", childSessionContainer.orientation);
310
311 sessions.push(session);
312 }
313
314 // Change orientation and verify all children updated
315 rootSessionContainer.orientation = Qt.LandscapeOrientation;
316
317 for (i = 0; i < data.count; i++) {
318 var delegate = findChild(rootSessionContainer, "childDelegate" + i);
319 var childSessionContainer = findChild(delegate, "sessionContainer");
320
321 tryCompare(rootSessionContainer, "orientation", childSessionContainer.orientation);
322 }
323
324 // Clean up
325 for (i = data.count-1; i >= 0; i--) {
326 ApplicationTest.removeSession(sessions[i]);
327 }
328 }
266 }329 }
267}330}

Subscribers

People subscribed via source and target branches