Merge lp:~ci-train-bot/unity8/unity8-ubuntu-xenial-landing-064 into lp:unity8

Proposed by Michał Sawicz
Status: Merged
Merged at revision: 2274
Proposed branch: lp:~ci-train-bot/unity8/unity8-ubuntu-xenial-landing-064
Merge into: lp:unity8
Diff against target: 10220 lines (+4844/-1194)
151 files modified
CMakeLists.txt (+1/-1)
cmake/modules/QmlTest.cmake (+1/-1)
data/com.canonical.Unity8.gschema.xml (+11/-0)
data/unity8-dash.conf (+1/-0)
debian/changelog (+91/-0)
debian/control (+7/-6)
debian/unity8-common.udev (+2/-0)
debian/unity8-doc.install (+1/-0)
doc/devices.conf (+30/-0)
plugins/AccountsService/AccountsService.cpp (+244/-397)
plugins/AccountsService/AccountsService.h (+26/-21)
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp (+11/-4)
plugins/AccountsService/AccountsServiceDBusAdaptor.h (+5/-6)
plugins/Dash/AudioProgressBar.qml (+1/-0)
plugins/Dash/CardCreator.js (+69/-34)
plugins/Dash/CardCreatorCache.qml (+3/-3)
plugins/Dash/plugin.cpp (+6/-6)
plugins/GlobalShortcut/globalshortcutregistry.cpp (+4/-4)
plugins/IntegratedLightDM/liblightdm/CMakeLists.txt (+16/-3)
plugins/IntegratedLightDM/liblightdm/UsersModel.cpp (+4/-18)
plugins/IntegratedLightDM/liblightdm/UsersModel.h (+1/-1)
plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp (+44/-10)
plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h (+15/-3)
plugins/Unity/Indicators/indicatorsmanager.cpp (+2/-2)
plugins/Unity/Indicators/rootstateparser.h (+1/-0)
plugins/Unity/Launcher/desktopfilehandler.cpp (+2/-2)
plugins/Unity/Launcher/launcheritem.cpp (+1/-0)
plugins/Unity/Launcher/launcheritem.h (+1/-1)
plugins/Unity/Launcher/launchermodel.cpp (+15/-5)
plugins/Unity/Launcher/launchermodel.h (+1/-1)
plugins/Utils/CMakeLists.txt (+1/-0)
plugins/Utils/deviceconfigparser.cpp (+150/-0)
plugins/Utils/deviceconfigparser.h (+62/-0)
plugins/Utils/plugin.cpp (+2/-0)
po/unity8.pot (+29/-27)
qml/Components/EdgeBarrier.qml (+1/-1)
qml/Components/InputMethod.qml (+1/-9)
qml/Components/Lockscreen.qml (+86/-100)
qml/Components/ModeSwitchWarningDialog.qml (+1/-1)
qml/Components/PassphraseLockscreen.qml (+5/-4)
qml/Components/PhysicalKeysMapper.qml (+24/-0)
qml/Components/PinLockscreen.qml (+22/-1)
qml/Components/ShellDialog.qml (+8/-0)
qml/Dash/CardCarousel.qml (+0/-1)
qml/Dash/CardGrid.qml (+0/-1)
qml/Dash/CardHorizontalList.qml (+0/-1)
qml/Dash/CardTool.qml (+2/-26)
qml/Dash/CardVerticalJournal.qml (+0/-1)
qml/Dash/Dash.qml (+11/-11)
qml/Dash/GenericScopeView.qml (+2/-0)
qml/Dash/Previews/PreviewHeader.qml (+37/-9)
qml/Dash/Previews/PreviewOverlay.qml (+1/-1)
qml/Dash/Previews/PreviewSharing.qml (+17/-7)
qml/Dash/ScopesListCategoryItem.qml (+8/-4)
qml/DeviceConfiguration.qml (+56/-18)
qml/DisabledScreenNotice.qml (+44/-20)
qml/Greeter/CoverPage.qml (+13/-2)
qml/Greeter/Infographics.qml (+2/-1)
qml/Greeter/NarrowView.qml (+14/-1)
qml/Launcher/Launcher.qml (+144/-11)
qml/Launcher/LauncherDelegate.qml (+55/-20)
qml/Launcher/LauncherPanel.qml (+122/-51)
qml/Launcher/graphics/launcher-app-focus-ring.svg (+12/-0)
qml/Notifications/Notification.qml (+6/-2)
qml/OrientedShell.qml (+26/-1)
qml/Panel/Handle.qml (+2/-2)
qml/Panel/Indicators/MenuItemFactory.qml (+0/-1)
qml/Panel/IndicatorsMenu.qml (+1/-1)
qml/Panel/Panel.qml (+5/-1)
qml/ScopeTool.qml (+0/-8)
qml/Shell.qml (+51/-1)
qml/Stages/AbstractStage.qml (+3/-1)
qml/Stages/DesktopSpread.qml (+64/-17)
qml/Stages/DesktopSpreadDelegate.qml (+15/-1)
qml/Stages/DesktopStage.qml (+34/-34)
qml/Stages/PhoneStage.qml (+77/-3)
qml/Stages/SpreadDelegate.qml (+20/-0)
qml/Stages/TabletStage.qml (+83/-3)
qml/Stages/WindowResizeArea.qml (+8/-5)
src/CMakeLists.txt (+1/-1)
src/CachingNetworkManagerFactory.cpp (+2/-2)
src/CachingNetworkManagerFactory.h (+3/-2)
src/Dash/CMakeLists.txt (+1/-1)
tests/autopilot/unity8/dash.py (+1/-2)
tests/autopilot/unity8/shell/tests/test_helpers.py (+0/-2)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+64/-0)
tests/mocks/GSettings.1.0/fake_gsettings.h (+18/-0)
tests/mocks/IntegratedLightDM/liblightdm/UsersModel.cpp (+0/-14)
tests/mocks/Unity/Application/MirSurface.cpp (+6/-2)
tests/mocks/Unity/Application/MirSurface.h (+2/-1)
tests/mocks/Unity/Application/SurfaceManager.cpp (+8/-9)
tests/mocks/Unity/Application/SurfaceManager.h (+3/-3)
tests/mocks/Unity/Application/VirtualKeyboard.cpp (+3/-2)
tests/mocks/Unity/Application/VirtualKeyboard.h (+1/-1)
tests/mocks/Unity/Application/plugin.cpp (+2/-1)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+2/-0)
tests/mocks/Utils/CMakeLists.txt (+1/-0)
tests/mocks/Utils/plugin.cpp (+2/-0)
tests/plugins/AccountsService/CMakeLists.txt (+5/-0)
tests/plugins/AccountsService/PropertiesServer.cpp (+16/-4)
tests/plugins/AccountsService/PropertiesServer.h (+2/-1)
tests/plugins/AccountsService/UscServer.cpp (+28/-0)
tests/plugins/AccountsService/UscServer.h (+39/-0)
tests/plugins/AccountsService/client.cpp (+63/-9)
tests/plugins/AccountsService/interfaces.xml (+16/-0)
tests/plugins/AccountsService/server.cpp (+12/-0)
tests/plugins/Dash/cardcreator/1.res (+4/-6)
tests/plugins/Dash/cardcreator/1.res.cardcreator (+119/-0)
tests/plugins/Dash/cardcreator/10.res (+3/-5)
tests/plugins/Dash/cardcreator/10.res.cardcreator (+137/-0)
tests/plugins/Dash/cardcreator/11.res (+5/-7)
tests/plugins/Dash/cardcreator/11.res.cardcreator (+210/-0)
tests/plugins/Dash/cardcreator/2.res (+3/-5)
tests/plugins/Dash/cardcreator/2.res.cardcreator (+136/-0)
tests/plugins/Dash/cardcreator/3.res (+3/-5)
tests/plugins/Dash/cardcreator/3.res.cardcreator (+137/-0)
tests/plugins/Dash/cardcreator/4.res (+3/-5)
tests/plugins/Dash/cardcreator/4.res.cardcreator (+109/-0)
tests/plugins/Dash/cardcreator/5.res (+5/-7)
tests/plugins/Dash/cardcreator/5.res.cardcreator (+156/-0)
tests/plugins/Dash/cardcreator/6.res (+2/-4)
tests/plugins/Dash/cardcreator/6.res.cardcreator (+126/-0)
tests/plugins/Dash/cardcreator/7.res (+3/-5)
tests/plugins/Dash/cardcreator/7.res.cardcreator (+149/-0)
tests/plugins/Dash/cardcreator/8.res (+3/-5)
tests/plugins/Dash/cardcreator/8.res.cardcreator (+107/-0)
tests/plugins/Dash/cardcreator/9.res (+4/-5)
tests/plugins/Dash/cardcreator/9.res.cardcreator (+119/-0)
tests/plugins/Dash/cardcreatortest.cpp (+35/-25)
tests/plugins/Dash/cardcreatortest.qml (+4/-4)
tests/plugins/IntegratedLightDM/CMakeLists.txt (+25/-0)
tests/plugins/IntegratedLightDM/integrated.cpp (+91/-0)
tests/plugins/Utils/CMakeLists.txt (+7/-1)
tests/plugins/Utils/DeviceConfigParserTest.cpp (+70/-0)
tests/qmltests/CMakeLists.txt (+1/-0)
tests/qmltests/Components/tst_Lockscreen.qml (+14/-7)
tests/qmltests/Dash/Previews/tst_PreviewHeader.qml (+18/-1)
tests/qmltests/Dash/Previews/tst_PreviewSharing.qml (+17/-3)
tests/qmltests/Dash/tst_CardTool.qml (+4/-4)
tests/qmltests/Dash/tst_Dash.qml (+89/-0)
tests/qmltests/Greeter/tst_NarrowView.qml (+9/-0)
tests/qmltests/Launcher/tst_Launcher.qml (+254/-18)
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml (+2/-4)
tests/qmltests/Stages/tst_DesktopStage.qml (+2/-1)
tests/qmltests/Stages/tst_PhoneStage.qml (+19/-6)
tests/qmltests/Stages/tst_SpreadDelegate.qml (+7/-0)
tests/qmltests/Stages/tst_TabletStage.qml (+19/-1)
tests/qmltests/tst_DeviceConfiguration.qml (+49/-0)
tests/qmltests/tst_DisabledScreenNotice.qml (+76/-2)
tests/qmltests/tst_OrientedShell.qml (+1/-1)
tests/qmltests/tst_Shell.qml (+243/-61)
To merge this branch: bzr merge lp:~ci-train-bot/unity8/unity8-ubuntu-xenial-landing-064
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+288755@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2016-02-12 00:12:30 +0000
3+++ CMakeLists.txt 2016-03-11 11:34:41 +0000
4@@ -131,7 +131,7 @@
5 set(STDOUT_LOGGER "-o" "-,txt")
6 endif()
7
8-execute_process(COMMAND arch OUTPUT_VARIABLE ARCH)
9+execute_process(COMMAND dpkg-architecture -qDEB_HOST_ARCH OUTPUT_VARIABLE ARCH)
10 if (NOT ARCH MATCHES "arm*")
11 set(ENABLE_TOUCH_EMULATION true)
12 add_definitions(-DUNITY8_ENABLE_TOUCH_EMULATION)
13
14=== modified file 'cmake/modules/QmlTest.cmake'
15--- cmake/modules/QmlTest.cmake 2015-05-21 20:24:47 +0000
16+++ cmake/modules/QmlTest.cmake 2016-03-11 11:34:41 +0000
17@@ -183,7 +183,7 @@
18 cmake_parse_arguments(QMLTEST "${QMLTEST_OPTIONS}" "${QMLTEST_SINGLE}" "${QMLTEST_MULTI}" ${ARGN})
19 mangle_arguments()
20
21- bake_arguments("${QMLTEST_ARG_PREFIX}" args -qmljsdebugger=port:3768)
22+ bake_arguments("${QMLTEST_ARG_PREFIX}" args -qmljsdebugger=port:3768,3800)
23
24 set(qmltry_command
25 $<TARGET_FILE:${TARGET}>
26
27=== modified file 'data/com.canonical.Unity8.gschema.xml'
28--- data/com.canonical.Unity8.gschema.xml 2015-11-24 17:44:18 +0000
29+++ data/com.canonical.Unity8.gschema.xml 2016-03-11 11:34:41 +0000
30@@ -27,6 +27,17 @@
31 <summary>Maximum push needed to overcome edge barrier</summary>
32 <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description>
33 </key>
34+ <key type="b" name="autohide-launcher">
35+ <default>true</default>
36+ <summary>Autohide the launcher</summary>
37+ <description>This will only be applied in windowed mode. In staged mode, the launcher will always hide.</description>
38+ </key>
39+ <key type="u" name="launcher-width">
40+ <default>8</default>
41+ <range min="6" max="12"/>
42+ <summary>Width of the launcher in grid units.</summary>
43+ <description>Changes the width of the launcher in all usage modes.</description>
44+ </key>
45 </schema>
46
47 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
48
49=== modified file 'data/unity8-dash.conf'
50--- data/unity8-dash.conf 2015-04-21 15:41:09 +0000
51+++ data/unity8-dash.conf 2016-03-11 11:34:41 +0000
52@@ -14,6 +14,7 @@
53 oom score 50
54
55 respawn
56+respawn limit unlimited
57
58 env APP_ID=unity8-dash
59
60
61=== modified file 'debian/changelog'
62--- debian/changelog 2016-03-08 20:59:35 +0000
63+++ debian/changelog 2016-03-11 11:34:41 +0000
64@@ -1,3 +1,94 @@
65+unity8 (8.11+16.04.20160310.4-0ubuntu1) xenial; urgency=medium
66+
67+ [ Albert Astals Cid ]
68+ * Add context for Re-dock as asked by translators (LP: #1534608)
69+ * Add emblem to the preview header widget (LP: #1424720)
70+ * Add haptics to ScopesListCategoryItem buttons
71+ * Audio Cards: Make some of the image loading async (LP: #1533432)
72+ * Do not create fallback code for the card tool fake card (LP:
73+ #1545865)
74+ * Fix resizing the dash bringing temp scopes size out of sync (LP:
75+ #1543130)
76+ * Minor fixes for unity-scope-tool
77+ * Resolve title alignment on card creator time instead of on runtime
78+ * Use fixedHeaderHeight only in the non cardtool cards
79+ * Use the new undeprecated connectivityqt::Connectivity
80+ * asynchronous is only false on the fake card in cardtool
81+ * clazy fixes
82+
83+ [ Albert Astals Cid, CI Train Bot ]
84+ * click scope: Add the else branch so we reset the card size in all
85+ situations
86+
87+ [ Andrea Cimitan ]
88+ * PreviewSharing widget now accepts both string and array of
89+ widgetData["share-data"]["uri"] (LP: #1549056)
90+ * Update AP tests for new single preview
91+ * Use Text.Wrap for body notification text (LP: #1544909)
92+
93+ [ Andrea Cimitan, Lukáš Tinkl, Michael Zanetti, Nick Dedekind ]
94+ * some fixes for the new palette (LP: #1554616)
95+
96+ [ CI Train Bot ]
97+ * Resync trunk.
98+ * Update translation template
99+
100+ [ CI Train Bot, Daniel d'Andrada ]
101+ * Ensure the QML engine doesn't delete our mock MirSurfaces on its
102+ own.
103+
104+ [ Daniel d'Andrada ]
105+ * tst_Shell: Remove unused qml items
106+
107+ [ Josh Arenson ]
108+ * Allow the shell to blacklist input devices and force the OSK shown.
109+ (LP: #1542224)
110+
111+ [ Lukáš Tinkl ]
112+ * Disallow resizing windows up, past the Panel (LP: #1544766)
113+ * Elide the window title not to let it overflow into the indicators
114+ area (LP: #1535767)
115+ * Enable the PIN lockscreen to be used with a HW keyboard (LP:
116+ #1550359)
117+ * Fix tiny windows when switching stages
118+ * Provide a range of ports to QML JS Debugger
119+ * Watch for launcher item icon changes (LP: #1543290)
120+
121+ [ Michael Terry ]
122+ * Proxy more mouse and touchpad properties to USC (LP: #1540398) (LP:
123+ #1543344, #1540398)
124+ * Refactor the AccountsService plugin and make it slightly faster.
125+ * To let the user log in if a mouse is connected, hide the greeter
126+ cover page on a mouse click (but NOT a touch click). (LP: #1540497)
127+ * Watch AccountsService for changes to the user's real name. This was
128+ preventing us from noticing when the user set their name in the
129+ welcome wizard.
130+
131+ [ Michael Zanetti ]
132+ * Allow alt+tabbing in staged mode too (LP: #1540502)
133+ * Allow invoking the staged mode spreads by mouse right edge pushes
134+ too (LP: #1540392)
135+ * Allow loading the device configuration from an external file
136+ * Implement Launcher's keyboard navigation and updated pip design
137+ * Make launcher scalable, allow it locking (LP: #1511015)
138+ * Properly parent launcher items in all cases (LP: #1495732)
139+ * Read inputMethod surface from the new property int QtMir (LP:
140+ #1545286)
141+ * Some visual updates and rotation lock for the virtual touchpad (LP:
142+ #1549087)
143+ * Visual updates for the windowed spread (LP: #1488148)
144+ * stabilize swipeAwayGreeter()
145+
146+ [ Michał Sawicz ]
147+ * Add udev rules to make sure we have access to uinput
148+ * Make dash respawn indefinitely (LP: #1550056)
149+ * Use dpkg-architecture, not arch, to disable touch emulation
150+
151+ [ Vesa Rautiainen ]
152+ * Fixing the vertical position of desktop spread item icon.
153+
154+ -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 10 Mar 2016 22:44:16 +0000
155+
156 unity8 (8.11+16.04.20160308-0ubuntu1) xenial; urgency=medium
157
158 [ Albert Astals Cid ]
159
160=== modified file 'debian/control'
161--- debian/control 2016-03-04 21:03:43 +0000
162+++ debian/control 2016-03-11 11:34:41 +0000
163@@ -13,7 +13,7 @@
164 libandroid-properties-dev,
165 graphviz,
166 gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815),
167- libconnectivity-qt1-dev,
168+ libconnectivity-qt1-dev (>= 0.7.1),
169 libevdev-dev,
170 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
171 libgl1-mesa-dri,
172@@ -55,7 +55,7 @@
173 qtdeclarative5-qtmultimedia-plugin (>= 5.4.1-1ubuntu19~overlay2),
174 qtdeclarative5-ubuntu-content1,
175 qtdeclarative5-ubuntu-settings-components (>= 0.7),
176- qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1796) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1796),
177+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845),
178 qtdeclarative5-ubuntu-web-plugin,
179 ttf-ubuntu-font-family,
180 Standards-Version: 3.9.4
181@@ -70,7 +70,7 @@
182 Package: indicators-client
183 Architecture: amd64 armhf i386
184 Depends: qmenumodel-qml (>= 0.2.9),
185- qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1796) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1796),
186+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845),
187 unity8 (= ${binary:Version}),
188 ${misc:Depends},
189 ${shlibs:Depends},
190@@ -101,7 +101,6 @@
191 qml-module-qt-labs-folderlistmodel,
192 qml-module-qtquick-xmllistmodel,
193 qml-module-qtsysteminfo,
194- qtdeclarative5-gsettings1.0,
195 qtdeclarative5-qtmir-plugin (>= 0.4.5),
196 qtdeclarative5-ubuntu-telephony0.1,
197 qtdeclarative5-ubuntu-web-plugin,
198@@ -128,7 +127,7 @@
199 Depends: qml-module-qtquick-layouts,
200 qtdeclarative5-ubuntu-settings-components (>= 0.7),
201 qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
202- qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1796) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1796),
203+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845),
204 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
205 ubuntu-thumbnailer-impl-0,
206 unity-application-impl-13,
207@@ -158,7 +157,7 @@
208 python3-fixtures,
209 python3-gi,
210 qttestability-autopilot (>= 1.4),
211- ubuntu-ui-toolkit-autopilot (>= 1.3.1796),
212+ ubuntu-ui-toolkit-autopilot (>= 1.3.1845),
213 unity-scope-click,
214 unity8 (= ${source:Version}),
215 unity8-fake-env (= ${source:Version}),
216@@ -192,6 +191,8 @@
217 libhardware2,
218 pay-service,
219 unity-schemas (>= 7.3.1+14.10.20140915),
220+ qtdeclarative5-gsettings1.0,
221+ qml-module-qtmultimedia,
222 ${misc:Depends},
223 ${shlibs:Depends},
224 Provides: unity-launcher-impl,
225
226=== added file 'debian/unity8-common.udev'
227--- debian/unity8-common.udev 1970-01-01 00:00:00 +0000
228+++ debian/unity8-common.udev 2016-03-11 11:34:41 +0000
229@@ -0,0 +1,2 @@
230+# Make local foreground session able to inject input
231+KERNEL=="uinput", SUBSYSTEM=="misc", TAG+="uaccess"
232
233=== modified file 'debian/unity8-doc.install'
234--- debian/unity8-doc.install 2014-01-30 22:32:37 +0000
235+++ debian/unity8-doc.install 2016-03-11 11:34:41 +0000
236@@ -1,1 +1,2 @@
237+doc/devices.conf usr/share/doc/unity8/
238 usr/share/doc/unity8/*
239
240=== added file 'doc/devices.conf'
241--- doc/devices.conf 1970-01-01 00:00:00 +0000
242+++ doc/devices.conf 2016-03-11 11:34:41 +0000
243@@ -0,0 +1,30 @@
244+# This file can hold multiple device configs. Devices are separated by sections.
245+#
246+# SupportedOrientations holds a list of all enabled orientations. A standard
247+# phone will usually have Portrait,Landcape,InvertedLandscape in order to
248+# disable upside down usage.
249+#
250+# PrimaryOrientation gives the orientation the device will start up with
251+# when there is no orientations sensor input available (yet) or lock to
252+# when an application specifies to be locked to PrimaryOrientation.
253+#
254+# The other Orientation settings can be used to re-map the orientations.
255+# A device might be used with different orientations than how the screen
256+# is physically mounted on the hardware.
257+#
258+# Category can be phone, tablet, or desktop. This option determines
259+# whether the side stage is shown (tablet) or not (phone). Using
260+# desktop will load the shell in windowed mode. Note that the user
261+# can override/change this by connecting input hardware or change
262+# user settings.
263+#
264+# Any options not listed will default to the values of the example below.
265+
266+[devicename]
267+SupportedOrientations=Portrait,InvertedPortrait,Landscape,InvertedLandscape
268+PrimaryOrientation=PrimaryOrienation
269+PortraitOrientation=Portrait
270+InvertedPortraitOrientation=InvertedPortrait
271+LandscapeOrientation=Landscape
272+InvertedLandscapeOrientation=InvertedLandscape
273+Category=phone
274
275=== modified file 'plugins/AccountsService/AccountsService.cpp'
276--- plugins/AccountsService/AccountsService.cpp 2016-01-21 21:04:00 +0000
277+++ plugins/AccountsService/AccountsService.cpp 2016-03-11 11:34:41 +0000
278@@ -24,17 +24,52 @@
279 #include <QStringList>
280 #include <QDebug>
281
282+#define IFACE_ACCOUNTS_USER QStringLiteral("org.freedesktop.Accounts.User")
283+#define IFACE_LOCATION_HERE QStringLiteral("com.ubuntu.location.providers.here.AccountsService")
284+#define IFACE_UBUNTU_INPUT QStringLiteral("com.ubuntu.AccountsService.Input")
285+#define IFACE_UBUNTU_SECURITY QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy")
286+#define IFACE_UBUNTU_SECURITY_OLD QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy")
287+#define IFACE_UNITY QStringLiteral("com.canonical.unity.AccountsService")
288+#define IFACE_UNITY_PRIVATE QStringLiteral("com.canonical.unity.AccountsService.Private")
289+
290+#define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile")
291+#define PROP_DEMO_EDGES QStringLiteral("demo-edges")
292+#define PROP_ENABLE_INDICATORS_WHILE_LOCKED QStringLiteral("EnableIndicatorsWhileLocked")
293+#define PROP_ENABLE_LAUNCHER_WHILE_LOCKED QStringLiteral("EnableLauncherWhileLocked")
294+#define PROP_FAILED_LOGINS QStringLiteral("FailedLogins")
295+#define PROP_LICENSE_ACCEPTED QStringLiteral("LicenseAccepted")
296+#define PROP_LICENSE_BASE_PATH QStringLiteral("LicenseBasePath")
297+#define PROP_MOUSE_CURSOR_SPEED QStringLiteral("MouseCursorSpeed")
298+#define PROP_MOUSE_DOUBLE_CLICK_SPEED QStringLiteral("MouseDoubleClickSpeed")
299+#define PROP_MOUSE_PRIMARY_BUTTON QStringLiteral("MousePrimaryButton")
300+#define PROP_MOUSE_SCROLL_SPEED QStringLiteral("MouseScrollSpeed")
301+#define PROP_PASSWORD_DISPLAY_HINT QStringLiteral("PasswordDisplayHint")
302+#define PROP_STATS_WELCOME_SCREEN QStringLiteral("StatsWelcomeScreen")
303+#define PROP_TOUCHPAD_CURSOR_SPEED QStringLiteral("TouchpadCursorSpeed")
304+#define PROP_TOUCHPAD_DISABLE_WHILE_TYPING QStringLiteral("TouchpadDisableWhileTyping")
305+#define PROP_TOUCHPAD_DISABLE_WITH_MOUSE QStringLiteral("TouchpadDisableWithMouse")
306+#define PROP_TOUCHPAD_DOUBLE_CLICK_SPEED QStringLiteral("TouchpadDoubleClickSpeed")
307+#define PROP_TOUCHPAD_PRIMARY_BUTTON QStringLiteral("TouchpadPrimaryButton")
308+#define PROP_TOUCHPAD_SCROLL_SPEED QStringLiteral("TouchpadScrollSpeed")
309+#define PROP_TOUCHPAD_TAP_TO_CLICK QStringLiteral("TouchpadTapToClick")
310+#define PROP_TOUCHPAD_TWO_FINGER_SCROLL QStringLiteral("TouchpadTwoFingerScroll")
311+
312+
313+QVariant primaryButtonConverter(const QVariant &value)
314+{
315+ QString stringValue = value.toString();
316+ if (stringValue == "left") {
317+ return QVariant::fromValue(0);
318+ } else if (stringValue == "right") {
319+ return QVariant::fromValue(1); // Mir is less clear on this -- any non-zero value is the same
320+ } else {
321+ return QVariant::fromValue(0); // default to left
322+ }
323+}
324+
325 AccountsService::AccountsService(QObject* parent, const QString &user)
326- : QObject(parent),
327- m_service(new AccountsServiceDBusAdaptor(this)),
328- m_demoEdges(false),
329- m_enableLauncherWhileLocked(false),
330- m_enableIndicatorsWhileLocked(false),
331- m_statsWelcomeScreen(false),
332- m_passwordDisplayHint(Keyboard),
333- m_failedLogins(0),
334- m_hereEnabled(false),
335- m_hereLicensePath() // null means not set yet
336+ : QObject(parent)
337+ , m_service(new AccountsServiceDBusAdaptor(this))
338 {
339 m_unityInput = new QDBusInterface(QStringLiteral("com.canonical.Unity.Input"),
340 QStringLiteral("/com/canonical/Unity/Input"),
341@@ -44,6 +79,43 @@
342 connect(m_service, &AccountsServiceDBusAdaptor::propertiesChanged, this, &AccountsService::onPropertiesChanged);
343 connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
344
345+ registerProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE, QStringLiteral("backgroundFileChanged"));
346+ registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, QStringLiteral("hereEnabledChanged"));
347+ registerProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH, QStringLiteral("hereLicensePathChanged"));
348+ registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED, QStringLiteral("enableLauncherWhileLockedChanged"));
349+ registerProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED, QStringLiteral("enableIndicatorsWhileLockedChanged"));
350+ registerProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT, QStringLiteral("passwordDisplayHintChanged"));
351+ registerProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN, QStringLiteral("statsWelcomeScreenChanged"));
352+ registerProperty(IFACE_UNITY, PROP_DEMO_EDGES, QStringLiteral("demoEdgesChanged"));
353+ registerProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, QStringLiteral("failedLoginsChanged"));
354+
355+ registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_CURSOR_SPEED,
356+ m_unityInput, QStringLiteral("setMouseCursorSpeed"));
357+ registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_DOUBLE_CLICK_SPEED,
358+ m_unityInput, QStringLiteral("setMouseDoubleClickSpeed"));
359+ registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_PRIMARY_BUTTON,
360+ m_unityInput, QStringLiteral("setMousePrimaryButton"),
361+ primaryButtonConverter);
362+ registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_SCROLL_SPEED,
363+ m_unityInput, QStringLiteral("setMouseScrollSpeed"));
364+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_CURSOR_SPEED,
365+ m_unityInput, QStringLiteral("setTouchpadCursorSpeed"));
366+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_SCROLL_SPEED,
367+ m_unityInput, QStringLiteral("setTouchpadScrollSpeed"));
368+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WHILE_TYPING,
369+ m_unityInput, QStringLiteral("setTouchpadDisableWhileTyping"));
370+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DISABLE_WITH_MOUSE,
371+ m_unityInput, QStringLiteral("setTouchpadDisableWithMouse"));
372+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_DOUBLE_CLICK_SPEED,
373+ m_unityInput, QStringLiteral("setTouchpadDoubleClickSpeed"));
374+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_PRIMARY_BUTTON,
375+ m_unityInput, QStringLiteral("setTouchpadPrimaryButton"),
376+ primaryButtonConverter);
377+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TAP_TO_CLICK,
378+ m_unityInput, QStringLiteral("setTouchpadTapToClick"));
379+ registerProxy(IFACE_UBUNTU_INPUT, PROP_TOUCHPAD_TWO_FINGER_SCROLL,
380+ m_unityInput, QStringLiteral("setTouchpadTwoFingerScroll"));
381+
382 setUser(!user.isEmpty() ? user : QString::fromUtf8(qgetenv("USER")));
383 }
384
385@@ -57,410 +129,200 @@
386 if (user.isEmpty() || m_user == user)
387 return;
388
389+ bool wasEmpty = m_user.isEmpty();
390+
391 m_user = user;
392 Q_EMIT userChanged();
393
394- updateDemoEdges(false);
395- updateEnableLauncherWhileLocked(false);
396- updateEnableIndicatorsWhileLocked(false);
397- updateBackgroundFile(false);
398- updateMouseCursorSpeed();
399- updateTouchpadCursorSpeed();
400- updateStatsWelcomeScreen(false);
401- updatePasswordDisplayHint(false);
402- updateFailedLogins(false);
403- updateHereEnabled(false);
404- updateHereLicensePath(false);
405+ // Do the first update synchronously, as a cheap way to block rendering
406+ // until we have the right values on bootup.
407+ refresh(!wasEmpty);
408 }
409
410 bool AccountsService::demoEdges() const
411 {
412- return m_demoEdges;
413+ auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES);
414+ return value.toBool();
415 }
416
417 void AccountsService::setDemoEdges(bool demoEdges)
418 {
419- if (m_demoEdges != demoEdges) {
420- m_demoEdges = demoEdges;
421- m_service->setUserPropertyAsync(m_user, QStringLiteral("com.canonical.unity.AccountsService"), QStringLiteral("demo-edges"), demoEdges);
422-
423- Q_EMIT demoEdgesChanged();
424- }
425+ setProperty(IFACE_UNITY, PROP_DEMO_EDGES, demoEdges);
426 }
427
428 bool AccountsService::enableLauncherWhileLocked() const
429 {
430- return m_enableLauncherWhileLocked;
431+ auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED);
432+ return value.toBool();
433 }
434
435 bool AccountsService::enableIndicatorsWhileLocked() const
436 {
437- return m_enableIndicatorsWhileLocked;
438+ auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_INDICATORS_WHILE_LOCKED);
439+ return value.toBool();
440 }
441
442 QString AccountsService::backgroundFile() const
443 {
444- return m_backgroundFile;
445+ auto value = getProperty(IFACE_ACCOUNTS_USER, PROP_BACKGROUND_FILE);
446+ return value.toString();
447 }
448
449 bool AccountsService::statsWelcomeScreen() const
450 {
451- return m_statsWelcomeScreen;
452+ auto value = getProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN);
453+ return value.toBool();
454 }
455
456 AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const
457 {
458- return m_passwordDisplayHint;
459+ auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT);
460+ return (PasswordDisplayHint)value.toInt();
461 }
462
463 bool AccountsService::hereEnabled() const
464 {
465- return m_hereEnabled;
466+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED);
467+ return value.toBool();
468 }
469
470 void AccountsService::setHereEnabled(bool enabled)
471 {
472- if (m_hereEnabled != enabled) {
473- m_hereEnabled = enabled;
474- m_service->setUserPropertyAsync(m_user, QStringLiteral("com.ubuntu.location.providers.here.AccountsService"), QStringLiteral("LicenseAccepted"), enabled);
475-
476- Q_EMIT hereEnabledChanged();
477- }
478+ setProperty(IFACE_LOCATION_HERE, PROP_LICENSE_ACCEPTED, enabled);
479 }
480
481 QString AccountsService::hereLicensePath() const
482 {
483- return m_hereLicensePath;
484+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
485+ QString hereLicensePath = value.toString();
486+ if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
487+ hereLicensePath = QStringLiteral("");
488+ return hereLicensePath;
489 }
490
491 bool AccountsService::hereLicensePathValid() const
492 {
493- return !m_hereLicensePath.isNull();
494-}
495-
496-void AccountsService::updateDemoEdges(bool async)
497-{
498- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
499- QStringLiteral("com.canonical.unity.AccountsService"),
500- QStringLiteral("demo-edges"));
501- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
502-
503- connect(watcher, &QDBusPendingCallWatcher::finished,
504- this, [this](QDBusPendingCallWatcher* watcher) {
505-
506- QDBusPendingReply<QDBusVariant> reply = *watcher;
507- watcher->deleteLater();
508- if (reply.isError()) {
509- qWarning() << "Failed to get 'demo-edges' property - " << reply.error().message();
510- return;
511- }
512-
513- auto demoEdges = reply.value().variant().toBool();
514- if (m_demoEdges != demoEdges) {
515- m_demoEdges = demoEdges;
516- Q_EMIT demoEdgesChanged();
517- }
518- });
519- if (!async) {
520- watcher->waitForFinished();
521- delete watcher;
522- }
523-}
524-
525-void AccountsService::updateEnableLauncherWhileLocked(bool async)
526-{
527- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
528- QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"),
529- QStringLiteral("EnableLauncherWhileLocked"));
530- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
531-
532- connect(watcher, &QDBusPendingCallWatcher::finished,
533- this, [this](QDBusPendingCallWatcher* watcher) {
534-
535- QDBusPendingReply<QVariant> reply = *watcher;
536- watcher->deleteLater();
537- if (reply.isError()) {
538- qWarning() << "Failed to get 'EnableLauncherWhileLocked' property - " << reply.error().message();
539- return;
540- }
541-
542- const bool enableLauncherWhileLocked = reply.value().toBool();
543- if (m_enableLauncherWhileLocked != enableLauncherWhileLocked) {
544- m_enableLauncherWhileLocked = enableLauncherWhileLocked;
545- Q_EMIT enableLauncherWhileLockedChanged();
546- }
547- });
548- if (!async) {
549- watcher->waitForFinished();
550- delete watcher;
551- }
552-}
553-
554-void AccountsService::updateEnableIndicatorsWhileLocked(bool async)
555-{
556- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
557- QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"),
558- QStringLiteral("EnableIndicatorsWhileLocked"));
559- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
560-
561- connect(watcher, &QDBusPendingCallWatcher::finished,
562- this, [this](QDBusPendingCallWatcher* watcher) {
563-
564- QDBusPendingReply<QVariant> reply = *watcher;
565- watcher->deleteLater();
566- if (reply.isError()) {
567- qWarning() << "Failed to get 'EnableIndicatorsWhileLocked' property - " << reply.error().message();
568- return;
569- }
570-
571- const bool enableIndicatorsWhileLocked = reply.value().toBool();
572- if (m_enableIndicatorsWhileLocked != enableIndicatorsWhileLocked) {
573- m_enableIndicatorsWhileLocked = enableIndicatorsWhileLocked;
574- Q_EMIT enableIndicatorsWhileLockedChanged();
575- }
576- });
577- if (!async) {
578- watcher->waitForFinished();
579- delete watcher;
580- }
581-}
582-
583-void AccountsService::updateBackgroundFile(bool async)
584-{
585- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
586- QStringLiteral("org.freedesktop.Accounts.User"),
587- QStringLiteral("BackgroundFile"));
588- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
589-
590- connect(watcher, &QDBusPendingCallWatcher::finished,
591- this, [this](QDBusPendingCallWatcher* watcher) {
592-
593- QDBusPendingReply<QVariant> reply = *watcher;
594- watcher->deleteLater();
595- if (reply.isError()) {
596- qWarning() << "Failed to get 'BackgroundFile' property - " << reply.error().message();
597- return;
598- }
599-
600- const QString backgroundFile = reply.value().toString();
601- if (m_backgroundFile != backgroundFile) {
602- m_backgroundFile = backgroundFile;
603- Q_EMIT backgroundFileChanged();
604- }
605- });
606- if (!async) {
607- watcher->waitForFinished();
608- delete watcher;
609- }
610-}
611-
612-void AccountsService::updateMouseCursorSpeed()
613-{
614- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
615- QStringLiteral("com.ubuntu.AccountsService.Input"),
616- QStringLiteral("MouseCursorSpeed"));
617- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
618-
619- connect(watcher, &QDBusPendingCallWatcher::finished,
620- this, [this](QDBusPendingCallWatcher* watcher) {
621-
622- QDBusPendingReply<QVariant> reply = *watcher;
623- watcher->deleteLater();
624- if (reply.isError()) {
625- qWarning() << "Failed to get 'MouseCursorSpeed' property - " << reply.error().message();
626- return;
627- }
628-
629- // Merely proxy this along to USC. We don't care about keeping a copy
630- // or exporting it internally.
631- m_unityInput->asyncCall(QStringLiteral("setMouseCursorSpeed"), reply.value());
632- });
633-}
634-
635-void AccountsService::updateTouchpadCursorSpeed()
636-{
637- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
638- QStringLiteral("com.ubuntu.AccountsService.Input"),
639- QStringLiteral("TouchpadCursorSpeed"));
640- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
641-
642- connect(watcher, &QDBusPendingCallWatcher::finished,
643- this, [this](QDBusPendingCallWatcher* watcher) {
644-
645- QDBusPendingReply<QVariant> reply = *watcher;
646- watcher->deleteLater();
647- if (reply.isError()) {
648- qWarning() << "Failed to get 'TouchpadCursorSpeed' property - " << reply.error().message();
649- return;
650- }
651-
652- // Merely proxy this along to USC. We don't care about keeping a copy
653- // or exporting it internally.
654- m_unityInput->asyncCall(QStringLiteral("setTouchpadCursorSpeed"), reply.value());
655- });
656-}
657-
658-void AccountsService::updateStatsWelcomeScreen(bool async)
659-{
660- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
661- QStringLiteral("com.ubuntu.touch.AccountsService.SecurityPrivacy"),
662- QStringLiteral("StatsWelcomeScreen"));
663- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
664-
665- connect(watcher, &QDBusPendingCallWatcher::finished,
666- this, [this](QDBusPendingCallWatcher* watcher) {
667-
668- QDBusPendingReply<QVariant> reply = *watcher;
669- watcher->deleteLater();
670- if (reply.isError()) {
671- qWarning() << "Failed to get 'StatsWelcomeScreen' property - " << reply.error().message();
672- return;
673- }
674-
675- const bool statsWelcomeScreen = reply.value().toBool();
676- if (m_statsWelcomeScreen != statsWelcomeScreen) {
677- m_statsWelcomeScreen = statsWelcomeScreen;
678- Q_EMIT statsWelcomeScreenChanged();
679- }
680- });
681- if (!async) {
682- watcher->waitForFinished();
683- delete watcher;
684- }
685-}
686-
687-void AccountsService::updatePasswordDisplayHint(bool async)
688-{
689- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
690- QStringLiteral("com.ubuntu.AccountsService.SecurityPrivacy"),
691- QStringLiteral("PasswordDisplayHint"));
692- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
693-
694- connect(watcher, &QDBusPendingCallWatcher::finished,
695- this, [this](QDBusPendingCallWatcher* watcher) {
696-
697- QDBusPendingReply<QVariant> reply = *watcher;
698- watcher->deleteLater();
699- if (reply.isError()) {
700- qWarning() << "Failed to get 'PasswordDisplayHint' property - " << reply.error().message();
701- return;
702- }
703-
704- const PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)reply.value().toInt();
705- if (m_passwordDisplayHint != passwordDisplayHint) {
706- m_passwordDisplayHint = passwordDisplayHint;
707- Q_EMIT passwordDisplayHintChanged();
708- }
709- });
710- if (!async) {
711- watcher->waitForFinished();
712- delete watcher;
713- }
714-}
715-
716-void AccountsService::updateFailedLogins(bool async)
717-{
718- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
719- QStringLiteral("com.canonical.unity.AccountsService.Private"),
720- QStringLiteral("FailedLogins"));
721- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
722-
723- connect(watcher, &QDBusPendingCallWatcher::finished,
724- this, [this](QDBusPendingCallWatcher* watcher) {
725-
726- QDBusPendingReply<QVariant> reply = *watcher;
727- watcher->deleteLater();
728- if (reply.isError()) {
729- qWarning() << "Failed to get 'FailedLogins' property - " << reply.error().message();
730- return;
731- }
732-
733- const uint failedLogins = reply.value().toUInt();
734- if (m_failedLogins != failedLogins) {
735- m_failedLogins = failedLogins;
736- Q_EMIT failedLoginsChanged();
737- }
738- });
739- if (!async) {
740- watcher->waitForFinished();
741- delete watcher;
742- }
743-}
744-
745-void AccountsService::updateHereEnabled(bool async)
746-{
747- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
748- QStringLiteral("com.ubuntu.location.providers.here.AccountsService"),
749- QStringLiteral("LicenseAccepted"));
750- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
751-
752- connect(watcher, &QDBusPendingCallWatcher::finished,
753- this, [this](QDBusPendingCallWatcher* watcher) {
754-
755- QDBusPendingReply<QVariant> reply = *watcher;
756- watcher->deleteLater();
757- if (reply.isError()) {
758- qWarning() << "Failed to get 'LicenseAccepted' property - " << reply.error().message();
759- return;
760- }
761-
762- const bool hereEnabled = reply.value().toBool();
763- if (m_hereEnabled != hereEnabled) {
764- m_hereEnabled = hereEnabled;
765- Q_EMIT hereEnabledChanged();
766- }
767- });
768- if (!async) {
769- watcher->waitForFinished();
770- delete watcher;
771- }
772-}
773-
774-void AccountsService::updateHereLicensePath(bool async)
775-{
776- QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
777- QStringLiteral("com.ubuntu.location.providers.here.AccountsService"),
778- QStringLiteral("LicenseBasePath"));
779- QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
780-
781- connect(watcher, &QDBusPendingCallWatcher::finished,
782- this, [this](QDBusPendingCallWatcher* watcher) {
783-
784- QDBusPendingReply<QVariant> reply = *watcher;
785- watcher->deleteLater();
786- if (reply.isError()) {
787- qWarning() << "Failed to get 'LicenseBasePath' property - " << reply.error().message();
788- return;
789- }
790-
791- QString hereLicensePath = reply.value().toString();
792- if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
793- hereLicensePath = QLatin1String("");
794-
795- if (m_hereLicensePath.isNull() || m_hereLicensePath != hereLicensePath) {
796- m_hereLicensePath = hereLicensePath;
797- Q_EMIT hereLicensePathChanged();
798- }
799- });
800- if (!async) {
801- watcher->waitForFinished();
802- delete watcher;
803- }
804+ auto value = getProperty(IFACE_LOCATION_HERE, PROP_LICENSE_BASE_PATH);
805+ return !value.toString().isNull();
806 }
807
808 uint AccountsService::failedLogins() const
809 {
810- return m_failedLogins;
811+ return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS).toUInt();
812 }
813
814 void AccountsService::setFailedLogins(uint failedLogins)
815 {
816- if (m_failedLogins != failedLogins) {
817- m_failedLogins = failedLogins;
818- m_service->setUserPropertyAsync(m_user, QStringLiteral("com.canonical.unity.AccountsService.Private"), QStringLiteral("FailedLogins"), failedLogins);
819-
820- Q_EMIT failedLoginsChanged();
821- }
822+ setProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, failedLogins);
823+}
824+
825+// ====================================================
826+// Everything below this line is generic helper methods
827+// ====================================================
828+
829+void AccountsService::emitChangedForProperty(const QString &interface, const QString &property)
830+{
831+ QString signalName = m_properties[interface][property].signal;
832+ QMetaObject::invokeMethod(this, signalName.toUtf8().data());
833+}
834+
835+QVariant AccountsService::getProperty(const QString &interface, const QString &property) const
836+{
837+ return m_properties[interface][property].value;
838+}
839+
840+void AccountsService::setProperty(const QString &interface, const QString &property, const QVariant &value)
841+{
842+ if (m_properties[interface][property].value != value) {
843+ m_properties[interface][property].value = value;
844+ m_service->setUserPropertyAsync(m_user, interface, property, value);
845+ emitChangedForProperty(interface, property);
846+ }
847+}
848+
849+void AccountsService::updateCache(const QString &interface, const QString &property, const QVariant &value)
850+{
851+ PropertyInfo &info = m_properties[interface][property];
852+
853+ if (info.proxyInterface) {
854+ QVariant finalValue;
855+ if (info.proxyConverter) {
856+ finalValue = info.proxyConverter(value);
857+ } else {
858+ finalValue = value;
859+ }
860+ info.proxyInterface->asyncCall(info.proxyMethod, finalValue);
861+ return; // don't bother saving a copy
862+ }
863+
864+ if (info.value != value) {
865+ info.value = value;
866+ emitChangedForProperty(interface, property);
867+ }
868+}
869+
870+void AccountsService::updateProperty(const QString &interface, const QString &property)
871+{
872+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
873+ interface,
874+ property);
875+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
876+
877+ connect(watcher, &QDBusPendingCallWatcher::finished,
878+ this, [this, interface, property](QDBusPendingCallWatcher* watcher) {
879+
880+ QDBusPendingReply<QVariant> reply = *watcher;
881+ watcher->deleteLater();
882+ if (reply.isError()) {
883+ qWarning() << "Failed to get '" << property << "' property:" << reply.error().message();
884+ return;
885+ }
886+
887+ updateCache(interface, property, reply.value());
888+ });
889+}
890+
891+void AccountsService::updateAllProperties(const QString &interface, bool async)
892+{
893+ QDBusPendingCall pendingReply = m_service->getAllPropertiesAsync(m_user,
894+ interface);
895+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
896+
897+ connect(watcher, &QDBusPendingCallWatcher::finished,
898+ this, [this, interface](QDBusPendingCallWatcher* watcher) {
899+
900+ QDBusPendingReply< QHash<QString, QVariant> > reply = *watcher;
901+ watcher->deleteLater();
902+ if (reply.isError()) {
903+ qWarning() << "Failed to get all properties for" << interface << ":" << reply.error().message();
904+ return;
905+ }
906+
907+ auto valueHash = reply.value();
908+ auto i = valueHash.constBegin();
909+ while (i != valueHash.constEnd()) {
910+ updateCache(interface, i.key(), i.value());
911+ ++i;
912+ }
913+ });
914+ if (!async) {
915+ watcher->waitForFinished();
916+ }
917+}
918+
919+void AccountsService::registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method, ProxyConverter converter)
920+{
921+ registerProperty(interface, property, nullptr);
922+
923+ m_properties[interface][property].proxyInterface = iface;
924+ m_properties[interface][property].proxyMethod = method;
925+ m_properties[interface][property].proxyConverter = converter;
926+}
927+
928+void AccountsService::registerProperty(const QString &interface, const QString &property, const QString &signal)
929+{
930+ m_properties[interface][property] = PropertyInfo();
931+ m_properties[interface][property].signal = signal;
932 }
933
934 void AccountsService::onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
935@@ -469,42 +331,13 @@
936 return;
937 }
938
939- if (interface == QLatin1String("com.canonical.unity.AccountsService")) {
940- if (changed.contains(QStringLiteral("demo-edges"))) {
941- updateDemoEdges();
942- }
943- } else if (interface == QLatin1String("com.canonical.unity.AccountsService.Private")) {
944- if (changed.contains(QStringLiteral("FailedLogins"))) {
945- updateFailedLogins();
946- }
947- } else if (interface == QLatin1String("com.ubuntu.AccountsService.Input")) {
948- if (changed.contains(QStringLiteral("MouseCursorSpeed"))) {
949- updateMouseCursorSpeed();
950- }
951- if (changed.contains(QStringLiteral("TouchpadCursorSpeed"))) {
952- updateTouchpadCursorSpeed();
953- }
954- } else if (interface == QLatin1String("com.ubuntu.touch.AccountsService.SecurityPrivacy")) {
955- if (changed.contains(QStringLiteral("StatsWelcomeScreen"))) {
956- updateStatsWelcomeScreen();
957- }
958- } else if (interface == QLatin1String("com.ubuntu.AccountsService.SecurityPrivacy")) {
959- if (changed.contains(QStringLiteral("PasswordDisplayHint"))) {
960- updatePasswordDisplayHint();
961- }
962- if (changed.contains(QStringLiteral("EnableLauncherWhileLocked"))) {
963- updateEnableLauncherWhileLocked();
964- }
965- if (changed.contains(QStringLiteral("EnableIndicatorsWhileLocked"))) {
966- updateEnableIndicatorsWhileLocked();
967- }
968- } else if (interface == QLatin1String("com.ubuntu.location.providers.here.AccountsService")) {
969- if (changed.contains(QStringLiteral("LicenseAccepted"))) {
970- updateHereEnabled();
971- }
972- if (changed.contains(QStringLiteral("LicenseBasePath"))) {
973- updateHereLicensePath();
974- }
975+ auto propHash = m_properties.value(interface);
976+ auto i = propHash.constBegin();
977+ while (i != propHash.constEnd()) {
978+ if (changed.contains(i.key())) {
979+ updateProperty(interface, i.key());
980+ }
981+ ++i;
982 }
983 }
984
985@@ -514,6 +347,20 @@
986 return;
987 }
988
989- // Standard properties might have changed
990- updateBackgroundFile();
991+ // Any of the standard properties might have changed!
992+ auto propHash = m_properties.value(IFACE_ACCOUNTS_USER);
993+ auto i = propHash.constBegin();
994+ while (i != propHash.constEnd()) {
995+ updateProperty(IFACE_ACCOUNTS_USER, i.key());
996+ ++i;
997+ }
998+}
999+
1000+void AccountsService::refresh(bool async)
1001+{
1002+ auto i = m_properties.constBegin();
1003+ while (i != m_properties.constEnd()) {
1004+ updateAllProperties(i.key(), async);
1005+ ++i;
1006+ }
1007 }
1008
1009=== modified file 'plugins/AccountsService/AccountsService.h'
1010--- plugins/AccountsService/AccountsService.h 2016-01-21 21:04:00 +0000
1011+++ plugins/AccountsService/AccountsService.h 2016-03-11 11:34:41 +0000
1012@@ -19,8 +19,10 @@
1013 #ifndef UNITY_ACCOUNTSSERVICE_H
1014 #define UNITY_ACCOUNTSSERVICE_H
1015
1016+#include <QHash>
1017 #include <QObject>
1018 #include <QString>
1019+#include <QVariant>
1020
1021 class AccountsServiceDBusAdaptor;
1022 class QDBusInterface;
1023@@ -109,30 +111,33 @@
1024 void onMaybeChanged(const QString &user);
1025
1026 private:
1027- void updateDemoEdges(bool async = true);
1028- void updateEnableLauncherWhileLocked(bool async = true);
1029- void updateEnableIndicatorsWhileLocked(bool async = true);
1030- void updateBackgroundFile(bool async = true);
1031- void updateMouseCursorSpeed();
1032- void updateTouchpadCursorSpeed();
1033- void updateStatsWelcomeScreen(bool async = true);
1034- void updatePasswordDisplayHint(bool async = true);
1035- void updateFailedLogins(bool async = true);
1036- void updateHereEnabled(bool async = true);
1037- void updateHereLicensePath(bool async = true);
1038-
1039+ typedef QVariant (*ProxyConverter)(const QVariant &);
1040+
1041+ void refresh(bool async);
1042+ void registerProperty(const QString &interface, const QString &property, const QString &signal);
1043+ void registerProxy(const QString &interface, const QString &property, QDBusInterface *iface, const QString &method, ProxyConverter converter = nullptr);
1044+
1045+ void updateAllProperties(const QString &interface, bool async);
1046+ void updateProperty(const QString &interface, const QString &property);
1047+ void updateCache(const QString &interface, const QString &property, const QVariant &value);
1048+
1049+ void setProperty(const QString &interface, const QString &property, const QVariant &value);
1050+ QVariant getProperty(const QString &interface, const QString &property) const;
1051+
1052+ void emitChangedForProperty(const QString &interface, const QString &property);
1053+
1054+ struct PropertyInfo {
1055+ QVariant value{};
1056+ QString signal{};
1057+ QDBusInterface *proxyInterface{};
1058+ QString proxyMethod{};
1059+ ProxyConverter proxyConverter{};
1060+ };
1061+ typedef QHash< QString, QHash<QString, PropertyInfo> > PropertyHash;
1062+ PropertyHash m_properties;
1063 AccountsServiceDBusAdaptor *m_service;
1064 QDBusInterface *m_unityInput;
1065 QString m_user;
1066- bool m_demoEdges;
1067- bool m_enableLauncherWhileLocked;
1068- bool m_enableIndicatorsWhileLocked;
1069- QString m_backgroundFile;
1070- bool m_statsWelcomeScreen;
1071- PasswordDisplayHint m_passwordDisplayHint;
1072- uint m_failedLogins;
1073- bool m_hereEnabled;
1074- QString m_hereLicensePath;
1075 };
1076
1077 #endif
1078
1079=== modified file 'plugins/AccountsService/AccountsServiceDBusAdaptor.cpp'
1080--- plugins/AccountsService/AccountsServiceDBusAdaptor.cpp 2015-10-26 14:05:14 +0000
1081+++ plugins/AccountsService/AccountsServiceDBusAdaptor.cpp 2016-03-11 11:34:41 +0000
1082@@ -1,5 +1,5 @@
1083 /*
1084- * Copyright (C) 2013 Canonical, Ltd.
1085+ * Copyright (C) 2013-2016 Canonical, Ltd.
1086 *
1087 * This program is free software; you can redistribute it and/or modify
1088 * it under the terms of the GNU General Public License as published by
1089@@ -12,8 +12,6 @@
1090 *
1091 * You should have received a copy of the GNU General Public License
1092 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1093- *
1094- * Author: Michael Terry <michael.terry@canonical.com>
1095 */
1096
1097 #include "AccountsServiceDBusAdaptor.h"
1098@@ -37,6 +35,15 @@
1099 connection, this);
1100 }
1101
1102+QDBusPendingReply<QVariantMap> AccountsServiceDBusAdaptor::getAllPropertiesAsync(const QString &user, const QString &interface)
1103+{
1104+ QDBusInterface *iface = getUserInterface(user);
1105+ if (iface != nullptr && iface->isValid()) {
1106+ return iface->asyncCall(QStringLiteral("GetAll"), interface);
1107+ }
1108+ return QDBusPendingReply<QVariantMap>(QDBusMessage::createError(QDBusError::Other, QStringLiteral("Invalid Interface")));
1109+}
1110+
1111 QDBusPendingReply<QVariant> AccountsServiceDBusAdaptor::getUserPropertyAsync(const QString &user, const QString &interface, const QString &property)
1112 {
1113 QDBusInterface *iface = getUserInterface(user);
1114@@ -80,7 +87,7 @@
1115 m_ignoreNextChanged = false;
1116 }
1117
1118-QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
1119+QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path) const
1120 {
1121 QMap<QString, QDBusInterface *>::const_iterator i;
1122 for (i = m_users.constBegin(); i != m_users.constEnd(); ++i) {
1123
1124=== modified file 'plugins/AccountsService/AccountsServiceDBusAdaptor.h'
1125--- plugins/AccountsService/AccountsServiceDBusAdaptor.h 2015-10-26 14:05:14 +0000
1126+++ plugins/AccountsService/AccountsServiceDBusAdaptor.h 2016-03-11 11:34:41 +0000
1127@@ -1,5 +1,5 @@
1128 /*
1129- * Copyright (C) 2013 Canonical, Ltd.
1130+ * Copyright (C) 2013-2016 Canonical, Ltd.
1131 *
1132 * This program is free software; you can redistribute it and/or modify
1133 * it under the terms of the GNU General Public License as published by
1134@@ -12,8 +12,6 @@
1135 *
1136 * You should have received a copy of the GNU General Public License
1137 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1138- *
1139- * Authors: Michael Terry <michael.terry@canonical.com>
1140 */
1141
1142 #ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
1143@@ -35,8 +33,9 @@
1144 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
1145 ~AccountsServiceDBusAdaptor() = default;
1146
1147- Q_INVOKABLE QDBusPendingReply<QVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property);
1148- Q_INVOKABLE QDBusPendingCall setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
1149+ QDBusPendingReply<QVariantMap> getAllPropertiesAsync(const QString &user, const QString &interface);
1150+ QDBusPendingReply<QVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property);
1151+ QDBusPendingCall setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
1152
1153 Q_SIGNALS:
1154 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
1155@@ -48,7 +47,7 @@
1156
1157 private:
1158 QDBusInterface *getUserInterface(const QString &user);
1159- QString getUserForPath(const QString &path);
1160+ QString getUserForPath(const QString &path) const;
1161
1162 QDBusInterface *m_accountsManager;
1163 QMap<QString, QDBusInterface *> m_users;
1164
1165=== modified file 'plugins/Dash/AudioProgressBar.qml'
1166--- plugins/Dash/AudioProgressBar.qml 2015-12-03 14:44:08 +0000
1167+++ plugins/Dash/AudioProgressBar.qml 2016-03-11 11:34:41 +0000
1168@@ -31,6 +31,7 @@
1169 anchors { left: parent.left; right: parent.right }
1170 height: units.dp(6)
1171 source: "graphics/music_progress_bg.png"
1172+ asynchronous: true
1173 sourceSize.width: width
1174 sourceSize.height: height
1175 }
1176
1177=== modified file 'plugins/Dash/CardCreator.js'
1178--- plugins/Dash/CardCreator.js 2016-02-12 00:11:52 +0000
1179+++ plugins/Dash/CardCreator.js 2016-03-11 11:34:41 +0000
1180@@ -18,12 +18,13 @@
1181
1182 // %1 is the template["card-background"]["elements"][0]
1183 // %2 is the template["card-background"]["elements"][1]
1184-// %3 is the template["card-background"] string
1185+// %3 is whether the loader should be asynchronous or not
1186+// %4 is the template["card-background"] string
1187 var kBackgroundLoaderCode = 'Loader {\n\
1188 id: backgroundLoader; \n\
1189 objectName: "backgroundLoader"; \n\
1190 anchors.fill: parent; \n\
1191- asynchronous: root.asynchronous; \n\
1192+ asynchronous: %3; \n\
1193 visible: status == Loader.Ready; \n\
1194 sourceComponent: UbuntuShape { \n\
1195 objectName: "background"; \n\
1196@@ -46,7 +47,7 @@
1197 objectName: "backgroundImage"; \n\
1198 source: { \n\
1199 if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\
1200- else return %3; \n\
1201+ else return %4; \n\
1202 } \n\
1203 } \n\
1204 function getColor(index) { \n\
1205@@ -63,8 +64,9 @@
1206 // %3 is used as image height
1207 // %4 is used for artShapeSource.hideSource and inner Loader visible
1208 // %5 is used as aspect ratio fallback
1209-// %6 is injected as code to artImage
1210-// %7 is used as image fallback
1211+// %6 is whether the loader should be asynchronous or not
1212+// %7 is injected as code to artImage
1213+// %8 is used as image fallback
1214 var kArtShapeHolderCode = 'Item { \n\
1215 id: artShapeHolder; \n\
1216 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
1217@@ -73,9 +75,9 @@
1218 Loader { \n\
1219 id: artShapeLoader; \n\
1220 objectName: "artShapeLoader"; \n\
1221- readonly property string cardArt: cardData && cardData["art"] || %7; \n\
1222+ readonly property string cardArt: cardData && cardData["art"] || %8; \n\
1223 active: cardArt != ""; \n\
1224- asynchronous: root.asynchronous; \n\
1225+ asynchronous: %6; \n\
1226 visible: status == Loader.Ready; \n\
1227 sourceComponent: Item { \n\
1228 id: artShape; \n\
1229@@ -132,10 +134,10 @@
1230 id: artImage; \n\
1231 objectName: "artImage"; \n\
1232 source: artShapeLoader.cardArt; \n\
1233- asynchronous: root.asynchronous; \n\
1234+ asynchronous: %6; \n\
1235 width: %2; \n\
1236 height: %3; \n\
1237- %6 \n\
1238+ %7 \n\
1239 } \n\
1240 } \n\
1241 } \n\
1242@@ -144,6 +146,7 @@
1243 // %1 is anchors.fill
1244 // %2 is width
1245 // %3 is height
1246+// %4 is whether the icon should be asynchronous or not
1247 var kAudioButtonCode = 'AbstractButton { \n\
1248 id: audioButton; \n\
1249 anchors.fill: %1; \n\
1250@@ -169,6 +172,7 @@
1251 opacity: 0.9; \n\
1252 name: DashAudioPlayer.playing && AudioUrlComparer.compare(parent.source, DashAudioPlayer.currentSource) ? "media-playback-pause" : "media-playback-start"; \n\
1253 color: "white"; \n\
1254+ asynchronous: %4; \n\
1255 } \n\
1256 onClicked: { \n\
1257 if (AudioUrlComparer.compare(source, DashAudioPlayer.currentSource)) { \n\
1258@@ -187,12 +191,14 @@
1259 } \n\
1260 }';
1261
1262+// %1 is whether the loader should be asynchronous or not
1263+// %2 is the header height code
1264 var kOverlayLoaderCode = 'Loader { \n\
1265 id: overlayLoader; \n\
1266- readonly property real overlayHeight: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
1267+ readonly property real overlayHeight: %2 + units.gu(2); \n\
1268 anchors.fill: artShapeHolder; \n\
1269 active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\
1270- asynchronous: root.asynchronous; \n\
1271+ asynchronous: %1; \n\
1272 visible: showHeader && status == Loader.Ready; \n\
1273 sourceComponent: UbuntuShapeOverlay { \n\
1274 id: overlay; \n\
1275@@ -211,17 +217,19 @@
1276 objectName: "outerRow"; \n\
1277 property real margins: units.gu(1); \n\
1278 spacing: margins; \n\
1279- height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
1280+ %2\
1281 anchors { %1 } \n\
1282 anchors.right: parent.right; \n\
1283 anchors.margins: margins; \n\
1284 anchors.rightMargin: 0; \n\
1285 data: [ \n\
1286- %2 \n\
1287+ %3 \n\
1288 ] \n\
1289 }\n';
1290 var args = Array.prototype.slice.call(arguments);
1291- var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(args.join(',\n'));
1292+ var isCardTool = args.shift();
1293+ var heightCode = isCardTool ? "" : "height: root.fixedHeaderHeight; \n";
1294+ var code = kHeaderRowCodeTemplate.arg(args.shift()).arg(heightCode).arg(args.join(',\n'));
1295 return code;
1296 }
1297
1298@@ -242,10 +250,11 @@
1299 }
1300
1301 // %1 is used as anchors of mascotShapeLoader
1302+// %2 is whether the loader should be asynchronous or not
1303 var kMascotShapeLoaderCode = 'Loader { \n\
1304 id: mascotShapeLoader; \n\
1305 objectName: "mascotShapeLoader"; \n\
1306- asynchronous: root.asynchronous; \n\
1307+ asynchronous: %2; \n\
1308 active: mascotImage.status === Image.Ready; \n\
1309 visible: showHeader && active && status == Loader.Ready; \n\
1310 width: units.gu(6); \n\
1311@@ -275,6 +284,7 @@
1312 // %2 is used as color of titleLabel
1313 // %3 is used as extra condition for visible of titleLabel
1314 // %4 is used as title width
1315+// %5 is used as horizontal alignment
1316 var kTitleLabelCode = 'Label { \n\
1317 id: titleLabel; \n\
1318 objectName: "titleLabel"; \n\
1319@@ -289,7 +299,7 @@
1320 width: %4; \n\
1321 text: root.title; \n\
1322 font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal; \n\
1323- horizontalAlignment: root.titleAlignment; \n\
1324+ horizontalAlignment: %5; \n\
1325 }\n';
1326
1327 // %1 is used as extra anchors of emblemIcon
1328@@ -398,7 +408,7 @@
1329 return colorString;
1330 }
1331
1332-function cardString(template, components) {
1333+function cardString(template, components, isCardTool) {
1334 var code;
1335
1336 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
1337@@ -410,16 +420,16 @@
1338 property string backgroundShapeStyle: "inset"; \n\
1339 property real fontScale: 1.0; \n\
1340 property var scopeStyle: null; \n\
1341- property int titleAlignment: Text.AlignLeft; \n\
1342- property int fixedHeaderHeight: -1; \n\
1343+ %2\
1344 property size fixedArtShapeSize: Qt.size(-1, -1); \n\
1345 readonly property string title: cardData && cardData["title"] || ""; \n\
1346- property bool asynchronous: true; \n\
1347 property bool showHeader: true; \n\
1348 implicitWidth: childrenRect.width; \n\
1349 enabled: %1; \n\
1350 \n'.arg(templateInteractive);
1351
1352+ code = code.arg(isCardTool ? "" : "property int fixedHeaderHeight: -1; \n");
1353+
1354 var hasArt = components["art"] && components["art"]["field"] || false;
1355 var hasSummary = components["summary"] || false;
1356 var isConciergeMode = components["art"] && components["art"]["conciergeMode"] || false;
1357@@ -435,6 +445,7 @@
1358 var hasHeaderRow = hasMascot && hasTitle;
1359 var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false;
1360 var isAudio = template["quick-preview-type"] === "audio";
1361+ var asynchronous = isCardTool ? "false" : "true";
1362
1363 if (isAudio) {
1364 // For now we only support audio cards with [optional] art, title, subtitle
1365@@ -468,7 +479,7 @@
1366 backgroundElements1 = '"%1"'.arg(element1);
1367 }
1368 }
1369- code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(templateCardBackground);
1370+ code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(asynchronous).arg(templateCardBackground);
1371 }
1372
1373 if (hasArt) {
1374@@ -497,23 +508,31 @@
1375 if (isNaN(aspectRatio)) {
1376 aspectRatio = 1;
1377 }
1378- var fallback = components["art"] && components["art"]["fallback"] || "";
1379+ var fallback = !isCardTool && components["art"] && components["art"]["fallback"] || "";
1380 fallback = encodeURI(fallback);
1381 var fallbackStatusCode = "";
1382 var fallbackURICode = '""';
1383 if (fallback !== "") {
1384 // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode
1385- // which in kArtShapeHolderCode is %7
1386- fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %7;';
1387+ // which in kArtShapeHolderCode is %8
1388+ fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;';
1389 fallbackURICode = 'decodeURI("%1")'.arg(fallback);
1390 }
1391- code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode).arg(isConciergeMode ? "false" : "true").arg(aspectRatio).arg(fallbackStatusCode).arg(fallbackURICode);
1392+ code += kArtShapeHolderCode.arg(artAnchors)
1393+ .arg(widthCode)
1394+ .arg(heightCode)
1395+ .arg(isConciergeMode ? "false" : "true")
1396+ .arg(aspectRatio)
1397+ .arg(asynchronous)
1398+ .arg(fallbackStatusCode)
1399+ .arg(fallbackURICode);
1400 } else {
1401 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
1402 }
1403
1404 if (headerAsOverlay) {
1405- code += kOverlayLoaderCode;
1406+ var headerHeightCode = isCardTool ? "headerHeight" : "root.fixedHeaderHeight";
1407+ code += kOverlayLoaderCode.arg(asynchronous).arg(headerHeightCode);
1408 }
1409
1410 var headerVerticalAnchors;
1411@@ -595,11 +614,11 @@
1412 }
1413
1414 if (useMascotShape) {
1415- mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
1416+ mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors).arg(asynchronous);
1417 }
1418
1419 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
1420- var fallback = components["mascot"] && components["mascot"]["fallback"] || "";
1421+ var fallback = !isCardTool && components["mascot"] && components["mascot"]["fallback"] || "";
1422 fallback = encodeURI(fallback);
1423 var fallbackStatusCode = "";
1424 var fallbackURICode = '""';
1425@@ -715,9 +734,24 @@
1426 }
1427 }
1428
1429+ var titleAlignment = "Text.AlignHCenter";
1430+ if (template["card-layout"] === "horizontal"
1431+ || typeof components["title"] !== "object"
1432+ || components["title"]["align"] === "left") titleAlignment = "Text.AlignLeft";
1433+ var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"];
1434+ for (var key in keys) {
1435+ key = keys[key];
1436+ try {
1437+ if (typeof components[key] === "string"
1438+ || typeof components[key]["field"] === "string") titleAlignment = "Text.AlignLeft";
1439+ } catch (e) {
1440+ continue;
1441+ }
1442+ }
1443+
1444 // code for different elements
1445 var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
1446- var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra).arg(titleWidth);
1447+ var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra).arg(titleWidth).arg(titleAlignment);
1448 var subtitleCode;
1449 var attributesCode;
1450
1451@@ -759,7 +793,7 @@
1452 if (mascotShapeCode != '') {
1453 rowCode.unshift(mascotShapeCode);
1454 }
1455- code += kHeaderRowCodeGenerator(headerVerticalAnchors + headerLeftAnchor, rowCode)
1456+ code += kHeaderRowCodeGenerator(isCardTool, headerVerticalAnchors + headerLeftAnchor, rowCode)
1457 } else {
1458 code += mascotShapeCode + mascotCode + titleSubtitleCode;
1459 }
1460@@ -783,9 +817,10 @@
1461 } else {
1462 audioButtonAnchorsFill = 'undefined';
1463 audioButtonWidth = 'height';
1464- audioButtonHeight = '(root.fixedHeaderHeight > 0 ? root.fixedHeaderHeight : headerHeight) + 2 * units.gu(1)';
1465+ audioButtonHeight = isCardTool ? 'headerHeight + 2 * units.gu(1)'
1466+ : 'root.fixedHeaderHeight + 2 * units.gu(1)';
1467 }
1468- code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight);
1469+ code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight).arg(asynchronous);
1470 }
1471
1472 if (hasSummary) {
1473@@ -854,13 +889,13 @@
1474 return code;
1475 }
1476
1477-function createCardComponent(parent, template, components, identifier) {
1478+function createCardComponent(parent, template, components, isCardTool, identifier) {
1479 var imports = 'import QtQuick 2.4; \n\
1480 import Ubuntu.Components 1.3; \n\
1481 import Ubuntu.Settings.Components 0.1; \n\
1482 import Dash 0.1;\n\
1483 import Utils 0.1;\n';
1484- var card = cardString(template, components);
1485+ var card = cardString(template, components, isCardTool);
1486 var code = imports + 'Component {\n' + card + '}\n';
1487
1488 try {
1489
1490=== modified file 'plugins/Dash/CardCreatorCache.qml'
1491--- plugins/Dash/CardCreatorCache.qml 2016-01-21 17:56:08 +0000
1492+++ plugins/Dash/CardCreatorCache.qml 2016-03-11 11:34:41 +0000
1493@@ -23,16 +23,16 @@
1494
1495 property var cache: new Object();
1496
1497- function getCardComponent(template, components) {
1498+ function getCardComponent(template, components, isCardTool) {
1499 if (template === undefined || components === undefined)
1500 return undefined;
1501
1502 var tString = JSON.stringify(template);
1503 var cString = JSON.stringify(components);
1504- var allString = tString + cString;
1505+ var allString = tString + cString + isCardTool;
1506 var component = cache[allString];
1507 if (component === undefined) {
1508- component = CardCreator.createCardComponent(root, template, components, allString);
1509+ component = CardCreator.createCardComponent(root, template, components, isCardTool, allString);
1510 cache[allString] = component;
1511 }
1512 return component;
1513
1514=== modified file 'plugins/Dash/plugin.cpp'
1515--- plugins/Dash/plugin.cpp 2015-09-18 07:44:50 +0000
1516+++ plugins/Dash/plugin.cpp 2016-03-11 11:34:41 +0000
1517@@ -28,12 +28,12 @@
1518 static QUrl oauthCleanedUrl(QUrl u)
1519 {
1520 QUrlQuery q(u);
1521- q.removeQueryItem("oauth_nonce");
1522- q.removeQueryItem("oauth_timestamp");
1523- q.removeQueryItem("oauth_consumer_key");
1524- q.removeQueryItem("oauth_signature_method");
1525- q.removeQueryItem("oauth_version");
1526- q.removeQueryItem("oauth_signature");
1527+ q.removeQueryItem(QStringLiteral("oauth_nonce"));
1528+ q.removeQueryItem(QStringLiteral("oauth_timestamp"));
1529+ q.removeQueryItem(QStringLiteral("oauth_consumer_key"));
1530+ q.removeQueryItem(QStringLiteral("oauth_signature_method"));
1531+ q.removeQueryItem(QStringLiteral("oauth_version"));
1532+ q.removeQueryItem(QStringLiteral("oauth_signature"));
1533 u.setQuery(q);
1534 return u;
1535 }
1536
1537=== modified file 'plugins/GlobalShortcut/globalshortcutregistry.cpp'
1538--- plugins/GlobalShortcut/globalshortcutregistry.cpp 2015-11-20 15:01:39 +0000
1539+++ plugins/GlobalShortcut/globalshortcutregistry.cpp 2016-03-11 11:34:41 +0000
1540@@ -35,13 +35,13 @@
1541
1542 bool GlobalShortcutRegistry::hasShortcut(const QVariant &seq) const
1543 {
1544- return m_shortcuts.keys().contains(seq);
1545+ return m_shortcuts.contains(seq);
1546 }
1547
1548 void GlobalShortcutRegistry::addShortcut(const QVariant &seq, GlobalShortcut *sc)
1549 {
1550 if (sc) {
1551- if (!m_shortcuts.keys().contains(seq)) { // create a new entry
1552+ if (!m_shortcuts.contains(seq)) { // create a new entry
1553 m_shortcuts.insert(seq, {sc});
1554 } else { // append to an existing one
1555 auto shortcuts = m_shortcuts[seq];
1556@@ -75,8 +75,8 @@
1557
1558 if (event->type() == QEvent::KeyPress) {
1559 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
1560- QKeySequence seq = QKeySequence(keyEvent->key() + keyEvent->modifiers());
1561- if (m_shortcuts.keys().contains(seq)) {
1562+ int seq = keyEvent->key() + keyEvent->modifiers();
1563+ if (m_shortcuts.contains(seq)) {
1564 const auto shortcuts = m_shortcuts.value(seq);
1565 Q_FOREACH(const auto &shortcut, shortcuts) {
1566 if (shortcut) {
1567
1568=== modified file 'plugins/IntegratedLightDM/liblightdm/CMakeLists.txt'
1569--- plugins/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-02-01 15:15:09 +0000
1570+++ plugins/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-03-11 11:34:41 +0000
1571@@ -5,13 +5,16 @@
1572 UsersModel.cpp
1573 GreeterPrivate.cpp
1574 UsersModelPrivate.cpp
1575+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
1576 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
1577 )
1578
1579 add_library(integratedLightDM STATIC ${LibLightDM_SOURCES})
1580+add_library(integratedLightDMSession STATIC ${LibLightDM_SOURCES})
1581 add_library(MockLightDM-demo-shared SHARED ${LibLightDM_SOURCES})
1582
1583 include_directories(
1584+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService
1585 ${CMAKE_CURRENT_BINARY_DIR}
1586 ${GLIB_INCLUDE_DIRS}
1587 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
1588@@ -22,17 +25,27 @@
1589 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
1590 -lpam
1591 )
1592+target_link_libraries(integratedLightDMSession
1593+ ${GLIB_LIBRARIES}
1594+ ${LIBUSERMETRICSOUTPUT_LDFLAGS}
1595+ -lpam
1596+)
1597 target_link_libraries(MockLightDM-demo-shared
1598 ${GLIB_LIBRARIES}
1599 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
1600 -lpam
1601 )
1602
1603-qt5_use_modules(integratedLightDM Concurrent Gui)
1604-qt5_use_modules(MockLightDM-demo-shared Concurrent Gui)
1605+qt5_use_modules(integratedLightDM Concurrent DBus Gui)
1606+qt5_use_modules(integratedLightDMSession Concurrent DBus Gui)
1607+qt5_use_modules(MockLightDM-demo-shared Concurrent DBus Gui)
1608
1609-set_target_properties(integratedLightDM PROPERTIES COMPILE_FLAGS -fPIC)
1610+set_target_properties(integratedLightDM PROPERTIES
1611+ COMPILE_FLAGS "-DSM_BUSNAME=systemBus -fPIC")
1612+set_target_properties(integratedLightDMSession PROPERTIES
1613+ COMPILE_FLAGS "-DSM_BUSNAME=sessionBus -fPIC")
1614 set_target_properties(MockLightDM-demo-shared PROPERTIES
1615+ COMPILE_FLAGS "-DSM_BUSNAME=systemBus"
1616 OUTPUT_NAME lightdm-qt5-2)
1617
1618 install(TARGETS MockLightDM-demo-shared
1619
1620=== modified file 'plugins/IntegratedLightDM/liblightdm/UsersModel.cpp'
1621--- plugins/IntegratedLightDM/liblightdm/UsersModel.cpp 2015-09-14 09:11:08 +0000
1622+++ plugins/IntegratedLightDM/liblightdm/UsersModel.cpp 2016-03-11 11:34:41 +0000
1623@@ -54,24 +54,10 @@
1624 roles[ImagePathRole] = "imagePath";
1625 setRoleNames(roles);
1626
1627- // Now modify our mock user backgrounds
1628- QDir bgdir = QDir(QStringLiteral("/usr/share/demo-assets/shell/backgrounds/"));
1629- QStringList backgrounds = bgdir.entryList(QDir::Files | QDir::NoDotAndDotDot);
1630-
1631- for (int i = 0, j = 0; i < d->entries.size(); i++) {
1632- Entry &entry = d->entries[i];
1633- if (entry.background.isNull() && !backgrounds.isEmpty()) {
1634- entry.background = bgdir.filePath(backgrounds[j++]);
1635- if (j >= backgrounds.length()) {
1636- j = 0;
1637- }
1638- }
1639- }
1640-}
1641-
1642-UsersModel::~UsersModel()
1643-{
1644- delete d_ptr;
1645+ connect(d_ptr, &UsersModelPrivate::dataChanged, this, [this](int i) {
1646+ QModelIndex index = createIndex(i, 0);
1647+ Q_EMIT dataChanged(index, index);
1648+ });
1649 }
1650
1651 int UsersModel::rowCount(const QModelIndex &parent) const
1652
1653=== modified file 'plugins/IntegratedLightDM/liblightdm/UsersModel.h'
1654--- plugins/IntegratedLightDM/liblightdm/UsersModel.h 2015-04-30 09:31:51 +0000
1655+++ plugins/IntegratedLightDM/liblightdm/UsersModel.h 2016-03-11 11:34:41 +0000
1656@@ -41,7 +41,7 @@
1657
1658 public:
1659 explicit UsersModel(QObject *parent = 0);
1660- virtual ~UsersModel();
1661+ virtual ~UsersModel() = default;
1662
1663 enum UserModelRoles {NameRole = Qt::UserRole,
1664 RealNameRole,
1665
1666=== modified file 'plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp'
1667--- plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2016-02-04 14:10:42 +0000
1668+++ plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2016-03-11 11:34:41 +0000
1669@@ -18,7 +18,11 @@
1670
1671 #include "UsersModelPrivate.h"
1672
1673+#include "AccountsServiceDBusAdaptor.h"
1674+#include "UsersModel.h"
1675+
1676 #include <glib.h>
1677+#include <QDebug>
1678 #include <QDir>
1679 #include <QSettings>
1680 #include <QStringList>
1681@@ -27,7 +31,9 @@
1682 {
1683
1684 UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
1685- : q_ptr(parent)
1686+ : QObject(parent),
1687+ q_ptr(parent),
1688+ m_service(new AccountsServiceDBusAdaptor(this))
1689 {
1690 QFileInfo demoFile(QDir::homePath() + "/.unity8-greeter-demo");
1691 QString currentUser = g_get_user_name();
1692@@ -43,15 +49,43 @@
1693 entries.append({user, name, 0, 0, false, false, 0, 0});
1694 }
1695 } else {
1696- // If we were using the actual liblightdm, we could just ask it
1697- // for the user's real name. But we aren't. We *should* ask
1698- // AccountsService for the real name, like liblightdm does internally,
1699- // but this is close enough since AS and passwd are always in sync.
1700- QString realName = QString::fromUtf8(g_get_real_name()); // gets name from passwd entry
1701- if (realName == QStringLiteral("Unknown")) { // glib doesn't translate this string
1702- realName.clear();
1703- }
1704- entries.append({currentUser, realName, 0, 0, false, false, 0, 0});
1705+ entries.append({currentUser, 0, 0, 0, false, false, 0, 0});
1706+
1707+ connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged,
1708+ this, [this](const QString &user) {
1709+ if (user == entries[0].username) {
1710+ updateName(true);
1711+ }
1712+ });
1713+ updateName(false);
1714+ }
1715+}
1716+
1717+void UsersModelPrivate::updateName(bool async)
1718+{
1719+ auto pendingReply = m_service->getUserPropertyAsync(entries[0].username,
1720+ QStringLiteral("org.freedesktop.Accounts.User"),
1721+ QStringLiteral("RealName"));
1722+ auto *watcher = new QDBusPendingCallWatcher(pendingReply, this);
1723+
1724+ connect(watcher, &QDBusPendingCallWatcher::finished,
1725+ this, [this](QDBusPendingCallWatcher* watcher) {
1726+
1727+ QDBusPendingReply<QVariant> reply = *watcher;
1728+ watcher->deleteLater();
1729+ if (reply.isError()) {
1730+ qWarning() << "Failed to get 'RealName' property - " << reply.error().message();
1731+ return;
1732+ }
1733+
1734+ const QString realName = reply.value().toString();
1735+ if (entries[0].real_name != realName) {
1736+ entries[0].real_name = realName;
1737+ Q_EMIT dataChanged(0);
1738+ }
1739+ });
1740+ if (!async) {
1741+ watcher->waitForFinished();
1742 }
1743 }
1744
1745
1746=== modified file 'plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h'
1747--- plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h 2015-01-20 11:50:19 +0000
1748+++ plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h 2016-03-11 11:34:41 +0000
1749@@ -19,8 +19,11 @@
1750 #ifndef UNITY_MOCK_USERSMODEL_PRIVATE_H
1751 #define UNITY_MOCK_USERSMODEL_PRIVATE_H
1752
1753-#include <QtCore/QList>
1754-#include <QtCore/QString>
1755+#include <QList>
1756+#include <QObject>
1757+#include <QString>
1758+
1759+class AccountsServiceDBusAdaptor;
1760
1761 namespace QLightDM
1762 {
1763@@ -39,19 +42,28 @@
1764 QString infographic;
1765 };
1766
1767-class UsersModelPrivate
1768+class UsersModelPrivate : public QObject
1769 {
1770+ Q_OBJECT
1771+
1772 public:
1773 explicit UsersModelPrivate(UsersModel *parent = 0);
1774 virtual ~UsersModelPrivate() = default;
1775
1776 QList<Entry> entries;
1777
1778+Q_SIGNALS:
1779+ void dataChanged(int);
1780+
1781 protected:
1782 UsersModel * const q_ptr;
1783
1784 private:
1785 Q_DECLARE_PUBLIC(UsersModel)
1786+
1787+ void updateName(bool async);
1788+
1789+ AccountsServiceDBusAdaptor *m_service;
1790 };
1791
1792 }
1793
1794=== modified file 'plugins/Unity/Indicators/indicatorsmanager.cpp'
1795--- plugins/Unity/Indicators/indicatorsmanager.cpp 2015-12-02 12:02:50 +0000
1796+++ plugins/Unity/Indicators/indicatorsmanager.cpp 2016-03-11 11:34:41 +0000
1797@@ -116,7 +116,7 @@
1798 QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
1799 const QString name = indicator_settings.value(QStringLiteral("Indicator Service/Name")).toString();
1800
1801- if (m_platform.isPC() && name == "indicator-keyboard") {
1802+ if (m_platform.isPC() && name == QLatin1String("indicator-keyboard")) {
1803 return; // convergence: skip this indicator until it works in Mir
1804 }
1805
1806@@ -293,7 +293,7 @@
1807 // The rest of the indicators respect their default profile (which is "phone", even on desktop PCs)
1808 if ((new_indicator->identifier() == QStringLiteral("indicator-session") && m_platform.isMultiSession())
1809 || (new_indicator->identifier() == QStringLiteral("indicator-power") && m_platform.isPC())) {
1810- new_indicator->setProfile("desktop");
1811+ new_indicator->setProfile(QStringLiteral("desktop"));
1812 } else {
1813 new_indicator->setProfile(m_profile);
1814 }
1815
1816=== modified file 'plugins/Unity/Indicators/rootstateparser.h'
1817--- plugins/Unity/Indicators/rootstateparser.h 2014-11-11 15:28:13 +0000
1818+++ plugins/Unity/Indicators/rootstateparser.h 2016-03-11 11:34:41 +0000
1819@@ -23,6 +23,7 @@
1820
1821 class UNITYINDICATORS_EXPORT RootStateParser : public ActionStateParser
1822 {
1823+Q_OBJECT
1824 public:
1825 RootStateParser(QObject* parent = nullptr);
1826 virtual QVariant toQVariant(GVariant* state) const override;
1827
1828=== modified file 'plugins/Unity/Launcher/desktopfilehandler.cpp'
1829--- plugins/Unity/Launcher/desktopfilehandler.cpp 2015-09-30 12:43:53 +0000
1830+++ plugins/Unity/Launcher/desktopfilehandler.cpp 2016-03-11 11:34:41 +0000
1831@@ -146,9 +146,9 @@
1832 QString iconString = settings.value(QStringLiteral("Icon")).toString();
1833 QString pathString = settings.value(QStringLiteral("Path")).toString();
1834
1835- if (QFileInfo(iconString).exists()) {
1836+ if (QFileInfo::exists(iconString)) {
1837 return QFileInfo(iconString).absoluteFilePath();
1838- } else if (QFileInfo(pathString + '/' + iconString).exists()) {
1839+ } else if (QFileInfo::exists(pathString + '/' + iconString)) {
1840 return pathString + '/' + iconString;
1841 }
1842 return "image://theme/" + iconString;
1843
1844=== modified file 'plugins/Unity/Launcher/launcheritem.cpp'
1845--- plugins/Unity/Launcher/launcheritem.cpp 2015-09-14 09:11:08 +0000
1846+++ plugins/Unity/Launcher/launcheritem.cpp 2016-03-11 11:34:41 +0000
1847@@ -37,6 +37,7 @@
1848 m_alerting(false),
1849 m_quickList(new QuickListModel(this))
1850 {
1851+ Q_ASSERT(parent != nullptr);
1852 QuickListEntry nameAction;
1853 nameAction.setActionId(QStringLiteral("launch_item"));
1854 nameAction.setText(m_name);
1855
1856=== modified file 'plugins/Unity/Launcher/launcheritem.h'
1857--- plugins/Unity/Launcher/launcheritem.h 2015-07-23 14:13:57 +0000
1858+++ plugins/Unity/Launcher/launcheritem.h 2016-03-11 11:34:41 +0000
1859@@ -32,7 +32,7 @@
1860 {
1861 Q_OBJECT
1862 public:
1863- LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0);
1864+ LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent);
1865
1866 QString appId() const override;
1867 QString name() const override;
1868
1869=== modified file 'plugins/Unity/Launcher/launchermodel.cpp'
1870--- plugins/Unity/Launcher/launchermodel.cpp 2015-09-14 09:11:08 +0000
1871+++ plugins/Unity/Launcher/launchermodel.cpp 2016-03-11 11:34:41 +0000
1872@@ -103,7 +103,7 @@
1873 LauncherItem *item = m_list.at(index);
1874 if (!item->focused()) {
1875 item->setAlerting(alerting);
1876- Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleAlerting);
1877+ Q_EMIT dataChanged(modelIndex, modelIndex, {RoleAlerting});
1878 }
1879 }
1880 }
1881@@ -389,7 +389,8 @@
1882 if (countVisible && desktopFile.isValid()) {
1883 LauncherItem *item = new LauncherItem(appId,
1884 desktopFile.displayName(),
1885- desktopFile.icon());
1886+ desktopFile.icon(),
1887+ this);
1888 item->setCountVisible(true);
1889 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
1890 m_list.append(item);
1891@@ -414,10 +415,19 @@
1892 } else {
1893 int idx = m_list.indexOf(item);
1894 item->setName(desktopFile.displayName());
1895- item->setIcon(desktopFile.icon());
1896 item->setPinned(item->pinned()); // update pinned text if needed
1897 item->setRunning(item->running());
1898- Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleIcon, RoleRunning});
1899+ Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleRunning});
1900+
1901+ const QString oldIcon = item->icon();
1902+ if (oldIcon == desktopFile.icon()) { // same icon file, perhaps different contents, simulate changing the icon name to force reload
1903+ item->setIcon(QString());
1904+ Q_EMIT dataChanged(index(idx), index(idx), {RoleIcon});
1905+ }
1906+
1907+ // now set the icon for real
1908+ item->setIcon(desktopFile.icon());
1909+ Q_EMIT dataChanged(index(idx), index(idx), {RoleIcon});
1910 }
1911 }
1912
1913@@ -489,7 +499,7 @@
1914 if (idx >= 0) {
1915 LauncherItem *item = m_list.at(idx);
1916 setAlerting(item->appId(), true);
1917- Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleAlerting);
1918+ Q_EMIT dataChanged(index(idx), index(idx), {RoleAlerting});
1919 }
1920 }
1921
1922
1923=== modified file 'plugins/Unity/Launcher/launchermodel.h'
1924--- plugins/Unity/Launcher/launchermodel.h 2015-07-29 12:32:57 +0000
1925+++ plugins/Unity/Launcher/launchermodel.h 2016-03-11 11:34:41 +0000
1926@@ -38,7 +38,7 @@
1927 Q_OBJECT
1928
1929 public:
1930- LauncherModel(QObject *parent = 0);
1931+ LauncherModel(QObject *parent = nullptr);
1932 ~LauncherModel();
1933
1934 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
1935
1936=== modified file 'plugins/Utils/CMakeLists.txt'
1937--- plugins/Utils/CMakeLists.txt 2016-02-08 09:37:48 +0000
1938+++ plugins/Utils/CMakeLists.txt 2016-03-11 11:34:41 +0000
1939@@ -23,6 +23,7 @@
1940 windowstatestorage.cpp
1941 timezoneFormatter.cpp
1942 inputeventgenerator.cpp
1943+ deviceconfigparser.cpp
1944 plugin.cpp
1945 )
1946
1947
1948=== added file 'plugins/Utils/deviceconfigparser.cpp'
1949--- plugins/Utils/deviceconfigparser.cpp 1970-01-01 00:00:00 +0000
1950+++ plugins/Utils/deviceconfigparser.cpp 2016-03-11 11:34:41 +0000
1951@@ -0,0 +1,150 @@
1952+/*
1953+ * Copyright 2016 Canonical Ltd.
1954+ *
1955+ * This program is free software; you can redistribute it and/or modify
1956+ * it under the terms of the GNU Lesser General Public License as published by
1957+ * the Free Software Foundation; version 3.
1958+ *
1959+ * This program is distributed in the hope that it will be useful,
1960+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1961+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1962+ * GNU Lesser General Public License for more details.
1963+ *
1964+ * You should have received a copy of the GNU Lesser General Public License
1965+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1966+ */
1967+
1968+#include "deviceconfigparser.h"
1969+
1970+#include <QSettings>
1971+#include <QFileInfo>
1972+#include <QDebug>
1973+#include <QStandardPaths>
1974+
1975+DeviceConfigParser::DeviceConfigParser(QObject *parent): QObject(parent)
1976+{
1977+ QString path;
1978+ Q_FOREACH (const QString &standardPath, QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation)) {
1979+ if (QFileInfo(standardPath + "/devices.conf").exists()) {
1980+ path = standardPath + "/devices.conf";
1981+ break;
1982+ }
1983+ }
1984+
1985+ if (path.isEmpty()) {
1986+ path = "/etc/ubuntu/devices.conf";
1987+ }
1988+ qDebug() << "Using" << path << "as device configuration file";
1989+ m_config = new QSettings(path, QSettings::IniFormat, this);
1990+}
1991+
1992+QString DeviceConfigParser::name() const
1993+{
1994+ return m_name;
1995+}
1996+
1997+void DeviceConfigParser::setName(const QString &name)
1998+{
1999+ if (m_name == name) {
2000+ return;
2001+ }
2002+ m_name = name;
2003+ Q_EMIT changed();
2004+}
2005+
2006+Qt::ScreenOrientation DeviceConfigParser::primaryOrientation() const
2007+{
2008+ return stringToOrientation(readOrientationFromConfig("PrimaryOrientation"), Qt::PrimaryOrientation);
2009+}
2010+
2011+Qt::ScreenOrientations DeviceConfigParser::supportedOrientations() const
2012+{
2013+ QStringList values = readOrientationsFromConfig("SupportedOrientations");
2014+ if (values.isEmpty()) {
2015+ return Qt::PortraitOrientation
2016+ | Qt::InvertedPortraitOrientation
2017+ | Qt::LandscapeOrientation
2018+ | Qt::InvertedLandscapeOrientation;
2019+ }
2020+
2021+ Qt::ScreenOrientations ret = Qt::PrimaryOrientation;
2022+ Q_FOREACH(const QString &orientationString, values) {
2023+ ret |= stringToOrientation(orientationString, Qt::PrimaryOrientation);
2024+ }
2025+ return ret;
2026+}
2027+
2028+Qt::ScreenOrientation DeviceConfigParser::landscapeOrientation() const
2029+{
2030+ return stringToOrientation(readOrientationFromConfig("LandscapeOrientation"), Qt::LandscapeOrientation);
2031+}
2032+
2033+Qt::ScreenOrientation DeviceConfigParser::invertedLandscapeOrientation() const
2034+{
2035+ return stringToOrientation(readOrientationFromConfig("InvertedLandscapeOrientation"), Qt::InvertedLandscapeOrientation);
2036+}
2037+
2038+Qt::ScreenOrientation DeviceConfigParser::portraitOrientation() const
2039+{
2040+ return stringToOrientation(readOrientationFromConfig("PortraitOrientation"), Qt::PortraitOrientation);
2041+}
2042+
2043+Qt::ScreenOrientation DeviceConfigParser::invertedPortraitOrientation() const
2044+{
2045+ return stringToOrientation(readOrientationFromConfig("InvertedPortraitOrientation"), Qt::InvertedPortraitOrientation);
2046+}
2047+
2048+QString DeviceConfigParser::category() const
2049+{
2050+ QStringList supportedValues = {"phone", "tablet", "desktop"};
2051+ m_config->beginGroup(m_name);
2052+ QString value = m_config->value("Category", "phone").toString();
2053+ if (!supportedValues.contains(value)) {
2054+ qWarning().nospace().noquote() << "Unknown option \"" << value << "\" in " << m_config->fileName()
2055+ << ". Supported options are: " << supportedValues.join(", ") << ".";
2056+ return "phone";
2057+ }
2058+ m_config->endGroup();
2059+ return value;
2060+}
2061+
2062+QStringList DeviceConfigParser::readOrientationsFromConfig(const QString &key) const
2063+{
2064+ m_config->beginGroup(m_name);
2065+
2066+ QStringList ret;
2067+ if (m_config->contains(key)) {
2068+ ret = m_config->value(key).toStringList();
2069+ }
2070+
2071+ m_config->endGroup();
2072+ return ret;
2073+}
2074+
2075+QString DeviceConfigParser::readOrientationFromConfig(const QString &key) const
2076+{
2077+ QStringList ret = readOrientationsFromConfig(key);
2078+ return ret.count() > 0 ? ret.first() : QString();
2079+}
2080+
2081+Qt::ScreenOrientation DeviceConfigParser::stringToOrientation(const QString &orientationString, Qt::ScreenOrientation defaultValue) const
2082+{
2083+ if (orientationString == "Landscape") {
2084+ return Qt::LandscapeOrientation;
2085+ }
2086+ if (orientationString == "InvertedLandscape") {
2087+ return Qt::InvertedLandscapeOrientation;
2088+ }
2089+ if (orientationString == "Portrait") {
2090+ return Qt::PortraitOrientation;
2091+ }
2092+ if (orientationString == "InvertedPortrait") {
2093+ return Qt::InvertedPortraitOrientation;
2094+ }
2095+ if (!orientationString.isEmpty()) {
2096+ // Some option we don't know. Give some hint on what went wrong.
2097+ qWarning().nospace().noquote() << "Unknown option \"" << orientationString << "\" in " << m_config->fileName()
2098+ << ". Supported options are: Landscape, InvertedLandscape, Portrait and InvertedPortrait.";
2099+ }
2100+ return defaultValue;
2101+}
2102
2103=== added file 'plugins/Utils/deviceconfigparser.h'
2104--- plugins/Utils/deviceconfigparser.h 1970-01-01 00:00:00 +0000
2105+++ plugins/Utils/deviceconfigparser.h 2016-03-11 11:34:41 +0000
2106@@ -0,0 +1,62 @@
2107+/*
2108+ * Copyright 2016 Canonical Ltd.
2109+ *
2110+ * This program is free software; you can redistribute it and/or modify
2111+ * it under the terms of the GNU Lesser General Public License as published by
2112+ * the Free Software Foundation; version 3.
2113+ *
2114+ * This program is distributed in the hope that it will be useful,
2115+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2116+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2117+ * GNU Lesser General Public License for more details.
2118+ *
2119+ * You should have received a copy of the GNU Lesser General Public License
2120+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2121+ */
2122+
2123+#ifndef DEVICECONFIGPARSER_H
2124+#define DEVICECONFIGPARSER_H
2125+
2126+#include <QObject>
2127+#include <QSettings>
2128+
2129+class DeviceConfigParser: public QObject
2130+{
2131+ Q_OBJECT
2132+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY changed)
2133+
2134+ Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY changed)
2135+ Q_PROPERTY(Qt::ScreenOrientations supportedOrientations READ supportedOrientations NOTIFY changed)
2136+ Q_PROPERTY(Qt::ScreenOrientation landscapeOrientation READ landscapeOrientation NOTIFY changed)
2137+ Q_PROPERTY(Qt::ScreenOrientation invertedLandscapeOrientation READ invertedLandscapeOrientation NOTIFY changed)
2138+ Q_PROPERTY(Qt::ScreenOrientation portraitOrientation READ portraitOrientation NOTIFY changed)
2139+ Q_PROPERTY(Qt::ScreenOrientation invertedPortraitOrientation READ invertedPortraitOrientation NOTIFY changed)
2140+ Q_PROPERTY(QString category READ category NOTIFY changed)
2141+
2142+public:
2143+ DeviceConfigParser(QObject *parent = nullptr);
2144+
2145+ QString name() const;
2146+ void setName(const QString &name);
2147+
2148+ Qt::ScreenOrientation primaryOrientation() const;
2149+ Qt::ScreenOrientations supportedOrientations() const;
2150+ Qt::ScreenOrientation landscapeOrientation() const;
2151+ Qt::ScreenOrientation invertedLandscapeOrientation() const;
2152+ Qt::ScreenOrientation portraitOrientation() const;
2153+ Qt::ScreenOrientation invertedPortraitOrientation() const;
2154+ QString category() const;
2155+
2156+Q_SIGNALS:
2157+ void changed();
2158+
2159+private:
2160+ QString m_name;
2161+ QSettings *m_config;
2162+
2163+ QStringList readOrientationsFromConfig(const QString &key) const;
2164+ QString readOrientationFromConfig(const QString &key) const;
2165+ Qt::ScreenOrientation stringToOrientation(const QString &orientationString, Qt::ScreenOrientation defaultValue) const;
2166+};
2167+
2168+#endif
2169
2170=== modified file 'plugins/Utils/plugin.cpp'
2171--- plugins/Utils/plugin.cpp 2016-01-29 11:52:14 +0000
2172+++ plugins/Utils/plugin.cpp 2016-03-11 11:34:41 +0000
2173@@ -37,6 +37,7 @@
2174 #include "timezoneFormatter.h"
2175 #include "applicationsfiltermodel.h"
2176 #include "inputeventgenerator.h"
2177+#include "deviceconfigparser.h"
2178
2179 static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
2180 {
2181@@ -70,6 +71,7 @@
2182 qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger");
2183 qmlRegisterType<ApplicationsFilterModel>(uri, 0, 1, "ApplicationsFilterModel");
2184 qmlRegisterType<InputEventGenerator>(uri, 0, 1, "InputEventGenerator");
2185+ qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
2186 }
2187
2188 void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
2189
2190=== modified file 'po/unity8.pot'
2191--- po/unity8.pot 2016-03-08 21:04:17 +0000
2192+++ po/unity8.pot 2016-03-11 11:34:41 +0000
2193@@ -8,7 +8,7 @@
2194 msgstr ""
2195 "Project-Id-Version: unity8\n"
2196 "Report-Msgid-Bugs-To: \n"
2197-"POT-Creation-Date: 2016-03-08 21:04+0000\n"
2198+"POT-Creation-Date: 2016-03-10 22:48+0000\n"
2199 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
2200 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
2201 "Language-Team: LANGUAGE <LL@li.org>\n"
2202@@ -22,16 +22,16 @@
2203 msgid "Password: "
2204 msgstr ""
2205
2206-#: plugins/Unity/Launcher/launcheritem.cpp:47
2207-#: plugins/Unity/Launcher/launcheritem.cpp:106
2208+#: plugins/Unity/Launcher/launcheritem.cpp:48
2209+#: plugins/Unity/Launcher/launcheritem.cpp:107
2210 msgid "Pin shortcut"
2211 msgstr ""
2212
2213-#: plugins/Unity/Launcher/launcheritem.cpp:52
2214+#: plugins/Unity/Launcher/launcheritem.cpp:53
2215 msgid "Quit"
2216 msgstr ""
2217
2218-#: plugins/Unity/Launcher/launcheritem.cpp:106
2219+#: plugins/Unity/Launcher/launcheritem.cpp:107
2220 msgid "Unpin shortcut"
2221 msgstr ""
2222
2223@@ -135,15 +135,15 @@
2224 msgid "Restart"
2225 msgstr ""
2226
2227-#: qml/Components/Lockscreen.qml:245
2228+#: qml/Components/Lockscreen.qml:231
2229 msgid "Return to Call"
2230 msgstr ""
2231
2232-#: qml/Components/Lockscreen.qml:245
2233+#: qml/Components/Lockscreen.qml:231
2234 msgid "Emergency Call"
2235 msgstr ""
2236
2237-#: qml/Components/Lockscreen.qml:277
2238+#: qml/Components/Lockscreen.qml:263
2239 msgid "OK"
2240 msgstr ""
2241
2242@@ -152,6 +152,8 @@
2243 msgstr ""
2244
2245 #: qml/Components/ModeSwitchWarningDialog.qml:57
2246+msgctxt ""
2247+"Re-dock means connect the device again to an external screen/mouse/keyboard"
2248 msgid "Re-dock, save your work and close these apps to continue."
2249 msgstr ""
2250
2251@@ -194,15 +196,15 @@
2252 msgid "Add to Favorites"
2253 msgstr ""
2254
2255-#: qml/Dash/GenericScopeView.qml:565 qml/Dash/GenericScopeView.qml:723
2256+#: qml/Dash/GenericScopeView.qml:567 qml/Dash/GenericScopeView.qml:725
2257 msgid "See less"
2258 msgstr ""
2259
2260-#: qml/Dash/GenericScopeView.qml:565
2261+#: qml/Dash/GenericScopeView.qml:567
2262 msgid "See all"
2263 msgstr ""
2264
2265-#: qml/Dash/GenericScopeView.qml:627
2266+#: qml/Dash/GenericScopeView.qml:629
2267 msgctxt "Label: Hint for dash search line edit"
2268 msgid "Search"
2269 msgstr ""
2270@@ -228,7 +230,7 @@
2271 msgid "Add a review"
2272 msgstr ""
2273
2274-#: qml/Dash/Previews/PreviewSharing.qml:50
2275+#: qml/Dash/Previews/PreviewSharing.qml:66
2276 msgid "Preview Share Item"
2277 msgstr ""
2278
2279@@ -256,13 +258,13 @@
2280 msgid "Also installed"
2281 msgstr ""
2282
2283-#: qml/DisabledScreenNotice.qml:87
2284+#: qml/DisabledScreenNotice.qml:104
2285 msgid ""
2286 "Your device is now connected to an external display. Use this screen as a "
2287-"touch pad to interact with the mouse."
2288+"touch pad to interact with the pointer."
2289 msgstr ""
2290
2291-#: qml/Greeter/CoverPage.qml:107
2292+#: qml/Greeter/CoverPage.qml:118
2293 msgid "Unlock"
2294 msgstr ""
2295
2296@@ -341,62 +343,62 @@
2297 msgid "Conference"
2298 msgstr ""
2299
2300-#: qml/Panel/Indicators/MenuItemFactory.qml:753
2301+#: qml/Panel/Indicators/MenuItemFactory.qml:752
2302 msgid "Nothing is playing"
2303 msgstr ""
2304
2305-#: qml/Panel/Indicators/MenuItemFactory.qml:882
2306+#: qml/Panel/Indicators/MenuItemFactory.qml:881
2307 #, qt-format
2308 msgid "%1 hour"
2309 msgid_plural "%1 hours"
2310 msgstr[0] ""
2311 msgstr[1] ""
2312
2313-#: qml/Panel/Indicators/MenuItemFactory.qml:886
2314+#: qml/Panel/Indicators/MenuItemFactory.qml:885
2315 #, qt-format
2316 msgid "%1 minute"
2317 msgid_plural "%1 minutes"
2318 msgstr[0] ""
2319 msgstr[1] ""
2320
2321-#: qml/Panel/Indicators/MenuItemFactory.qml:891
2322+#: qml/Panel/Indicators/MenuItemFactory.qml:890
2323 #, qt-format
2324 msgid "%1 second"
2325 msgid_plural "%1 seconds"
2326 msgstr[0] ""
2327 msgstr[1] ""
2328
2329-#: qml/Panel/Indicators/MenuItemFactory.qml:894
2330+#: qml/Panel/Indicators/MenuItemFactory.qml:893
2331 msgid "0 seconds"
2332 msgstr ""
2333
2334 #. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
2335-#: qml/Panel/Indicators/MenuItemFactory.qml:896
2336+#: qml/Panel/Indicators/MenuItemFactory.qml:895
2337 #, qt-format
2338 msgid "%1 remaining"
2339 msgstr ""
2340
2341-#: qml/Panel/Indicators/MenuItemFactory.qml:902
2342+#: qml/Panel/Indicators/MenuItemFactory.qml:901
2343 msgid "In queue…"
2344 msgstr ""
2345
2346-#: qml/Panel/Indicators/MenuItemFactory.qml:906
2347+#: qml/Panel/Indicators/MenuItemFactory.qml:905
2348 msgid "Downloading"
2349 msgstr ""
2350
2351-#: qml/Panel/Indicators/MenuItemFactory.qml:908
2352+#: qml/Panel/Indicators/MenuItemFactory.qml:907
2353 msgid "Paused, tap to resume"
2354 msgstr ""
2355
2356-#: qml/Panel/Indicators/MenuItemFactory.qml:910
2357+#: qml/Panel/Indicators/MenuItemFactory.qml:909
2358 msgid "Canceled"
2359 msgstr ""
2360
2361-#: qml/Panel/Indicators/MenuItemFactory.qml:912
2362+#: qml/Panel/Indicators/MenuItemFactory.qml:911
2363 msgid "Finished"
2364 msgstr ""
2365
2366-#: qml/Panel/Indicators/MenuItemFactory.qml:914
2367+#: qml/Panel/Indicators/MenuItemFactory.qml:913
2368 msgid "Failed, tap to retry"
2369 msgstr ""
2370
2371
2372=== modified file 'qml/Components/EdgeBarrier.qml'
2373--- qml/Components/EdgeBarrier.qml 2015-11-24 17:44:18 +0000
2374+++ qml/Components/EdgeBarrier.qml 2016-03-11 11:34:41 +0000
2375@@ -105,7 +105,7 @@
2376 },
2377 Transition {
2378 from: "resisting"; to: "passed"
2379- UbuntuNumberAnimation { target: materialContainer; property: "opacity" }
2380+ UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration; target: materialContainer; property: "opacity" }
2381 }
2382 ]
2383 }
2384
2385=== modified file 'qml/Components/InputMethod.qml'
2386--- qml/Components/InputMethod.qml 2015-12-02 10:34:31 +0000
2387+++ qml/Components/InputMethod.qml 2016-03-11 11:34:41 +0000
2388@@ -22,15 +22,6 @@
2389 Item {
2390 id: root
2391
2392- Connections {
2393- target: SurfaceManager
2394- onSurfaceCreated: {
2395- if (surface.type == Mir.InputMethodType) {
2396- surfaceItem.surface = surface;
2397- }
2398- }
2399- }
2400-
2401 property int transitionDuration: UbuntuAnimation.FastDuration
2402
2403 MirSurfaceItem {
2404@@ -41,6 +32,7 @@
2405
2406 surfaceWidth: width
2407 surfaceHeight: height
2408+ surface: SurfaceManager.inputMethodSurface
2409
2410 onLiveChanged: {
2411 if (surface !== null && !live) {
2412
2413=== modified file 'qml/Components/Lockscreen.qml'
2414--- qml/Components/Lockscreen.qml 2015-07-15 15:07:19 +0000
2415+++ qml/Components/Lockscreen.qml 2016-03-11 11:34:41 +0000
2416@@ -121,107 +121,93 @@
2417 opacity: root.darkenBackground
2418 }
2419
2420- MouseArea {
2421- anchors.fill: root
2422- onClicked: {
2423- if (pinPadLoader.item)
2424- pinPadLoader.item.forceActiveFocus()
2425- }
2426- }
2427-
2428- FocusScope {
2429- id: loaderScope
2430+ Loader {
2431+ id: pinPadLoader
2432+ objectName: "pinPadLoader"
2433 anchors.fill: parent
2434-
2435- Loader {
2436- id: pinPadLoader
2437- objectName: "pinPadLoader"
2438- anchors.fill: parent
2439- property bool resetting: false
2440- property bool waiting: false
2441- property bool showWrongText: false
2442-
2443- source: {
2444- if (resetting || !root.required) {
2445- return ""
2446- } else if (root.delayMinutes > 0) {
2447- return "DelayedLockscreen.qml"
2448- } else if (root.alphaNumeric) {
2449- return "PassphraseLockscreen.qml"
2450- } else {
2451- return "PinLockscreen.qml"
2452- }
2453- }
2454- onSourceChanged: {
2455- waiting = false
2456- showWrongText = false
2457- if (loaderScope.activeFocus && pinPadLoader.item)
2458- pinPadLoader.item.forceActiveFocus()
2459- }
2460-
2461- Connections {
2462- target: pinPadLoader.item
2463-
2464- onEntered: {
2465- pinPadLoader.waiting = true
2466- root.entered(passphrase);
2467- }
2468-
2469- onCancel: {
2470- root.cancel()
2471- }
2472- }
2473-
2474- Binding {
2475- target: pinPadLoader.item
2476- property: "minPinLength"
2477- value: root.minPinLength
2478- }
2479- Binding {
2480- target: pinPadLoader.item
2481- property: "maxPinLength"
2482- value: root.maxPinLength
2483- }
2484- Binding {
2485- target: pinPadLoader.item
2486- property: "infoText"
2487- value: root.infoText
2488- }
2489- Binding {
2490- target: pinPadLoader.item
2491- property: "retryText"
2492- value: root.retryText
2493- }
2494- Binding {
2495- target: pinPadLoader.item
2496- property: "errorText"
2497- value: pinPadLoader.showWrongText ? root.errorText : ""
2498- }
2499- Binding {
2500- target: pinPadLoader.item
2501- property: "entryEnabled"
2502- value: !pinPadLoader.waiting
2503- }
2504- Binding {
2505- target: pinPadLoader.item
2506- property: "alphaNumeric"
2507- value: root.alphaNumeric
2508- }
2509- Binding {
2510- target: pinPadLoader.item
2511- property: "delayMinutes"
2512- value: root.delayMinutes
2513- }
2514- Binding {
2515- target: pinPadLoader.item
2516- property: "showCancelButton"
2517- value: root.showCancelButton
2518- }
2519- Binding {
2520- target: pinPadLoader.item
2521- property: "foregroundColor"
2522- value: root.foregroundColor
2523- }
2524+ property bool resetting: false
2525+ property bool waiting: false
2526+ property bool showWrongText: false
2527+ focus: true
2528+
2529+ source: {
2530+ if (resetting || !root.required) {
2531+ return ""
2532+ } else if (root.delayMinutes > 0) {
2533+ return "DelayedLockscreen.qml"
2534+ } else if (root.alphaNumeric) {
2535+ return "PassphraseLockscreen.qml"
2536+ } else {
2537+ return "PinLockscreen.qml"
2538+ }
2539+ }
2540+ onSourceChanged: {
2541+ waiting = false
2542+ showWrongText = false
2543+ }
2544+
2545+ Connections {
2546+ target: pinPadLoader.item
2547+
2548+ onEntered: {
2549+ pinPadLoader.waiting = true
2550+ root.entered(passphrase);
2551+ }
2552+
2553+ onCancel: {
2554+ root.cancel()
2555+ }
2556+ }
2557+
2558+ Binding {
2559+ target: pinPadLoader.item
2560+ property: "minPinLength"
2561+ value: root.minPinLength
2562+ }
2563+ Binding {
2564+ target: pinPadLoader.item
2565+ property: "maxPinLength"
2566+ value: root.maxPinLength
2567+ }
2568+ Binding {
2569+ target: pinPadLoader.item
2570+ property: "infoText"
2571+ value: root.infoText
2572+ }
2573+ Binding {
2574+ target: pinPadLoader.item
2575+ property: "retryText"
2576+ value: root.retryText
2577+ }
2578+ Binding {
2579+ target: pinPadLoader.item
2580+ property: "errorText"
2581+ value: pinPadLoader.showWrongText ? root.errorText : ""
2582+ }
2583+ Binding {
2584+ target: pinPadLoader.item
2585+ property: "entryEnabled"
2586+ value: !pinPadLoader.waiting
2587+ }
2588+ Binding {
2589+ target: pinPadLoader.item
2590+ property: "alphaNumeric"
2591+ value: root.alphaNumeric
2592+ }
2593+ Binding {
2594+ target: pinPadLoader.item
2595+ property: "delayMinutes"
2596+ value: root.delayMinutes
2597+ }
2598+ Binding {
2599+ target: pinPadLoader.item
2600+ property: "showCancelButton"
2601+ value: root.showCancelButton
2602+ }
2603+ Binding {
2604+ target: pinPadLoader.item
2605+ property: "foregroundColor"
2606+ value: root.foregroundColor
2607 }
2608 }
2609
2610
2611=== modified file 'qml/Components/ModeSwitchWarningDialog.qml'
2612--- qml/Components/ModeSwitchWarningDialog.qml 2015-11-25 13:57:34 +0000
2613+++ qml/Components/ModeSwitchWarningDialog.qml 2016-03-11 11:34:41 +0000
2614@@ -54,7 +54,7 @@
2615 }
2616
2617 Label {
2618- text: i18n.tr("Re-dock, save your work and close these apps to continue.")
2619+ text: i18n.ctr("Re-dock means connect the device again to an external screen/mouse/keyboard", "Re-dock, save your work and close these apps to continue.")
2620 wrapMode: Text.WordWrap
2621 color: "#888888"
2622 }
2623
2624=== modified file 'qml/Components/PassphraseLockscreen.qml'
2625--- qml/Components/PassphraseLockscreen.qml 2015-07-15 15:07:19 +0000
2626+++ qml/Components/PassphraseLockscreen.qml 2016-03-11 11:34:41 +0000
2627@@ -18,10 +18,11 @@
2628 import Ubuntu.Components 1.3
2629 import "../Components"
2630
2631-Item {
2632+FocusScope {
2633 id: root
2634 y: units.gu(4)
2635 height: shakeContainer.height
2636+ focus: true
2637
2638 property string infoText
2639 property string errorText
2640@@ -42,8 +43,6 @@
2641 }
2642 }
2643
2644- onActiveFocusChanged: if (activeFocus) pinentryField.forceActiveFocus()
2645-
2646 Column {
2647 id: shakeContainer
2648 anchors.horizontalCenter: parent.horizontalCenter
2649@@ -59,14 +58,16 @@
2650 text: root.infoText
2651 }
2652
2653- Item {
2654+ FocusScope {
2655 id: entryContainer
2656 anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
2657 height: units.gu(4)
2658+ focus: true
2659
2660 TextInput {
2661 id: pinentryField
2662 objectName: "pinentryField"
2663+ focus: true
2664
2665 property bool incorrectOverride: false
2666
2667
2668=== modified file 'qml/Components/PhysicalKeysMapper.qml'
2669--- qml/Components/PhysicalKeysMapper.qml 2016-01-13 18:43:34 +0000
2670+++ qml/Components/PhysicalKeysMapper.qml 2016-03-11 11:34:41 +0000
2671@@ -42,12 +42,15 @@
2672 signal screenshotTriggered;
2673
2674 readonly property bool altTabPressed: d.altTabPressed
2675+ readonly property bool superPressed: d.superPressed
2676+ readonly property bool superTabPressed: d.superTabPressed
2677
2678 property int powerKeyLongPressTime: 2000
2679
2680 // For testing. If running windowed (e.g. tryShell), Alt+Tab is taken by the
2681 // running desktop, set this to true to use Ctrl+Tab instead.
2682 property bool controlInsteadOfAlt: false
2683+ property bool controlInsteadOfSuper: false
2684
2685 QtObject {
2686 id: d
2687@@ -59,6 +62,9 @@
2688 property bool altPressed: false
2689 property bool altTabPressed: false
2690
2691+ property bool superPressed: false
2692+ property bool superTabPressed: false
2693+
2694 property var powerButtonPressStart: 0
2695
2696 // We need to eat ALT presses until we know what they're for (Alt+Tab or going to the app?)
2697@@ -119,11 +125,23 @@
2698 event.accepted = true;
2699 d.altPressInjected = false;
2700 }
2701+
2702+ // Adding MetaModifier here because that's what keyboards do. Pressing Super_L actually gives
2703+ // Super_L + MetaModifier. This helps to make sure we only invoke superPressed if no other
2704+ // Modifier is pressed too.
2705+ } else if (((event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R) && event.modifiers === Qt.MetaModifier)
2706+ || (root.controlInsteadOfSuper && event.key == Qt.Key_Control)
2707+ ) {
2708+ d.superPressed = true;
2709 } else if (event.key == Qt.Key_Tab) {
2710 if (d.altPressed && !d.altTabPressed) {
2711 d.altTabPressed = true;
2712 event.accepted = true;
2713 }
2714+ if (d.superPressed && !d.superTabPressed) {
2715+ d.superTabPressed = true;
2716+ event.accepted = true;
2717+ }
2718 }
2719 }
2720
2721@@ -154,6 +172,12 @@
2722 if (d.altTabPressed) {
2723 event.accepted = true;
2724 }
2725+ } else if (event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R || (root.controlInsteadOfSuper && event.key == Qt.Key_Control)) {
2726+ d.superPressed = false;
2727+ if (d.superTabPressed) {
2728+ d.superTabPressed = false;
2729+ event.accepted = true;
2730+ }
2731 }
2732 }
2733 }
2734
2735=== modified file 'qml/Components/PinLockscreen.qml'
2736--- qml/Components/PinLockscreen.qml 2015-07-15 15:07:19 +0000
2737+++ qml/Components/PinLockscreen.qml 2016-03-11 11:34:41 +0000
2738@@ -19,8 +19,9 @@
2739 import Ubuntu.Components.ListItems 1.3
2740 import "../Components"
2741
2742-Item {
2743+FocusScope {
2744 id: root
2745+ focus: true
2746
2747 property string infoText
2748 property string retryText
2749@@ -45,6 +46,24 @@
2750 }
2751 }
2752
2753+ Keys.onPressed: {
2754+ if (pinentryField.text.length == root.maxPinLength)
2755+ return;
2756+
2757+ if (event.key === Qt.Key_Backspace) {
2758+ pinentryField.backspace();
2759+ } else if (event.key === Qt.Key_Delete || event.key === Qt.Key_Escape) {
2760+ closeButton.clicked()
2761+ } else if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
2762+ confirmButton.clicked()
2763+ } else {
2764+ var digit = parseInt(event.text);
2765+ if (!isNaN(digit) && typeof digit == "number") {
2766+ pinentryField.appendNumber(digit);
2767+ }
2768+ }
2769+ }
2770+
2771 Column {
2772 anchors {
2773 left: parent.left;
2774@@ -204,6 +223,7 @@
2775 width: numbersGrid.buttonWidth
2776 }
2777 PinPadButton {
2778+ id: closeButton
2779 iconName: "close"
2780 height: units.gu(5) // visual spec has this row a little closer in
2781 width: numbersGrid.buttonWidth
2782@@ -216,6 +236,7 @@
2783 width: numbersGrid.buttonWidth
2784 }
2785 PinPadButton {
2786+ id: confirmButton
2787 iconName: "tick"
2788 objectName: "confirmButton"
2789 height: units.gu(5)
2790
2791=== modified file 'qml/Components/ShellDialog.qml'
2792--- qml/Components/ShellDialog.qml 2015-11-06 10:06:58 +0000
2793+++ qml/Components/ShellDialog.qml 2016-03-11 11:34:41 +0000
2794@@ -37,7 +37,15 @@
2795
2796 focus: true
2797
2798+ // FIXME: this is a hack because Dialog subtheming seems broken atm
2799+ // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1555548
2800+ ThemeSettings {
2801+ id: themeHack
2802+ name: "Ubuntu.Components.Themes.Ambiance"
2803+ }
2804+
2805 Component.onCompleted: {
2806+ __foreground.theme = themeHack
2807 show();
2808 }
2809 }
2810
2811=== modified file 'qml/Dash/CardCarousel.qml'
2812--- qml/Dash/CardCarousel.qml 2016-01-28 14:11:14 +0000
2813+++ qml/Dash/CardCarousel.qml 2016-03-11 11:34:41 +0000
2814@@ -66,7 +66,6 @@
2815 item.cardData = Qt.binding(function() { return model; });
2816 item.fontScale = Qt.binding(function() { return carousel.fontScale; });
2817 item.showHeader = Qt.binding(function() { return loader.explicitlyScaled; });
2818- item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
2819 item.artShapeStyle = "shadow";
2820 item.scopeStyle = cardCarousel.scopeStyle;
2821 }
2822
2823=== modified file 'qml/Dash/CardGrid.qml'
2824--- qml/Dash/CardGrid.qml 2016-02-02 08:47:07 +0000
2825+++ qml/Dash/CardGrid.qml 2016-03-11 11:34:41 +0000
2826@@ -70,7 +70,6 @@
2827 item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; });
2828 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
2829 item.cardData = Qt.binding(function() { return model; });
2830- item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
2831 item.scopeStyle = root.scopeStyle;
2832 item.artShapeStyle = root.artShapeStyle;
2833 item.backgroundShapeStyle = root.backgroundShapeStyle;
2834
2835=== modified file 'qml/Dash/CardHorizontalList.qml'
2836--- qml/Dash/CardHorizontalList.qml 2016-01-28 14:11:14 +0000
2837+++ qml/Dash/CardHorizontalList.qml 2016-03-11 11:34:41 +0000
2838@@ -53,7 +53,6 @@
2839 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
2840 item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; });
2841 item.cardData = Qt.binding(function() { return model; });
2842- item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
2843 item.scopeStyle = root.scopeStyle;
2844 }
2845 Connections {
2846
2847=== modified file 'qml/Dash/CardTool.qml'
2848--- qml/Dash/CardTool.qml 2016-01-28 14:11:14 +0000
2849+++ qml/Dash/CardTool.qml 2016-03-11 11:34:41 +0000
2850@@ -66,7 +66,7 @@
2851 return layout;
2852 }
2853
2854- property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components);
2855+ property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, false);
2856
2857 // FIXME: Saviq
2858 // Only way for the card below to actually be laid out completely.
2859@@ -139,29 +139,6 @@
2860 readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0
2861 property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0
2862
2863- /*!
2864- \brief Desired alignment of title
2865- */
2866- readonly property int titleAlignment: {
2867- if (template["card-layout"] === "horizontal"
2868- || typeof components["title"] !== "object"
2869- || components["title"]["align"] === "left") return Text.AlignLeft;
2870-
2871- var keys = ["mascot", "emblem", "subtitle", "attributes", "summary"];
2872-
2873- for (var key in keys) {
2874- key = keys[key];
2875- try {
2876- if (typeof components[key] === "string"
2877- || typeof components[key]["field"] === "string") return Text.AlignLeft;
2878- } catch (e) {
2879- continue;
2880- }
2881- }
2882-
2883- return Text.AlignHCenter;
2884- }
2885-
2886 QtObject {
2887 id: carouselTool
2888
2889@@ -216,10 +193,9 @@
2890 "summary": "—\n—\n—\n—\n—",
2891 "attributes": attributesModel.model
2892 }
2893- sourceComponent: cardTool.cardComponent
2894+ sourceComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true);
2895 onLoaded: {
2896 item.objectName = "cardToolCard";
2897- item.asynchronous = false;
2898 item.width = Qt.binding(function() { return cardTool.cardWidth !== -1 ? cardTool.cardWidth : item.implicitWidth; });
2899 item.height = Qt.binding(function() { return cardTool.cardHeight !== -1 ? cardTool.cardHeight : item.implicitHeight; });
2900 }
2901
2902=== modified file 'qml/Dash/CardVerticalJournal.qml'
2903--- qml/Dash/CardVerticalJournal.qml 2016-01-28 14:11:14 +0000
2904+++ qml/Dash/CardVerticalJournal.qml 2016-03-11 11:34:41 +0000
2905@@ -72,7 +72,6 @@
2906 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
2907 item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; });
2908 item.cardData = Qt.binding(function() { return model; });
2909- item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
2910 item.scopeStyle = root.scopeStyle;
2911 }
2912 Connections {
2913
2914=== modified file 'qml/Dash/Dash.qml'
2915--- qml/Dash/Dash.qml 2015-11-19 16:55:31 +0000
2916+++ qml/Dash/Dash.qml 2016-03-11 11:34:41 +0000
2917@@ -37,6 +37,7 @@
2918 }
2919
2920 property bool windowActive: window.active
2921+ property bool showOverlayScope: false
2922
2923 DashCommunicatorService {
2924 objectName: "dashCommunicatorService"
2925@@ -80,7 +81,7 @@
2926 return
2927 }
2928
2929- closeOverlayScope();
2930+ dash.showOverlayScope = false;
2931
2932 dashContent.closePreview();
2933
2934@@ -93,12 +94,6 @@
2935 dashContent.setCurrentScopeAtIndex(scopeIndex, animate, reset)
2936 }
2937
2938- function closeOverlayScope() {
2939- if (dashContent.x != 0) {
2940- dashContent.x = 0;
2941- }
2942- }
2943-
2944 Scopes {
2945 id: scopes
2946 }
2947@@ -133,12 +128,13 @@
2948 height: dash.height
2949 scopes: scopes
2950 visible: x != -width
2951+ x: dash.showOverlayScope ? -width : 0
2952 onGotoScope: {
2953 dash.setCurrentScope(scopeId, true, false);
2954 }
2955 onOpenScope: {
2956 scopeItem.scope = scope;
2957- x = -width;
2958+ dash.showOverlayScope = true;
2959 }
2960 Behavior on x {
2961 UbuntuNumberAnimation {
2962@@ -207,7 +203,7 @@
2963 bottomEdgeController.enableAnimation = true;
2964 bottomEdgeController.progress = 0;
2965 scopeItem.scope = scope;
2966- dashContent.x = -dashContent.width;
2967+ dash.showOverlayScope = true;
2968 }
2969 onGotoScope: {
2970 bottomEdgeController.enableAnimation = true;
2971@@ -226,7 +222,7 @@
2972 id: scopeItem
2973 objectName: "dashTempScopeItem"
2974
2975- x: dashContent.x + width
2976+ x: dash.showOverlayScope ? 0 : width
2977 y: dashContent.y
2978 width: parent.width
2979 height: parent.height
2980@@ -234,7 +230,7 @@
2981 hasBackAction: true
2982 isCurrent: visible
2983 onBackClicked: {
2984- closeOverlayScope();
2985+ dash.showOverlayScope = false;
2986 closePreview();
2987 }
2988
2989@@ -250,6 +246,10 @@
2990 scopes.closeScope(oldScope);
2991 }
2992 }
2993+
2994+ Behavior on x {
2995+ UbuntuNumberAnimation { }
2996+ }
2997 }
2998
2999 Rectangle {
3000
3001=== modified file 'qml/Dash/GenericScopeView.qml'
3002--- qml/Dash/GenericScopeView.qml 2016-02-19 11:50:12 +0000
3003+++ qml/Dash/GenericScopeView.qml 2016-03-11 11:34:41 +0000
3004@@ -370,6 +370,8 @@
3005 } else {
3006 cardTool.cardWidth = units.gu(10);
3007 }
3008+ } else {
3009+ cardTool.cardWidth = units.gu(12);
3010 }
3011 item.minimumHorizontalSpacing = item.defaultMinimumHorizontalSpacing;
3012 }
3013
3014=== modified file 'qml/Dash/Previews/PreviewHeader.qml'
3015--- qml/Dash/Previews/PreviewHeader.qml 2016-01-08 14:19:08 +0000
3016+++ qml/Dash/Previews/PreviewHeader.qml 2016-03-11 11:34:41 +0000
3017@@ -25,6 +25,7 @@
3018 * The mascot fall back image comes in widgetData["fallback"]
3019 * The subtitle comes in widgetData["subtitle"]
3020 * The attributes comes in widgetData["attributes"]
3021+ * The emblem comes in widgetData["emblem"]
3022 */
3023
3024 PreviewWidget {
3025@@ -40,6 +41,7 @@
3026 readonly property string title: root.widgetData["title"] || ""
3027 readonly property string subtitle: root.widgetData["subtitle"] || ""
3028 readonly property var attributes: root.widgetData["attributes"] || null
3029+ readonly property url emblem: root.widgetData["emblem"] || ""
3030 readonly property color fontColor: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText
3031
3032 // Rewire the source since we may have unwired it on onStatusChanged
3033@@ -98,16 +100,42 @@
3034 spacing: units.dp(2)
3035 anchors.verticalCenter: parent.verticalCenter
3036
3037- Label {
3038- id: titleLabel
3039- objectName: "titleLabel"
3040+ Item {
3041 anchors { left: parent.left; right: parent.right }
3042- elide: Text.ElideRight
3043- font.weight: Font.Normal
3044- fontSize: "large"
3045- wrapMode: Text.Wrap
3046- color: headerRoot.fontColor
3047- text: headerRoot.title
3048+ height: titleLabel.height
3049+
3050+ Label {
3051+ id: titleLabel
3052+ objectName: "titleLabel"
3053+ anchors {
3054+ left: parent.left;
3055+ right: iconLoader.right
3056+ rightMargin: iconLoader.width > 0 ? units.gu(0.5) : 0
3057+ }
3058+ elide: Text.ElideRight
3059+ font.weight: Font.Normal
3060+ fontSize: "large"
3061+ wrapMode: Text.Wrap
3062+ color: headerRoot.fontColor
3063+ text: headerRoot.title
3064+ }
3065+
3066+ Loader {
3067+ id: iconLoader
3068+ active: headerRoot.emblem != ""
3069+ anchors {
3070+ bottom: titleLabel.baseline
3071+ right: parent.right
3072+ }
3073+ sourceComponent: Icon {
3074+ objectName: "emblemIcon"
3075+ source: headerRoot.emblem
3076+ color: headerRoot.fontColor
3077+ height: source != "" ? titleLabel.font.pixelSize : 0
3078+ // FIXME Workaround for bug https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1421293
3079+ width: implicitWidth > 0 && implicitHeight > 0 ? (implicitWidth / implicitHeight * height) : implicitWidth
3080+ }
3081+ }
3082 }
3083
3084 Loader {
3085
3086=== modified file 'qml/Dash/Previews/PreviewOverlay.qml'
3087--- qml/Dash/Previews/PreviewOverlay.qml 2015-07-15 15:07:19 +0000
3088+++ qml/Dash/Previews/PreviewOverlay.qml 2016-03-11 11:34:41 +0000
3089@@ -158,7 +158,7 @@
3090 anchors.centerIn: parent
3091 width: units.gu(2.5)
3092 height: width
3093- color: theme.palette.normal.foregroundText
3094+ color: "white"
3095 name: "close"
3096 }
3097 }
3098
3099=== modified file 'qml/Dash/Previews/PreviewSharing.qml'
3100--- qml/Dash/Previews/PreviewSharing.qml 2015-12-17 15:42:39 +0000
3101+++ qml/Dash/Previews/PreviewSharing.qml 2016-03-11 11:34:41 +0000
3102@@ -44,6 +44,22 @@
3103 }
3104 }
3105
3106+ function createExportedItems(url) {
3107+ var items = new Array();
3108+ if (typeof url === "string") {
3109+ var exportItem = exportItemComponent.createObject();
3110+ exportItem.url = url;
3111+ items.push(exportItem);
3112+ } else {
3113+ for (var i = 0; i < url.length; i++) {
3114+ var exportItem = exportItemComponent.createObject();
3115+ exportItem.url = url[i];
3116+ items.push(exportItem);
3117+ }
3118+ }
3119+ return items;
3120+ }
3121+
3122 Component {
3123 id: exportItemComponent
3124 ContentItem {
3125@@ -76,13 +92,7 @@
3126 onPeerSelected: {
3127 var transfer = peer.request();
3128 if (transfer.state === ContentTransfer.InProgress) {
3129- var items = new Array();
3130- for (var i = 0; i < url.length; i++) {
3131- var exportItem = exportItemComponent.createObject();
3132- exportItem.url = url[i];
3133- items.push(exportItem);
3134- }
3135- transfer.items = items;
3136+ transfer.items = createExportedItems(url);
3137 transfer.state = ContentTransfer.Charged;
3138 }
3139 peerPicker.visible = false;
3140
3141=== modified file 'qml/Dash/ScopesListCategoryItem.qml'
3142--- qml/Dash/ScopesListCategoryItem.qml 2015-11-04 14:57:13 +0000
3143+++ qml/Dash/ScopesListCategoryItem.qml 2016-03-11 11:34:41 +0000
3144@@ -18,7 +18,7 @@
3145 import QtQuick.Layouts 1.1
3146 import Ubuntu.Components 1.3
3147
3148-MouseArea {
3149+AbstractButton {
3150 id: root
3151
3152 signal requestFavorite(string scopeId, bool favorite)
3153@@ -84,15 +84,19 @@
3154 visible: text != ""
3155 }
3156 }
3157- MouseArea {
3158+ AbstractButton {
3159 id: starArea
3160 objectName: "starArea"
3161 height: parent.height
3162 width: height
3163 anchors.right: parent.right
3164 onClicked: if (!editMode) root.requestFavorite(model.scopeId, !isFavorite);
3165- onPressed: if (editMode) root.handlePressed(starArea);
3166- onReleased: if (editMode) root.handleReleased(starArea);
3167+ onPressedChanged: {
3168+ if (editMode) {
3169+ if (pressed) root.handlePressed(starArea.__mouseArea);
3170+ else root.handleReleased(starArea.__mouseArea);
3171+ }
3172+ }
3173 visible: editMode || showStar
3174 Icon {
3175 id: star
3176
3177=== modified file 'qml/DeviceConfiguration.qml'
3178--- qml/DeviceConfiguration.qml 2015-12-01 13:56:54 +0000
3179+++ qml/DeviceConfiguration.qml 2016-03-11 11:34:41 +0000
3180@@ -1,5 +1,5 @@
3181 /*
3182- * Copyright (C) 2015 Canonical, Ltd.
3183+ * Copyright (C) 2015-2016 Canonical, Ltd.
3184 *
3185 * This program is free software; you can redistribute it and/or modify
3186 * it under the terms of the GNU General Public License as published by
3187@@ -15,6 +15,7 @@
3188 */
3189
3190 import QtQuick 2.4
3191+import Utils 0.1
3192
3193 QtObject {
3194 id: root
3195@@ -34,57 +35,83 @@
3196
3197 readonly property alias category: priv.category
3198
3199+ readonly property var deviceConfigParser: DeviceConfigParser {
3200+ name: root.name
3201+ }
3202+
3203 readonly property var priv: StateGroup {
3204 id: priv
3205
3206- property int primaryOrientation: root.useNativeOrientation
3207-
3208- property int supportedOrientations: Qt.PortraitOrientation
3209- | Qt.InvertedPortraitOrientation
3210- | Qt.LandscapeOrientation
3211- | Qt.InvertedLandscapeOrientation
3212-
3213- property int landscapeOrientation: Qt.LandscapeOrientation
3214- property int invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
3215- property int portraitOrientation: Qt.PortraitOrientation
3216- property int invertedPortraitOrientation: Qt.InvertedPortraitOrientation
3217-
3218- // Supported values so far:
3219- // "phone", "tablet" or "desktop"
3220- property string category: "phone"
3221+ property int primaryOrientation: deviceConfigParser.primaryOrientation == Qt.PrimaryOrientation ?
3222+ root.useNativeOrientation : deviceConfigParser.primaryOrientation
3223+
3224+ property int supportedOrientations: deviceConfigParser.supportedOrientations
3225+
3226+ property int landscapeOrientation: deviceConfigParser.landscapeOrientation
3227+ property int invertedLandscapeOrientation: deviceConfigParser.invertedLandscapeOrientation
3228+ property int portraitOrientation: deviceConfigParser.portraitOrientation
3229+ property int invertedPortraitOrientation: deviceConfigParser.invertedPortraitOrientation
3230+ property string category: deviceConfigParser.category
3231
3232 states: [
3233 State {
3234 name: "mako"
3235 PropertyChanges {
3236 target: priv
3237+ primaryOrientation: root.useNativeOrientation
3238 supportedOrientations: Qt.PortraitOrientation
3239 | Qt.LandscapeOrientation
3240 | Qt.InvertedLandscapeOrientation
3241+ landscapeOrientation: Qt.LandscapeOrientation
3242+ invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
3243+ portraitOrientation: Qt.PortraitOrientation
3244+ invertedPortraitOrientation: Qt.InvertedPortraitOrientation
3245+ category: "phone"
3246 }
3247 },
3248 State {
3249 name: "krillin"
3250 PropertyChanges {
3251 target: priv
3252+ primaryOrientation: root.useNativeOrientation
3253 supportedOrientations: Qt.PortraitOrientation
3254 | Qt.LandscapeOrientation
3255 | Qt.InvertedLandscapeOrientation
3256+ landscapeOrientation: Qt.LandscapeOrientation
3257+ invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
3258+ portraitOrientation: Qt.PortraitOrientation
3259+ invertedPortraitOrientation: Qt.InvertedPortraitOrientation
3260+ category: "phone"
3261 }
3262 },
3263 State {
3264 name: "arale"
3265 PropertyChanges {
3266 target: priv
3267+ primaryOrientation: root.useNativeOrientation
3268 supportedOrientations: Qt.PortraitOrientation
3269 | Qt.LandscapeOrientation
3270 | Qt.InvertedLandscapeOrientation
3271+ landscapeOrientation: Qt.LandscapeOrientation
3272+ invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
3273+ portraitOrientation: Qt.PortraitOrientation
3274+ invertedPortraitOrientation: Qt.InvertedPortraitOrientation
3275+ category: "phone"
3276 }
3277 },
3278 State {
3279 name: "manta"
3280 PropertyChanges {
3281 target: priv
3282+ primaryOrientation: root.useNativeOrientation
3283+ supportedOrientations: Qt.PortraitOrientation
3284+ | Qt.InvertedPortraitOrientation
3285+ | Qt.LandscapeOrientation
3286+ | Qt.InvertedLandscapeOrientation
3287+ landscapeOrientation: Qt.LandscapeOrientation
3288+ invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
3289+ portraitOrientation: Qt.PortraitOrientation
3290+ invertedPortraitOrientation: Qt.InvertedPortraitOrientation
3291 category: "tablet"
3292 }
3293 },
3294@@ -92,9 +119,15 @@
3295 name: "flo"
3296 PropertyChanges {
3297 target: priv
3298+ primaryOrientation: Qt.InvertedLandscapeOrientation
3299+ supportedOrientations: Qt.PortraitOrientation
3300+ | Qt.InvertedPortraitOrientation
3301+ | Qt.LandscapeOrientation
3302+ | Qt.InvertedLandscapeOrientation
3303 landscapeOrientation: Qt.InvertedLandscapeOrientation
3304 invertedLandscapeOrientation: Qt.LandscapeOrientation
3305- primaryOrientation: Qt.InvertedLandscapeOrientation
3306+ portraitOrientation: Qt.PortraitOrientation
3307+ invertedPortraitOrientation: Qt.InvertedPortraitOrientation
3308 category: "tablet"
3309 }
3310 },
3311@@ -102,8 +135,13 @@
3312 name: "desktop"
3313 PropertyChanges {
3314 target: priv
3315+ primaryOrientation: root.useNativeOrientation
3316+ supportedOrientations: root.useNativeOrientation
3317+ landscapeOrientation: Qt.LandscapeOrientation
3318+ invertedLandscapeOrientation: Qt.InvertedLandscapeOrientation
3319+ portraitOrientation: Qt.PortraitOrientation
3320+ invertedPortraitOrientation: Qt.InvertedPortraitOrientation
3321 category: "desktop"
3322- supportedOrientations: root.useNativeOrientation
3323 }
3324 }
3325 ]
3326
3327=== modified file 'qml/DisabledScreenNotice.qml'
3328--- qml/DisabledScreenNotice.qml 2016-01-26 15:29:54 +0000
3329+++ qml/DisabledScreenNotice.qml 2016-03-11 11:34:41 +0000
3330@@ -17,6 +17,7 @@
3331 import QtQuick 2.4
3332 import QtQuick.Layouts 1.1
3333 import Ubuntu.Components 1.3
3334+import Unity.Session 0.1
3335 import QtQuick.Window 2.2
3336 import "Components"
3337
3338@@ -25,19 +26,36 @@
3339
3340 property bool infoNoteDisplayed: true
3341
3342- WallpaperResolver {
3343- width: root.width
3344- id: wallpaperResolver
3345+ // For testing
3346+ property var screen: Screen
3347+ property var orientationLock: OrientationLock
3348+
3349+ DeviceConfiguration {
3350+ id: deviceConfiguration
3351+ name: applicationArguments.deviceName
3352 }
3353
3354 Item {
3355 id: contentContainer
3356+ objectName: "contentContainer"
3357 anchors.centerIn: parent
3358 height: rotation == 90 || rotation == 270 ? parent.width : parent.height
3359 width: rotation == 90 || rotation == 270 ? parent.height : parent.width
3360
3361+ property int savedOrientation: deviceConfiguration.primaryOrientation == deviceConfiguration.useNativeOrientation
3362+ ? (root.width > root.height ? Qt.LandscapeOrientation : Qt.PortraitOrientation)
3363+ : deviceConfiguration.primaryOrientation
3364+
3365 rotation: {
3366- switch (Screen.orientation) {
3367+ var usedOrientation = root.screen.orientation;
3368+
3369+ if (root.orientationLock.enabled) {
3370+ usedOrientation = savedOrientation;
3371+ }
3372+
3373+ savedOrientation = usedOrientation;
3374+
3375+ switch (usedOrientation) {
3376 case Qt.PortraitOrientation:
3377 return 0;
3378 case Qt.LandscapeOrientation:
3379@@ -47,6 +65,8 @@
3380 case Qt.InvertedLandscapeOrientation:
3381 return 90;
3382 }
3383+
3384+ return 0;
3385 }
3386 transformOrigin: Item.Center
3387
3388@@ -60,9 +80,9 @@
3389 }
3390 }
3391
3392- Image {
3393+ Rectangle {
3394 anchors.fill: parent
3395- source: wallpaperResolver.background
3396+ color: "#3b3b3b"
3397 }
3398
3399 Item {
3400@@ -74,22 +94,26 @@
3401 UbuntuNumberAnimation { }
3402 }
3403
3404- Rectangle {
3405- anchors.fill: parent
3406- color: "black"
3407- opacity: 0.4
3408- }
3409-
3410- Label {
3411- id: text
3412+ Column {
3413 anchors.centerIn: parent
3414 width: parent.width - units.gu(8)
3415- text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the mouse.")
3416- color: "white"
3417- horizontalAlignment: Text.AlignHCenter
3418- verticalAlignment: Text.AlignVCenter
3419- fontSize: "x-large"
3420- wrapMode: Text.Wrap
3421+ spacing: units.gu(4)
3422+
3423+ Label {
3424+ id: text
3425+ text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.")
3426+ color: "white"
3427+ width: parent.width
3428+ fontSize: "large"
3429+ wrapMode: Text.Wrap
3430+ }
3431+ Icon {
3432+ height: units.gu(8)
3433+ width: height
3434+ name: "input-touchpad-symbolic"
3435+ color: "white"
3436+ anchors.horizontalCenter: parent.horizontalCenter
3437+ }
3438 }
3439 }
3440
3441
3442=== modified file 'qml/Greeter/CoverPage.qml'
3443--- qml/Greeter/CoverPage.qml 2015-07-15 15:07:19 +0000
3444+++ qml/Greeter/CoverPage.qml 2016-03-11 11:34:41 +0000
3445@@ -1,5 +1,5 @@
3446 /*
3447- * Copyright (C) 2013,2014,2015 Canonical, Ltd.
3448+ * Copyright (C) 2013-2016 Canonical, Ltd.
3449 *
3450 * This program is free software; you can redistribute it and/or modify
3451 * it under the terms of the GNU General Public License as published by
3452@@ -34,6 +34,7 @@
3453 readonly property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
3454
3455 signal tease()
3456+ signal clicked()
3457
3458 function hideRight() {
3459 d.forceRightOnNextHideAnimation = true;
3460@@ -55,7 +56,17 @@
3461 // instead, we can get a little extra horizontal push by using transforms.
3462 transform: Translate { id: translation; x: root.draggable ? launcherOffset : 0 }
3463
3464- MouseArea { anchors.fill: parent; }
3465+ // Eat events elsewhere on the coverpage, except mouse clicks which we pass
3466+ // up (they are used in the NarrowView to hide the cover page)
3467+ MouseArea {
3468+ anchors.fill: parent
3469+ onClicked: root.clicked()
3470+
3471+ MultiPointTouchArea {
3472+ anchors.fill: parent
3473+ mouseEnabled: false
3474+ }
3475+ }
3476
3477 Rectangle {
3478 // In case background fails to load
3479
3480=== modified file 'qml/Greeter/Infographics.qml'
3481--- qml/Greeter/Infographics.qml 2015-09-29 12:28:10 +0000
3482+++ qml/Greeter/Infographics.qml 2016-03-11 11:34:41 +0000
3483@@ -1,5 +1,5 @@
3484 /*
3485- * Copyright (C) 2013 Canonical, Ltd.
3486+ * Copyright (C) 2013-2016 Canonical, Ltd.
3487 *
3488 * This program is free software; you can redistribute it and/or modify
3489 * it under the terms of the GNU General Public License as published by
3490@@ -402,6 +402,7 @@
3491
3492 MouseArea {
3493 anchors.fill: dataCircle
3494+ enabled: notification.text != ""
3495
3496 onDoubleClicked: {
3497 if (!d.animating) {
3498
3499=== modified file 'qml/Greeter/NarrowView.qml'
3500--- qml/Greeter/NarrowView.qml 2015-11-19 16:55:31 +0000
3501+++ qml/Greeter/NarrowView.qml 2016-03-11 11:34:41 +0000
3502@@ -1,5 +1,5 @@
3503 /*
3504- * Copyright (C) 2015 Canonical, Ltd.
3505+ * Copyright (C) 2015-2016 Canonical, Ltd.
3506 *
3507 * This program is free software; you can redistribute it and/or modify
3508 * it under the terms of the GNU General Public License as published by
3509@@ -125,6 +125,18 @@
3510 onCancel: coverPage.show()
3511 onEmergencyCall: root.emergencyCall()
3512
3513+ onEnabledChanged: {
3514+ if (enabled) {
3515+ lockscreen.forceActiveFocus();
3516+ }
3517+ }
3518+
3519+ onVisibleChanged: {
3520+ if (visible) {
3521+ lockscreen.forceActiveFocus();
3522+ }
3523+ }
3524+
3525 function maybeShow() {
3526 if (root.locked && !shown) {
3527 showNow();
3528@@ -145,6 +157,7 @@
3529 width: parent.width
3530 background: root.background
3531 onTease: root.tease()
3532+ onClicked: hide()
3533
3534 onShowProgressChanged: {
3535 if (showProgress === 1) {
3536
3537=== modified file 'qml/Launcher/Launcher.qml'
3538--- qml/Launcher/Launcher.qml 2016-01-19 15:26:15 +0000
3539+++ qml/Launcher/Launcher.qml 2016-03-11 11:34:41 +0000
3540@@ -19,21 +19,26 @@
3541 import Ubuntu.Components 1.3
3542 import Ubuntu.Gestures 0.1
3543 import Unity.Launcher 0.1
3544+import GlobalShortcut 1.0
3545
3546-Item {
3547+FocusScope {
3548 id: root
3549
3550 property bool autohideEnabled: false
3551+ property bool lockedVisible: false
3552 property bool available: true // can be used to disable all interactions
3553 property alias inverted: panel.inverted
3554 property bool shadeBackground: true // can be used to disable background shade when launcher is visible
3555
3556- property int panelWidth: units.gu(8)
3557+ property int panelWidth: units.gu(10)
3558 property int dragAreaWidth: units.gu(1)
3559 property int minimizeDistance: units.gu(26)
3560 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
3561 (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
3562
3563+ property bool superPressed: false
3564+ property bool superTabPressed: false
3565+
3566 readonly property bool dragging: dragArea.dragging
3567 readonly property real dragDistance: dragArea.dragging ? dragArea.touchX : 0
3568 readonly property real visibleWidth: panel.width + panel.x
3569@@ -57,12 +62,55 @@
3570 }
3571 }
3572
3573+ onSuperPressedChanged: {
3574+ if (superPressed) {
3575+ superPressTimer.start();
3576+ superLongPressTimer.start();
3577+ } else {
3578+ superPressTimer.stop();
3579+ superLongPressTimer.stop();
3580+ launcher.switchToNextState("");
3581+ panel.shortcutHintsShown = false;
3582+ }
3583+ }
3584+
3585+ onSuperTabPressedChanged: {
3586+ if (superTabPressed) {
3587+ switchToNextState("visible")
3588+ panel.highlightIndex = -1;
3589+ root.focus = true;
3590+ superPressTimer.stop();
3591+ superLongPressTimer.stop();
3592+ } else {
3593+ if (panel.highlightIndex == -1) {
3594+ showDashHome();
3595+ } else if (panel.highlightIndex >= 0){
3596+ launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
3597+ }
3598+ panel.highlightIndex = -2;
3599+ switchToNextState("");
3600+ root.focus = false;
3601+ }
3602+ }
3603+
3604+ onLockedVisibleChanged: {
3605+ if (lockedVisible && state == "") {
3606+ panel.dismissTimer.stop();
3607+ fadeOutAnimation.stop();
3608+ switchToNextState("visible")
3609+ } else if (!lockedVisible && state == "visible") {
3610+ hide();
3611+ }
3612+ }
3613+
3614 function hide() {
3615 switchToNextState("")
3616 }
3617
3618 function fadeOut() {
3619- fadeOutAnimation.start();
3620+ if (!root.lockedVisible) {
3621+ fadeOutAnimation.start();
3622+ }
3623 }
3624
3625 function switchToNextState(state) {
3626@@ -90,6 +138,77 @@
3627 }
3628 }
3629
3630+ function openForKeyboardNavigation() {
3631+ panel.highlightIndex = -1; // The BFB
3632+ root.focus = true;
3633+ switchToNextState("visible")
3634+ }
3635+
3636+ Keys.onPressed: {
3637+ switch (event.key) {
3638+ case Qt.Key_Backtab:
3639+ panel.highlightPrevious();
3640+ event.accepted = true;
3641+ break;
3642+ case Qt.Key_Up:
3643+ if (root.inverted) {
3644+ panel.highlightNext()
3645+ } else {
3646+ panel.highlightPrevious();
3647+ }
3648+ event.accepted = true;
3649+ break;
3650+ case Qt.Key_Tab:
3651+ panel.highlightNext();
3652+ event.accepted = true;
3653+ break;
3654+ case Qt.Key_Down:
3655+ if (root.inverted) {
3656+ panel.highlightPrevious();
3657+ } else {
3658+ panel.highlightNext();
3659+ }
3660+ event.accepted = true;
3661+ break;
3662+ case Qt.Key_Right:
3663+ panel.openQuicklist(panel.highlightIndex)
3664+ event.accepted = true;
3665+ break;
3666+ case Qt.Key_Escape:
3667+ panel.highlightIndex = -2;
3668+ // Falling through intentionally
3669+ case Qt.Key_Enter:
3670+ case Qt.Key_Return:
3671+ case Qt.Key_Space:
3672+ if (panel.highlightIndex == -1) {
3673+ showDashHome();
3674+ } else if (panel.highlightIndex >= 0) {
3675+ launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
3676+ }
3677+ root.hide();
3678+ panel.highlightIndex = -2
3679+ event.accepted = true;
3680+ root.focus = false;
3681+ }
3682+ }
3683+
3684+ Timer {
3685+ id: superPressTimer
3686+ interval: 200
3687+ onTriggered: {
3688+ switchToNextState("visible")
3689+ }
3690+ }
3691+
3692+ Timer {
3693+ id: superLongPressTimer
3694+ interval: 1000
3695+ onTriggered: {
3696+ switchToNextState("visible")
3697+ panel.shortcutHintsShown = true;
3698+ }
3699+ }
3700+
3701 Timer {
3702 id: teaseTimer
3703 interval: mode == "teasing" ? 200 : 300
3704@@ -106,6 +225,13 @@
3705 interval: 1
3706 property string nextState: ""
3707 onTriggered: {
3708+ if (root.lockedVisible && nextState == "") {
3709+ // Due to binding updates when switching between modes
3710+ // it could happen that our request to show will be overwritten
3711+ // with a hide request. Rewrite it when we know hiding is not allowed.
3712+ nextState = "visible"
3713+ }
3714+
3715 // switching to an intermediate state here to make sure all the
3716 // values are restored, even if we were already in the target state
3717 root.state = "tmp"
3718@@ -151,7 +277,7 @@
3719
3720 MouseArea {
3721 id: launcherDragArea
3722- enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary")
3723+ enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary") && !root.lockedVisible
3724 anchors.fill: panel
3725 anchors.rightMargin: -units.gu(2)
3726 drag {
3727@@ -172,9 +298,10 @@
3728 InverseMouseArea {
3729 id: closeMouseArea
3730 anchors.fill: panel
3731- enabled: root.shadeBackground && root.state == "visible"
3732+ enabled: root.shadeBackground && root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)
3733 visible: enabled
3734 onPressed: {
3735+ panel.highlightIndex = -2
3736 root.hide();
3737 }
3738 }
3739@@ -183,7 +310,7 @@
3740 id: backgroundShade
3741 anchors.fill: parent
3742 color: "black"
3743- opacity: root.shadeBackground && root.state == "visible" ? 0.6 : 0
3744+ opacity: root.shadeBackground && root.state == "visible" && !root.lockedVisible ? 0.6 : 0
3745
3746 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
3747 }
3748@@ -202,8 +329,8 @@
3749 rotation: -90
3750 anchors.centerIn: parent
3751 gradient: Gradient {
3752- GradientStop { position: 0.0; color: panel.color}
3753- GradientStop { position: 1.0; color: Qt.rgba(panel.r,panel.g,panel.b,0)}
3754+ GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}
3755+ GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}
3756 }
3757 }
3758 }
3759@@ -227,7 +354,7 @@
3760 Connections {
3761 target: panel.dismissTimer
3762 onTriggered: {
3763- if (root.autohideEnabled) {
3764+ if (root.autohideEnabled && !root.lockedVisible) {
3765 if (!panel.preventHiding) {
3766 root.state = ""
3767 } else {
3768@@ -240,11 +367,11 @@
3769 property bool animate: true
3770
3771 onApplicationSelected: {
3772- root.state = ""
3773+ root.hide();
3774 launcherApplicationSelected(appId)
3775 }
3776 onShowDashHome: {
3777- root.state = ""
3778+ root.hide();
3779 root.showDashHome();
3780 }
3781
3782@@ -254,6 +381,12 @@
3783 }
3784 }
3785
3786+ onKbdNavigationCancelled: {
3787+ panel.highlightIndex = -2;
3788+ root.hide();
3789+ root.focus = false;
3790+ }
3791+
3792 Behavior on x {
3793 enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate;
3794 NumberAnimation {
3795
3796=== modified file 'qml/Launcher/LauncherDelegate.qml'
3797--- qml/Launcher/LauncherDelegate.qml 2015-11-19 16:55:31 +0000
3798+++ qml/Launcher/LauncherDelegate.qml 2016-03-11 11:34:41 +0000
3799@@ -20,6 +20,7 @@
3800 Item {
3801 id: root
3802
3803+ property int itemIndex: 0
3804 property string iconName
3805 property int count: 0
3806 property bool countVisible: false
3807@@ -29,10 +30,12 @@
3808 property real maxAngle: 0
3809 property bool inverted: false
3810 property bool alerting: false
3811- readonly property alias wiggling: wiggleAnim.running
3812+ property bool highlighted: false
3813+ property bool shortcutHintShown: false
3814
3815 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
3816 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
3817+ readonly property alias wiggling: wiggleAnim.running
3818
3819 property int itemWidth
3820 property int itemHeight
3821@@ -121,20 +124,32 @@
3822
3823 Item {
3824 id: iconItem
3825- width: parent.itemWidth + units.gu(1)
3826+ width: root.width
3827 height: parent.itemHeight + units.gu(1)
3828 anchors.centerIn: parent
3829
3830+ Image {
3831+ objectName: "focusRing"
3832+ anchors.centerIn: iconShape
3833+ height: width * 15 / 16
3834+ width: iconShape.width + units.gu(1)
3835+ source: "graphics/launcher-app-focus-ring.svg"
3836+ sourceSize.width: width
3837+ sourceSize.height: height
3838+ visible: root.highlighted
3839+ }
3840+
3841 ProportionalShape {
3842 id: iconShape
3843 anchors.centerIn: parent
3844- width: parent.width - units.gu(2)
3845+ width: root.itemWidth
3846 aspect: UbuntuShape.DropShadow
3847 source: Image {
3848 id: iconImage
3849 sourceSize.width: iconShape.width
3850 sourceSize.height: iconShape.height
3851 source: root.iconName
3852+ cache: false // see lpbug#1543290 why no cache
3853 }
3854 }
3855
3856@@ -144,7 +159,8 @@
3857 anchors {
3858 right: parent.right
3859 bottom: parent.bottom
3860- margins: units.dp(3)
3861+ rightMargin: (iconItem.width - root.itemWidth) / 2 - units.dp(2)
3862+ margins: units.dp(5)
3863 }
3864 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
3865 height: units.gu(2)
3866@@ -172,16 +188,11 @@
3867 id: progressOverlay
3868 objectName: "progressOverlay"
3869
3870- anchors {
3871- left: iconItem.left
3872- right: iconItem.right
3873- verticalCenter: parent.verticalCenter
3874- leftMargin: units.gu(1.5)
3875- rightMargin: units.gu(1.5)
3876- }
3877+ anchors.centerIn: parent
3878+ width: root.itemWidth * .8
3879 height: units.gu(1)
3880 visible: root.progress > -1
3881- color: UbuntuColors.darkGrey
3882+ backgroundColor: UbuntuColors.darkGrey
3883 borderSource: "none"
3884
3885 Item {
3886@@ -199,32 +210,56 @@
3887 top: parent.top
3888 bottom: parent.bottom
3889 }
3890- color: "white"
3891+ backgroundColor: "white"
3892 borderSource: "none"
3893 width: progressOverlay.width
3894 }
3895 }
3896 }
3897
3898- Image {
3899- objectName: "runningHighlight"
3900+ Column {
3901 anchors {
3902 left: parent.left
3903 verticalCenter: parent.verticalCenter
3904 }
3905- visible: root.itemRunning
3906- rotation: 180
3907- source: "graphics/focused_app_arrow.png"
3908+ spacing: units.gu(.5)
3909+ Repeater {
3910+ model: 1 // TODO: This should be "Math.min(3, app.surfaceCount)" once we have multiple surfaces
3911+ Rectangle {
3912+ objectName: "runningHighlight" + index
3913+ width: units.gu(0.25)
3914+ height: units.gu(.5)
3915+ color: "white"
3916+ visible: root.itemRunning
3917+ }
3918+ }
3919 }
3920
3921- Image {
3922+ Rectangle {
3923 objectName: "focusedHighlight"
3924 anchors {
3925 right: parent.right
3926 verticalCenter: parent.verticalCenter
3927 }
3928+ width: units.gu(0.25)
3929+ height: units.gu(.5)
3930+ color: "white"
3931 visible: root.itemFocused
3932- source: "graphics/focused_app_arrow.png"
3933+ }
3934+
3935+ Rectangle {
3936+ objectName: "shortcutHint"
3937+ anchors.centerIn: parent
3938+ width: units.gu(3)
3939+ height: width
3940+ color: "#E0292929"
3941+ visible: root.shortcutHintShown
3942+ Label {
3943+ anchors.centerIn: parent
3944+ text: (itemIndex + 1) % 10
3945+ color: "white"
3946+ font.weight: Font.DemiBold
3947+ }
3948 }
3949 }
3950
3951
3952=== modified file 'qml/Launcher/LauncherPanel.qml'
3953--- qml/Launcher/LauncherPanel.qml 2016-01-11 17:38:19 +0000
3954+++ qml/Launcher/LauncherPanel.qml 2016-03-11 11:34:41 +0000
3955@@ -19,12 +19,13 @@
3956 import Ubuntu.Components.ListItems 1.3 as ListItems
3957 import Unity.Launcher 0.1
3958 import Ubuntu.Components.Popups 1.3
3959+import GlobalShortcut 1.0
3960 import "../Components/ListItems"
3961 import "../Components/"
3962
3963 Rectangle {
3964 id: root
3965- color: "#B2000000"
3966+ color: "#E0292929"
3967
3968 rotation: inverted ? 180 : 0
3969
3970@@ -33,11 +34,13 @@
3971 property bool dragging: false
3972 property bool moving: launcherListView.moving || launcherListView.flicking
3973 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
3974- || mouseEventEater.containsMouse || dashItem.hovered
3975- property int highlightIndex: -1
3976+ || mouseEventEater.containsMouse || dashItem.hovered
3977+ property int highlightIndex: -2
3978+ property bool shortcutHintsShown: false
3979
3980 signal applicationSelected(string appId)
3981 signal showDashHome()
3982+ signal kbdNavigationCancelled()
3983
3984 onXChanged: {
3985 if (quickList.state == "open") {
3986@@ -45,6 +48,26 @@
3987 }
3988 }
3989
3990+ function highlightNext() {
3991+ highlightIndex++;
3992+ if (highlightIndex >= launcherListView.count) {
3993+ highlightIndex = -1;
3994+ }
3995+ launcherListView.moveToIndex(Math.max(highlightIndex, 0));
3996+ }
3997+ function highlightPrevious() {
3998+ highlightIndex--;
3999+ if (highlightIndex <= -2) {
4000+ highlightIndex = launcherListView.count - 1;
4001+ }
4002+ launcherListView.moveToIndex(Math.max(highlightIndex, 0));
4003+ }
4004+ function openQuicklist(index) {
4005+ quickList.open(index);
4006+ quickList.selectedIndex = 0;
4007+ quickList.focus = true;
4008+ }
4009+
4010 MouseArea {
4011 id: mouseEventEater
4012 anchors.fill: parent
4013@@ -57,24 +80,16 @@
4014 fill: parent
4015 }
4016
4017- Item {
4018+ Rectangle {
4019 objectName: "buttonShowDashHome"
4020 width: parent.width
4021- height: units.gu(7)
4022- clip: true
4023-
4024- UbuntuShape {
4025- anchors {
4026- fill: parent
4027- topMargin: -units.gu(2)
4028- }
4029- aspect: UbuntuShape.Flat
4030- backgroundColor: UbuntuColors.orange
4031- }
4032+ height: width * .9
4033+ color: UbuntuColors.orange
4034+ readonly property bool highlighted: root.highlightIndex == -1;
4035
4036 Image {
4037 objectName: "dashItem"
4038- width: units.gu(5)
4039+ width: parent.width * .6
4040 height: width
4041 anchors.centerIn: parent
4042 source: "graphics/home.png"
4043@@ -85,6 +100,14 @@
4044 anchors.fill: parent
4045 onClicked: root.showDashHome()
4046 }
4047+ Rectangle {
4048+ objectName: "bfbFocusHighlight"
4049+ anchors.fill: parent
4050+ border.color: "white"
4051+ border.width: units.dp(1)
4052+ color: "transparent"
4053+ visible: parent.highlighted
4054+ }
4055 }
4056
4057 Item {
4058@@ -102,10 +125,8 @@
4059 objectName: "launcherListView"
4060 anchors {
4061 fill: parent
4062- topMargin: -extensionSize + units.gu(0.5)
4063- bottomMargin: -extensionSize + units.gu(1)
4064- leftMargin: units.gu(0.5)
4065- rightMargin: units.gu(0.5)
4066+ topMargin: -extensionSize + width * .15
4067+ bottomMargin: -extensionSize + width * .15
4068 }
4069 topMargin: extensionSize
4070 bottomMargin: extensionSize
4071@@ -140,11 +161,11 @@
4072 }
4073
4074 // The height of the area where icons start getting folded
4075- property int foldingStartHeight: units.gu(6.5)
4076+ property int foldingStartHeight: itemHeight
4077 // The height of the area where the items reach the final folding angle
4078 property int foldingStopHeight: foldingStartHeight - itemHeight - spacing
4079- property int itemWidth: units.gu(7)
4080- property int itemHeight: units.gu(6.5)
4081+ property int itemWidth: width * .75
4082+ property int itemHeight: itemWidth * 15 / 16 + units.gu(1)
4083 property int clickFlickSpeed: units.gu(60)
4084 property int draggedIndex: dndArea.draggedIndex
4085 property real realContentY: contentY - originY + topMargin
4086@@ -172,12 +193,24 @@
4087
4088 UbuntuNumberAnimation {
4089 id: moveAnimation
4090+ objectName: "moveAnimation"
4091 target: launcherListView
4092 property: "contentY"
4093 function moveTo(contentY) {
4094 from = launcherListView.contentY;
4095 to = contentY;
4096- start();
4097+ restart();
4098+ }
4099+ }
4100+ function moveToIndex(index) {
4101+ var totalItemHeight = launcherListView.itemHeight + launcherListView.spacing
4102+ var itemPosition = index * totalItemHeight;
4103+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
4104+ var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : totalItemHeight
4105+ if (itemPosition + totalItemHeight + distanceToEnd > launcherListView.contentY + launcherListView.originY + launcherListView.topMargin + height) {
4106+ moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd - launcherListView.originY);
4107+ } else if (itemPosition - distanceToEnd < launcherListView.contentY - launcherListView.originY + launcherListView.topMargin) {
4108+ moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin + launcherListView.originY);
4109 }
4110 }
4111
4112@@ -192,9 +225,10 @@
4113 // the right app when running autopilot tests for
4114 // multiple apps.
4115 readonly property string appId: model.appId
4116+ itemIndex: index
4117 itemHeight: launcherListView.itemHeight
4118 itemWidth: launcherListView.itemWidth
4119- width: itemWidth
4120+ width: parent.width
4121 height: itemHeight
4122 iconName: model.icon
4123 count: model.count
4124@@ -204,6 +238,8 @@
4125 itemFocused: model.focused
4126 inverted: root.inverted
4127 alerting: model.alerting
4128+ highlighted: root.highlightIndex == index
4129+ shortcutHintShown: root.shortcutHintsShown && index <= 9
4130 z: -Math.abs(offset)
4131 maxAngle: 55
4132 property bool dragging: false
4133@@ -241,14 +277,7 @@
4134 onAlertingChanged: {
4135 if(alerting) {
4136 if (!dragging && (launcherListView.peekingIndex === -1 || launcher.visibleWidth > 0)) {
4137- var itemPosition = index * launcherListView.itemHeight;
4138- var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
4139- var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : launcherListView.itemHeight
4140- if (itemPosition + launcherListView.itemHeight + distanceToEnd > launcherListView.contentY + launcherListView.topMargin + height) {
4141- moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd);
4142- } else if (itemPosition - distanceToEnd < launcherListView.contentY + launcherListView.topMargin) {
4143- moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin);
4144- }
4145+ launcherListView.moveToIndex(index)
4146 if (!dragging && launcher.state !== "visible") {
4147 peekingAnimation.start()
4148 }
4149@@ -402,10 +431,7 @@
4150
4151 if (mouse.button & Qt.RightButton) { // context menu
4152 // Opening QuickList
4153- quickList.item = clickedItem;
4154- quickList.model = launcherListView.model.get(index).quickList;
4155- quickList.appId = launcherListView.model.get(index).appId;
4156- quickList.state = "open";
4157+ quickList.open(index);
4158 return;
4159 }
4160
4161@@ -413,10 +439,8 @@
4162
4163 // First/last item do the scrolling at more than 12 degrees
4164 if (index == 0 || index == launcherListView.count - 1) {
4165- if (clickedItem.angle > 12) {
4166- launcherListView.flick(0, -launcherListView.clickFlickSpeed);
4167- } else if (clickedItem.angle < -12) {
4168- launcherListView.flick(0, launcherListView.clickFlickSpeed);
4169+ if (clickedItem.angle > 12 || clickedItem.angle < -12) {
4170+ launcherListView.moveToIndex(index);
4171 } else {
4172 root.applicationSelected(LauncherModel.get(index).appId);
4173 }
4174@@ -424,10 +448,8 @@
4175 }
4176
4177 // the rest launches apps up to an angle of 30 degrees
4178- if (clickedItem.angle > 30) {
4179- launcherListView.flick(0, -launcherListView.clickFlickSpeed);
4180- } else if (clickedItem.angle < -30) {
4181- launcherListView.flick(0, launcherListView.clickFlickSpeed);
4182+ if (clickedItem.angle > 30 || clickedItem.angle < -30) {
4183+ launcherListView.moveToIndex(index);
4184 } else {
4185 root.applicationSelected(LauncherModel.get(index).appId);
4186 }
4187@@ -481,11 +503,7 @@
4188
4189 draggedIndex = Math.floor((mouse.y + launcherListView.realContentY) / launcherListView.realItemHeight);
4190
4191- // Opening QuickList
4192- quickList.item = selectedItem;
4193- quickList.model = launcherListView.model.get(draggedIndex).quickList;
4194- quickList.appId = launcherListView.model.get(draggedIndex).appId;
4195- quickList.state = "open";
4196+ quickList.open(draggedIndex)
4197
4198 launcherListView.interactive = false
4199
4200@@ -644,7 +662,9 @@
4201 enabled: quickList.state == "open" || pressed
4202
4203 onClicked: {
4204- quickList.state = ""
4205+ quickList.state = "";
4206+ quickList.focus = false;
4207+ root.kbdNavigationCancelled();
4208 }
4209
4210 // Forward for dragging to work when quickList is open
4211@@ -693,12 +713,60 @@
4212 property var model
4213 property string appId
4214 property var item
4215+ property int selectedIndex: -1
4216+
4217+ Keys.onPressed: {
4218+ switch (event.key) {
4219+ case Qt.Key_Down:
4220+ selectedIndex++;
4221+ if (selectedIndex >= popoverRepeater.count) {
4222+ selectedIndex = 0;
4223+ }
4224+ event.accepted = true;
4225+ break;
4226+ case Qt.Key_Up:
4227+ selectedIndex--;
4228+ if (selectedIndex < 0) {
4229+ selectedIndex = popoverRepeater.count - 1;
4230+ }
4231+ event.accepted = true;
4232+ break;
4233+ case Qt.Key_Left:
4234+ case Qt.Key_Escape:
4235+ quickList.selectedIndex = -1;
4236+ quickList.focus = false;
4237+ quickList.state = ""
4238+ event.accepted = true;
4239+ break;
4240+ case Qt.Key_Enter:
4241+ case Qt.Key_Return:
4242+ case Qt.Key_Space:
4243+ if (quickList.selectedIndex >= 0) {
4244+ LauncherModel.quickListActionInvoked(quickList.appId, quickList.selectedIndex)
4245+ }
4246+ quickList.selectedIndex = -1;
4247+ quickList.focus = false;
4248+ quickList.state = ""
4249+ root.kbdNavigationCancelled();
4250+ event.accepted = true;
4251+ break;
4252+ }
4253+ }
4254
4255 // internal
4256 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) + quickList.item.offset : units.gu(1)
4257 property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height :
4258 itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0
4259
4260+ function open(index) {
4261+ var itemPosition = index * launcherListView.itemHeight;
4262+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
4263+ item = launcherListView.itemAt(launcherListView.width / 2, itemPosition + launcherListView.itemHeight / 2);
4264+ quickList.model = launcherListView.model.get(index).quickList;
4265+ quickList.appId = launcherListView.model.get(index).appId;
4266+ quickList.state = "open";
4267+ }
4268+
4269 Column {
4270 id: quickListColumn
4271 width: parent.width
4272@@ -712,6 +780,7 @@
4273 objectName: "quickListEntry" + index
4274 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
4275 highlightWhenPressed: model.clickable
4276+ selected: index === quickList.selectedIndex
4277
4278 // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
4279 // ListItems don't know that they are sitting in a themed Popover where the color
4280@@ -727,6 +796,8 @@
4281 // Unsetting model to prevent showing changing entries during fading out
4282 // that may happen because of triggering an action.
4283 LauncherModel.quickListActionInvoked(quickList.appId, index);
4284+ quickList.focus = false;
4285+ root.kbdNavigationCancelled();
4286 quickList.model = undefined;
4287 }
4288 }
4289
4290=== added file 'qml/Launcher/graphics/launcher-app-focus-ring.svg'
4291--- qml/Launcher/graphics/launcher-app-focus-ring.svg 1970-01-01 00:00:00 +0000
4292+++ qml/Launcher/graphics/launcher-app-focus-ring.svg 2016-03-11 11:34:41 +0000
4293@@ -0,0 +1,12 @@
4294+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
4295+<svg width="172px" height="163px" viewBox="0 0 172 163" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
4296+ <!-- Generator: Sketch 3.4.4 (17249) - http://www.bohemiancoding.com/sketch -->
4297+ <title>Shape</title>
4298+ <desc>Created with Sketch.</desc>
4299+ <defs></defs>
4300+ <g id="•-Launcher" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
4301+ <g id="Artboard-9" sketch:type="MSArtboardGroup" transform="translate(-163.000000, -1436.000000)" fill="#E95420">
4302+ <path d="M221.983432,1440 L221.983432,1440 C195.6127,1440 184.708233,1442.4723 177.107949,1450.10734 C169.476819,1457.77336 167,1468.79245 167,1495.3481 L167,1538.9019 C167,1565.45755 169.476819,1576.47664 177.107949,1584.14266 C184.708233,1591.7777 195.6127,1594.25 221.983432,1594.25 L276.016868,1594.25 C302.387595,1594.25 313.291998,1591.77771 320.892221,1584.14264 C328.523252,1576.47663 331,1565.45769 331,1538.9019 L331,1495.3481 C331,1468.79231 328.523252,1457.77337 320.892221,1450.10736 C313.291998,1442.47229 302.387595,1440 276.016868,1440 L221.983432,1440 Z M221.983432,1436 L276.016868,1436 C302.345315,1436 314.848953,1438.36655 323.727108,1447.2854 C332.633306,1456.23243 335,1468.85167 335,1495.3481 L335,1538.9019 C335,1565.39833 332.633306,1578.01757 323.727108,1586.9646 C314.848953,1595.88345 302.345315,1598.25 276.016868,1598.25 L221.983432,1598.25 C195.654985,1598.25 183.151291,1595.88345 174.273077,1586.96463 C165.366772,1578.0176 163,1565.39822 163,1538.9019 L163,1495.3481 C163,1468.85178 165.366772,1456.2324 174.273077,1447.28537 C183.151291,1438.36655 195.654985,1436 221.983432,1436 L221.983432,1436 Z" id="Shape" sketch:type="MSShapeGroup"></path>
4303+ </g>
4304+ </g>
4305+</svg>
4306\ No newline at end of file
4307
4308=== modified file 'qml/Notifications/Notification.qml'
4309--- qml/Notifications/Notification.qml 2016-02-29 11:31:46 +0000
4310+++ qml/Notifications/Notification.qml 2016-03-11 11:34:41 +0000
4311@@ -23,7 +23,7 @@
4312 import Utils 0.1
4313 import "../Components"
4314
4315-Item {
4316+StyledItem {
4317 id: notification
4318
4319 property alias iconSource: icon.fileSource
4320@@ -58,6 +58,10 @@
4321 color: (type === Notification.Confirmation && notificationList.useModal && !greeter.shown) || darkOnBright ? sdLightGrey : Qt.rgba(0.132, 0.117, 0.109, 0.97)
4322 opacity: 1 - (x / notification.width) // FIXME: non-zero initially because of LP: #1354406 workaround, we want this to start at 0 upon creation eventually
4323
4324+ theme: ThemeSettings {
4325+ name: "Ubuntu.Components.Themes.Ambiance"
4326+ }
4327+
4328 state: {
4329 var result = "";
4330
4331@@ -297,7 +301,7 @@
4332 visible: body != "" && type !== Notification.Confirmation
4333 fontSize: "small"
4334 color: darkOnBright ? sdFontColor : theme.palette.normal.backgroundText
4335- wrapMode: Text.WordWrap
4336+ wrapMode: Text.Wrap
4337 maximumLineCount: type == Notification.SnapDecision ? 12 : 2
4338 elide: Text.ElideRight
4339 textFormat: Text.PlainText
4340
4341=== modified file 'qml/OrientedShell.qml'
4342--- qml/OrientedShell.qml 2016-01-28 11:31:48 +0000
4343+++ qml/OrientedShell.qml 2016-03-11 11:34:41 +0000
4344@@ -19,6 +19,7 @@
4345 import Unity.InputInfo 0.1
4346 import Unity.Session 0.1
4347 import Unity.Screens 0.1
4348+import Utils 0.1
4349 import GSettings 1.0
4350 import "Components"
4351 import "Rotation"
4352@@ -77,6 +78,8 @@
4353 InputDeviceModel {
4354 id: keyboardsModel
4355 deviceFilter: InputInfo.Keyboard
4356+ onDeviceAdded: forceOSKEnabled = autopilotDevicePresent();
4357+ onDeviceRemoved: forceOSKEnabled = autopilotDevicePresent();
4358 }
4359
4360 InputDeviceModel {
4361@@ -84,6 +87,27 @@
4362 deviceFilter: InputInfo.TouchScreen
4363 }
4364
4365+ /* FIXME: This exposes the NameRole as a work arround for lp:1542224.
4366+ * When QInputInfo exposes NameRole to QML, this should be removed.
4367+ */
4368+ property bool forceOSKEnabled: false
4369+ property var autopilotEmulatedDeviceNames: ["py-evdev-uinput"]
4370+ UnitySortFilterProxyModel {
4371+ id: autopilotDevices
4372+ model: keyboardsModel
4373+ }
4374+
4375+ function autopilotDevicePresent() {
4376+ for(var i = 0; i < autopilotDevices.count; i++) {
4377+ var device = autopilotDevices.get(i);
4378+ if (autopilotEmulatedDeviceNames.indexOf(device.name) != -1) {
4379+ console.warn("Forcing the OSK to be enabled as there is an autopilot eumlated device present.")
4380+ return true;
4381+ }
4382+ }
4383+ return false;
4384+ }
4385+
4386 Screens {
4387 id: screens
4388 }
4389@@ -195,7 +219,8 @@
4390 // have multiple keyboards around. For now we only enable one keyboard at a time
4391 // thus hiding it here if there is a physical one around or if we have a second
4392 // screen (the virtual touchpad & osk on the phone) attached.
4393- oskEnabled: keyboardsModel.count === 0 && screens.count === 1
4394+ oskEnabled: (keyboardsModel.count === 0 && screens.count === 1) ||
4395+ forceOSKEnabled
4396
4397 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
4398 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
4399
4400=== modified file 'qml/Panel/Handle.qml'
4401--- qml/Panel/Handle.qml 2016-03-08 20:59:14 +0000
4402+++ qml/Panel/Handle.qml 2016-03-11 11:34:41 +0000
4403@@ -19,7 +19,7 @@
4404
4405 Rectangle {
4406 id: handle
4407- color: UbuntuColors.slate
4408+ color: theme.palette.normal.foreground
4409 height: units.gu(2)
4410 property bool active: false
4411
4412@@ -35,7 +35,7 @@
4413 id: dot
4414 width: units.dp(3)
4415 height: width
4416- color: handle.active ? UbuntuColors.orange : UbuntuColors.ash
4417+ color: handle.active ? theme.palette.highlighted.foreground : theme.palette.normal.raised
4418 radius: units.dp(1)
4419 }
4420 }
4421
4422=== modified file 'qml/Panel/Indicators/MenuItemFactory.qml'
4423--- qml/Panel/Indicators/MenuItemFactory.qml 2016-03-08 20:59:14 +0000
4424+++ qml/Panel/Indicators/MenuItemFactory.qml 2016-03-11 11:34:41 +0000
4425@@ -228,7 +228,6 @@
4426 text: menuData && menuData.label || ""
4427 iconSource: menuData && menuData.icon || ""
4428 value : menuData && menuData.actionState || 0.0
4429- enabled: menuData && menuData.sensitive || false
4430 highlightWhenPressed: false
4431 }
4432 }
4433
4434=== modified file 'qml/Panel/IndicatorsMenu.qml'
4435--- qml/Panel/IndicatorsMenu.qml 2016-03-08 20:59:14 +0000
4436+++ qml/Panel/IndicatorsMenu.qml 2016-03-11 11:34:41 +0000
4437@@ -38,7 +38,7 @@
4438 property bool enableHint: true
4439 property bool contentEnabled: true
4440 property bool showOnClick: true
4441- property color panelColor: theme.palette.normal.background
4442+ property color panelColor: UbuntuColors.jet
4443
4444 signal showTapped(point position)
4445
4446
4447=== modified file 'qml/Panel/Panel.qml'
4448--- qml/Panel/Panel.qml 2016-03-08 20:59:14 +0000
4449+++ qml/Panel/Panel.qml 2016-03-11 11:34:41 +0000
4450@@ -89,7 +89,7 @@
4451
4452 Rectangle {
4453 id: indicatorAreaBackground
4454- color: callHint.visible ? UbuntuColors.green : theme.palette.normal.background
4455+ color: callHint.visible ? UbuntuColors.green : indicators.panelColor
4456 anchors {
4457 top: parent.top
4458 left: parent.left
4459@@ -169,8 +169,10 @@
4460 objectName: "windowDecorationTitle"
4461 anchors {
4462 left: parent.left
4463+ right: __indicators.left
4464 top: parent.top
4465 leftMargin: units.gu(1)
4466+ rightMargin: units.gu(1)
4467 topMargin: units.gu(0.5)
4468 bottomMargin: units.gu(0.5)
4469 }
4470@@ -181,6 +183,8 @@
4471 fontSize: "medium"
4472 font.weight: Font.Normal
4473 text: PanelState.title
4474+ elide: Text.ElideRight
4475+ maximumLineCount: 1
4476 }
4477
4478 // TODO here would the Locally integrated menus come
4479
4480=== modified file 'qml/ScopeTool.qml'
4481--- qml/ScopeTool.qml 2015-07-15 15:07:19 +0000
4482+++ qml/ScopeTool.qml 2016-03-11 11:34:41 +0000
4483@@ -52,14 +52,6 @@
4484 color: "#FCFCFC"
4485 }
4486
4487- Image {
4488- anchors.fill: dashContent
4489- source: root.width > root.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
4490- fillMode: Image.PreserveAspectCrop
4491- horizontalAlignment: Image.AlignRight
4492- verticalAlignment: Image.AlignTop
4493- }
4494-
4495 DashContent {
4496 id: dashContent
4497
4498
4499=== modified file 'qml/Shell.qml'
4500--- qml/Shell.qml 2016-03-08 20:59:08 +0000
4501+++ qml/Shell.qml 2016-03-11 11:34:41 +0000
4502@@ -25,6 +25,7 @@
4503 import Unity.Connectivity 0.1
4504 import Unity.Launcher 0.1
4505 import GlobalShortcut 1.0 // has to be before Utils, because of WindowKeysFilter
4506+import GSettings 1.0
4507 import Utils 0.1
4508 import Powerd 0.1
4509 import SessionBroadcast 0.1
4510@@ -187,6 +188,11 @@
4511 }
4512 }
4513
4514+ GSettings {
4515+ id: settings
4516+ schema.id: "com.canonical.Unity8"
4517+ }
4518+
4519 Item {
4520 id: stages
4521 objectName: "stages"
4522@@ -343,6 +349,11 @@
4523 property: "altTabPressed"
4524 value: physicalKeysMapper.altTabPressed
4525 }
4526+ Binding {
4527+ target: applicationsDisplayLoader.item
4528+ property: "leftMargin"
4529+ value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
4530+ }
4531 }
4532
4533 Tutorial {
4534@@ -373,7 +384,11 @@
4535 InputMethod {
4536 id: inputMethod
4537 objectName: "inputMethod"
4538- anchors { fill: parent; topMargin: panel.panelHeight }
4539+ anchors {
4540+ fill: parent
4541+ topMargin: panel.panelHeight
4542+ leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
4543+ }
4544 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
4545 }
4546
4547@@ -557,6 +572,10 @@
4548 && !greeter.hasLockedApp
4549 inverted: shell.usageScenario !== "desktop"
4550 shadeBackground: !tutorial.running
4551+ superPressed: physicalKeysMapper.superPressed
4552+ superTabPressed: physicalKeysMapper.superTabPressed
4553+ panelWidth: units.gu(settings.launcherWidth)
4554+ lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
4555
4556 onShowDashHome: showHome()
4557 onDash: showDash()
4558@@ -576,6 +595,37 @@
4559 panel.indicators.hide()
4560 }
4561 }
4562+ onFocusChanged: {
4563+ if (!focus) {
4564+ applicationsDisplayLoader.focus = true;
4565+ }
4566+ }
4567+
4568+ GlobalShortcut {
4569+ shortcut: Qt.AltModifier | Qt.Key_F1
4570+ onTriggered: {
4571+ launcher.openForKeyboardNavigation();
4572+ }
4573+ }
4574+ GlobalShortcut {
4575+ shortcut: Qt.MetaModifier | Qt.Key_0
4576+ onTriggered: {
4577+ if (LauncherModel.get(9)) {
4578+ activateApplication(LauncherModel.get(9).appId);
4579+ }
4580+ }
4581+ }
4582+ Repeater {
4583+ model: 9
4584+ GlobalShortcut {
4585+ shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
4586+ onTriggered: {
4587+ if (LauncherModel.get(index)) {
4588+ activateApplication(LauncherModel.get(index).appId);
4589+ }
4590+ }
4591+ }
4592+ }
4593 }
4594
4595 Wizard {
4596
4597=== modified file 'qml/Stages/AbstractStage.qml'
4598--- qml/Stages/AbstractStage.qml 2016-01-14 13:03:20 +0000
4599+++ qml/Stages/AbstractStage.qml 2016-03-11 11:34:41 +0000
4600@@ -21,7 +21,7 @@
4601 Rectangle {
4602 id: root
4603
4604- color: "#111111"
4605+ color: "#060606"
4606
4607 // Controls to be set from outside
4608 property bool altTabPressed
4609@@ -39,6 +39,8 @@
4610 property int shellOrientationAngle
4611 property bool spreadEnabled: true // If false, animations and right edge will be disabled
4612 property bool suspended
4613+ // A Stage should paint a wallpaper etc over its full size but not use the margins for window placement
4614+ property int leftMargin: 0
4615
4616 // To be read from outside
4617 property var mainApp: null
4618
4619=== modified file 'qml/Stages/DesktopSpread.qml'
4620--- qml/Stages/DesktopSpread.qml 2015-11-24 17:44:18 +0000
4621+++ qml/Stages/DesktopSpread.qml 2016-03-11 11:34:41 +0000
4622@@ -19,6 +19,7 @@
4623 import Ubuntu.Components 1.3
4624 import Ubuntu.Gestures 0.1
4625 import Unity.Application 0.1
4626+import "../Components"
4627
4628 FocusScope {
4629 id: root
4630@@ -26,8 +27,11 @@
4631 property bool altTabPressed: false
4632 property Item workspace: null
4633
4634+ readonly property alias ready: blurLayer.ready
4635 readonly property alias highlightedIndex: spreadRepeater.highlightedIndex
4636
4637+ signal playFocusAnimation(int index)
4638+
4639 function show() {
4640 spreadContainer.animateIn = true;
4641 root.state = "altTab";
4642@@ -91,6 +95,9 @@
4643
4644 function focusSelected() {
4645 if (spreadRepeater.highlightedIndex != -1) {
4646+ if (spreadContainer.visible) {
4647+ root.playFocusAnimation(spreadRepeater.highlightedIndex)
4648+ }
4649 var application = ApplicationManager.get(spreadRepeater.highlightedIndex);
4650 ApplicationManager.requestFocusApplication(application.appId);
4651 }
4652@@ -101,6 +108,31 @@
4653 state = ""
4654 }
4655
4656+ BlurLayer {
4657+ id: blurLayer
4658+ anchors.fill: parent
4659+ source: root.workspace
4660+ visible: false
4661+ }
4662+
4663+ Rectangle {
4664+ id: spreadBackground
4665+ anchors.fill: parent
4666+ color: "#B2000000"
4667+ visible: false
4668+ opacity: visible ? 1 : 0
4669+ Behavior on opacity {
4670+ UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4671+ }
4672+ }
4673+
4674+ MouseArea {
4675+ id: eventEater
4676+ anchors.fill: parent
4677+ visible: spreadBackground.visible
4678+ enabled: visible
4679+ }
4680+
4681 Item {
4682 id: spreadContainer
4683 objectName: "spreadContainer"
4684@@ -226,13 +258,20 @@
4685 Transition {
4686 from: ""
4687 to: "altTab"
4688- PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
4689- PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
4690- PropertyAnimation {
4691- target: spreadDelegate; properties: "x"
4692- from: root.width
4693- duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration :0
4694- easing: UbuntuAnimation.StandardEasing
4695+ SequentialAnimation {
4696+ ParallelAnimation {
4697+ PropertyAction { target: spreadDelegate; properties: "y,height,width,angle,z,itemScale,itemScaleOriginY,visible" }
4698+ PropertyAction { target: clippedSpreadDelegate; properties: "anchors.topMargin" }
4699+ PropertyAnimation {
4700+ target: spreadDelegate; properties: "x"
4701+ from: root.width
4702+ duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration :0
4703+ easing: UbuntuAnimation.StandardEasing
4704+ }
4705+ UbuntuNumberAnimation { target: clippedSpreadDelegate; property: "shadowOpacity"; from: 0; to: spreadMaths.shadowOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
4706+ UbuntuNumberAnimation { target: tileInfo; property: "opacity"; from: 0; to: spreadMaths.tileInfoOpacity; duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0 }
4707+ }
4708+ PropertyAction { target: spreadSelectArea; property: "enabled" }
4709 }
4710 }
4711 ]
4712@@ -240,7 +279,11 @@
4713 MouseArea {
4714 id: tileInfo
4715 objectName: "tileInfo"
4716- anchors { left: parent.left; top: clippedSpreadDelegate.bottom; topMargin: units.gu(5) }
4717+ anchors {
4718+ left: parent.left
4719+ top: clippedSpreadDelegate.bottom
4720+ topMargin: ((spreadMaths.sceneHeight - spreadDelegate.y) - clippedSpreadDelegate.height) * 0.2
4721+ }
4722 property int nextItemX: spreadRepeater.count > index + 1 ? spreadRepeater.itemAt(index + 1).x : spreadDelegate.x + units.gu(30)
4723 width: Math.min(units.gu(30), nextItemX - spreadDelegate.x)
4724 height: titleInfoColumn.height
4725@@ -262,12 +305,20 @@
4726 anchors { left: parent.left; top: parent.top; right: parent.right }
4727 spacing: units.gu(1)
4728
4729- UbuntuShape {
4730+ UbuntuShapeForItem {
4731 Layout.preferredHeight: Math.min(units.gu(6), root.height * .05)
4732 Layout.preferredWidth: height * 8 / 7.6
4733 image: Image {
4734 anchors.fill: parent
4735 source: model.icon
4736+ Rectangle {
4737+ anchors.fill: parent
4738+ color: "black"
4739+ opacity: clippedSpreadDelegate.highlightShown ? 0 : .1
4740+ Behavior on opacity {
4741+ UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4742+ }
4743+ }
4744 }
4745 }
4746 Label {
4747@@ -420,7 +471,7 @@
4748
4749 property var source: ShaderEffectSource {
4750 id: shaderEffectSource
4751- sourceItem: appContainer
4752+ sourceItem: root.workspace
4753 }
4754
4755 fragmentShader: "
4756@@ -494,20 +545,17 @@
4757 from: "*"
4758 to: "altTab"
4759 SequentialAnimation {
4760- PropertyAction { target: hoverMouseArea; property: "progressiveScrollingEnabled"; value: false }
4761 PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: Math.min(ApplicationManager.count - 1, 1) }
4762- PauseAnimation { duration: 140 }
4763+ PauseAnimation { duration: spreadContainer.animateIn ? 0 : 140 }
4764 PropertyAction { target: workspaceSelector; property: "visible" }
4765 PropertyAction { target: spreadContainer; property: "visible" }
4766 ParallelAnimation {
4767- UbuntuNumberAnimation {
4768- target: blurLayer; properties: "saturation,blurRadius";
4769- duration: spreadContainer.animateIn ? UbuntuAnimation.FastDuration : 0
4770- }
4771+ UbuntuNumberAnimation { target: blurLayer; properties: "saturation,blurRadius"; duration: UbuntuAnimation.SnapDuration }
4772 PropertyAction { target: spreadFlickable; property: "visible" }
4773 PropertyAction { targets: [currentSelectedLabel,spreadBackground]; property: "visible" }
4774 PropertyAction { target: spreadFlickable; property: "contentX"; value: 0 }
4775 }
4776+ PropertyAction { target: hoverMouseArea; properties: "enabled,progressiveScrollingEnabled"; value: false }
4777 }
4778 },
4779 Transition {
4780@@ -518,6 +566,5 @@
4781 PropertyAction { target: spreadRepeater; property: "highlightedIndex"; value: -1 }
4782 PropertyAction { target: spreadContainer; property: "animateIn"; value: false }
4783 }
4784-
4785 ]
4786 }
4787
4788=== modified file 'qml/Stages/DesktopSpreadDelegate.qml'
4789--- qml/Stages/DesktopSpreadDelegate.qml 2015-12-01 12:17:24 +0000
4790+++ qml/Stages/DesktopSpreadDelegate.qml 2016-03-11 11:34:41 +0000
4791@@ -56,6 +56,11 @@
4792 }
4793 ]
4794
4795+ scale: highlightShown ? 1.025 : 1
4796+ Behavior on scale {
4797+ UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4798+ }
4799+
4800 BorderImage {
4801 anchors {
4802 fill: root
4803@@ -70,7 +75,7 @@
4804 anchors.fill: parent
4805 anchors.margins: -units.gu(1)
4806 color: "white"
4807- opacity: highlightShown ? 0.15 : 0
4808+ opacity: highlightShown ? 0.55 : 0
4809 antialiasing: true
4810 }
4811
4812@@ -108,4 +113,13 @@
4813 ]
4814 }
4815 }
4816+
4817+ Rectangle {
4818+ anchors.fill: parent
4819+ color: "black"
4820+ opacity: root.highlightShown ? 0 : .1
4821+ Behavior on opacity {
4822+ UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
4823+ }
4824+ }
4825 }
4826
4827=== modified file 'qml/Stages/DesktopStage.qml'
4828--- qml/Stages/DesktopStage.qml 2016-02-03 14:00:47 +0000
4829+++ qml/Stages/DesktopStage.qml 2016-03-11 11:34:41 +0000
4830@@ -224,6 +224,7 @@
4831 PanelState.dropShadow = false;
4832 }
4833
4834+
4835 FocusScope {
4836 id: appContainer
4837 objectName: "appContainer"
4838@@ -274,6 +275,7 @@
4839 readonly property alias maximizedLeft: appDelegatePrivate.maximizedLeft
4840 readonly property alias maximizedRight: appDelegatePrivate.maximizedRight
4841 readonly property alias minimized: appDelegatePrivate.minimized
4842+ readonly property alias fullscreen: decoratedWindow.fullscreen
4843
4844 readonly property string appId: model.appId
4845 property bool animationsEnabled: true
4846@@ -293,6 +295,7 @@
4847 visible: !visuallyMinimized &&
4848 !greeter.fullyShown &&
4849 (priv.foregroundMaximizedAppZ === -1 || priv.foregroundMaximizedAppZ <= z) ||
4850+ decoratedWindow.fullscreen ||
4851 (spread.state == "altTab" && index === spread.highlightedIndex)
4852
4853 Binding {
4854@@ -348,13 +351,26 @@
4855 ApplicationManager.focusApplication(appId);
4856 }
4857
4858+ function playFocusAnimation() {
4859+ focusAnimation.start()
4860+ }
4861+
4862+ UbuntuNumberAnimation {
4863+ id: focusAnimation
4864+ target: appDelegate
4865+ property: "scale"
4866+ from: 0.98
4867+ to: 1
4868+ duration: UbuntuAnimation.SnapDuration
4869+ }
4870+
4871 states: [
4872 State {
4873 name: "fullscreen"; when: decoratedWindow.fullscreen
4874- extend: "maximized"
4875 PropertyChanges {
4876 target: appDelegate;
4877- y: -PanelState.panelHeight
4878+ x: 0; y: -PanelState.panelHeight
4879+ requestedWidth: appContainer.width; requestedHeight: appContainer.height;
4880 }
4881 },
4882 State {
4883@@ -371,21 +387,21 @@
4884 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
4885 PropertyChanges {
4886 target: appDelegate;
4887- x: 0; y: 0;
4888- requestedWidth: root.width; requestedHeight: root.height;
4889+ x: root.leftMargin; y: 0;
4890+ requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appContainer.height;
4891 visuallyMinimized: false;
4892 visuallyMaximized: true
4893 }
4894 },
4895 State {
4896 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
4897- PropertyChanges { target: appDelegate; x: 0; y: PanelState.panelHeight;
4898- requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
4899+ PropertyChanges { target: appDelegate; x: root.leftMargin; y: PanelState.panelHeight;
4900+ requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight }
4901 },
4902 State {
4903 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
4904- PropertyChanges { target: appDelegate; x: root.width/2; y: PanelState.panelHeight;
4905- requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
4906+ PropertyChanges { target: appDelegate; x: (appContainer.width + root.leftMargin)/2; y: PanelState.panelHeight;
4907+ requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight }
4908 },
4909 State {
4910 name: "minimized"; when: appDelegate.minimized
4911@@ -438,7 +454,7 @@
4912 target: appDelegate
4913 property: "z"
4914 value: ApplicationManager.count + 1
4915- when: index == spread.highlightedIndex && blurLayer.ready
4916+ when: index == spread.highlightedIndex && spread.ready
4917 }
4918
4919 WindowResizeArea {
4920@@ -448,8 +464,9 @@
4921 minHeight: units.gu(10)
4922 borderThickness: units.gu(2)
4923 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
4924- screenWidth: root.width
4925- screenHeight: root.height
4926+ screenWidth: appContainer.width
4927+ screenHeight: appContainer.height
4928+ leftMargin: root.leftMargin
4929
4930 onPressed: { ApplicationManager.focusApplication(model.appId) }
4931 }
4932@@ -473,27 +490,6 @@
4933 }
4934 }
4935
4936- BlurLayer {
4937- id: blurLayer
4938- anchors.fill: parent
4939- source: appContainer
4940- visible: false
4941- }
4942-
4943- Rectangle {
4944- id: spreadBackground
4945- anchors.fill: parent
4946- color: "#55000000"
4947- visible: false
4948- }
4949-
4950- MouseArea {
4951- id: eventEater
4952- anchors.fill: parent
4953- visible: spreadBackground.visible
4954- enabled: visible
4955- }
4956-
4957 EdgeBarrier {
4958 id: edgeBarrier
4959
4960@@ -509,7 +505,7 @@
4961 rotation: 90
4962 anchors.centerIn: parent
4963 gradient: Gradient {
4964- GradientStop { position: 0.0; color: Qt.rgba(0.16,0.16,0.16,0.7)}
4965+ GradientStop { position: 0.0; color: Qt.rgba(0.16,0.16,0.16,0.5)}
4966 GradientStop { position: 1.0; color: Qt.rgba(0.16,0.16,0.16,0)}
4967 }
4968 }
4969@@ -527,9 +523,13 @@
4970 DesktopSpread {
4971 id: spread
4972 objectName: "spread"
4973- anchors.fill: parent
4974+ anchors.fill: appContainer
4975 workspace: appContainer
4976 focus: state == "altTab"
4977 altTabPressed: root.altTabPressed
4978+
4979+ onPlayFocusAnimation: {
4980+ appRepeater.itemAt(index).playFocusAnimation();
4981+ }
4982 }
4983 }
4984
4985=== modified file 'qml/Stages/PhoneStage.qml'
4986--- qml/Stages/PhoneStage.qml 2016-01-14 13:03:20 +0000
4987+++ qml/Stages/PhoneStage.qml 2016-03-11 11:34:41 +0000
4988@@ -44,6 +44,33 @@
4989 }
4990 }
4991
4992+ onAltTabPressedChanged: {
4993+ if (!spreadEnabled || !altTabEnabled) {
4994+ return;
4995+ }
4996+ if (altTabPressed) {
4997+ spreadView.snapToSpread();
4998+ priv.highlightIndex = Math.min(spreadRepeater.count - 1, 1);
4999+ } else {
5000+ spreadView.snapTo(priv.highlightIndex)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches