diff --git a/data/com.canonical.Unity8.gschema.xml b/data/com.canonical.Unity8.gschema.xml
index fa531b873f..429064c1db 100644
--- a/data/com.canonical.Unity8.gschema.xml
+++ b/data/com.canonical.Unity8.gschema.xml
@@ -63,6 +63,11 @@
Whether the OSK switch should be visible
Toggle the visibility of the OSK switch
+
+ false
+ Disable top margin for the notch
+ This will restore the previous behavior on devices with a notch. If this option is enabled some indicators might not be visible.
+
diff --git a/plugins/Utils/deviceconfigparser.cpp b/plugins/Utils/deviceconfigparser.cpp
index 3db61a28d6..d63c110482 100644
--- a/plugins/Utils/deviceconfigparser.cpp
+++ b/plugins/Utils/deviceconfigparser.cpp
@@ -134,6 +134,24 @@ bool DeviceConfigParser::readBoolFromConfig(const QString &key, bool defaultValu
return ret;
}
+int DeviceConfigParser::topMargin() const
+{
+ return readIntegerFromConfig("TopMargin", 0);
+}
+
+int DeviceConfigParser::readIntegerFromConfig(const QString &key, int defaultValue) const
+{
+ m_config->beginGroup(m_name);
+
+ int ret = defaultValue;
+ if (m_config->contains(key)) {
+ ret = m_config->value(key).toInt();
+ }
+
+ m_config->endGroup();
+ return ret;
+}
+
QStringList DeviceConfigParser::readOrientationsFromConfig(const QString &key) const
{
m_config->beginGroup(m_name);
diff --git a/plugins/Utils/deviceconfigparser.h b/plugins/Utils/deviceconfigparser.h
index f20108f075..3da4624546 100644
--- a/plugins/Utils/deviceconfigparser.h
+++ b/plugins/Utils/deviceconfigparser.h
@@ -34,6 +34,7 @@ class DeviceConfigParser: public QObject
Q_PROPERTY(Qt::ScreenOrientation invertedPortraitOrientation READ invertedPortraitOrientation NOTIFY changed)
Q_PROPERTY(QString category READ category NOTIFY changed)
Q_PROPERTY(bool supportsMultiColorLed READ supportsMultiColorLed NOTIFY changed)
+ Q_PROPERTY(int topMargin READ topMargin NOTIFY changed)
public:
DeviceConfigParser(QObject *parent = nullptr);
@@ -49,6 +50,7 @@ class DeviceConfigParser: public QObject
Qt::ScreenOrientation invertedPortraitOrientation() const;
QString category() const;
bool supportsMultiColorLed() const;
+ int topMargin() const;
Q_SIGNALS:
void changed();
@@ -61,6 +63,7 @@ class DeviceConfigParser: public QObject
QString readOrientationFromConfig(const QString &key) const;
Qt::ScreenOrientation stringToOrientation(const QString &orientationString, Qt::ScreenOrientation defaultValue) const;
bool readBoolFromConfig(const QString &key, bool defaultValue) const;
+ int readIntegerFromConfig(const QString &key, int defaultValue) const;
};
#endif
diff --git a/qml/DeviceConfiguration.qml b/qml/DeviceConfiguration.qml
index c73f43a915..0189616802 100644
--- a/qml/DeviceConfiguration.qml
+++ b/qml/DeviceConfiguration.qml
@@ -32,6 +32,7 @@ QtObject {
readonly property alias invertedLandscapeOrientation: priv.invertedLandscapeOrientation
readonly property alias portraitOrientation: priv.portraitOrientation
readonly property alias invertedPortraitOrientation: priv.invertedPortraitOrientation
+ readonly property alias topMargin: priv.topMargin
readonly property alias category: priv.category
@@ -55,6 +56,7 @@ QtObject {
property int invertedPortraitOrientation: deviceConfigParser.invertedPortraitOrientation
property string category: deviceConfigParser.category
property bool supportsMultiColorLed: deviceConfigParser.supportsMultiColorLed
+ property int topMargin: deviceConfigParser.topMargin
states: [
State {
@@ -104,6 +106,22 @@ QtObject {
category: "phone"
}
},
+ State {
+ name: "has-notch"
+ PropertyChanges {
+ target: priv
+ primaryOrientation: root.useNativeOrientation
+ supportedOrientations: Qt.PortraitOrientation
+ | Qt.LandscapeOrientation
+ | Qt.InvertedLandscapeOrientation
+ landscapeOrientation: Qt.LandscapeOrientation
+ invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
+ portraitOrientation: Qt.PortraitOrientation
+ invertedPortraitOrientation: Qt.InvertedPortraitOrientation
+ category: "phone"
+ topMargin: 20
+ }
+ },
State {
name: "manta"
PropertyChanges {
@@ -147,6 +165,7 @@ QtObject {
portraitOrientation: Qt.PortraitOrientation
invertedPortraitOrientation: Qt.InvertedPortraitOrientation
category: "desktop"
+ topMargin: 0
}
},
State {
diff --git a/qml/OrientedShell.qml b/qml/OrientedShell.qml
index e03a37ae87..038163bfa4 100644
--- a/qml/OrientedShell.qml
+++ b/qml/OrientedShell.qml
@@ -263,74 +263,81 @@ Item {
shellSnapshot: shellSnapshot
}
- Shell {
- id: shell
- objectName: "shell"
- width: root.width
- height: root.height
- orientation: root.angleToOrientation(orientationAngle)
- orientations: root.orientations
- nativeWidth: root.width
- nativeHeight: root.height
- mode: applicationArguments.mode
- interactiveBlur: applicationArguments.interactiveBlur
- hasMouse: pointerInputDevices > 0
- hasKeyboard: keyboardsModel.count > 0
- hasTouchscreen: touchScreensModel.count > 0
- supportsMultiColorLed: deviceConfiguration.supportsMultiColorLed
- lightIndicators: root.lightIndicators
-
- // Since we dont have proper multiscreen support yet
- // hardcode screen count to only show osk on this screen
- // when it's the only one connected.
- // FIXME once multiscreen has landed
- oskEnabled: (!hasKeyboard && screens.count === 1) ||
- unity8Settings.alwaysShowOsk || forceOSKEnabled
-
- usageScenario: {
- if (unity8Settings.usageMode === "Windowed") {
- return "desktop";
- } else {
- if (deviceConfiguration.category === "phone") {
- return "phone";
+ Item {
+ id: shellContainer
+ objectName: "shellContainer"
+ anchors.fill: parent
+ anchors.topMargin: !unity8Settings.disableTopMargin ? deviceConfiguration.topMargin : 0
+
+ Shell {
+ id: shell
+ objectName: "shell"
+ width: parent.width
+ height: parent.height
+ orientation: root.angleToOrientation(orientationAngle)
+ orientations: root.orientations
+ nativeWidth: parent.width
+ nativeHeight: parent.height
+ mode: applicationArguments.mode
+ interactiveBlur: applicationArguments.interactiveBlur
+ hasMouse: pointerInputDevices > 0
+ hasKeyboard: keyboardsModel.count > 0
+ hasTouchscreen: touchScreensModel.count > 0
+ supportsMultiColorLed: deviceConfiguration.supportsMultiColorLed
+ lightIndicators: root.lightIndicators
+
+ // Since we dont have proper multiscreen support yet
+ // hardcode screen count to only show osk on this screen
+ // when it's the only one connected.
+ // FIXME once multiscreen has landed
+ oskEnabled: (!hasKeyboard && screens.count === 1) ||
+ unity8Settings.alwaysShowOsk || forceOSKEnabled
+
+ usageScenario: {
+ if (unity8Settings.usageMode === "Windowed") {
+ return "desktop";
} else {
- return "tablet";
+ if (deviceConfiguration.category === "phone") {
+ return "phone";
+ } else {
+ return "tablet";
+ }
}
}
- }
- property real transformRotationAngle
- property real transformOriginX
- property real transformOriginY
+ property real transformRotationAngle
+ property real transformOriginX
+ property real transformOriginY
- transform: Rotation {
- origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
- angle: shell.transformRotationAngle
+ transform: Rotation {
+ origin.x: shell.transformOriginX; origin.y: shell.transformOriginY; axis { x: 0; y: 0; z: 1 }
+ angle: shell.transformRotationAngle
+ }
}
- }
- Rectangle {
- id: shellCover
- color: "black"
- anchors.fill: parent
- visible: false
- }
+ Rectangle {
+ id: shellCover
+ color: "black"
+ anchors.fill: parent
+ visible: false
+ }
- ItemSnapshot {
- id: shellSnapshot
- target: shell
- visible: false
- width: root.width
- height: root.height
-
- property real transformRotationAngle
- property real transformOriginX
- property real transformOriginY
-
- transform: Rotation {
- origin.x: shellSnapshot.transformOriginX; origin.y: shellSnapshot.transformOriginY;
- axis { x: 0; y: 0; z: 1 }
- angle: shellSnapshot.transformRotationAngle
+ ItemSnapshot {
+ id: shellSnapshot
+ target: shell
+ visible: false
+ width: parent.width
+ height: parent.height
+
+ property real transformRotationAngle
+ property real transformOriginX
+ property real transformOriginY
+
+ transform: Rotation {
+ origin.x: shellSnapshot.transformOriginX; origin.y: shellSnapshot.transformOriginY;
+ axis { x: 0; y: 0; z: 1 }
+ angle: shellSnapshot.transformRotationAngle
+ }
}
}
}
diff --git a/qml/Rotation/HalfLoopRotationAnimation.qml b/qml/Rotation/HalfLoopRotationAnimation.qml
index 864e865766..bfab4e3f48 100644
--- a/qml/Rotation/HalfLoopRotationAnimation.qml
+++ b/qml/Rotation/HalfLoopRotationAnimation.qml
@@ -30,8 +30,8 @@ SequentialAnimation {
ScriptAction { script: {
info.transitioning = true;
shell.orientationAngle = root.toAngle;
- shell.x = (orientedShell.width - shell.width) / 2
- shell.y = (orientedShell.height - shell.height) / 2;
+ shell.x = (shellContainer.width - shell.width) / 2
+ shell.y = (shellContainer.height - shell.height) / 2;
shell.transformOriginX = shell.width / 2;
shell.transformOriginY = shell.height / 2;
shell.updateFocusedAppOrientation();
diff --git a/qml/Rotation/NinetyRotationAnimation.qml b/qml/Rotation/NinetyRotationAnimation.qml
index f170e0048f..8ab612d6d0 100644
--- a/qml/Rotation/NinetyRotationAnimation.qml
+++ b/qml/Rotation/NinetyRotationAnimation.qml
@@ -24,8 +24,8 @@ SequentialAnimation {
property var info
property var shell
- readonly property real fromY: fromAngle === 0 || fromAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
- readonly property real toY: toAngle === 0 || toAngle === 90 ? 0 : orientedShell.height - orientedShell.width;
+ readonly property real fromY: fromAngle === 0 || fromAngle === 90 ? 0 : shellContainer.height - shellContainer.width;
+ readonly property real toY: toAngle === 0 || toAngle === 90 ? 0 : shellContainer.height - shellContainer.width;
readonly property bool flipShellDimensions: toAngle == 90 || toAngle == 270
ScriptAction { script: {
@@ -33,10 +33,10 @@ SequentialAnimation {
shell.orientationAngle = root.toAngle;
shell.x = 0;
- shell.width = flipShellDimensions ? orientedShell.height : orientedShell.width;
- shell.height = flipShellDimensions ? orientedShell.width : orientedShell.height;
- shell.transformOriginX = orientedShell.width / 2;
- shell.transformOriginY = orientedShell.width / 2;
+ shell.width = flipShellDimensions ? shellContainer.height : shellContainer.width;
+ shell.height = flipShellDimensions ? shellContainer.width : shellContainer.height;
+ shell.transformOriginX = shellContainer.width / 2;
+ shell.transformOriginY = shellContainer.width / 2;
shell.updateFocusedAppOrientation();
shellCover.visible = true;
diff --git a/qml/Rotation/UpdateShellTransformations.qml b/qml/Rotation/UpdateShellTransformations.qml
index 55812fb677..f9ba2085b9 100644
--- a/qml/Rotation/UpdateShellTransformations.qml
+++ b/qml/Rotation/UpdateShellTransformations.qml
@@ -25,17 +25,18 @@ ScriptAction {
shell.transformRotationAngle = rotationAngle;
// They must all be bindings as orientedShell's size can change
+ // ( shellContainer takes into account the margin in case a notch is present )
if (rotationAngle === 90 || rotationAngle === 270) {
- shell.width = Qt.binding(function() { return orientedShell.height; });
- shell.height = Qt.binding(function() { return orientedShell.width; });
+ shell.width = Qt.binding(function() { return shellContainer.height; });
+ shell.height = Qt.binding(function() { return shellContainer.width; });
} else {
- shell.width = Qt.binding(function() { return orientedShell.width; });
- shell.height = Qt.binding(function() { return orientedShell.height; });
+ shell.width = Qt.binding(function() { return shellContainer.width; });
+ shell.height = Qt.binding(function() { return shellContainer.height; });
}
- shell.x = Qt.binding(function() { return (orientedShell.width - shell.width) / 2; });
- shell.y = Qt.binding(function() { return (orientedShell.height - shell.height) / 2; });
+ shell.x = Qt.binding(function() { return (shellContainer.width - shell.width) / 2; });
+ shell.y = Qt.binding(function() { return (shellContainer.height - shell.height) / 2; });
shell.transformOriginX = Qt.binding(function() { return shell.width / 2; });
shell.transformOriginY = Qt.binding(function() { return shell.height / 2; });
}
diff --git a/tests/mocks/GSettings.1.0/fake_gsettings.cpp b/tests/mocks/GSettings.1.0/fake_gsettings.cpp
index c72dec76a1..58f2a0645c 100644
--- a/tests/mocks/GSettings.1.0/fake_gsettings.cpp
+++ b/tests/mocks/GSettings.1.0/fake_gsettings.cpp
@@ -29,6 +29,7 @@ GSettingsControllerQml::GSettingsControllerQml()
, m_edgeDragWidth(2)
, m_enableIndicatorMenu(true)
, m_oskSwitchVisible(false)
+ , m_disableTopMargin(false)
{
}
@@ -173,6 +174,19 @@ void GSettingsControllerQml::setOskSwitchVisible(bool oskSwitchVisible)
}
}
+bool GSettingsControllerQml::disableTopMargin() const
+{
+ return m_disableTopMargin;
+}
+
+void GSettingsControllerQml::setDisableTopMargin(bool disableTopMargin)
+{
+ if (m_disableTopMargin != disableTopMargin) {
+ m_disableTopMargin = disableTopMargin;
+ Q_EMIT disableTopMarginChanged(disableTopMargin);
+ }
+}
+
GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
}
@@ -241,6 +255,8 @@ void GSettingsQml::componentComplete()
this, &GSettingsQml::enableIndicatorMenuChanged);
connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::oskSwitchVisibleChanged,
this, &GSettingsQml::oskSwitchVisibleChanged);
+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::disableTopMarginChanged,
+ this, &GSettingsQml::disableTopMarginChanged);
Q_EMIT disableHeightChanged();
Q_EMIT pictureUriChanged();
@@ -374,6 +390,14 @@ QVariant GSettingsQml::oskSwitchVisible() const
return QVariant();
}
+QVariant GSettingsQml::disableTopMargin() const
+{
+ if (m_valid && m_schema->id() == "com.canonical.Unity8") {
+ return GSettingsControllerQml::instance()->disableTopMargin();
+ }
+ return QVariant();
+}
+
void GSettingsQml::setLifecycleExemptAppids(const QVariant &appIds)
{
if (m_valid && m_schema->id() == "com.canonical.qtmir") {
@@ -415,3 +439,10 @@ void GSettingsQml::setOskSwitchVisible(const QVariant &oskSwitchVisible)
GSettingsControllerQml::instance()->setOskSwitchVisible(oskSwitchVisible.toBool());
}
}
+
+void GSettingsQml::setDisableTopMargin(const QVariant &disableTopMargin)
+{
+ if (m_valid && m_schema->id() == "com.canonical.Unity8") {
+ GSettingsControllerQml::instance()->setDisableTopMargin(disableTopMargin.toBool());
+ }
+}
diff --git a/tests/mocks/GSettings.1.0/fake_gsettings.h b/tests/mocks/GSettings.1.0/fake_gsettings.h
index aef88a8fed..4ac8ab326e 100644
--- a/tests/mocks/GSettings.1.0/fake_gsettings.h
+++ b/tests/mocks/GSettings.1.0/fake_gsettings.h
@@ -59,6 +59,7 @@ class GSettingsQml: public QObject, public QQmlParserStatus
Q_PROPERTY(QVariant edgeDragWidth READ edgeDragWidth WRITE setEdgeDragWidth NOTIFY edgeDragWidthChanged)
Q_PROPERTY(QVariant enableIndicatorMenu READ enableIndicatorMenu WRITE setEnableIndicatorMenu NOTIFY enableIndicatorMenuChanged)
Q_PROPERTY(QVariant oskSwitchVisible READ oskSwitchVisible WRITE setOskSwitchVisible NOTIFY oskSwitchVisibleChanged)
+ Q_PROPERTY(QVariant disableTopMargin READ disableTopMargin WRITE setDisableTopMargin NOTIFY disableTopMarginChanged)
public:
GSettingsQml(QObject *parent = nullptr);
@@ -77,6 +78,7 @@ class GSettingsQml: public QObject, public QQmlParserStatus
QVariant edgeDragWidth() const;
QVariant enableIndicatorMenu() const;
QVariant oskSwitchVisible() const;
+ QVariant disableTopMargin() const;
void setDisableHeight(const QVariant &val);
void setPictureUri(const QVariant &str);
@@ -88,6 +90,7 @@ class GSettingsQml: public QObject, public QQmlParserStatus
void setEdgeDragWidth(const QVariant &edgeDragWidth);
void setEnableIndicatorMenu(const QVariant &enableIndicatorMenu);
void setOskSwitchVisible(const QVariant &oskSwitchVisible);
+ void setDisableTopMargin(const QVariant &disableTopMargin);
Q_SIGNALS:
void disableHeightChanged();
@@ -101,6 +104,7 @@ class GSettingsQml: public QObject, public QQmlParserStatus
void edgeDragWidthChanged();
void enableIndicatorMenuChanged();
void oskSwitchVisibleChanged();
+ void disableTopMarginChanged();
private:
GSettingsSchemaQml* m_schema;
@@ -147,6 +151,9 @@ class GSettingsControllerQml: public QObject
bool oskSwitchVisible() const;
Q_INVOKABLE void setOskSwitchVisible(bool oskSwitchVisible);
+ bool disableTopMargin() const;
+ Q_INVOKABLE void setDisableTopMargin(bool disableTopMargin);
+
Q_SIGNALS:
void disableHeightChanged();
void pictureUriChanged(const QString&);
@@ -158,6 +165,7 @@ class GSettingsControllerQml: public QObject
void edgeDragWidthChanged(uint edgeDragWidth);
void enableIndicatorMenuChanged(bool enableIndicatorMenu);
void oskSwitchVisibleChanged(bool oskSwitchVisible);
+ void disableTopMarginChanged(bool disableTopMargin);
private:
GSettingsControllerQml();
@@ -172,6 +180,7 @@ class GSettingsControllerQml: public QObject
uint m_edgeDragWidth;
bool m_enableIndicatorMenu;
bool m_oskSwitchVisible;
+ bool m_disableTopMargin;
static GSettingsControllerQml* s_controllerInstance;
QList m_registeredGSettings;
diff --git a/tests/plugins/Utils/DeviceConfigParserTest.cpp b/tests/plugins/Utils/DeviceConfigParserTest.cpp
index bc8b0cdbaf..cfbe979652 100644
--- a/tests/plugins/Utils/DeviceConfigParserTest.cpp
+++ b/tests/plugins/Utils/DeviceConfigParserTest.cpp
@@ -44,6 +44,7 @@ private Q_SLOTS:
QCOMPARE(p.landscapeOrientation(), Qt::LandscapeOrientation);
QCOMPARE(p.invertedLandscapeOrientation(), Qt::InvertedLandscapeOrientation);
QCOMPARE(p.supportsMultiColorLed(), true);
+ QCOMPARE(p.topMargin(), 0);
}
void testCustomFile() {
@@ -54,6 +55,7 @@ private Q_SLOTS:
s.setValue("SupportedOrientations", QStringList() << "Portrait" << "Landscape" << "InvertedLandscape");
s.setValue("PrimaryOrientation", "InvertedLandscape");
s.setValue("SupportsMultiColorLed", false);
+ s.setValue("TopMargin", 20);
s.sync();
qputenv("XDG_CONFIG_HOME", dir.path().toUtf8());
@@ -67,6 +69,7 @@ private Q_SLOTS:
QCOMPARE(p.landscapeOrientation(), Qt::LandscapeOrientation);
QCOMPARE(p.invertedLandscapeOrientation(), Qt::InvertedLandscapeOrientation);
QCOMPARE(p.supportsMultiColorLed(), false);
+ QCOMPARE(p.topMargin(), 20);
}
};
diff --git a/tests/qmltests/tst_OrientedShell.qml b/tests/qmltests/tst_OrientedShell.qml
index 50eebfdefa..626571a4bc 100644
--- a/tests/qmltests/tst_OrientedShell.qml
+++ b/tests/qmltests/tst_OrientedShell.qml
@@ -109,6 +109,22 @@ Rectangle {
primaryOrientationAngle: 0
}
},
+ State {
+ name: "has-notch"
+ PropertyChanges {
+ target: shellRect
+ width: units.gu(40)
+ height: units.gu(71)
+ }
+ PropertyChanges {
+ target: root
+ physicalOrientation0: Qt.PortraitOrientation
+ physicalOrientation90: Qt.InvertedLandscapeOrientation
+ physicalOrientation180: Qt.InvertedPortraitOrientation
+ physicalOrientation270: Qt.LandscapeOrientation
+ primaryOrientationAngle: 0
+ }
+ },
State {
name: "manta"
PropertyChanges {
@@ -320,7 +336,7 @@ Rectangle {
anchors { left: parent.left; right: parent.right }
activeFocusOnPress: false
text: "Device Name"
- model: ["mako", "manta", "flo", "desktop"]
+ model: ["mako", "has-notch", "manta", "flo", "desktop"]
onSelectedIndexChanged: {
destroyShell();
applicationArguments.deviceName = model[selectedIndex];
@@ -1700,6 +1716,23 @@ Rectangle {
MockInputDeviceBackend.addMockDevice("/kbd0", InputInfo.Keyboard);
tryCompare(promptKeyboard, "visible", true);
+ function test_disableTopMarginSetting_data() {
+ return [
+ {tag: "top margin enabled", disabled: false, expectedMargin: 20},
+ {tag: "top margin disabled", disabled: true, expectedMargin: 0}
+ ]
+ }
+
+ function test_disableTopMarginSetting(data) {
+ /* Test the GSettings option to disable the topMargin
+ * that reverts to the previous behavior when a
+ * topMargin is specified for the notch.
+ */
+ var orientedShell = loadShell("has-notch");
+ var shellContainer = findChild(orientedShell, "shellContainer");
+ GSettingsController.setDisableTopMargin(data.disabled);
+
+ tryCompare(shellContainer.anchors, "topMargin", data.expectedMargin);
}
}
}