on xenial help sign in
Implement background changing through gsettings. Make sure it does fallback to default background when needed.

Approved by PS Jenkins bot, Albert Astals Cid.

commit22f302ede03b903b34ca43fcd3acd590577aef3b authorAndrea Cimitan <andrea.cimitan@canonical.com> dateMon 19 Aug 2013, 11:35 (13 years ago) parent9925da6be85892
15 files changed+343−16
Components/CrossFadeImage.qml+3−1 Greeter/GreeterContent.qml−1 Shell.qml+37−12 debian/control+3−1 tests/data/unity/backgrounds/blue.png tests/data/unity/backgrounds/red.png tests/mocks/CMakeLists.txt+1 tests/mocks/GSettings.1.0/CMakeLists.txt+23 tests/mocks/GSettings.1.0/fake_gsettings.cpp+102 tests/mocks/GSettings.1.0/fake_gsettings.h+90 tests/mocks/GSettings.1.0/plugin.cpp+33 tests/mocks/GSettings.1.0/plugin.h+31 tests/mocks/GSettings.1.0/qmldir+2 tests/qmltests/CMakeLists.txt+1−1 tests/qmltests/tst_Shell.qml+17
Components/CrossFadeImage.qml+3−1
@@ -85,7 +85,7 @@ Item {
8585 Connections {
8686 target: __nextImage
8787 onStatusChanged: {
88− if (__nextImage.status == Image.Ready) {
88+ if (__nextImage.status == Image.Ready || __nextImage.status == Image.Error) {
8989 swapImages();
9090 }
9191 }
@@ -96,6 +96,7 @@ Item {
9696 anchors.fill: parent
9797 cache: false
9898 asynchronous: true
99+ fillMode: Image.PreserveAspectCrop
99100 z: 1
100101 }
101102
@@ -104,6 +105,7 @@ Item {
104105 anchors.fill: parent
105106 cache: false
106107 asynchronous: true
108+ fillMode: Image.PreserveAspectCrop
107109 z: 0
108110 }
109111
Greeter/GreeterContent.qml−1
@@ -37,7 +37,6 @@ MouseArea {
3737
3838 source: shell.background
3939 anchors.fill: parent
40− crossFade: false
4140 fadeInFirst: false
4241 }
4342
Shell.qml+37−12
@@ -15,6 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18+import GSettings 1.0
1819import Ubuntu.Application 0.1
1920import Ubuntu.Components 0.1
2021import Ubuntu.Gestures 0.1
@@ -41,8 +42,8 @@ FocusScope {
4142 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
4243
4344 property real edgeSize: units.gu(2)
44− property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
45− property url background: default_background
45+ property url defaultBackground: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
46+ property url background
4647 readonly property real panelHeight: panel.panelHeight
4748
4849 property bool dashShown: dash.shown
@@ -115,6 +116,36 @@ FocusScope {
115116 }
116117 }
117118
119+ GSettings {
120+ id: backgroundSettings
121+ schema.id: "org.gnome.desktop.background"
122+ }
123+ property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
124+ onGSettingsPictureChanged: {
125+ shell.background = gSettingsPicture
126+ }
127+
128+ // This is a dummy image that is needed to determine if the picture url
129+ // in backgroundSettings points to a valid picture file.
130+ // We can't do this with the real background image because setting a
131+ // new source in onStatusChanged triggers a binding loop detection
132+ // inside Image, which causes it not to render even though a valid source
133+ // would be set. We don't mind about this image staying black and just
134+ // use it for verification to populate the source for the real
135+ // background image.
136+ Image {
137+ source: shell.background
138+ height: 0
139+ width: 0
140+ sourceSize.height: 0
141+ sourceSize.width: 0
142+ onStatusChanged: {
143+ if (status == Image.Error && source != shell.defaultBackground) {
144+ shell.background = defaultBackground
145+ }
146+ }
147+ }
148+
118149 VolumeControl {
119150 id: volumeControl
120151 }
@@ -139,12 +170,12 @@ FocusScope {
139170 // through the translucent parts of the shell surface.
140171 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
141172
142− Image {
173+ CrossFadeImage {
143174 id: backgroundImage
144− source: shell.background
145− sourceSize.width: parent.width
146− sourceSize.height: parent.height
175+ objectName: "backgroundImage"
176+
147177 anchors.fill: parent
178+ source: shell.background
148179 }
149180
150181 Rectangle {
@@ -189,7 +220,6 @@ FocusScope {
189220 }
190221 }
191222
192−
193223 Item {
194224 id: stagesOuterContainer
195225
@@ -254,7 +284,6 @@ FocusScope {
254284 ignoreUnknownSignals: true
255285 }
256286
257−
258287 Stage {
259288 id: mainStage
260289
@@ -429,10 +458,6 @@ FocusScope {
429458 }
430459
431460 onUnlocked: greeter.hide()
432− onSelected: {
433− var bgPath = greeter.model.data(uid, LightDM.UserRoles.BackgroundPathRole)
434− shell.background = bgPath ? bgPath : default_background
435− }
436461
437462 onLeftTeaserPressedChanged: {
438463 if (leftTeaserPressed) {
debian/control+3−1
@@ -60,8 +60,10 @@ Description: Indicators client test application
6060
6161Package: unity8
6262Architecture: any
63−Depends: qmenumodel-qml (>= 0.2.7),
63+Depends: gsettings-desktop-schemas,
64+ qmenumodel-qml (>= 0.2.7),
6465 qtdeclarative5-dee-plugin,
66+ qtdeclarative5-gsettings1.0,
6567 qtdeclarative5-ubuntu-ui-toolkit-plugin,
6668 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
6769 qtdeclarative5-xmllistmodel-plugin,
tests/data/unity/backgrounds/blue.pngnew file

Binary file not shown.

tests/data/unity/backgrounds/red.pngnew file

Binary file not shown.

tests/mocks/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1+add_subdirectory(GSettings.1.0)
12add_subdirectory(HudClient)
23add_subdirectory(libusermetrics)
34add_subdirectory(LightDM)
tests/mocks/GSettings.1.0/CMakeLists.txtnew file+23
@@ -0,0 +1,23 @@
1+include_directories(
2+ ${CMAKE_CURRENT_BINARY_DIR}
3+ ${Qt5Core_INCLUDE_DIRS}
4+ ${Qt5Quick_INCLUDE_DIRS}
5+)
6+
7+set(GSettingsQML_SOURCES
8+ fake_gsettings.cpp
9+ plugin.cpp
10+)
11+
12+add_library(FakeGSettingsQml MODULE ${GSettingsQML_SOURCES})
13+target_link_libraries(FakeGSettingsQml
14+ ${Qt5Core_LIBRARIES}
15+ ${Qt5Quick_LIBRARIES}
16+)
17+
18+qt5_use_modules(FakeGSettingsQml Qml)
19+
20+# copy qmldir file into build directory for shadow builds
21+file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
22+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
23+ )
tests/mocks/GSettings.1.0/fake_gsettings.cppnew file+102
@@ -0,0 +1,102 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU 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 "fake_gsettings.h"
18+
19+#include <QList>
20+
21+GSettingsControllerQml* GSettingsControllerQml::s_controllerInstance = 0;
22+
23+GSettingsControllerQml::GSettingsControllerQml() {
24+}
25+
26+GSettingsControllerQml::~GSettingsControllerQml() {
27+ s_controllerInstance = 0;
28+}
29+
30+GSettingsControllerQml* GSettingsControllerQml::instance() {
31+ if (!s_controllerInstance) {
32+ s_controllerInstance = new GSettingsControllerQml();
33+ }
34+ return s_controllerInstance;
35+}
36+
37+void GSettingsControllerQml::registerSettingsObject(GSettingsQml *obj) {
38+ m_registeredGSettings.append(obj);
39+}
40+
41+void GSettingsControllerQml::unRegisterSettingsObject(GSettingsQml *obj) {
42+ m_registeredGSettings.removeOne(obj);
43+}
44+
45+void GSettingsControllerQml::setPictureUri(const QString &str) {
46+ Q_FOREACH (GSettingsQml *obj, m_registeredGSettings) {
47+ obj->setPictureUri(str);
48+ }
49+}
50+
51+GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
52+}
53+
54+QByteArray GSettingsSchemaQml::id() const {
55+ return m_id;
56+}
57+
58+void GSettingsSchemaQml::setId(const QByteArray &id) {
59+ if (m_id.isEmpty()) {
60+ qWarning("GSettings.schema.id may only be set on construction");
61+ return;
62+ }
63+
64+ m_id = id;
65+}
66+
67+QByteArray GSettingsSchemaQml::path() const {
68+ return m_path;
69+}
70+
71+void GSettingsSchemaQml::setPath(const QByteArray &path) {
72+ if (m_path.isEmpty()) {
73+ qWarning("GSettings.schema.path may only be set on construction");
74+ return;
75+ }
76+
77+ m_path = path;
78+}
79+
80+GSettingsQml::GSettingsQml(QObject *parent): QObject(parent) {
81+ m_schema = new GSettingsSchemaQml(this);
82+ GSettingsControllerQml::instance()->registerSettingsObject(this);
83+}
84+
85+GSettingsQml::~GSettingsQml() {
86+ GSettingsControllerQml::instance()->unRegisterSettingsObject(this);
87+}
88+
89+GSettingsSchemaQml * GSettingsQml::schema() const {
90+ return m_schema;
91+}
92+
93+QString GSettingsQml::pictureUri() const {
94+ return m_pictureUri;
95+}
96+
97+void GSettingsQml::setPictureUri(const QString &str) {
98+ if (str != m_pictureUri) {
99+ m_pictureUri = str;
100+ Q_EMIT pictureUriChanged(m_pictureUri);
101+ }
102+}
tests/mocks/GSettings.1.0/fake_gsettings.hnew file+90
@@ -0,0 +1,90 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU 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 FAKE_GSETTINGS_H
18+#define FAKE_GSETTINGS_H
19+
20+#include <QList>
21+#include <QtQml>
22+
23+class GSettingsSchemaQml: public QObject
24+{
25+ Q_OBJECT
26+
27+ Q_PROPERTY(QByteArray id READ id WRITE setId)
28+
29+public:
30+ GSettingsSchemaQml(QObject *parent = NULL);
31+
32+ QByteArray id() const;
33+ void setId(const QByteArray &id);
34+
35+ QByteArray path() const;
36+ void setPath(const QByteArray &path);
37+
38+private:
39+ QByteArray m_id;
40+ QByteArray m_path;
41+};
42+
43+class GSettingsQml: public QObject
44+{
45+ Q_OBJECT
46+
47+ Q_PROPERTY(GSettingsSchemaQml* schema READ schema NOTIFY schemaChanged)
48+ Q_PROPERTY(QString pictureUri READ pictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
49+
50+public:
51+ GSettingsQml(QObject *parent = NULL);
52+ ~GSettingsQml();
53+
54+ GSettingsSchemaQml * schema() const;
55+ QString pictureUri() const;
56+
57+ void setPictureUri(const QString &str);
58+
59+Q_SIGNALS:
60+ void schemaChanged();
61+ void pictureUriChanged(const QString&);
62+
63+private:
64+ GSettingsSchemaQml* m_schema;
65+
66+ QString m_pictureUri;
67+
68+ friend class GSettingsSchemaQml;
69+};
70+
71+class GSettingsControllerQml: public QObject
72+{
73+ Q_OBJECT
74+
75+public:
76+ static GSettingsControllerQml* instance();
77+ ~GSettingsControllerQml();
78+
79+ void registerSettingsObject(GSettingsQml *obj);
80+ void unRegisterSettingsObject(GSettingsQml *obj);
81+ Q_INVOKABLE void setPictureUri(const QString &str);
82+
83+private:
84+ GSettingsControllerQml();
85+
86+ static GSettingsControllerQml* s_controllerInstance;
87+ QList<GSettingsQml *> m_registeredGSettings;
88+};
89+
90+#endif // FAKE_GSETTINGS_H
tests/mocks/GSettings.1.0/plugin.cppnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "plugin.h"
18+#include "fake_gsettings.h"
19+
20+#include <QtQml>
21+
22+static QObject* controllerProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
23+{
24+ return GSettingsControllerQml::instance();
25+}
26+
27+void FakeGSettingsQmlPlugin::registerTypes(const char *uri)
28+{
29+ qmlRegisterSingletonType<GSettingsControllerQml>(uri, 1, 0, "GSettingsController", controllerProvider);
30+ qmlRegisterType<GSettingsQml>(uri, 1, 0, "GSettings");
31+ qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
32+ "GSettingsSchema can only be used inside of a GSettings component");
33+}
tests/mocks/GSettings.1.0/plugin.hnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef PLUGIN_H
18+#define PLUGIN_H
19+
20+#include <QtQml/QQmlExtensionPlugin>
21+
22+class FakeGSettingsQmlPlugin : public QQmlExtensionPlugin
23+{
24+ Q_OBJECT
25+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26+
27+public:
28+ void registerTypes(const char *uri);
29+};
30+
31+#endif // PLUGIN_H
tests/mocks/GSettings.1.0/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module GSettings
2+plugin FakeGSettingsQml
tests/qmltests/CMakeLists.txt+1−1
@@ -26,7 +26,7 @@ set(qmltest_DEFAULT_TARGETS qmluitests)
2626set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
2727set(qmltest_DEFAULT_PROPERTIES "")
2828
29−add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
29+add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
3030 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
3131add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
3232add_qml_test(Components DraggingArea)
tests/qmltests/tst_Shell.qml+17
@@ -19,6 +19,7 @@
1919
2020import QtQuick 2.0
2121import QtTest 1.0
22+import GSettings 1.0
2223import Ubuntu.Application 0.1
2324import Unity.Test 0.1 as UT
2425import Powerd 0.1
@@ -315,5 +316,21 @@ Item {
315316 }
316317 } while (!isStill);
317318 }
319+
320+ function test_wallpaper_data() {
321+ return [
322+ {tag: "red", url: "tests/data/unity/backgrounds/red.png", expectedUrl: "tests/data/unity/backgrounds/red.png"},
323+ {tag: "blue", url: "tests/data/unity/backgrounds/blue.png", expectedUrl: "tests/data/unity/backgrounds/blue.png"},
324+ {tag: "invalid", url: "invalid", expectedUrl: shell.defaultBackground},
325+ {tag: "empty", url: "", expectedUrl: shell.defaultBackground}
326+ ]
327+ }
328+
329+ function test_wallpaper(data) {
330+ var backgroundImage = findChild(shell, "backgroundImage")
331+ GSettingsController.setPictureUri(data.url)
332+ tryCompareFunction(function() { return backgroundImage.source.toString().indexOf(data.expectedUrl) !== -1; }, true)
333+ tryCompare(backgroundImage, "status", Image.Ready)
334+ }
318335 }
319336}