on xenial help sign in
merge trunk
commit2e241d3442c080dc8274a5cd092be6ec9259ccae authorLukáš Tinkl <lukas.tinkl@canonical.com> dateWed 14 Dec 2016, 16:39 (10 years ago) parent68493d5497f799
41 files changed+985−384
CMakeLists.txt+13 debian/changelog+33 plugins/LightDM/FullLightDM/CMakeLists.txt+5−1 plugins/Unity/Indicators/CMakeLists.txt+3 plugins/Utils/ElapsedTimer.h+1−1 plugins/Utils/Timer.cpp+5−2 plugins/Utils/Timer.h+5−6 plugins/Utils/globalfunctions.cpp+5 plugins/Utils/globalfunctions.h+2 po/unity8.pot+80−43 qml/Components/VirtualTouchPad.qml+269−1 qml/Dash/Previews/PreviewAudioPlayback.qml+1 qml/DisabledScreenNotice.qml+3−55 qml/Greeter/Greeter.qml+1−5 qml/Greeter/LoginList.qml+1−1 qml/Greeter/WideView.qml+7−2 qml/Launcher/Launcher.qml+35−7 qml/Panel/Indicators/MenuItemFactory.qml+22−1 qml/Shell.qml+1−1 qml/Stage/MoveHandler.qml+2−2 qml/Stage/Spread/WindowedRightEdgeMaths.qml+19−4 qml/Stage/Stage.qml+64−33 qml/Stage/WindowResizeArea.qml+2−70 qml/Stage/WindowStateSaver.qml+63 src/ShellApplication.cpp+1 tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp+1−1 tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp+23−23 tests/mocks/QtMultimedia/videooutput.h+1−1 tests/plugins/Utils/WindowInputMonitorTest.cpp+76−9 tests/qmltests/Components/tst_VirtualTouchPad.qml+55−1 tests/qmltests/Dash/Previews/tst_Preview.qml+63 tests/qmltests/Dash/tst_Dash.qml+4−3 tests/qmltests/Launcher/tst_Launcher.qml+3−3 tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+6−1 tests/qmltests/Stage/tst_ApplicationWindow.qml+2−20 tests/qmltests/Stage/tst_DesktopStage.qml+71 tests/qmltests/Stage/tst_WindowResizeArea.qml+1−66 tests/qmltests/tst_DisabledScreenNotice.qml+23−9 tests/qmltests/tst_Shell.qml+4−7 tests/uqmlscene/CMakeLists.txt+5−1 tests/utils/modules/Unity/Test/UnityTestCase.qml+4−4
CMakeLists.txt+13
@@ -40,6 +40,19 @@ if(cmake_build_type_lower MATCHES coverage)
4040 ENABLE_COVERAGE_REPORT(TARGETS ${SHELL_APP} FILTER /usr/include ${CMAKE_SOURCE_DIR}/tests/* ${CMAKE_BINARY_DIR}/*)
4141endif()
4242
43+find_package (ECM 1.7.0 QUIET NO_MODULE)
44+if (ECM_FOUND)
45+ # Provides us with -DECM_ENABLE_SANITIZERS='X'
46+ # Where X can be address, thread, memory, leak, undefined
47+ include("${ECM_MODULE_DIR}/ECMEnableSanitizers.cmake")
48+endif()
49+
50+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
51+ if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0")
52+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override" )
53+ endif()
54+endif()
55+
4356# Make sure we have all the needed symbols
4457set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")
4558set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,defs")
debian/changelog+33
@@ -1,3 +1,36 @@
1+unity8 (8.15+17.04.20161207.1-0ubuntu1) zesty; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Add the Wsuggest-override flag to gcc
5+ * Add support for compiler sanitizers via ECM
6+ * Use timeStep as delay time (LP: #1642919)
7+ * Bring back fix for 1517830 (LP: #1517830)
8+ * Fix compile warnings in mocks
9+ * Do not hide panel when launching an application if the mouse is on
10+ the panel (LP: #1591311)
11+
12+ [ Daniel d'Andrada ]
13+ * Fix "make tryApplicationWindow"
14+ * Take save/restore functions out of WindowResizeArea
15+
16+ [ Josh Arenson ]
17+ * Enable the greeter to remember which session the user last logged
18+ into (LP: #1631365)
19+
20+ [ Lukáš Tinkl ]
21+ * Fix the Super key not invoking the dash scope home (LP: #1607427)
22+
23+ [ Michael Zanetti ]
24+ * Add the ApplicationDrawer
25+ * tune right edge push (LP: #1646094)
26+ * improve close button visiblity when hovering with the mouse
27+ * Update virtual touchpad visuals and add a tutorial. (LP: #1585220)
28+
29+ [ Pete Woods ]
30+ * MenuItemFactory: Add subtitle support to SwitchItem widget
31+
32+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 07 Dec 2016 13:49:24 +0000
33+
134unity8 (8.15+17.04.20161129-0ubuntu1) zesty; urgency=medium
235
336 [ Albert Astals Cid ]
plugins/LightDM/FullLightDM/CMakeLists.txt+5−1
@@ -6,10 +6,14 @@ add_definitions(-DFULL_LIGHTDM)
66
77include_directories(
88 ../
9− ${LIBLIGHTDM_INCLUDE_DIRS}
109 ${CMAKE_CURRENT_BINARY_DIR}
1110 )
1211
12+include_directories(
13+ SYSTEM
14+ ${LIBLIGHTDM_INCLUDE_DIRS}
15+ )
16+
1317foreach(source_file ${QMLPLUGIN_SRC})
1418 list(APPEND RELATIVE_QMLPLUGIN_SRC ../${source_file})
1519endforeach()
plugins/Unity/Indicators/CMakeLists.txt+3
@@ -11,6 +11,9 @@ include_directories(
1111include_directories(
1212 SYSTEM
1313 ${GLIB_INCLUDE_DIRS}
14+)
15+include_directories(
16+ SYSTEM
1417 ${GIO_INCLUDE_DIRS}
1518 ${QMENUMODEL_INCLUDE_DIRS}
1619)
plugins/Utils/ElapsedTimer.h+1−1
@@ -41,7 +41,7 @@ class ElapsedTimer : public AbstractElapsedTimer {
4141public:
4242 void start() override { m_timer.start(); }
4343 qint64 msecsSinceReference() const override { return m_timer.msecsSinceReference(); }
44− qint64 elapsed() const override { return m_timer.elapsed(); }
44+ qint64 elapsed() const override { return m_timer.isValid() ? m_timer.elapsed() : 0; }
4545private:
4646 QElapsedTimer m_timer;
4747};
plugins/Utils/Timer.cpp+5−2
@@ -37,13 +37,16 @@ void Timer::setInterval(int msecs)
3737void Timer::start()
3838{
3939 m_timer.start();
40− AbstractTimer::start();
4140}
4241
4342void Timer::stop()
4443{
4544 m_timer.stop();
46− AbstractTimer::stop();
45+}
46+
47+bool Timer::isRunning() const
48+{
49+ return m_timer.isActive();
4750}
4851
4952bool Timer::isSingleShot() const
plugins/Utils/Timer.h+5−6
@@ -30,18 +30,16 @@ class AbstractTimer : public QObject
3030{
3131 Q_OBJECT
3232public:
33− AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
33+ AbstractTimer(QObject *parent) : QObject(parent) {}
3434 virtual int interval() const = 0;
3535 virtual void setInterval(int msecs) = 0;
36− virtual void start() { m_isRunning = true; }
37− virtual void stop() { m_isRunning = false; }
38− bool isRunning() const { return m_isRunning; }
36+ virtual void start() = 0;
37+ virtual void stop() = 0;
38+ virtual bool isRunning() const = 0;
3939 virtual bool isSingleShot() const = 0;
4040 virtual void setSingleShot(bool value) = 0;
4141Q_SIGNALS:
4242 void timeout();
43−private:
44− bool m_isRunning;
4543};
4644
4745/** A QTimer wrapper */
@@ -55,6 +53,7 @@ public:
5553 void setInterval(int msecs) override;
5654 void start() override;
5755 void stop() override;
56+ bool isRunning() const override;
5857 bool isSingleShot() const override;
5958 void setSingleShot(bool value) override;
6059private:
plugins/Utils/globalfunctions.cpp+5
@@ -51,3 +51,8 @@ QQuickItem *GlobalFunctions::itemAt(QQuickItem* parent, int x, int y, QJSValue m
5151 }
5252 return nullptr;
5353}
54+
55+bool GlobalFunctions::itemUnderMouse(QQuickItem* item)
56+{
57+ return item && item->isUnderMouse();
58+}
plugins/Utils/globalfunctions.h+2
@@ -37,6 +37,8 @@ public:
3737 int x,
3838 int y,
3939 QJSValue matcher);
40+
41+ static Q_INVOKABLE bool itemUnderMouse(QQuickItem* item);
4042};
4143
4244#endif // GLOBALFUNCTIONS_H
po/unity8.pot+80−43
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2016-11-29 09:43+0000\n"
11+"POT-Creation-Date: 2016-12-07 13:49+0000\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -23,7 +23,7 @@ msgid "Password: "
2323msgstr ""
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:50
26−#: plugins/Unity/Launcher/launcheritem.cpp:109
26+#: plugins/Unity/Launcher/launcheritem.cpp:122
2727msgid "Pin shortcut"
2828msgstr ""
2929
@@ -31,7 +31,7 @@ msgstr ""
3131msgid "Quit"
3232msgstr ""
3333
34−#: plugins/Unity/Launcher/launcheritem.cpp:109
34+#: plugins/Unity/Launcher/launcheritem.cpp:122
3535msgid "Unpin shortcut"
3636msgstr ""
3737
@@ -175,87 +175,95 @@ msgstr ""
175175msgid "Same as clicking on a launcher icon."
176176msgstr ""
177177
178−#: qml/Components/KeyboardShortcutsOverlay.qml:181
178+#: qml/Components/KeyboardShortcutsOverlay.qml:177
179+msgid "Super + A"
180+msgstr ""
181+
182+#: qml/Components/KeyboardShortcutsOverlay.qml:182
183+msgid "Opens the Application Drawer."
184+msgstr ""
185+
186+#: qml/Components/KeyboardShortcutsOverlay.qml:194
179187msgid "Scopes"
180188msgstr ""
181189
182−#: qml/Components/KeyboardShortcutsOverlay.qml:188
190+#: qml/Components/KeyboardShortcutsOverlay.qml:201
183191msgid "Super (Tap)"
184192msgstr ""
185193
186−#: qml/Components/KeyboardShortcutsOverlay.qml:193
194+#: qml/Components/KeyboardShortcutsOverlay.qml:206
187195msgid "Opens the Scopes home."
188196msgstr ""
189197
190−#: qml/Components/KeyboardShortcutsOverlay.qml:209
198+#: qml/Components/KeyboardShortcutsOverlay.qml:222
191199msgid "Switching"
192200msgstr ""
193201
194−#: qml/Components/KeyboardShortcutsOverlay.qml:216
202+#: qml/Components/KeyboardShortcutsOverlay.qml:229
195203msgid "Alt + Tab"
196204msgstr ""
197205
198−#: qml/Components/KeyboardShortcutsOverlay.qml:221
206+#: qml/Components/KeyboardShortcutsOverlay.qml:234
199207msgid "Switches between applications."
200208msgstr ""
201209
202−#: qml/Components/KeyboardShortcutsOverlay.qml:229
210+#: qml/Components/KeyboardShortcutsOverlay.qml:242
203211msgid "Super + W"
204212msgstr ""
205213
206−#: qml/Components/KeyboardShortcutsOverlay.qml:234
214+#: qml/Components/KeyboardShortcutsOverlay.qml:247
207215msgid "Opens the desktop spread."
208216msgstr ""
209217
210−#: qml/Components/KeyboardShortcutsOverlay.qml:242
218+#: qml/Components/KeyboardShortcutsOverlay.qml:255
211219msgid "Cursor Left or Right"
212220msgstr ""
213221
214−#: qml/Components/KeyboardShortcutsOverlay.qml:247
222+#: qml/Components/KeyboardShortcutsOverlay.qml:260
215223msgid "Moves the focus."
216224msgstr ""
217225
218−#: qml/Components/KeyboardShortcutsOverlay.qml:259
226+#: qml/Components/KeyboardShortcutsOverlay.qml:272
219227msgid "Windows"
220228msgstr ""
221229
222−#: qml/Components/KeyboardShortcutsOverlay.qml:266
230+#: qml/Components/KeyboardShortcutsOverlay.qml:279
223231msgid "Ctrl + Super + D"
224232msgstr ""
225233
226−#: qml/Components/KeyboardShortcutsOverlay.qml:271
234+#: qml/Components/KeyboardShortcutsOverlay.qml:284
227235msgid "Minimizes all windows."
228236msgstr ""
229237
230−#: qml/Components/KeyboardShortcutsOverlay.qml:279
238+#: qml/Components/KeyboardShortcutsOverlay.qml:292
231239msgid "Ctrl + Super + Up"
232240msgstr ""
233241
234−#: qml/Components/KeyboardShortcutsOverlay.qml:284
242+#: qml/Components/KeyboardShortcutsOverlay.qml:297
235243msgid "Maximizes the current window."
236244msgstr ""
237245
238−#: qml/Components/KeyboardShortcutsOverlay.qml:292
246+#: qml/Components/KeyboardShortcutsOverlay.qml:305
239247msgid "Ctrl + Super + Down"
240248msgstr ""
241249
242−#: qml/Components/KeyboardShortcutsOverlay.qml:297
250+#: qml/Components/KeyboardShortcutsOverlay.qml:310
243251msgid "Minimizes or restores the current window."
244252msgstr ""
245253
246−#: qml/Components/KeyboardShortcutsOverlay.qml:305
254+#: qml/Components/KeyboardShortcutsOverlay.qml:318
247255msgid "Ctrl + Super + Left or Right"
248256msgstr ""
249257
250−#: qml/Components/KeyboardShortcutsOverlay.qml:310
258+#: qml/Components/KeyboardShortcutsOverlay.qml:323
251259msgid "Semi-maximizes the current window."
252260msgstr ""
253261
254−#: qml/Components/KeyboardShortcutsOverlay.qml:318
262+#: qml/Components/KeyboardShortcutsOverlay.qml:331
255263msgid "Alt + F4"
256264msgstr ""
257265
258−#: qml/Components/KeyboardShortcutsOverlay.qml:323
266+#: qml/Components/KeyboardShortcutsOverlay.qml:336
259267msgid "Closes the current window."
260268msgstr ""
261269
@@ -311,6 +319,28 @@ msgstr ""
311319msgid "Preview Share Item"
312320msgstr ""
313321
322+#: qml/Components/VirtualTouchPad.qml:317
323+msgid ""
324+"Your device is now connected to an external display. Use this screen as a "
325+"touch pad to interact with the pointer."
326+msgstr ""
327+
328+#: qml/Components/VirtualTouchPad.qml:327
329+msgid "Tap left button to click."
330+msgstr ""
331+
332+#: qml/Components/VirtualTouchPad.qml:339
333+msgid "Tap right button to right click."
334+msgstr ""
335+
336+#: qml/Components/VirtualTouchPad.qml:351
337+msgid "Swipe with two fingers to scroll."
338+msgstr ""
339+
340+#: qml/Components/VirtualTouchPad.qml:396
341+msgid "Find more settings in the system settings."
342+msgstr ""
343+
314344#: qml/Dash/DashPageHeader.qml:361
315345msgctxt "Button: Open the Ubuntu Store"
316346msgid "Store"
@@ -408,12 +438,6 @@ msgstr ""
408438msgid "Also installed"
409439msgstr ""
410440
411−#: qml/DisabledScreenNotice.qml:109
412−msgid ""
413−"Your device is now connected to an external display. Use this screen as a "
414−"touch pad to interact with the pointer."
415−msgstr ""
416−
417441#: qml/Greeter/CoverPage.qml:127
418442msgid "Unlock"
419443msgstr ""
@@ -437,7 +461,7 @@ msgid_plural "Please wait %1 minutes and then try again…"
437461msgstr[0] ""
438462msgstr[1] ""
439463
440−#: qml/Greeter/Greeter.qml:596
464+#: qml/Greeter/Greeter.qml:592
441465msgid "Try again"
442466msgstr ""
443467
@@ -465,6 +489,19 @@ msgstr ""
465489msgid "Select desktop environment"
466490msgstr ""
467491
492+#: qml/Launcher/Drawer.qml:80
493+msgid "Search…"
494+msgstr ""
495+
496+#: qml/Launcher/Drawer.qml:101
497+msgctxt "Apps sorted alphabetically"
498+msgid "A-Z"
499+msgstr ""
500+
501+#: qml/Launcher/MoreAppsHeader.qml:32
502+msgid "More apps in the store"
503+msgstr ""
504+
468505#: qml/Notifications/NotificationMenuItemFactory.qml:124
469506msgid "Show password"
470507msgstr ""
@@ -477,62 +514,62 @@ msgstr ""
477514msgid "Conference"
478515msgstr ""
479516
480−#: qml/Panel/Indicators/MenuItemFactory.qml:847
517+#: qml/Panel/Indicators/MenuItemFactory.qml:868
481518msgid "Nothing is playing"
482519msgstr ""
483520
484−#: qml/Panel/Indicators/MenuItemFactory.qml:975
521+#: qml/Panel/Indicators/MenuItemFactory.qml:996
485522#, qt-format
486523msgid "%1 hour"
487524msgid_plural "%1 hours"
488525msgstr[0] ""
489526msgstr[1] ""
490527
491−#: qml/Panel/Indicators/MenuItemFactory.qml:979
528+#: qml/Panel/Indicators/MenuItemFactory.qml:1000
492529#, qt-format
493530msgid "%1 minute"
494531msgid_plural "%1 minutes"
495532msgstr[0] ""
496533msgstr[1] ""
497534
498−#: qml/Panel/Indicators/MenuItemFactory.qml:984
535+#: qml/Panel/Indicators/MenuItemFactory.qml:1005
499536#, qt-format
500537msgid "%1 second"
501538msgid_plural "%1 seconds"
502539msgstr[0] ""
503540msgstr[1] ""
504541
505−#: qml/Panel/Indicators/MenuItemFactory.qml:987
542+#: qml/Panel/Indicators/MenuItemFactory.qml:1008
506543msgid "0 seconds"
507544msgstr ""
508545
509546#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
510−#: qml/Panel/Indicators/MenuItemFactory.qml:989
547+#: qml/Panel/Indicators/MenuItemFactory.qml:1010
511548#, qt-format
512549msgid "%1 remaining"
513550msgstr ""
514551
515−#: qml/Panel/Indicators/MenuItemFactory.qml:995
552+#: qml/Panel/Indicators/MenuItemFactory.qml:1016
516553msgid "In queue…"
517554msgstr ""
518555
519−#: qml/Panel/Indicators/MenuItemFactory.qml:999
556+#: qml/Panel/Indicators/MenuItemFactory.qml:1020
520557msgid "Downloading"
521558msgstr ""
522559
523−#: qml/Panel/Indicators/MenuItemFactory.qml:1001
560+#: qml/Panel/Indicators/MenuItemFactory.qml:1022
524561msgid "Paused, tap to resume"
525562msgstr ""
526563
527−#: qml/Panel/Indicators/MenuItemFactory.qml:1003
564+#: qml/Panel/Indicators/MenuItemFactory.qml:1024
528565msgid "Canceled"
529566msgstr ""
530567
531−#: qml/Panel/Indicators/MenuItemFactory.qml:1005
568+#: qml/Panel/Indicators/MenuItemFactory.qml:1026
532569msgid "Finished"
533570msgstr ""
534571
535−#: qml/Panel/Indicators/MenuItemFactory.qml:1007
572+#: qml/Panel/Indicators/MenuItemFactory.qml:1028
536573msgid "Failed, tap to retry"
537574msgstr ""
538575
qml/Components/VirtualTouchPad.qml+269−1
@@ -15,20 +15,58 @@
1515 */
1616
1717import QtQuick 2.4
18+import QtQuick.Layouts 1.1
1819import Ubuntu.Components 1.3
20+import Qt.labs.settings 1.0
21+import Unity.Screens 0.1
1922import UInput 0.1
23+import "../Components"
2024
2125Item {
26+ id: root
2227 property var uinput: UInput {
2328 Component.onCompleted: createMouse();
2429 Component.onDestruction: removeMouse();
2530 }
2631
27− readonly property bool pressed: point1.pressed || point2.pressed
32+ Component.onCompleted: {
33+ if (!settings.touchpadTutorialHasRun) {
34+ root.runTutorial()
35+ }
36+ }
37+
38+ function runTutorial() {
39+ // If the tutorial animation is started too early, e.g. in Component.onCompleted,
40+ // root width & height might be reported as 0x0 still. As animations read their
41+ // values at startup and won't update them, lets make sure to only start once
42+ // we have some actual size.
43+ if (root.width > 0 && root.height > 0) {
44+ tutorial.start();
45+ } else {
46+ tutorialTimer.start();
47+ }
48+ }
49+
50+ Timer {
51+ id: tutorialTimer
52+ interval: 50
53+ repeat: false
54+ running: false
55+ onTriggered: root.runTutorial();
56+ }
57+
58+ readonly property bool pressed: point1.pressed || point2.pressed || leftButton.pressed || rightButton.pressed
59+
60+ property var settings: Settings {
61+ objectName: "virtualTouchPadSettings"
62+ property bool touchpadTutorialHasRun: false
63+ property bool oskEnabled: true
64+ }
2865
2966 MultiPointTouchArea {
3067 objectName: "touchPadArea"
3168 anchors.fill: parent
69+ enabled: !tutorial.running || tutorial.paused
3270
3371 // FIXME: Once we have Qt DPR support, this should be Qt.styleHints.startDragDistance
3472 readonly property int clickThreshold: internalGu * 1.5
@@ -37,6 +75,11 @@ Item {
3775 property bool isDrag: false
3876
3977 onPressed: {
78+ if (tutorial.paused) {
79+ tutorial.resume();
80+ return;
81+ }
82+
4083 // If double-tapping *really* fast, it could happen that we end up having only point2 pressed
4184 // Make sure we check for both combos, only point1 or only point2
4285 if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))
@@ -135,4 +178,229 @@ Item {
135178 }
136179 ]
137180 }
181+
182+ RowLayout {
183+ anchors { left: parent.left; right: parent.right; bottom: parent.bottom; margins: -internalGu * 1 }
184+ height: internalGu * 10
185+ spacing: internalGu * 1
186+
187+ MouseArea {
188+ id: leftButton
189+ objectName: "leftButton"
190+ Layout.fillWidth: true
191+ Layout.fillHeight: true
192+ onPressed: uinput.pressMouse(UInput.ButtonLeft);
193+ onReleased: uinput.releaseMouse(UInput.ButtonLeft);
194+ property bool highlight: false
195+ UbuntuShape {
196+ anchors.fill: parent
197+ backgroundColor: leftButton.highlight || leftButton.pressed ? UbuntuColors.ash : UbuntuColors.inkstone
198+ Behavior on backgroundColor { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
199+ }
200+ }
201+
202+ MouseArea {
203+ id: rightButton
204+ objectName: "rightButton"
205+ Layout.fillWidth: true
206+ Layout.fillHeight: true
207+ onPressed: uinput.pressMouse(UInput.ButtonRight);
208+ onReleased: uinput.releaseMouse(UInput.ButtonRight);
209+ property bool highlight: false
210+ UbuntuShape {
211+ anchors.fill: parent
212+ backgroundColor: rightButton.highlight || rightButton.pressed ? UbuntuColors.ash : UbuntuColors.inkstone
213+ Behavior on backgroundColor { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
214+ }
215+ }
216+ }
217+
218+ AbstractButton {
219+ id: oskButton
220+ objectName: "oskButton"
221+ anchors { right: parent.right; top: parent.top; margins: internalGu * 2 }
222+ height: internalGu * 6
223+ width: height
224+
225+ onClicked: {
226+ settings.oskEnabled = !settings.oskEnabled
227+ }
228+
229+ Rectangle {
230+ anchors.fill: parent
231+ radius: width / 2
232+ color: UbuntuColors.inkstone
233+ }
234+
235+ Icon {
236+ anchors.fill: parent
237+ anchors.margins: internalGu * 1.5
238+ name: "input-keyboard-symbolic"
239+ }
240+ }
241+
242+ Screens {
243+ id: screens
244+ }
245+
246+ InputMethod {
247+ id: inputMethod
248+ // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
249+ enabled: screens.count > 1 && settings.oskEnabled && !tutorial.running
250+ objectName: "inputMethod"
251+ anchors.fill: parent
252+ }
253+
254+ Label {
255+ id: tutorialLabel
256+ objectName: "tutorialLabel"
257+ anchors { left: parent.left; top: parent.top; right: parent.right; margins: internalGu * 4; topMargin: internalGu * 10 }
258+ opacity: 0
259+ visible: opacity > 0
260+ font.pixelSize: 2 * internalGu
261+ color: "white"
262+ wrapMode: Text.WordWrap
263+ }
264+
265+ Icon {
266+ id: tutorialImage
267+ objectName: "tutorialImage"
268+ height: internalGu * 8
269+ width: height
270+ name: "input-touchpad-symbolic"
271+ color: "white"
272+ opacity: 0
273+ visible: opacity > 0
274+ anchors { top: tutorialLabel.bottom; horizontalCenter: parent.horizontalCenter; margins: internalGu * 2 }
275+ }
276+
277+ Item {
278+ id: tutorialFinger1
279+ objectName: "tutorialFinger1"
280+ width: internalGu * 5
281+ height: width
282+ property real scale: 1
283+ opacity: 0
284+ visible: opacity > 0
285+ Rectangle {
286+ width: parent.width * parent.scale
287+ height: width
288+ anchors.centerIn: parent
289+ radius: width / 2
290+ color: UbuntuColors.inkstone
291+ }
292+ }
293+
294+ Item {
295+ id: tutorialFinger2
296+ objectName: "tutorialFinger2"
297+ width: internalGu * 5
298+ height: width
299+ property real scale: 1
300+ opacity: 0
301+ visible: opacity > 0
302+ Rectangle {
303+ width: parent.width * parent.scale
304+ height: width
305+ anchors.centerIn: parent
306+ radius: width / 2
307+ color: UbuntuColors.inkstone
308+ }
309+ }
310+
311+ SequentialAnimation {
312+ id: tutorial
313+ objectName: "tutorialAnimation"
314+
315+ PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "enabled"; value: false }
316+ PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "opacity"; value: 0 }
317+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.") }
318+ UbuntuNumberAnimation { targets: [tutorialLabel, tutorialImage]; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
319+ PropertyAction { target: tutorial; property: "paused"; value: true }
320+ PauseAnimation { duration: 500 } // it takes a bit until pausing actually takes effect
321+ UbuntuNumberAnimation { targets: [tutorialLabel, tutorialImage]; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
322+
323+ UbuntuNumberAnimation { target: leftButton; property: "opacity"; to: 1 }
324+ UbuntuNumberAnimation { target: rightButton; property: "opacity"; to: 1 }
325+
326+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
327+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Tap left button to click.") }
328+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
329+ SequentialAnimation {
330+ loops: 2
331+ PropertyAction { target: leftButton; property: "highlight"; value: true }
332+ PauseAnimation { duration: UbuntuAnimation.FastDuration }
333+ PropertyAction { target: leftButton; property: "highlight"; value: false }
334+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
335+ }
336+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
337+
338+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
339+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Tap right button to right click.") }
340+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
341+ SequentialAnimation {
342+ loops: 2
343+ PropertyAction { target: rightButton; property: "highlight"; value: true }
344+ PauseAnimation { duration: UbuntuAnimation.FastDuration }
345+ PropertyAction { target: rightButton; property: "highlight"; value: false }
346+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
347+ }
348+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
349+
350+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
351+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Swipe with two fingers to scroll.") }
352+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
353+ PropertyAction { target: tutorialFinger1; property: "x"; value: root.width / 2 - tutorialFinger1.width - internalGu * 1 }
354+ PropertyAction { target: tutorialFinger2; property: "x"; value: root.width / 2 + tutorialFinger1.width + internalGu * 1 - tutorialFinger2.width }
355+ PropertyAction { target: tutorialFinger1; property: "y"; value: root.height / 2 - internalGu * 10 }
356+ PropertyAction { target: tutorialFinger2; property: "y"; value: root.height / 2 - internalGu * 10 }
357+ SequentialAnimation {
358+ ParallelAnimation {
359+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
360+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
361+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
362+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
363+ }
364+ ParallelAnimation {
365+ UbuntuNumberAnimation { target: tutorialFinger1; property: "y"; to: root.height / 2 + internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
366+ UbuntuNumberAnimation { target: tutorialFinger2; property: "y"; to: root.height / 2 + internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
367+ }
368+ ParallelAnimation {
369+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
370+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
371+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
372+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
373+ }
374+ PauseAnimation { duration: UbuntuAnimation.SlowDuration }
375+ ParallelAnimation {
376+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
377+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
378+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
379+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
380+ }
381+ ParallelAnimation {
382+ UbuntuNumberAnimation { target: tutorialFinger1; property: "y"; to: root.height / 2 - internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
383+ UbuntuNumberAnimation { target: tutorialFinger2; property: "y"; to: root.height / 2 - internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
384+ }
385+ ParallelAnimation {
386+ UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
387+ UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
388+ UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
389+ UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
390+ }
391+ PauseAnimation { duration: UbuntuAnimation.SlowDuration }
392+ }
393+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
394+
395+ PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
396+ PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Find more settings in the system settings.") }
397+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
398+ PauseAnimation { duration: 2000 }
399+ UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
400+
401+ UbuntuNumberAnimation { target: oskButton; property: "opacity"; to: 1 }
402+ PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "enabled"; value: true }
403+
404+ PropertyAction { target: settings; property: "touchpadTutorialHasRun"; value: true }
405+ }
138406}
qml/Dash/Previews/PreviewAudioPlayback.qml+1
@@ -70,6 +70,7 @@ PreviewWidget {
7070 objectName: "playButton"
7171 width: trackRow.column1Width
7272 height: width
73+ activeFocusOnPress: false
7374
7475 onClicked: {
7576 if (trackItem.isPlayingItem) {
qml/DisabledScreenNotice.qml+3−55
@@ -18,15 +18,12 @@ import QtQuick 2.4
1818import QtQuick.Layouts 1.1
1919import Ubuntu.Components 1.3
2020import Unity.Session 0.1
21−import Unity.Screens 0.1
2221import QtQuick.Window 2.2
2322import "Components"
2423
2524Item {
2625 id: root
2726
28− property bool infoNoteDisplayed: true
29−
3027 // For testing
3128 property var screen: Screen
3229 property var orientationLock: OrientationLock
@@ -36,10 +33,6 @@ Item {
3633 name: applicationArguments.deviceName
3734 }
3835
39− Screens {
40− id: screens
41− }
42−
4336 Item {
4437 id: contentContainer
4538 objectName: "contentContainer"
@@ -75,58 +68,13 @@ Item {
7568 }
7669 transformOrigin: Item.Center
7770
78− VirtualTouchPad {
79− anchors.fill: parent
80−
81− onPressedChanged: {
82− if (pressed && infoNoteDisplayed) {
83− infoNoteDisplayed = false;
84− }
85− }
86− }
87−
8871 Rectangle {
8972 anchors.fill: parent
90− color: "#3b3b3b"
73+ color: UbuntuColors.jet
9174 }
9275
93− Item {
94− objectName: "infoNoticeArea"
95− anchors.fill: parent
96− opacity: infoNoteDisplayed ? 1 : 0
97− visible: opacity > 0
98− Behavior on opacity {
99− UbuntuNumberAnimation { }
100− }
101−
102− Column {
103− anchors.centerIn: parent
104− width: parent.width - (internalGu * 8)
105− spacing: internalGu * 4
106−
107− Label {
108− id: text
109− text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.")
110− color: "white"
111− width: parent.width
112− font.pixelSize: 2.5 * internalGu
113− wrapMode: Text.Wrap
114− }
115− Icon {
116− height: internalGu * 8
117− width: height
118− name: "input-touchpad-symbolic"
119− color: "white"
120− anchors.horizontalCenter: parent.horizontalCenter
121− }
122− }
123− }
124−
125− InputMethod {
126− id: inputMethod
127− // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
128− enabled: screens.count > 1
129− objectName: "inputMethod"
76+ VirtualTouchPad {
77+ objectName: "virtualTouchPad"
13078 anchors.fill: parent
13179 }
13280 }
qml/Greeter/Greeter.qml+1−5
@@ -145,11 +145,7 @@ Showable {
145145 }
146146 }
147147
148− if (loader.item.sessionToStart === LightDMService.greeter.defaultSession) {
149− return LightDMService.greeter.defaultSession;
150− } else {
151− return "ubuntu"; // The default / fallback
152− }
148+ return LightDMService.greeter.defaultSession;
153149 }
154150
155151 QtObject {
qml/Greeter/LoginList.qml+1−1
@@ -165,7 +165,7 @@ StyledItem {
165165 }
166166
167167 delegate: Item {
168− width: parent.width
168+ width: userList.width
169169 height: root.cellHeight
170170
171171 readonly property bool belowHighlight: (userList.currentIndex < 0 && index > 0) || (userList.currentIndex >= 0 && index > userList.currentIndex)
qml/Greeter/WideView.qml+7−2
@@ -125,6 +125,8 @@ FocusScope {
125125 id: loginList
126126 objectName: "loginList"
127127
128+ property int selectedUserIndex: 0
129+
128130 width: units.gu(40)
129131 anchors {
130132 left: parent.left
@@ -139,9 +141,12 @@ FocusScope {
139141 Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
140142
141143 model: root.userModel
142− currentSession: LightDMService.greeter.defaultSession
144+ currentSession: LightDMService.users.data(selectedUserIndex, LightDMService.userRoles.SessionRole);
143145 onResponded: root.responded(response)
144− onSelected: root.selected(index)
146+ onSelected: {
147+ root.selected(index)
148+ loginList.selectedUserIndex = index;
149+ }
145150 onSessionChooserButtonClicked: parent.state = "SessionsList"
146151
147152 Keys.forwardTo: [sessionChooserLoader.item]
qml/Launcher/Launcher.qml+35−7
@@ -19,10 +19,13 @@ import "../Components"
1919import Ubuntu.Components 1.3
2020import Ubuntu.Gestures 0.1
2121import Unity.Launcher 0.1
22+import Utils 0.1 as Utils
2223
2324FocusScope {
2425 id: root
2526
27+ readonly property int ignoreHideIfMouseOverLauncher: 1
28+
2629 property bool autohideEnabled: false
2730 property bool lockedVisible: false
2831 property bool available: true // can be used to disable all interactions
@@ -105,7 +108,10 @@ FocusScope {
105108 }
106109 }
107110
108− function hide() {
111+ function hide(flags) {
112+ if ((flags & ignoreHideIfMouseOverLauncher) && Utils.Functions.itemUnderMouse(panel)) {
113+ return;
114+ }
109115 switchToNextState("")
110116 }
111117
@@ -416,11 +422,11 @@ FocusScope {
416422 property bool animate: true
417423
418424 onApplicationSelected: {
419− root.hide();
425+ root.hide(ignoreHideIfMouseOverLauncher);
420426 launcherApplicationSelected(appId)
421427 }
422428 onShowDashHome: {
423− root.hide();
429+ root.hide(ignoreHideIfMouseOverLauncher);
424430 root.showDashHome();
425431 }
426432
@@ -498,12 +504,33 @@ FocusScope {
498504
499505 function easeInOutCubic(t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }
500506
507+ property var lastDragPoints: []
508+
509+ function dragDirection() {
510+ if (lastDragPoints.length < 5) {
511+ return "unknown";
512+ }
513+
514+ var toRight = true;
515+ var toLeft = true;
516+ for (var i = lastDragPoints.length - 5; i < lastDragPoints.length; i++) {
517+ if (toRight && lastDragPoints[i] < lastDragPoints[i-1]) {
518+ toRight = false;
519+ }
520+ if (toLeft && lastDragPoints[i] > lastDragPoints[i-1]) {
521+ toLeft = false;
522+ }
523+ }
524+ return toRight ? "right" : toLeft ? "left" : "unknown";
525+ }
526+
501527 onDistanceChanged: {
502528 if (dragging && launcher.state != "visible" && launcher.state != "drawer") {
503529 panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
504530 }
505531
506532 if (root.drawerEnabled && dragging && launcher.state != "drawer") {
533+ lastDragPoints.push(distance)
507534 var drawerHintDistance = panel.width + units.gu(1)
508535 if (distance < drawerHintDistance) {
509536 drawer.anchors.rightMargin = -Math.min(Math.max(0, distance), drawer.width);
@@ -519,18 +546,19 @@ FocusScope {
519546 onDraggingChanged: {
520547 if (!dragging) {
521548 if (distance > panel.width / 2) {
522− if (root.drawerEnabled && distance > panel.width * 3) {
523− root.switchToNextState("drawer")
549+ if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
550+ root.switchToNextState("drawer");
524551 root.focus = true;
525552 drawer.focus = true;
526553 } else {
527− root.switchToNextState("visible")
554+ root.switchToNextState("visible");
528555 }
529556 } else if (root.state === "") {
530557 // didn't drag far enough. rollback
531− root.switchToNextState("")
558+ root.switchToNextState("");
532559 }
533560 }
561+ lastDragPoints = [];
534562 }
535563 }
536564
qml/Panel/Indicators/MenuItemFactory.qml+22−1
@@ -106,7 +106,7 @@ Item {
106106 }
107107
108108 if (component === undefined) {
109− console.debug("Don't know how to make " + modelData.type + " for " + indicator);
109+ console.debug("Don't know how to make " + type + " for " + indicator);
110110 }
111111
112112 return component
@@ -398,7 +398,9 @@ Item {
398398 id: switchItem
399399 objectName: "switchMenu"
400400 property QtObject menuData: null
401+ property var menuModel: menuFactory.menuModel
401402 property int menuIndex: -1
403+ property var extendedData: menuData && menuData.ext || undefined
402404 property bool serverChecked: menuData && menuData.isToggled || false
403405
404406 text: menuData && menuData.label || ""
@@ -407,6 +409,25 @@ Item {
407409 checked: serverChecked
408410 highlightWhenPressed: false
409411
412+ property var subtitleAction: UnityMenuAction {
413+ model: menuModel
414+ index: menuIndex
415+ name: getExtendedProperty(extendedData, "xCanonicalSubtitleAction", "")
416+ }
417+ subtitle.text: subtitleAction.valid ? subtitleAction.state : ""
418+
419+ onMenuModelChanged: {
420+ loadAttributes();
421+ }
422+ onMenuIndexChanged: {
423+ loadAttributes();
424+ }
425+
426+ function loadAttributes() {
427+ if (!menuModel || menuIndex == -1) return;
428+ menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-subtitle-action': 'string'});
429+ }
430+
410431 ServerPropertySynchroniser {
411432 objectName: "sync"
412433 syncTimeout: Utils.Constants.indicatorValueTimeout
qml/Shell.qml+1−1
@@ -124,7 +124,7 @@ StyledItem {
124124 greeter.notifyAppFocusRequested(appId);
125125
126126 panel.indicators.hide();
127− launcher.hide();
127+ launcher.hide(launcher.ignoreHideIfMouseOverLauncher);
128128 }
129129
130130 // For autopilot consumption
qml/Stage/MoveHandler.qml+2−2
@@ -90,8 +90,8 @@ QtObject {
9090 if (target.anyMaximized) {
9191 // keep distanceX relative to the normal window width minus the window control buttons (+spacing)
9292 // so that dragging it back doesn't make the window jump around to weird positions, away from the mouse pointer
93− priv.distanceX = MathUtils.clampAndProject(pos.x, 0, target.width, buttonsWidth, target.resizeArea.normalWidth);
94− priv.distanceY = MathUtils.clampAndProject(pos.y, 0, target.height, 0, target.resizeArea.normalHeight);
93+ priv.distanceX = MathUtils.clampAndProject(pos.x, 0, target.width, buttonsWidth, target.normalWidth);
94+ priv.distanceY = MathUtils.clampAndProject(pos.y, 0, target.height, 0, target.normalHeight);
9595 } else {
9696 priv.distanceX = pos.x;
9797 priv.distanceY = pos.y;
qml/Stage/Spread/WindowedRightEdgeMaths.qml+19−4
@@ -25,21 +25,31 @@ QtObject {
2525 // Input
2626 property int itemIndex: 0
2727 property int normalZ: 0
28− property real progress: 0
2928 property int startWidth: 0
3029 property int startHeight: 0
3130 property int startX: 0
3231 property int targetX: 0
3332 property int startY: 0
3433 property int targetY: 0
35−// property real startAngle: 40
3634 property real targetAngle: 0
3735 property int targetHeight: 0
3836 property real targetScale: 0
37+ property real swipeProgress: 0
38+ property real pushProgress: 0
3939
4040 // Config
4141 property real breakPoint: 0.4
4242
43+ // internal
44+ readonly property real progress: {
45+ if (pushProgress > 0) {
46+ // we don't do the full animation when pushing, just a little bit
47+ return MathUtils.linearAnimation(0, 1, 0, breakPoint + .1, pushProgress)
48+ } else {
49+ return swipeProgress;
50+ }
51+ }
52+
4353 // Output
4454
4555 readonly property real scaleToPreviewProgress: {
@@ -68,12 +78,17 @@ QtObject {
6878
6979 readonly property int animatedZ: {
7080 if (progress < breakPoint + (1 - breakPoint) / 2) {
71− return itemIndex == 1 ? normalZ + 2 : normalZ
81+ if (swipeProgress > 0) {
82+ return itemIndex == 1 ? normalZ + 2 : normalZ
83+ }
84+ if (pushProgress > 0) {
85+ return normalZ;
86+ }
7287 }
7388 return itemIndex
7489 }
7590
76− readonly property real opacityMask: itemIndex == 1 ? MathUtils.linearAnimation(0, breakPoint, 0, 1, progress) : 1
91+ readonly property real opacityMask: (swipeProgress > 0 && itemIndex == 1) ? MathUtils.linearAnimation(0, breakPoint, 0, 1, progress) : 1
7792
7893 readonly property real animatedScale: progress < breakPoint ? 1 : MathUtils.linearAnimation(breakPoint, 1, 1, targetScale, progress)
7994
qml/Stage/Stage.qml+64−33
@@ -710,6 +710,29 @@ FocusScope {
710710 property real restoredX
711711 property real restoredY
712712
713+ // Keeps track of the window geometry while in normal or restored state
714+ // Useful when returning from some maxmized state or when saving the geometry while maximized
715+ // FIXME: find a better solution
716+ property real normalX: 0
717+ property real normalY: 0
718+ property real normalWidth: 0
719+ property real normalHeight: 0
720+ function updateNormalGeometry() {
721+ if (appDelegate.state == "normal" || appDelegate.state == "restored") {
722+ normalX = appDelegate.requestedX;
723+ normalY = appDelegate.requestedY;
724+ normalWidth = appDelegate.width;
725+ normalHeight = appDelegate.height;
726+ }
727+ }
728+ Connections {
729+ target: appDelegate
730+ onXChanged: appDelegate.updateNormalGeometry();
731+ onYChanged: appDelegate.updateNormalGeometry();
732+ onWidthChanged: appDelegate.updateNormalGeometry();
733+ onHeightChanged: appDelegate.updateNormalGeometry();
734+ }
735+
713736 Binding {
714737 target: appDelegate
715738 property: "y"
@@ -850,6 +873,16 @@ FocusScope {
850873 MirFocusController.focusedSurface = null;
851874 }
852875 }
876+
877+ WindowStateSaver {
878+ id: windowStateSaver
879+ target: appDelegate
880+ screenWidth: appContainer.width
881+ screenHeight: appContainer.height
882+ leftMargin: root.leftMargin
883+ minimumY: PanelState.panelHeight
884+ }
885+
853886 Component.onCompleted: {
854887 if (application && application.rotatesWindowContents) {
855888 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -861,7 +894,7 @@ FocusScope {
861894 windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
862895 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
863896 // Now load any saved state. This needs to happen *after* the cascading!
864− resizeArea.loadWindowState();
897+ windowStateSaver.load();
865898
866899 // NB: We're differentiating if this delegate was created in response to a new entry in the model
867900 // or if the Repeater is just populating itself with delegates to match the model it received.
@@ -878,6 +911,8 @@ FocusScope {
878911 _constructing = false;
879912 }
880913 Component.onDestruction: {
914+ windowStateSaver.save();
915+
881916 if (!root.parent) {
882917 // This stage is about to be destroyed. Don't mess up with the model at this point
883918 return;
@@ -1161,7 +1196,8 @@ FocusScope {
11611196 when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
11621197 PropertyChanges {
11631198 target: windowedRightEdgeMaths
1164− progress: Math.max(rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0, edgeBarrier.progress)
1199+ swipeProgress: rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0
1200+ pushProgress: edgeBarrier.progress
11651201 }
11661202 PropertyChanges {
11671203 target: appDelegate
@@ -1479,27 +1515,22 @@ FocusScope {
14791515 id: resizeArea
14801516 objectName: "windowResizeArea"
14811517
1518+ anchors.fill: appDelegate
1519+
14821520 // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
14831521 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
14841522
14851523 target: appDelegate
1524+ minimumY: PanelState.panelHeight // disallow resizing up past Panel
14861525 minWidth: units.gu(10)
14871526 minHeight: units.gu(10)
14881527 borderThickness: units.gu(2)
1489− windowId: model.application.appId // FIXME: Change this to point to windowId once we have such a thing
1490− screenWidth: appContainer.width
1491− screenHeight: appContainer.height
1492− leftMargin: root.leftMargin
14931528 enabled: false
14941529 visible: enabled
14951530
14961531 onPressed: {
14971532 appDelegate.focus = true;
14981533 }
1499−
1500− Component.onDestruction: {
1501− saveWindowState();
1502− }
15031534 }
15041535
15051536 DecoratedWindow {
@@ -1649,10 +1680,10 @@ FocusScope {
16491680 }
16501681 }
16511682
1652− Image {
1653− id: closeImage
1683+ MouseArea {
1684+ id: closeMouseArea
1685+ objectName: "closeMouseArea"
16541686 anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
1655− source: "graphics/window-close.svg"
16561687 readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
16571688 visible: !appDelegate.isDash && dragArea.distance == 0
16581689 && index == spreadItem.highlightedIndex
@@ -1660,20 +1691,20 @@ FocusScope {
16601691 && mousePos.y > -units.gu(4)
16611692 && mousePos.x > -units.gu(4)
16621693 && mousePos.x < (decoratedWindow.width * 2 / 3)
1663− height: units.gu(2)
1694+ height: units.gu(6)
16641695 width: height
1665− sourceSize.width: width
1666− sourceSize.height: height
1667−
1668− MouseArea {
1669− id: closeMouseArea
1670− objectName: "closeMouseArea"
1671− anchors.fill: closeImage
1672− anchors.margins: -units.gu(2)
1673− onClicked: {
1674− priv.closingIndex = index;
1675− appDelegate.close();
1676− }
1696+
1697+ onClicked: {
1698+ priv.closingIndex = index;
1699+ appDelegate.close();
1700+ }
1701+ Image {
1702+ id: closeImage
1703+ source: "graphics/window-close.svg"
1704+ anchors.fill: closeMouseArea
1705+ anchors.margins: units.gu(2)
1706+ sourceSize.width: width
1707+ sourceSize.height: height
16771708 }
16781709 }
16791710 }
@@ -1732,13 +1763,13 @@ FocusScope {
17321763 }
17331764
17341765 // Find the hovered item and mark it active
1735− var mapped = mapToItem(appContainer, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1736− var itemUnder = appContainer.childAt(mapped.x, mapped.y)
1737− if (itemUnder) {
1738− mapped = mapToItem(itemUnder, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1739− var delegateChild = itemUnder.childAt(mapped.x, mapped.y)
1740− if (delegateChild && (delegateChild.objectName === "dragArea" || delegateChild.objectName === "windowInfoItem")) {
1741− spreadItem.highlightedIndex = appRepeater.indexOf(itemUnder)
1766+ for (var i = appRepeater.count - 1; i >= 0; i--) {
1767+ var appDelegate = appRepeater.itemAt(i);
1768+ var mapped = mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
1769+ var itemUnder = appDelegate.childAt(mapped.x, mapped.y);
1770+ if (itemUnder && (itemUnder.objectName === "dragArea" || itemUnder.objectName === "windowInfoItem" || itemUnder.objectName == "closeMouseArea")) {
1771+ spreadItem.highlightedIndex = i;
1772+ break;
17421773 }
17431774 }
17441775
qml/Stage/WindowResizeArea.qml+2−70
@@ -18,91 +18,23 @@ import QtQuick 2.4
1818import Ubuntu.Components 1.3
1919import Utils 0.1
2020import Unity.Application 0.1 // for Mir.cursorName
21−import "../Components/PanelState"
2221
2322MouseArea {
2423 id: root
2524
26− anchors.fill: target
2725 anchors.margins: -borderThickness
2826
2927 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
3028
31− property var windowStateStorage: WindowStateStorage
3229 readonly property alias dragging: d.dragging
33− readonly property alias normalWidth: priv.normalWidth
34− readonly property alias normalHeight: priv.normalHeight
3530
3631 // The target item managed by this. Must be a parent or a sibling
3732 // The area will anchor to it and manage resize events
3833 property Item target: null
39− property string windowId: ""
4034 property int borderThickness: 0
35+ property real minimumY: -100000000 // By default, impose no limit
4136 property int minWidth: 0
4237 property int minHeight: 0
43− property int defaultWidth: units.gu(60)
44− property int defaultHeight: units.gu(50)
45− property int screenWidth: 0
46− property int screenHeight: 0
47− property int leftMargin: 0
48−
49− QtObject {
50− id: priv
51− objectName: "priv"
52−
53− property int normalX: 0
54− property int normalY: 0
55− property int normalWidth: 0
56− property int normalHeight: 0
57−
58− function updateNormalGeometry() {
59− if (root.target.state == "normal" || root.target.state == "restored") {
60− normalX = root.target.requestedX
61− normalY = root.target.requestedY
62− normalWidth = root.target.width
63− normalHeight = root.target.height
64− }
65− }
66− }
67−
68− Connections {
69− target: root.target
70− onXChanged: priv.updateNormalGeometry();
71− onYChanged: priv.updateNormalGeometry();
72− onWidthChanged: priv.updateNormalGeometry();
73− onHeightChanged: priv.updateNormalGeometry();
74− }
75−
76− function loadWindowState() {
77− var windowGeometry = windowStateStorage.getGeometry(root.windowId,
78− Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
79−
80−
81− target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, d.minimumWidth), screenWidth - root.leftMargin); });
82− target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, d.minimumHeight),
83− root.screenHeight - (target.fullscreen ? 0 : PanelState.panelHeight)); });
84− target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, root.screenWidth - root.leftMargin - target.windowedWidth),
85− (target.fullscreen ? 0 : root.leftMargin)); });
86− target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.windowedHeight), PanelState.panelHeight); });
87−
88− var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
89− target.restore(false /* animated */, windowState);
90−
91− priv.updateNormalGeometry();
92−
93− // initialize the x/y to restore to
94− target.restoredX = priv.normalX;
95− target.restoredY = priv.normalY;
96− }
97−
98− function saveWindowState() {
99− var state = target.windowState;
100− if (state === WindowStateStorage.WindowStateRestored) {
101− state = WindowStateStorage.WindowStateNormal;
102− }
103− windowStateStorage.saveState(root.windowId, state & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
104− windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight));
105− }
10638
10739 QtObject {
10840 id: d
@@ -311,7 +243,7 @@ MouseArea {
311243 }
312244
313245 if (d.topBorder) {
314− var newTargetY = Math.max(d.startY + deltaY, PanelState.panelHeight); // disallow resizing up past Panel
246+ var newTargetY = Math.max(d.startY + deltaY, root.minimumY);
315247 var bottomBorderY = target.windowedY + target.height;
316248 if (bottomBorderY > newTargetY + d.minimumHeight) {
317249 if (bottomBorderY < newTargetY + d.maximumHeight) {
qml/Stage/WindowStateSaver.qmlnew file+63
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Utils 0.1
20+
21+QtObject {
22+ id: root
23+
24+ // set from outside
25+ property var target
26+ property int screenWidth: 0
27+ property int screenHeight: 0
28+ property int leftMargin: 0
29+ property int minimumY: 0
30+
31+ function load() {
32+ var defaultWidth = units.gu(60);
33+ var defaultHeight = units.gu(50);
34+ var windowGeometry = WindowStateStorage.getGeometry(target.appId,
35+ Qt.rect(target.windowedX, target.windowedY, defaultWidth, defaultHeight));
36+
37+ target.windowedWidth = Qt.binding(function() { return Math.min(Math.max(windowGeometry.width, target.minimumWidth), screenWidth - root.leftMargin); });
38+ target.windowedHeight = Qt.binding(function() { return Math.min(Math.max(windowGeometry.height, target.minimumHeight),
39+ screenHeight - (target.fullscreen ? 0 : minimumY)); });
40+ target.windowedX = Qt.binding(function() { return Math.max(Math.min(windowGeometry.x, screenWidth - root.leftMargin - target.windowedWidth),
41+ (target.fullscreen ? 0 : root.leftMargin)); });
42+ target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, screenHeight - target.windowedHeight), minimumY); });
43+
44+ var windowState = WindowStateStorage.getState(target.appId, WindowStateStorage.WindowStateNormal)
45+ target.restore(false /* animated */, windowState);
46+
47+ target.updateNormalGeometry();
48+
49+ // initialize the x/y to restore to
50+ target.restoredX = target.normalX;
51+ target.restoredY = target.normalY;
52+ }
53+
54+ function save() {
55+ var state = target.windowState;
56+ if (state === WindowStateStorage.WindowStateRestored) {
57+ state = WindowStateStorage.WindowStateNormal;
58+ }
59+
60+ WindowStateStorage.saveState(target.appId, state & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
61+ WindowStateStorage.saveGeometry(target.appId, Qt.rect(target.normalX, target.normalY, target.normalWidth, target.normalHeight));
62+ }
63+}
src/ShellApplication.cpp+1
@@ -36,6 +36,7 @@ ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
3636{
3737
3838 setApplicationName(QStringLiteral("unity8"));
39+ setOrganizationName(QStringLiteral("Canonical"));
3940
4041 connect(this, &QGuiApplication::screenAdded, this, &ShellApplication::onScreenAdded);
4142
tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp+1−1
@@ -22,6 +22,7 @@ namespace QLightDM
2222
2323SessionsModelPrivate::SessionsModelPrivate(SessionsModel* parent)
2424 : testScenario("singleSession")
25+ , q_ptr(parent)
2526 , m_availableSessions(
2627 {
2728 {"ubuntu", "", "Ubuntu", ""},
@@ -36,7 +37,6 @@ SessionsModelPrivate::SessionsModelPrivate(SessionsModel* parent)
3637 {"xterm", "", "Recovery Console", ""},
3738 {"", "", "Unknown?", ""}
3839 })
39− , q_ptr(parent)
4040{
4141 numSessions = numAvailableSessions();
4242 resetEntries();
tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp+23−23
@@ -73,7 +73,7 @@ void UsersModelPrivate::resetEntries_single()
7373{
7474 entries =
7575 {
76− { "single", "Single User", 0, 0, false, false, "ubuntu", 0 },
76+ { "single", "Single User", 0, 0, false, false, "ubuntu", 0, 0 },
7777 };
7878}
7979
@@ -81,7 +81,7 @@ void UsersModelPrivate::resetEntries_singlePassphrase()
8181{
8282 entries =
8383 {
84− { "single", "Single User", 0, 0, false, false, "ubuntu", 0 },
84+ { "single", "Single User", 0, 0, false, false, "ubuntu", 0, 0 },
8585 };
8686}
8787
@@ -89,7 +89,7 @@ void UsersModelPrivate::resetEntries_singlePin()
8989{
9090 entries =
9191 {
92− { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0 },
92+ { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0, 0 },
9393 };
9494}
9595
@@ -97,27 +97,27 @@ void UsersModelPrivate::resetEntries_full()
9797{
9898 entries =
9999 {
100− { "has-password", "Has Password", 0, 0, false, false, "ubuntu", 0 },
101− { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0 },
102− { "different-prompt", "Different Prompt", 0, 0, false, false, "ubuntu", 0 },
103− { "no-password", "No Password", 0, 0, false, false, "ubuntu", 0 },
104− { "auth-error", "Auth Error", 0, 0, false, false, "ubuntu", 0 },
105− { "two-factor", "Two Factor", 0, 0, false, false, "ubuntu", 0 },
106− { "info-prompt", "Info Prompt", 0, 0, false, false, "ubuntu", 0 },
107− { "html-info-prompt", "HTML Info Prompt", 0, 0, false, false, "ubuntu", 0 },
108− { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, "ubuntu", 0 },
109− { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, "ubuntu", 0 },
110− { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, "ubuntu", 0 },
111− { "long-name", "Long name (far far too long to fit, seriously this would never fit on the screen, you will never see this part of the name)", 0, 0, false, false, "ubuntu", 0 },
112− { "color-background", "Color Background", "#E95420", 0, false, false, "ubuntu", 0 },
100+ { "has-password", "Has Password", 0, 0, false, false, "ubuntu", 0, 0 },
101+ { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0, 0 },
102+ { "different-prompt", "Different Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
103+ { "no-password", "No Password", 0, 0, false, false, "ubuntu", 0, 0 },
104+ { "auth-error", "Auth Error", 0, 0, false, false, "ubuntu", 0, 0 },
105+ { "two-factor", "Two Factor", 0, 0, false, false, "ubuntu", 0, 0 },
106+ { "info-prompt", "Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
107+ { "html-info-prompt", "HTML Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
108+ { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
109+ { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
110+ { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, "ubuntu", 0, 0 },
111+ { "long-name", "Long name (far far too long to fit, seriously this would never fit on the screen, you will never see this part of the name)", 0, 0, false, false, "ubuntu", 0, 0 },
112+ { "color-background", "Color Background", "#E95420", 0, false, false, "ubuntu", 0, 0 },
113113 // white and black are a bit redundant, but useful for manually testing if UI is still readable
114− { "white-background", "White Background", "#ffffff", 0, false, false, "ubuntu", 0 },
115− { "black-background", "Black Background", "#000000", 0, false, false, "ubuntu", 0 },
116− { "no-background", "No Background", "", 0, false, false, "ubuntu", 0 },
117− { "unicode", "가나다라마", 0, 0, false, false, "ubuntu", 0 },
118− { "no-response", "No Response", 0, 0, false, false, "ubuntu", 0 },
119− { "empty-name", "", 0, 0, false, false, "ubuntu", 0 },
120− { "active", "Active Account", 0, 0, true, false, "ubuntu", 0 },
114+ { "white-background", "White Background", "#ffffff", 0, false, false, "ubuntu", 0, 0 },
115+ { "black-background", "Black Background", "#000000", 0, false, false, "ubuntu", 0, 0 },
116+ { "no-background", "No Background", "", 0, false, false, "ubuntu", 0, 0 },
117+ { "unicode", "가나다라마", 0, 0, false, false, "ubuntu", 0, 0 },
118+ { "no-response", "No Response", 0, 0, false, false, "ubuntu", 0, 0 },
119+ { "empty-name", "", 0, 0, false, false, "ubuntu", 0, 0 },
120+ { "active", "Active Account", 0, 0, true, false, "ubuntu", 0, 0 },
121121 };
122122}
123123
tests/mocks/QtMultimedia/videooutput.h+1−1
@@ -31,7 +31,7 @@ public:
3131 QObject *source() const { return m_source.data(); }
3232 void setSource(QObject *source);
3333
34− void itemChange(ItemChange change, const ItemChangeData & value);
34+ void itemChange(ItemChange change, const ItemChangeData & value) override;
3535
3636Q_SIGNALS:
3737 void sourceChanged();
tests/plugins/Utils/WindowInputMonitorTest.cpp+76−9
@@ -25,14 +25,15 @@ class FakeElapsedTimer : public AbstractElapsedTimer {
2525public:
2626 static qint64 msecsSinceEpoch;
2727
28− FakeElapsedTimer() { start(); }
28+ FakeElapsedTimer() {}
2929
30− void start() override { m_msecsSinceReference = msecsSinceEpoch; }
30+ void start() override { m_msecsSinceReference = msecsSinceEpoch; m_valid = true; }
3131 qint64 msecsSinceReference() const override { return m_msecsSinceReference; }
32− qint64 elapsed() const override { return msecsSinceEpoch - m_msecsSinceReference; }
32+ qint64 elapsed() const override { return m_valid ? msecsSinceEpoch - m_msecsSinceReference : qrand(); }
3333
3434private:
3535 qint64 m_msecsSinceReference;
36+ bool m_valid{false};
3637};
3738qint64 FakeElapsedTimer::msecsSinceEpoch = 0;
3839
@@ -48,11 +49,14 @@ public:
4849 int interval() const override;
4950 void setInterval(int msecs) override;
5051 void start() override;
52+ void stop() override;
53+ bool isRunning() const override;
5154 bool isSingleShot() const override;
5255 void setSingleShot(bool value) override;
5356private:
5457 int m_interval;
5558 bool m_singleShot;
59+ bool m_isRunning;
5660 qint64 m_nextTimeoutTime;
5761};
5862
@@ -85,6 +89,8 @@ private Q_SLOTS:
8589 void tapWhileTouching();
8690 void multipleHomeKeys();
8791
92+ void repeatedSuperPress();
93+
8894private:
8995 void passTime(qint64 timeSpanMs);
9096
@@ -98,11 +104,10 @@ void WindowInputMonitorTest::init()
98104
99105void WindowInputMonitorTest::cleanup()
100106{
101− delete m_fakeTimerFactory;
107+ delete m_fakeTimerFactory;
102108 m_fakeTimerFactory = nullptr;
103109}
104110
105−
106111void WindowInputMonitorTest::passTime(qint64 timeSpanMs)
107112{
108113 qint64 finalTime = FakeElapsedTimer::msecsSinceEpoch + timeSpanMs;
@@ -133,7 +138,7 @@ void WindowInputMonitorTest::touchTapTouch()
133138 QFETCH(int, silenceAfterTap);
134139 QFETCH(int, expectedActivatedCount);
135140 QFETCH(Qt::Key, key);
136− WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
141+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
137142 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
138143 QVERIFY(activatedSpy.isValid());
139144
@@ -194,7 +199,7 @@ void WindowInputMonitorTest::touchTapTouch()
194199
195200void WindowInputMonitorTest::tapWhileTouching()
196201{
197− WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
202+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
198203 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
199204 QVERIFY(activatedSpy.isValid());
200205
@@ -229,7 +234,7 @@ void WindowInputMonitorTest::tapWhileTouching()
229234 */
230235void WindowInputMonitorTest::multipleHomeKeys()
231236{
232− WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
237+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
233238 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
234239 QVERIFY(activatedSpy.isValid());
235240
@@ -258,12 +263,64 @@ void WindowInputMonitorTest::multipleHomeKeys()
258263 QCOMPARE(activatedSpy.count(), 1);
259264}
260265
266+// regression test for lp:1607427
267+void WindowInputMonitorTest::repeatedSuperPress()
268+{
269+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
270+ QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
271+ QVERIFY(activatedSpy.isValid());
272+
273+ // 1st try
274+ passTime(1000);
275+ {
276+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
277+ homeKeyWatcher.update(&keyEvent);
278+ }
279+ passTime(50);
280+ {
281+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
282+ homeKeyWatcher.update(&keyEvent);
283+ }
284+ passTime(1000);
285+ QCOMPARE(activatedSpy.count(), 1);
286+
287+ // a touch event in between
288+ {
289+ QTouchEvent touchEvent(QEvent::TouchBegin);
290+ homeKeyWatcher.update(&touchEvent);
291+ }
292+ {
293+ QTouchEvent touchEvent(QEvent::TouchUpdate);
294+ homeKeyWatcher.update(&touchEvent);
295+ }
296+ {
297+ QTouchEvent touchEvent(QEvent::TouchEnd);
298+ homeKeyWatcher.update(&touchEvent);
299+ }
300+
301+ passTime(1000);
302+ // 2nd try
303+ activatedSpy.clear();
304+ {
305+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
306+ homeKeyWatcher.update(&keyEvent);
307+ }
308+ passTime(50);
309+ {
310+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
311+ homeKeyWatcher.update(&keyEvent);
312+ }
313+ passTime(1000);
314+ QCOMPARE(activatedSpy.count(), 1);
315+}
316+
261317/////////////////////////////////// FakeTimer //////////////////////////////////
262318
263319FakeTimer::FakeTimer(QObject *parent)
264320 : UnityUtil::AbstractTimer(parent)
265321 , m_interval(0)
266322 , m_singleShot(true)
323+ , m_isRunning(false)
267324{
268325}
269326
@@ -285,10 +342,20 @@ void FakeTimer::update()
285342
286343void FakeTimer::start()
287344{
288− AbstractTimer::start();
345+ m_isRunning = true;
289346 m_nextTimeoutTime = FakeElapsedTimer::msecsSinceEpoch + (qint64)interval();
290347}
291348
349+void FakeTimer::stop()
350+{
351+ m_isRunning = false;
352+}
353+
354+bool FakeTimer::isRunning() const
355+{
356+ return m_isRunning;
357+}
358+
292359int FakeTimer::interval() const
293360{
294361 return m_interval;
tests/qmltests/Components/tst_VirtualTouchPad.qml+55−1
@@ -21,14 +21,20 @@ import UInput 0.1
2121import "../../../qml/Components"
2222
2323
24−Item {
24+Rectangle {
2525 id: root
2626 width: units.gu(70)
2727 height: units.gu(70)
28+ color: "black"
2829
2930 VirtualTouchPad {
3031 id: touchScreenPad
3132 anchors.fill: parent
33+ property int internalGu: units.gu(1)
34+ settings: QtObject {
35+ property bool touchpadTutorialHasRun: true
36+ property bool oskEnabled: true
37+ }
3238 }
3339
3440 SignalSpy {
@@ -139,5 +145,53 @@ Item {
139145 event.release(1, startX2, startY + units.gu(11));
140146 event.commit();
141147 }
148+
149+ function test_tutorial() {
150+ var oskButton = findChild(touchScreenPad, "oskButton");
151+ var leftButton = findChild(touchScreenPad, "leftButton");
152+ var rightButton = findChild(touchScreenPad, "rightButton");
153+ var touchPad = findChild(touchScreenPad, "virtualTouchPad")
154+ var tutorial = findInvisibleChild(touchScreenPad, "tutorialAnimation")
155+ var tutorialFinger1 = findChild(touchScreenPad, "tutorialFinger1");
156+ var tutorialFinger2 = findChild(touchScreenPad, "tutorialFinger2");
157+ var tutorialLabel = findChild(touchScreenPad, "tutorialLabel");
158+ var tutorialImage = findChild(touchScreenPad, "tutorialImage");
159+
160+ mouseEventSpy1.signalName = "mousePressed"
161+ mouseEventSpy2.signalName = "mouseReleased"
162+
163+ mouseEventSpy1.clear();
164+ mouseEventSpy2.clear();
165+
166+ // run the tutorial
167+ touchScreenPad.runTutorial();
168+ tryCompare(tutorial, "running", true)
169+
170+ // Wait for it to pause
171+ tryCompare(tutorial, "paused", true)
172+
173+ // Click somewhere to make it continue
174+ mouseClick(root, root.width / 2, root.height /2)
175+ tryCompare(tutorial, "paused", false)
176+
177+ // Verify that the touchpad does NOT accept input while the tutorial is running
178+ mouseClick(root, root.width / 2, root.height /2)
179+ compare(mouseEventSpy1.count, 0)
180+ compare(mouseEventSpy2.count, 0)
181+
182+ // Wait for it to finish
183+ tryCompare(tutorial, "running", false, 60000)
184+
185+ // Make sure after the tutorial, all the visible states are proper
186+ tryCompare(oskButton, "visible", true)
187+ tryCompare(leftButton, "visible", true)
188+ tryCompare(rightButton, "visible", true)
189+
190+ tryCompare(tutorialFinger1, "visible", false)
191+ tryCompare(tutorialFinger2, "visible", false)
192+ tryCompare(tutorialImage, "visible", false)
193+ tryCompare(tutorialLabel, "visible", false)
194+ }
195+
142196 }
143197}
tests/qmltests/Dash/Previews/tst_Preview.qml+63
@@ -37,6 +37,51 @@ Rectangle {
3737 id: mockPreviewModel
3838 }
3939
40+ ListModel {
41+ id: tracksModel
42+ Component.onCompleted:
43+ {
44+ tracksModel.append( { "type" : "audio1",
45+ "widgetId" : "audiopw1",
46+ "properties" : { "tracks" : [
47+ { title: "Some track name", length: "30", source: "/not/existinga/path/testsound1" }
48+ ]
49+ }
50+ }
51+ );
52+ tracksModel.append(
53+ { "type" : "audio",
54+ "widgetId" : "audiopw",
55+ "properties" : { "tracks" : [
56+ { title: "Some track name", length: "30", source: "/not/existing/path/testsound1" },
57+ { title: "Some other track name", subtitle: "Subtitle", length: "83", source: "/not/existing/path/testsound2" },
58+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound3" },
59+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound4" },
60+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound5" },
61+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound6" },
62+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound7" },
63+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound8" },
64+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound9" },
65+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound10" },
66+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound11" },
67+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound12" },
68+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound13" },
69+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound14" },
70+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound15" },
71+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound16" },
72+ { title: "And another one", length: "7425", source: "/not/existing/path/testsound17" }
73+ ]
74+ }
75+ } );
76+ }
77+ }
78+
79+ QtObject {
80+ id: audiosModel
81+ property int widgetColumnCount: 1
82+ property var columnModel: { tracksModel }
83+ }
84+
4085 Preview {
4186 id: preview
4287 anchors.fill: parent
@@ -57,6 +102,7 @@ Rectangle {
57102 function init() {
58103 var widget = findChild(preview, "previewListRow0");
59104 widget.positionViewAtBeginning();
105+ preview.previewModel = mockPreviewModel;
60106 }
61107
62108 function test_triggered() {
@@ -147,5 +193,22 @@ Rectangle {
147193 skip("preview %1 or widget %2 have been destroyed, thus we can't safely continue this test".arg(preview_str).arg(widget_str))
148194 }
149195 }
196+
197+ function test_audios() {
198+ preview.previewModel = audiosModel;
199+ waitForRendering(preview);
200+
201+ // Scroll down
202+ var previewListRow0 = findChild(preview, "previewListRow0");
203+ flickToYEnd(previewListRow0);
204+
205+ var previewsContentY = previewListRow0.contentY;
206+
207+ var trackItem = findChild(preview, "trackItem16");
208+ mouseClick(findChild(trackItem, "playButton"));
209+
210+ expectFail("", "Clicking on a track should not change contentY.");
211+ tryCompareFunction(function () { return previewsContentY != previewListRow0.contentY; }, true);
212+ }
150213 }
151214}
tests/qmltests/Dash/tst_Dash.qml+4−3
@@ -310,8 +310,9 @@ Item {
310310 var stopX = units.gu(1)
311311 var stopY = startY;
312312 waitForRendering(dashContentList)
313− mouseFlick(dash, startX, startY, stopX, stopY);
314− mouseFlick(dash, startX, startY, stopX, stopY);
313+ mouseFlick(dash, startX, startY, stopX, stopY, true, true, units.gu(200));
314+ compare(dashContentList.currentIndex, 1, "Could not flick to scope id 1");
315+ mouseFlick(dash, startX, startY, stopX, stopY, units.gu(200));
315316 compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
316317 var dashCommunicatorService = findInvisibleChild(dash, "dashCommunicatorService");
317318 dashCommunicatorService.mockSetCurrentScope(0, true, false);
@@ -411,7 +412,7 @@ Item {
411412 compare(dashContentList.currentItem.scopeId, "clickscope");
412413
413414 // Move to second scope
414− mouseFlick(dash, dash.width / 2, units.gu(2), dash.width / 5, units.gu(2));
415+ mouseFlick(dash, dash.width / 2, units.gu(2), dash.width / 5, units.gu(2), true, true, units.gu(20));
415416 tryCompare(dashContentList, "currentIndex", 1);
416417 compare(dashContentList.currentItem.scopeId, "MockScope1");
417418 }
tests/qmltests/Launcher/tst_Launcher.qml+3−3
@@ -824,7 +824,7 @@ Rectangle {
824824
825825 // Dragging a bit (> 1.5 gu)
826826 newMouseX -= units.gu(2)
827− mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
827+ mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false)
828828 currentMouseX = newMouseX
829829
830830 // Other items need to expand and become 0.6 opaque
@@ -832,8 +832,8 @@ Rectangle {
832832 tryCompare(item0, "itemOpacity", 0.6)
833833
834834 // Dragging a bit more
835− newMouseY += initialItemHeight * 1.5
836− mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
835+ newMouseY += initialItemHeight * 1.25
836+ mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false)
837837 currentMouseY = newMouseY
838838
839839 tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 1)
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+6−1
@@ -370,7 +370,8 @@ Item {
370370 function test_create_switchMenu_data() {
371371 return [
372372 {label: "testLabel1", enabled: true, checked: false, icon: "file:///testIcon1" },
373− {label: "testLabel2", enabled: false, checked: true, icon: "file:///testIcon2" },
373+ {label: "testLabel2", enabled: false, checked: true, icon: "file:///testIcon2", subtitleAction: "action::subtitle1" },
374+ {label: "testLabel2", enabled: false, checked: true, icon: "file:///testIcon3", subtitleAction: "action::subtitle2" },
374375 ];
375376 }
376377
@@ -380,6 +381,9 @@ Item {
380381 menuData.sensitive = data.enabled;
381382 menuData.icon = data.icon;
382383 menuData.isToggled = data.checked;
384+ menuData.ext = {
385+ 'xCanonicalSubtitleAction': data.subtitleAction,
386+ };
383387
384388 loader.data = menuData;
385389 loader.sourceComponent = factory.load(menuData);
@@ -390,6 +394,7 @@ Item {
390394 compare(loader.item.iconSource, data.icon, "Icon does not match data");
391395 compare(loader.item.checked, data.checked, "Checked does not match data");
392396 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
397+ compare(loader.item.subtitleAction.name, data.subtitleAction === undefined ? "" : data.subtitleAction, "Subtitle action does not match data");
393398 }
394399
395400 function test_create_alarmMenu_data() {
tests/qmltests/Stage/tst_ApplicationWindow.qml+2−20
@@ -53,6 +53,8 @@ Rectangle {
5353 surfaceOrientationAngle: 0
5454 interactive: true
5555 focus: true
56+ requestedWidth: width
57+ requestedHeight: height
5658 Component.onDestruction: {
5759 applicationWindowLoader.itemDestroyed = true;
5860 }
@@ -150,26 +152,6 @@ Rectangle {
150152 }
151153 }
152154 }
153−
154− Button {
155− anchors { left: parent.left; right: parent.right }
156− activeFocusOnPress: false
157− text: "Rotate device \u27F3"
158− onClicked: {
159− var orientation = applicationWindowLoader.item.orientation
160− if (orientation == Qt.PortraitOrientation) {
161− orientation = Qt.LandscapeOrientation;
162− } else if (orientation == Qt.LandscapeOrientation) {
163− orientation = Qt.InvertedPortraitOrientation;
164− } else if (orientation == Qt.InvertedPortraitOrientation) {
165− orientation = Qt.InvertedLandscapeOrientation;
166− } else {
167− orientation = Qt.PortraitOrientation;
168− }
169− applicationWindowLoader.item.orientation = orientation;
170− }
171− }
172−
173155 }
174156 }
175157
tests/qmltests/Stage/tst_DesktopStage.qml+71
@@ -790,6 +790,77 @@ Item {
790790 tryCompare(dialerAppDelegate, "state", "maximized");
791791 }
792792
793+ function test_saveRestoreSize() {
794+ var originalWindowCount = topSurfaceList.count;
795+ var appDelegate = startApplication("dialer-app");
796+ compare(topSurfaceList.count, originalWindowCount + 1);
797+
798+ var initialWindowX = appDelegate.windowedX;
799+ var initialWindowY = appDelegate.windowedY;
800+ var initialWindowWidth = appDelegate.width
801+ var initialWindowHeight = appDelegate.height
802+
803+ var resizeDelta = units.gu(5)
804+ var startDragX = initialWindowX + initialWindowWidth + 1
805+ var startDragY = initialWindowY + initialWindowHeight + 1
806+ mouseFlick(root, startDragX, startDragY, startDragX + resizeDelta, startDragY + resizeDelta, true, true, units.gu(.5), 10);
807+
808+ tryCompare(appDelegate, "width", initialWindowWidth + resizeDelta);
809+ tryCompare(appDelegate, "height", initialWindowHeight + resizeDelta);
810+
811+ // Close the window and restart the application
812+ var closeButton = findChild(appDelegate, "closeWindowButton");
813+ appDelegate = null;
814+ verify(closeButton);
815+ mouseClick(closeButton);
816+ tryCompare(topSurfaceList, "count", originalWindowCount);
817+ wait(100); // plus some spare room
818+ appDelegate = startApplication("dialer-app");
819+
820+ // Make sure its size is again the same as before
821+ tryCompare(appDelegate, "width", initialWindowWidth + resizeDelta);
822+ tryCompare(appDelegate, "height", initialWindowHeight + resizeDelta);
823+ }
824+
825+ function test_saveRestoreMaximized() {
826+ var originalWindowCount = topSurfaceList.count;
827+ var appDelegate = startApplication("dialer-app");
828+ compare(topSurfaceList.count, originalWindowCount + 1);
829+
830+ var initialWindowX = appDelegate.windowedX;
831+ var initialWindowY = appDelegate.windowedY;
832+
833+ var moveDelta = units.gu(5);
834+
835+ appDelegate.windowedX = initialWindowX + moveDelta
836+ appDelegate.windowedY = initialWindowY + moveDelta
837+
838+ // Now change the state to maximized. The window should not keep updating the stored values
839+ maximizeAppDelegate(appDelegate);
840+
841+ // Close the window and restart the application
842+ var closeButton = findChild(appDelegate, "closeWindowButton");
843+ appDelegate = null;
844+ verify(closeButton);
845+ mouseClick(closeButton);
846+ closeButton = null;
847+ tryCompare(topSurfaceList, "count", originalWindowCount);
848+ wait(100); // plus some spare room
849+ appDelegate = startApplication("dialer-app");
850+
851+ // Make sure it's again where we left it in normal state before destroying
852+ tryCompare(appDelegate, "windowedX", initialWindowX + moveDelta)
853+ tryCompare(appDelegate, "windowedY", initialWindowY + moveDelta)
854+
855+ // Make sure maximize() has been called after restoring
856+ tryCompare(appDelegate, "state", "maximized")
857+
858+ // clean up
859+ // click on restore button (same one as maximize)
860+ var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
861+ mouseClick(maximizeButton);
862+ }
863+
793864 function test_grabbingCursorOnDecorationPress() {
794865 var appDelegate = startApplication("dialer-app");
795866 verify(appDelegate);
tests/qmltests/Stage/tst_WindowResizeArea.qml+1−66
@@ -88,22 +88,11 @@ Item {
8888
8989 WindowResizeArea {
9090 id: windowResizeArea
91+ anchors.fill: parent
9192 target: fakeWindow
9293 borderThickness: units.gu(2)
9394 minWidth: units.gu(15)
9495 minHeight: units.gu(10)
95− defaultWidth: units.gu(20)
96− defaultHeight: units.gu(20)
97− windowId: "test-window-id"
98− screenWidth: root.width
99− screenHeight: root.height
100−
101− Component.onCompleted: {
102− loadWindowState();
103− }
104− Component.onDestruction: {
105− saveWindowState();
106− }
10796 }
10897
10998 Rectangle {
@@ -312,30 +301,6 @@ Item {
312301 compare(fakeWindow.requestedY, Math.min(initialWindowY + data.dy, initialWindowY + maxMoveY));
313302 }
314303
315− function test_saveRestoreSize() {
316− var initialWindowX = fakeWindow.windowedX;
317− var initialWindowY = fakeWindow.windowedY;
318− var initialWindowWidth = fakeWindow.width
319− var initialWindowHeight = fakeWindow.height
320−
321− var resizeDelta = units.gu(5)
322− var startDragX = initialWindowX + initialWindowWidth + 1
323− var startDragY = initialWindowY + initialWindowHeight + 1
324− mouseFlick(root, startDragX, startDragY, startDragX + resizeDelta, startDragY + resizeDelta, true, true, units.gu(.5), 10);
325−
326− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
327− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
328−
329− // This will destroy the window and recreate it
330− windowLoader.active = false;
331− waitForRendering(root);
332− windowLoader.active = true;
333−
334− // Make sure its size is again the same as before
335− tryCompare(fakeWindow, "width", Math.max(initialWindowWidth + resizeDelta, fakeWindow.resizeAreaMinWidth));
336− tryCompare(fakeWindow, "height", Math.max(initialWindowHeight + resizeDelta, fakeWindow.resizeAreaMinHeight));
337− }
338−
339304 // This tests if dragging smaller than minSize and then larger again, will keep the edge sticking
340305 // to the mouse, instead of immediately making the window grow again when switching direction
341306 function test_resizeSmallerAndLarger_data() {
@@ -361,36 +326,6 @@ Item {
361326 tryCompare(fakeWindow, "height", initialWindowHeight);
362327 }
363328
364− function test_saveRestoreMaximized() {
365− var initialWindowX = fakeWindow.windowedX;
366− var initialWindowY = fakeWindow.windowedY;
367−
368− var moveDelta = units.gu(5);
369−
370− fakeWindow.windowedX = initialWindowX + moveDelta
371− fakeWindow.windowedY = initialWindowY + moveDelta
372−
373− // Now change the state to maximized. The window should not keep updating the stored values
374− fakeWindow.maximize()
375− fakeWindow.windowedX = 31415 // 0 is too risky to pass the test even when broken
376− fakeWindow.windowedY = 31415
377−
378− // This will destroy the window and recreate it
379− windowLoader.active = false;
380− waitForRendering(root);
381− windowLoader.active = true;
382−
383− // Make sure it's again where we left it in normal state before destroying
384− tryCompare(fakeWindow, "x", initialWindowX + moveDelta)
385− tryCompare(fakeWindow, "y", initialWindowX + moveDelta)
386−
387− // Make sure maximize() has been called after restoring
388− tryCompare(fakeWindow, "state", "maximized")
389−
390− // clean up
391− fakeWindow.restoreFromMaximized()
392− }
393−
394329 function test_restoreMovesIntoBounds_data() {
395330 return [
396331 {tag: "left off", x: -units.gu(5), y: units.gu(5), w: units.gu(10), h: units.gu(10)},
tests/qmltests/tst_DisabledScreenNotice.qml+23−9
@@ -32,6 +32,12 @@ Item {
3232 anchors.fill: parent
3333 anchors.rightMargin: units.gu(40)
3434
35+ // Mock some things here
36+ property int internalGu: units.gu(1)
37+ property var applicationArguments: QtObject {
38+ property string deviceName: "mako"
39+ }
40+
3541 screen: QtObject {
3642 property int orientation: {
3743 switch (orientationSelector.selectedIndex) {
@@ -52,8 +58,9 @@ Item {
5258 }
5359
5460 Column {
55− anchors.fill: parent
56− anchors.leftMargin: units.gu(40)
61+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
62+ width: units.gu(40)
63+ spacing: units.gu(1)
5764
5865 ItemSelector {
5966 id: orientationSelector
@@ -71,6 +78,20 @@ Item {
7178 Layout.fillWidth: true
7279 }
7380 }
81+ Button {
82+ text: "Reset first run settings"
83+ onClicked: {
84+ var settings = testCase.findInvisibleChild(touchScreenPad, "virtualTouchPadSettings");
85+ settings.touchpadTutorialHasRun = false;
86+ }
87+ }
88+ Button {
89+ text: "Run tutorial now"
90+ onClicked: {
91+ var touchPad = testCase.findChild(touchScreenPad, "virtualTouchPad")
92+ touchPad.runTutorial();
93+ }
94+ }
7495 }
7596
7697 UnityTestCase {
@@ -78,13 +99,6 @@ Item {
7899 name: "DisabledScreenNotice"
79100 when: windowShown
80101
81− function test_mouseAreaHidesOnFirstTap() {
82− var noticeArea = findChild(touchScreenPad, "infoNoticeArea")
83− compare(noticeArea.visible, true)
84− tap(root)
85− tryCompare(noticeArea, "visible", false)
86− }
87−
88102 function test_rotation_data() {
89103 return [
90104 {tag: "portrait", selectedOrientation: 0, expectedAngle: 0},
tests/qmltests/tst_Shell.qml+4−7
@@ -1857,14 +1857,11 @@ Rectangle {
18571857 var appRepeater = findChild(shell, "appRepeater");
18581858 var appDelegate = appRepeater.itemAt(0);
18591859
1860− var resizeArea = findChild(appDelegate, "windowResizeArea");
1861− var priv = findInvisibleChild(resizeArea, "priv");
1862−
18631860 // Make sure windows are at 0,0 or greater and they have a size that's > 0
1864− compare(priv.normalX >= 0, true)
1865− compare(priv.normalY >= 0, true)
1866− compare(priv.normalWidth > 0, true)
1867− compare(priv.normalHeight > 0, true)
1861+ compare(appDelegate.normalX >= 0, true)
1862+ compare(appDelegate.normalY >= 0, true)
1863+ compare(appDelegate.normalWidth > 0, true)
1864+ compare(appDelegate.normalHeight > 0, true)
18681865 }
18691866
18701867 // bug http://pad.lv/1431566
tests/uqmlscene/CMakeLists.txt+5−1
@@ -9,10 +9,14 @@ pkg_check_modules(XCB REQUIRED xcb)
99include_directories(
1010 ${CMAKE_CURRENT_BINARY_DIR}
1111 ${CMAKE_SOURCE_DIR}/src
12− ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
1312 ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
1413)
1514
15+include_directories(
16+ SYSTEM
17+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
18+)
19+
1620if (NOT "${XCB_INCLUDE_DIRS}" STREQUAL "")
1721 set_target_properties(uqmlscene PROPERTIES INCLUDE_DIRECTORIES ${XCB_INCLUDE_DIRS})
1822endif()
tests/utils/modules/Unity/Test/UnityTestCase.qml+4−4
@@ -163,9 +163,9 @@ TestCase {
163163 if (i === iterations - 1) {
164164 // Avoid any rounding errors by making the last move be at precisely
165165 // the point specified
166− mouseMove(item, toX, toY, iterations / speed)
166+ mouseMove(item, toX, toY, timeStep)
167167 } else {
168− mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
168+ mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, timeStep)
169169 }
170170 }
171171 if (releaseMouse) {
@@ -346,12 +346,12 @@ TestCase {
346346 if (i === iterations - 1) {
347347 // Avoid any rounding errors by making the last move be at precisely
348348 // the point specified
349− wait(iterations / speed)
349+ wait(timeStep)
350350 var event = touchEvent(item)
351351 event.move(0 /* touchId */, rootTo.x, rootTo.y)
352352 event.commit()
353353 } else {
354− wait(iterations / speed)
354+ wait(timeStep)
355355 var event = touchEvent(item)
356356 event.move(0 /* touchId */, rootFrom.x + (i + 1) * diffX, rootFrom.y + (i + 1) * diffY)
357357 event.commit()