on xenial help sign in
merge in 2202 as prereq
f49d7d0Michael Zanetti
data/com.canonical.Unity8.gschema.xml+5
@@ -48,6 +48,11 @@
48 <summary>Enable or disable the launcher</summary>
48 <summary>Enable or disable the launcher</summary>
49 <description>Toggle the availability of the launcher</description>
49 <description>Toggle the availability of the launcher</description>
50 </key>
50 </key>
51+ <key type="b" name="enable-indicator-menu">
52+ <default>true</default>
53+ <summary>Enable or disable the indicator pull down menus</summary>
54+ <description>Toggle the availability of the indicator pull down menus</description>
55+ </key>
51 </schema>
56 </schema>
52
57
53 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
58 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
debian/changelog+46
@@ -1,3 +1,49 @@
1+unity8 (8.15+17.04.20161129-0ubuntu1) zesty; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Fix PreviewProgress implicitHeight (LP: #1641943)
5+ * Adapt to dummy notification being gone
6+ * Fix autopilot test_lock_screen tests
7+ * Autopilot: Add more applications to the list for wider screens
8+ * Fix autopilot DashHelperTestCase.test_search
9+ * Also install the Screens mock
10+ * Give default value to gu-px size
11+
12+ [ Andrea Azzarone ]
13+ * Set Mir.cursorName to "grabbing" on first mouse press on a window
14+ decoration. Don't wait for press+motion. (LP: #1618078)
15+ * Do not show a divider between each quicklist entry but just between
16+ each section, similar to how unity7 does. (LP: #1637478)
17+
18+ [ Andrea Cimitan ]
19+ * Fix white text (LP: #1644468)
20+ * Make MascotLoader in CardCreator flat
21+ * Make the remaining UbuntuShape flat
22+ * added dropshadow from panel indicators to dash page header extra
23+ panel, so there is right shadow when the extra panel is narrow
24+ * Look up for expandable template dash category flag
25+
26+ [ Brian Douglass ]
27+ * Added a setting to enable/disable the indicator dropdown menu.
28+
29+ [ Daniel d'Andrada ]
30+ * There's no need for WindowDecoration to access the appDelegate
31+
32+ [ Lukáš Tinkl ]
33+ * Enable brightness (laptop backlight) handling on desktop/laptop PCs
34+ (LP: #1595947)
35+
36+ [ Michael Zanetti ]
37+ * disable spread interaction while locked (LP: #1641578)
38+
39+ [ Andrea Azzarone, Michał Sawicz ]
40+ * Implement launcher tooltips.
41+
42+ [ Olivier Tilloy ]
43+ * Remove dependency on transitional package. (LP: #1583079)
44+
45+ -- Michał Sawicz <michal.sawicz@canonical.com> Tue, 29 Nov 2016 09:43:33 +0000
46+
1unity8 (8.15+17.04.20161116.1-0ubuntu1) zesty; urgency=medium
47unity8 (8.15+17.04.20161116.1-0ubuntu1) zesty; urgency=medium
2
48
3 [ Marco Trevisan (Treviño) ]
49 [ Marco Trevisan (Treviño) ]
debian/control+2−1
@@ -50,6 +50,7 @@ Build-Depends: cmake,
50 python3-setuptools,
50 python3-setuptools,
51 qml-module-qt-labs-folderlistmodel,
51 qml-module-qt-labs-folderlistmodel,
52 qml-module-qt-labs-settings,
52 qml-module-qt-labs-settings,
53+ qml-module-qtqml-statemachine,
53 qml-module-qtmultimedia (>= 5.4.1-1ubuntu19~overlay2),
54 qml-module-qtmultimedia (>= 5.4.1-1ubuntu19~overlay2),
54 qml-module-qtquick-layouts,
55 qml-module-qtquick-layouts,
55 qml-module-qtquick-xmllistmodel,
56 qml-module-qtquick-xmllistmodel,
@@ -123,12 +124,12 @@ Depends: dmz-cursor-theme,
123 qml-module-biometryd,
124 qml-module-biometryd,
124 qml-module-qt-labs-folderlistmodel,
125 qml-module-qt-labs-folderlistmodel,
125 qml-module-qt-labs-settings,
126 qml-module-qt-labs-settings,
127+ qml-module-qtqml-statemachine,
126 qml-module-qtquick-xmllistmodel,
128 qml-module-qtquick-xmllistmodel,
127 qml-module-qtsysteminfo,
129 qml-module-qtsysteminfo,
128 qml-module-ubuntu-web,
130 qml-module-ubuntu-web,
129 qtdeclarative5-qtmir-plugin (>= 0.4.8),
131 qtdeclarative5-qtmir-plugin (>= 0.4.8),
130 qtdeclarative5-ubuntu-telephony0.1,
132 qtdeclarative5-ubuntu-telephony0.1,
131− qtdeclarative5-ubuntu-web-plugin,
132 ubuntu-system-settings (>= 0.4),
133 ubuntu-system-settings (>= 0.4),
133 unity-launcher-impl-10,
134 unity-launcher-impl-10,
134 unity8-common (= ${source:Version}),
135 unity8-common (= ${source:Version}),
plugins/Dash/CardCreator.js+1−1
@@ -269,7 +269,7 @@ var kMascotShapeLoaderCode = 'Loader { \n\
269 visible: showHeader && active && status === Loader.Ready; \n\
269 visible: showHeader && active && status === Loader.Ready; \n\
270 width: units.gu(6); \n\
270 width: units.gu(6); \n\
271 height: units.gu(5.625); \n\
271 height: units.gu(5.625); \n\
272− sourceComponent: UbuntuShape { image: mascotImage } \n\
272+ sourceComponent: UbuntuShape { aspect: UbuntuShape.Flat; image: mascotImage } \n\
273 anchors { %1 } \n\
273 anchors { %1 } \n\
274 }\n';
274 }\n';
275
275
plugins/Unity/Indicators/indicatorsmanager.cpp+1−4
@@ -282,13 +282,10 @@ Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
282 // convergence:
282 // convergence:
283 // 1) enable session indicator
283 // 1) enable session indicator
284 // 2) enable keyboard indicator
284 // 2) enable keyboard indicator
285− // 3) on a PC, switch the battery/power indicator to desktop mode,
286− // can't control brightness for now and phone-on-desktop broken (FIXME)
287 //
285 //
288 // The rest of the indicators respect their default profile (which is "phone", even on desktop PCs)
286 // The rest of the indicators respect their default profile (which is "phone", even on desktop PCs)
289 if ((new_indicator->identifier() == QStringLiteral("indicator-session"))
287 if ((new_indicator->identifier() == QStringLiteral("indicator-session"))
290− || new_indicator->identifier() == QStringLiteral("indicator-keyboard")
288+ || new_indicator->identifier() == QStringLiteral("indicator-keyboard")) {
291− || (new_indicator->identifier() == QStringLiteral("indicator-power") && m_platform.isPC())) {
292 new_indicator->setProfile(QString(m_profile).replace(QStringLiteral("phone"), QStringLiteral("desktop")));
289 new_indicator->setProfile(QString(m_profile).replace(QStringLiteral("phone"), QStringLiteral("desktop")));
293 } else {
290 } else {
294 new_indicator->setProfile(m_profile);
291 new_indicator->setProfile(m_profile);
plugins/Unity/Launcher/launcheritem.cpp+1
@@ -42,6 +42,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
42 QuickListEntry nameAction;
42 QuickListEntry nameAction;
43 nameAction.setActionId(QStringLiteral("launch_item"));
43 nameAction.setActionId(QStringLiteral("launch_item"));
44 nameAction.setText(m_name);
44 nameAction.setText(m_name);
45+ nameAction.setHasSeparator(true);
45 m_quickList->appendAction(nameAction);
46 m_quickList->appendAction(nameAction);
46
47
47 QuickListEntry pinningAction;
48 QuickListEntry pinningAction;
plugins/Unity/Launcher/quicklistentry.cpp+11
@@ -19,6 +19,7 @@
19#include "quicklistentry.h"
19#include "quicklistentry.h"
20
20
21QuickListEntry::QuickListEntry()
21QuickListEntry::QuickListEntry()
22+ : m_hasSeparator(false)
22{
23{
23}
24}
24
25
@@ -57,6 +58,16 @@ bool QuickListEntry::clickable() const
57 return !m_actionId.isEmpty();
58 return !m_actionId.isEmpty();
58}
59}
59
60
61+void QuickListEntry::setHasSeparator(bool hasSeparator)
62+{
63+ m_hasSeparator = hasSeparator;
64+}
65+
66+bool QuickListEntry::hasSeparator() const
67+{
68+ return m_hasSeparator;
69+}
70+
60bool QuickListEntry::operator==(const QuickListEntry &other)
71bool QuickListEntry::operator==(const QuickListEntry &other)
61{
72{
62 return !other.actionId().isEmpty() && other.actionId() == m_actionId;
73 return !other.actionId().isEmpty() && other.actionId() == m_actionId;
plugins/Unity/Launcher/quicklistentry.h+4
@@ -37,12 +37,16 @@ public:
37
37
38 bool clickable() const;
38 bool clickable() const;
39
39
40+ void setHasSeparator(bool hasSeparator);
41+ bool hasSeparator() const;
42+
40 bool operator==(const QuickListEntry & other);
43 bool operator==(const QuickListEntry & other);
41
44
42private:
45private:
43 QString m_actionId;
46 QString m_actionId;
44 QString m_text;
47 QString m_text;
45 QString m_icon;
48 QString m_icon;
49+ bool m_hasSeparator;
46};
50};
47
51
48#endif // QUICKLISTENTRY
52#endif // QUICKLISTENTRY
plugins/Unity/Launcher/quicklistmodel.cpp+2
@@ -79,6 +79,8 @@ QVariant QuickListModel::data(const QModelIndex &index, int role) const
79 return m_list.at(index.row()).icon();
79 return m_list.at(index.row()).icon();
80 case RoleClickable:
80 case RoleClickable:
81 return m_list.at(index.row()).clickable();
81 return m_list.at(index.row()).clickable();
82+ case RoleHasSeparator:
83+ return m_list.at(index.row()).hasSeparator();
82 }
84 }
83 return QVariant();
85 return QVariant();
84}
86}
po/unity8.pot+10−10
@@ -8,7 +8,7 @@ msgid ""
8msgstr ""
8msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"
10"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2016-11-16 10:44+0000\n"
11+"POT-Creation-Date: 2016-11-29 09:43+0000\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -22,16 +22,16 @@ msgstr ""
22msgid "Password: "
22msgid "Password: "
23msgstr ""
23msgstr ""
24
24
25−#: plugins/Unity/Launcher/launcheritem.cpp:49
25+#: plugins/Unity/Launcher/launcheritem.cpp:50
26−#: plugins/Unity/Launcher/launcheritem.cpp:108
26+#: plugins/Unity/Launcher/launcheritem.cpp:109
27msgid "Pin shortcut"
27msgid "Pin shortcut"
28msgstr ""
28msgstr ""
29
29
30−#: plugins/Unity/Launcher/launcheritem.cpp:54
30+#: plugins/Unity/Launcher/launcheritem.cpp:55
31msgid "Quit"
31msgid "Quit"
32msgstr ""
32msgstr ""
33
33
34−#: plugins/Unity/Launcher/launcheritem.cpp:108
34+#: plugins/Unity/Launcher/launcheritem.cpp:109
35msgid "Unpin shortcut"
35msgid "Unpin shortcut"
36msgstr ""
36msgstr ""
37
37
@@ -342,24 +342,24 @@ msgstr ""
342msgid "Reset"
342msgid "Reset"
343msgstr ""
343msgstr ""
344
344
345−#: qml/Dash/GenericScopeView.qml:545 qml/Dash/GenericScopeView.qml:716
345+#: qml/Dash/GenericScopeView.qml:547 qml/Dash/GenericScopeView.qml:718
346msgid "Show less"
346msgid "Show less"
347msgstr ""
347msgstr ""
348
348
349−#: qml/Dash/GenericScopeView.qml:545
349+#: qml/Dash/GenericScopeView.qml:547
350msgid "Show all"
350msgid "Show all"
351msgstr ""
351msgstr ""
352
352
353−#: qml/Dash/GenericScopeView.qml:576
353+#: qml/Dash/GenericScopeView.qml:578
354msgctxt "Label: Hint for dash search line edit"
354msgctxt "Label: Hint for dash search line edit"
355msgid "Search"
355msgid "Search"
356msgstr ""
356msgstr ""
357
357
358−#: qml/Dash/PageHeaderExtraPanel.qml:57
358+#: qml/Dash/PageHeaderExtraPanel.qml:67
359msgid "Recent Searches"
359msgid "Recent Searches"
360msgstr ""
360msgstr ""
361
361
362−#: qml/Dash/PageHeaderExtraPanel.qml:68
362+#: qml/Dash/PageHeaderExtraPanel.qml:78
363msgid "Clear All"
363msgid "Clear All"
364msgstr ""
364msgstr ""
365
365
qml/Components/BrightnessControl.qmlnew file+54
@@ -0,0 +1,54 @@
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 QMenuModel 0.1
20+import GlobalShortcut 1.0
21+
22+QtObject {
23+ objectName: "brightnessControl"
24+
25+ property GlobalShortcut brightnessUp: GlobalShortcut {
26+ shortcut: Qt.Key_MonBrightnessUp
27+ onTriggered: stepUp();
28+ }
29+
30+ property GlobalShortcut brightnessDown: GlobalShortcut {
31+ shortcut: Qt.Key_MonBrightnessDown
32+ onTriggered: stepDown();
33+ }
34+
35+ function stepUp() {
36+ actionGroup.brightness.updateState(MathUtils.clamp(actionGroup.brightness.state + 0.1, 0.01, 1.0));
37+ }
38+
39+ function stepDown() {
40+ actionGroup.brightness.updateState(MathUtils.clamp(actionGroup.brightness.state - 0.1, 0.01, 1.0));
41+ }
42+
43+ property QDBusActionGroup actionGroup: QDBusActionGroup {
44+ busType: DBus.SessionBus
45+ busName: "com.canonical.indicator.power"
46+ objectPath: "/com/canonical/indicator/power"
47+
48+ property variant brightness: action("brightness")
49+
50+ Component.onCompleted: {
51+ actionGroup.start();
52+ }
53+ }
54+}
qml/Components/LazyImage.qml+2
@@ -57,6 +57,7 @@ Item {
57 active: useUbuntuShape
57 active: useUbuntuShape
58 visible: opacity != 0
58 visible: opacity != 0
59 sourceComponent: UbuntuShape {
59 sourceComponent: UbuntuShape {
60+ aspect: UbuntuShape.Flat
60 backgroundColor: "#22FFFFFF"
61 backgroundColor: "#22FFFFFF"
61 }
62 }
62
63
@@ -92,6 +93,7 @@ Item {
92 visible: opacity != 0
93 visible: opacity != 0
93 sourceComponent: UbuntuShapeOverlay {
94 sourceComponent: UbuntuShapeOverlay {
94 property bool pressed: false
95 property bool pressed: false
96+ aspect: UbuntuShape.Flat
95 overlayColor: Qt.rgba(0, 0, 0, pressed ? 0.1 : 0)
97 overlayColor: Qt.rgba(0, 0, 0, pressed ? 0.1 : 0)
96 overlayRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
98 overlayRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
97 }
99 }
qml/Dash/DashPageHeader.qml+1−1
@@ -26,7 +26,6 @@ Item {
26 objectName: "pageHeader"
26 objectName: "pageHeader"
27 implicitHeight: headerContainer.height + signatureLineHeight
27 implicitHeight: headerContainer.height + signatureLineHeight
28 readonly property real signatureLineHeight: showSignatureLine ? units.gu(2.5) : headerBottomLine.height
28 readonly property real signatureLineHeight: showSignatureLine ? units.gu(2.5) : headerBottomLine.height
29− readonly property real headerDividerLuminance: Style.luminance(bottomBorder.color)
30
29
31 property int activeFiltersCount: 0
30 property int activeFiltersCount: 0
32 property bool scopeHasFilters: false
31 property bool scopeHasFilters: false
@@ -185,6 +184,7 @@ Item {
185
184
186 Column {
185 Column {
187 id: headersColumn
186 id: headersColumn
187+ objectName: "headersColumn"
188 anchors {
188 anchors {
189 left: parent.left
189 left: parent.left
190 right: parent.right
190 right: parent.right
qml/Dash/GenericScopeView.qml+4−2
@@ -243,8 +243,10 @@ FocusScope {
243
243
244 property Item seeAllButton: seeAll
244 property Item seeAllButton: seeAll
245
245
246+ readonly property bool forceNotExpandable: cardTool.template && cardTool.template["expandable"] === false
246 readonly property bool expandable: {
247 readonly property bool expandable: {
247 if (categoryView.model.count === 1) return false;
248 if (categoryView.model.count === 1) return false;
249+ if (forceNotExpandable) return false;
248 if (cardTool.template && cardTool.template["collapsed-rows"] === 0) return false;
250 if (cardTool.template && cardTool.template["collapsed-rows"] === 0) return false;
249 if (item && item.expandedHeight > item.collapsedHeight) return true;
251 if (item && item.expandedHeight > item.collapsedHeight) return true;
250 return false;
252 return false;
@@ -317,7 +319,7 @@ FocusScope {
317 }
319 }
318 }
320 }
319
321
320− readonly property bool expanded: baseItem.expanded || !baseItem.expandable
322+ readonly property bool expanded: !baseItem.forceNotExpandable && (baseItem.expanded || !baseItem.expandable)
321 height: expanded ? item.expandedHeight : item.collapsedHeight
323 height: expanded ? item.expandedHeight : item.collapsedHeight
322
324
323 source: {
325 source: {
@@ -657,7 +659,7 @@ FocusScope {
657 target: categoryView
659 target: categoryView
658
660
659 readonly property real contentY: categoryView.contentY - categoryView.originY
661 readonly property real contentY: categoryView.contentY - categoryView.originY
660− readonly property real headerDividerLuminance: categoryView.pageHeader.headerDividerLuminance
662+ readonly property color pullLabelColor: scopeStyle ? scopeStyle.foreground : theme.palette.normal.baseText
661 y: -contentY - units.gu(5)
663 y: -contentY - units.gu(5)
662
664
663 onRefresh: {
665 onRefresh: {
qml/Dash/PageHeaderExtraPanel.qml+10−11
@@ -43,6 +43,16 @@ Item {
43 dashNavigation.resetNavigation();
43 dashNavigation.resetNavigation();
44 }
44 }
45
45
46+ BorderImage {
47+ anchors {
48+ fill: parent
49+ leftMargin: -units.gu(1)
50+ rightMargin: -units.gu(1)
51+ bottomMargin: -units.gu(1)
52+ }
53+ source: "graphics/rectangular_dropshadow.sci"
54+ }
55+
46 Rectangle {
56 Rectangle {
47 color: "white"
57 color: "white"
48 anchors.fill: parent
58 anchors.fill: parent
@@ -188,15 +198,4 @@ Item {
188 onSingleSelectionFilterSelected: extraPanelOptionSelected()
198 onSingleSelectionFilterSelected: extraPanelOptionSelected()
189 }
199 }
190 }
200 }
191−
192− // This is outside the item
193− Image {
194− anchors {
195− top: parent.bottom
196− left: parent.left
197− right: parent.right
198− }
199− fillMode: Image.Stretch
200− source: "graphics/navigation_shadow.png"
201− }
202}
201}
qml/Dash/Previews/PreviewProgress.qml+1−1
@@ -28,7 +28,7 @@ import Ubuntu.DownloadDaemonListener 0.1
28PreviewWidget {
28PreviewWidget {
29 id: root
29 id: root
30
30
31− implicitHeight: progressBar.implicitHeight
31+ implicitHeight: progressBar.height
32 implicitWidth: progressBar.implicitWidth
32 implicitWidth: progressBar.implicitWidth
33
33
34 ProgressBar {
34 ProgressBar {
qml/Dash/PullToRefreshScopeStyle.qml+1−1
@@ -48,7 +48,7 @@ PullToRefreshStyle {
48 anchors.horizontalCenter: parent.horizontalCenter
48 anchors.horizontalCenter: parent.horizontalCenter
49 horizontalAlignment: Text.AlignHCenter
49 horizontalAlignment: Text.AlignHCenter
50 verticalAlignment: Text.AlignVCenter
50 verticalAlignment: Text.AlignVCenter
51− color: styledItem.headerDividerLuminance < 0.3 ? UbuntuColors.porcelain : UbuntuColors.jet
51+ color: styledItem.pullLabelColor
52 states: [
52 states: [
53 State {
53 State {
54 name: "pulling"
54 name: "pulling"
qml/Dash/ScopesListCategoryItem.qml+1
@@ -49,6 +49,7 @@ AbstractButton {
49 width: units.gu(5)
49 width: units.gu(5)
50 height: units.gu(5)
50 height: units.gu(5)
51 visible: !hideChildren
51 visible: !hideChildren
52+ aspect: UbuntuShape.Flat
52 sourceFillMode: UbuntuShape.PreserveAspectCrop
53 sourceFillMode: UbuntuShape.PreserveAspectCrop
53 source: Image {
54 source: Image {
54 id: shapeImage
55 id: shapeImage
qml/Dash/graphics/navigation_shadow@18.pngdeleted

Binary file not shown.

qml/Dash/graphics/navigation_shadow_light@18.pngdeleted

Binary file not shown.

qml/Dash/graphics/rectangular_dropshadow@30.pngnew file

Binary file not shown.

qml/Dash/graphics/rectangular_dropshadow@30.scinew file+5
@@ -0,0 +1,5 @@
1+border.left: 30
2+border.top: 30
3+border.bottom: 30
4+border.right: 30
5+source: rectangular_dropshadow@30.png
qml/Launcher/LauncherDelegate.qml+1
@@ -22,6 +22,7 @@ Item {
22
22
23 property int itemIndex: 0
23 property int itemIndex: 0
24 property string iconName
24 property string iconName
25+ property string name
25 property int count: 0
26 property int count: 0
26 property bool countVisible: false
27 property bool countVisible: false
27 property int progress: -1
28 property int progress: -1
qml/Launcher/LauncherPanel.qml+80−3
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18+import QtQml.StateMachine 1.0 as DSM
18import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
19import Unity.Launcher 0.1
20import Unity.Launcher 0.1
20import Ubuntu.Components.Popups 1.3
21import Ubuntu.Components.Popups 1.3
@@ -31,7 +32,7 @@ Rectangle {
31 property bool dragging: false
32 property bool dragging: false
32 property bool moving: launcherListView.moving || launcherListView.flicking
33 property bool moving: launcherListView.moving || launcherListView.flicking
33 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
34 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
34− || mouseEventEater.containsMouse || dashItem.hovered
35+ || dndArea.containsMouse || dashItem.hovered
35 property int highlightIndex: -2
36 property int highlightIndex: -2
36 property bool shortcutHintsShown: false
37 property bool shortcutHintsShown: false
37
38
@@ -40,7 +41,7 @@ Rectangle {
40 signal kbdNavigationCancelled()
41 signal kbdNavigationCancelled()
41
42
42 onXChanged: {
43 onXChanged: {
43− if (quickList.state == "open") {
44+ if (quickList.state === "open") {
44 quickList.state = ""
45 quickList.state = ""
45 }
46 }
46 }
47 }
@@ -69,7 +70,6 @@ Rectangle {
69 id: mouseEventEater
70 id: mouseEventEater
70 anchors.fill: parent
71 anchors.fill: parent
71 acceptedButtons: Qt.AllButtons
72 acceptedButtons: Qt.AllButtons
72− hoverEnabled: true
73 onWheel: wheel.accepted = true;
73 onWheel: wheel.accepted = true;
74 }
74 }
75
75
@@ -225,6 +225,7 @@ Rectangle {
225 // the right app when running autopilot tests for
225 // the right app when running autopilot tests for
226 // multiple apps.
226 // multiple apps.
227 readonly property string appId: model.appId
227 readonly property string appId: model.appId
228+ name: model.name
228 itemIndex: index
229 itemIndex: index
229 itemHeight: launcherListView.itemHeight
230 itemHeight: launcherListView.itemHeight
230 itemWidth: launcherListView.itemWidth
231 itemWidth: launcherListView.itemWidth
@@ -399,6 +400,7 @@ Rectangle {
399 id: dndArea
400 id: dndArea
400 objectName: "dndArea"
401 objectName: "dndArea"
401 acceptedButtons: Qt.LeftButton | Qt.RightButton
402 acceptedButtons: Qt.LeftButton | Qt.RightButton
403+ hoverEnabled: true
402 anchors {
404 anchors {
403 fill: parent
405 fill: parent
404 topMargin: launcherListView.topMargin
406 topMargin: launcherListView.topMargin
@@ -795,6 +797,7 @@ Rectangle {
795 highlightColor: !model.clickable ? quickList.color : undefined // make disabled items visually unclickable
797 highlightColor: !model.clickable ? quickList.color : undefined // make disabled items visually unclickable
796 divider.colorFrom: UbuntuColors.inkstone
798 divider.colorFrom: UbuntuColors.inkstone
797 divider.colorTo: UbuntuColors.inkstone
799 divider.colorTo: UbuntuColors.inkstone
800+ divider.visible: model.hasSeparator
798
801
799 Label {
802 Label {
800 id: label
803 id: label
@@ -828,4 +831,78 @@ Rectangle {
828 }
831 }
829 }
832 }
830 }
833 }
834+
835+ Tooltip {
836+ id: tooltipShape
837+ objectName: "tooltipShape"
838+
839+ visible: tooltipShownState.active
840+ rotation: root.rotation
841+ y: itemCenter - (height / 2)
842+
843+ anchors {
844+ left: root.inverted ? undefined : parent.right
845+ right: root.inverted ? parent.left : undefined
846+ margins: units.gu(1)
847+ }
848+
849+ readonly property var hoveredItem: dndArea.containsMouse ? launcherListView.itemAt(dndArea.mouseX, dndArea.mouseY + launcherListView.realContentY) : null
850+ readonly property int itemCenter: !hoveredItem ? 0 : root.mapFromItem(hoveredItem, 0, 0).y + (hoveredItem.height / 2) + hoveredItem.offset
851+
852+ text: !hoveredItem ? "" : hoveredItem.name
853+ }
854+
855+ DSM.StateMachine {
856+ id: tooltipStateMachine
857+ initialState: tooltipHiddenState
858+ running: true
859+
860+ DSM.State {
861+ id: tooltipHiddenState
862+
863+ DSM.SignalTransition {
864+ targetState: tooltipShownState
865+ signal: tooltipShape.hoveredItemChanged
866+ // !dndArea.pressed allows us to filter out touch input events
867+ guard: tooltipShape.hoveredItem !== null && !dndArea.pressed && !root.moving
868+ }
869+ }
870+
871+ DSM.State {
872+ id: tooltipShownState
873+
874+ DSM.SignalTransition {
875+ targetState: tooltipHiddenState
876+ signal: tooltipShape.hoveredItemChanged
877+ guard: tooltipShape.hoveredItem === null
878+ }
879+
880+ DSM.SignalTransition {
881+ targetState: tooltipDismissedState
882+ signal: dndArea.onPressed
883+ }
884+
885+ DSM.SignalTransition {
886+ targetState: tooltipDismissedState
887+ signal: quickList.stateChanged
888+ guard: quickList.state === "open"
889+ }
890+ }
891+
892+ DSM.State {
893+ id: tooltipDismissedState
894+
895+ DSM.SignalTransition {
896+ targetState: tooltipHiddenState
897+ signal: dndArea.positionChanged
898+ guard: quickList.state != "open" && !dndArea.pressed && !dndArea.moving
899+ }
900+
901+ DSM.SignalTransition {
902+ targetState: tooltipHiddenState
903+ signal: dndArea.exited
904+ guard: quickList.state != "open"
905+ }
906+ }
907+ }
831}
908}
qml/Launcher/Tooltip.qmlnew file+72
@@ -0,0 +1,72 @@
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+
20+UbuntuShape {
21+ id: root
22+
23+ // This property holds the delay (milliseconds) after which the tool tip is shown.
24+ // A tooltip with a negative delay is shown immediately. The default value is 500 ms.
25+ property int delay: 500
26+
27+ // This property holds the text shown on the tool tip.
28+ property alias text: label.text
29+
30+ aspect: UbuntuShape.Flat
31+ color: theme.palette.normal.background
32+ width: label.implicitWidth + units.gu(4)
33+ height: label.implicitHeight + units.gu(2)
34+ opacity: 0
35+
36+ Image {
37+ anchors {
38+ right: parent.left
39+ rightMargin: -units.dp(4)
40+ verticalCenter: parent.verticalCenter
41+ }
42+ source: "graphics/quicklist_tooltip.png"
43+ rotation: 90
44+ }
45+
46+ Label {
47+ id: label
48+ anchors.centerIn: parent
49+ color: theme.palette.normal.backgroundText
50+ }
51+
52+ states: [
53+ State {
54+ name: "visible"
55+ when: root.visible
56+ PropertyChanges {
57+ target: root
58+ opacity: 0.95
59+ }
60+ }
61+ ]
62+
63+ transitions: [
64+ Transition {
65+ from: ""; to: "visible"
66+ SequentialAnimation {
67+ PauseAnimation { duration: root.delay }
68+ UbuntuNumberAnimation { target: root; property: "opacity"; duration: UbuntuAnimation.BriskDuration }
69+ }
70+ }
71+ ]
72+}
qml/Shell.qml+3−3
@@ -307,8 +307,6 @@ StyledItem {
307 suspended: greeter.shown
307 suspended: greeter.shown
308 altTabPressed: physicalKeysMapper.altTabPressed
308 altTabPressed: physicalKeysMapper.altTabPressed
309 oskEnabled: shell.oskEnabled
309 oskEnabled: shell.oskEnabled
310−
311− // TODO: This is not implemented yet in the new stage...
312 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
310 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
313 }
311 }
314 }
312 }
@@ -447,6 +445,7 @@ StyledItem {
447 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
445 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
448 && (!greeter || !greeter.hasLockedApp)
446 && (!greeter || !greeter.hasLockedApp)
449 && !shell.waitingOnGreeter
447 && !shell.waitingOnGreeter
448+ && settings.enableIndicatorMenu
450 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
449 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
451
450
452 minimizedPanelHeight: units.gu(3)
451 minimizedPanelHeight: units.gu(3)
@@ -762,8 +761,9 @@ StyledItem {
762 Behavior on opacity { UbuntuNumberAnimation {} }
761 Behavior on opacity { UbuntuNumberAnimation {} }
763 }
762 }
764
763
765− // non-visual object
764+ // non-visual objects
766 KeymapSwitcher {}
765 KeymapSwitcher {}
766+ BrightnessControl {}
767
767
768 Rectangle {
768 Rectangle {
769 id: shutdownFadeOutRectangle
769 id: shutdownFadeOutRectangle
qml/Stage/DecoratedWindow.qml+1−1
@@ -149,7 +149,7 @@ FocusScope {
149
149
150 WindowDecoration {
150 WindowDecoration {
151 id: decoration
151 id: decoration
152− target: root.parent || null
152+ closeButtonVisible: root.application.appId !== "unity8-dash"
153 objectName: "appWindowDecoration"
153 objectName: "appWindowDecoration"
154 anchors { left: parent.left; top: parent.top; right: parent.right }
154 anchors { left: parent.left; top: parent.top; right: parent.right }
155 height: units.gu(3)
155 height: units.gu(3)
qml/Stage/MoveHandler.qml+8
@@ -54,6 +54,11 @@ QtObject {
54 property bool nearBottomLeftCorner: target.maximizedBottomLeft
54 property bool nearBottomLeftCorner: target.maximizedBottomLeft
55 property bool nearBottomRightCorner: target.maximizedBottomRight
55 property bool nearBottomRightCorner: target.maximizedBottomRight
56
56
57+ property Timer mouseDownTimer: Timer {
58+ interval: 175
59+ onTriggered: Mir.cursorName = "grabbing"
60+ }
61+
57 function resetEdges() {
62 function resetEdges() {
58 nearLeftEdge = false;
63 nearLeftEdge = false;
59 nearRightEdge = false;
64 nearRightEdge = false;
@@ -93,14 +98,17 @@ QtObject {
93 }
98 }
94
99
95 priv.dragging = true;
100 priv.dragging = true;
101+ priv.mouseDownTimer.start();
96 } else {
102 } else {
97 priv.dragging = false;
103 priv.dragging = false;
104+ priv.mouseDownTimer.stop();
98 Mir.cursorName = "";
105 Mir.cursorName = "";
99 }
106 }
100 }
107 }
101
108
102 function handlePositionChanged(mouse, sensingPoints) {
109 function handlePositionChanged(mouse, sensingPoints) {
103 if (priv.dragging) {
110 if (priv.dragging) {
111+ priv.mouseDownTimer.stop();
104 Mir.cursorName = "grabbing";
112 Mir.cursorName = "grabbing";
105
113
106 // restore from maximized when dragging away from edges/corners; guard against inadvertent changes when going into maximized state
114 // restore from maximized when dragging away from edges/corners; guard against inadvertent changes when going into maximized state
qml/Stage/Stage.qml+23−5
@@ -90,7 +90,9 @@ FocusScope {
90
90
91 onAltTabPressedChanged: {
91 onAltTabPressedChanged: {
92 if (altTabPressed) {
92 if (altTabPressed) {
93+ if (root.spreadEnabled) {
93− altTabDelayTimer.start();
94+ altTabDelayTimer.start();
95+ }
94 } else {
96 } else {
95 // Alt Tab has been released, did we already go to spread?
97 // Alt Tab has been released, did we already go to spread?
96 if (priv.goneToSpread) {
98 if (priv.goneToSpread) {
@@ -125,7 +127,9 @@ FocusScope {
125 function updateFocusedAppOrientation() { /* TODO */ }
127 function updateFocusedAppOrientation() { /* TODO */ }
126 function updateFocusedAppOrientationAnimated() { /* TODO */}
128 function updateFocusedAppOrientationAnimated() { /* TODO */}
127 function pushRightEdge(amount) {
129 function pushRightEdge(amount) {
130+ if (root.spreadEnabled) {
128− edgeBarrier.push(amount);
131+ edgeBarrier.push(amount);
132+ }
129 }
133 }
130
134
131 function closeSpread() {
135 function closeSpread() {
@@ -166,6 +170,7 @@ FocusScope {
166 GlobalShortcut {
170 GlobalShortcut {
167 id: showSpreadShortcut
171 id: showSpreadShortcut
168 shortcut: Qt.MetaModifier|Qt.Key_W
172 shortcut: Qt.MetaModifier|Qt.Key_W
173+ active: root.spreadEnabled
169 onTriggered: priv.goneToSpread = true
174 onTriggered: priv.goneToSpread = true
170 }
175 }
171
176
@@ -1526,9 +1531,21 @@ FocusScope {
1526 onRequestedHeightChanged: oldRequestedHeight = requestedHeight
1531 onRequestedHeightChanged: oldRequestedHeight = requestedHeight
1527
1532
1528 onCloseClicked: { appDelegate.close(); }
1533 onCloseClicked: { appDelegate.close(); }
1534+ onMaximizeClicked: {
1535+ if (appDelegate.canBeMaximized) {
1529− onMaximizeClicked: appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
1536+ appDelegate.anyMaximized ? appDelegate.restoreFromMaximized() : appDelegate.maximize();
1537+ }
1538+ }
1539+ onMaximizeHorizontallyClicked: {
1540+ if (appDelegate.canBeMaximizedHorizontally) {
1530− onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
1541+ appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
1542+ }
1543+ }
1544+ onMaximizeVerticallyClicked: {
1545+ if (appDelegate.canBeMaximizedVertically) {
1531− onMaximizeVerticallyClicked: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
1546+ appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
1547+ }
1548+ }
1532 onMinimizeClicked: appDelegate.minimize()
1549 onMinimizeClicked: appDelegate.minimize()
1533 onDecorationPressed: { appDelegate.focus = true; }
1550 onDecorationPressed: { appDelegate.focus = true; }
1534 onDecorationReleased: fakeRectangle.commit();
1551 onDecorationReleased: fakeRectangle.commit();
@@ -1785,6 +1802,7 @@ FocusScope {
1785 direction: Direction.Leftwards
1802 direction: Direction.Leftwards
1786 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1803 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
1787 width: root.dragAreaWidth
1804 width: root.dragAreaWidth
1805+ enabled: root.spreadEnabled
1788
1806
1789 property var gesturePoints: []
1807 property var gesturePoints: []
1790 property bool cancelled: false
1808 property bool cancelled: false
qml/Stage/WindowDecoration.qml+4−5
@@ -22,7 +22,7 @@ MouseArea {
22 id: root
22 id: root
23 clip: true
23 clip: true
24
24
25− property Item target // appDelegate
25+ property alias closeButtonVisible: buttons.closeButtonShown
26 property alias title: titleLabel.text
26 property alias title: titleLabel.text
27 property alias maximizeButtonShown: buttons.maximizeButtonShown
27 property alias maximizeButtonShown: buttons.maximizeButtonShown
28 property bool active: false
28 property bool active: false
@@ -40,7 +40,7 @@ MouseArea {
40 signal maximizeVerticallyClicked()
40 signal maximizeVerticallyClicked()
41
41
42 onDoubleClicked: {
42 onDoubleClicked: {
43− if (target.canBeMaximized && mouse.button == Qt.LeftButton) {
43+ if (mouse.button == Qt.LeftButton) {
44 root.maximizeClicked();
44 root.maximizeClicked();
45 }
45 }
46 }
46 }
@@ -77,9 +77,8 @@ MouseArea {
77 onCloseClicked: root.closeClicked();
77 onCloseClicked: root.closeClicked();
78 onMinimizeClicked: root.minimizeClicked();
78 onMinimizeClicked: root.minimizeClicked();
79 onMaximizeClicked: root.maximizeClicked();
79 onMaximizeClicked: root.maximizeClicked();
80− onMaximizeHorizontallyClicked: if (root.target.canBeMaximizedHorizontally) root.maximizeHorizontallyClicked();
80+ onMaximizeHorizontallyClicked: root.maximizeHorizontallyClicked();
81− onMaximizeVerticallyClicked: if (root.target.canBeMaximizedVertically) root.maximizeVerticallyClicked();
81+ onMaximizeVerticallyClicked: root.maximizeVerticallyClicked();
82− closeButtonShown: root.target.appId !== "unity8-dash"
83 }
82 }
84
83
85 Label {
84 Label {
tests/autopilot/unity8/dash.py+3−3
@@ -163,9 +163,9 @@ class Dash(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
163 search_button.globalRect.x + search_button.width / 2,
163 search_button.globalRect.x + search_button.width / 2,
164 search_button.globalRect.y + search_button.height / 2)
164 search_button.globalRect.y + search_button.height / 2)
165 self.pointing_device.click()
165 self.pointing_device.click()
166− headerContainer = current_header.select_single(
166+ headersColumn = current_header.select_single(
167− objectName="headerContainer")
167+ objectName="headersColumn")
168− headerContainer.contentY.wait_for(0)
168+ headersColumn.y.wait_for(0)
169 keyboard.type(query)
169 keyboard.type(query)
170 self.select_single(
170 self.select_single(
171 objectName="processingIndicator").visible.wait_for(False)
171 objectName="processingIndicator").visible.wait_for(False)
tests/autopilot/unity8/greeter/__init__.py+1−1
@@ -94,4 +94,4 @@ class Greeter(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
94
94
95 def get_prompt(self):
95 def get_prompt(self):
96 return self.select_single(
96 return self.select_single(
97− ubuntuuitoolkit.TextField, objectName='passwordInput')
97+ ubuntuuitoolkit.TextField, objectName='promptField')
tests/autopilot/unity8/shell/__init__.py+2
@@ -25,6 +25,8 @@ from functools import wraps
25import ubuntuuitoolkit
25import ubuntuuitoolkit
26from autopilot import logging as autopilot_logging
26from autopilot import logging as autopilot_logging
27from autopilot import input
27from autopilot import input
28+import gi
29+gi.require_version('Notify', '0.7')
28from gi.repository import Notify
30from gi.repository import Notify
29
31
30from unity8 import (
32from unity8 import (
tests/autopilot/unity8/shell/tests/__init__.py+4−1
@@ -156,7 +156,10 @@ class UnityTestCase(AutopilotTestCase):
156 def _setup_grid_size(self, scale_divisor):
156 def _setup_grid_size(self, scale_divisor):
157 """Use the grid size that may be supplied or use the default."""
157 """Use the grid size that may be supplied or use the default."""
158 if getattr(self, 'grid_unit_px', 0) == 0:
158 if getattr(self, 'grid_unit_px', 0) == 0:
159+ if os.getenv('GRID_UNIT_PX') == None:
160+ self.grid_size = 8
161+ else:
159− self.grid_size = int(os.getenv('GRID_UNIT_PX'))
162+ self.grid_size = int(os.getenv('GRID_UNIT_PX'))
160 else:
163 else:
161 self.grid_size = int(self.grid_unit_px / scale_divisor)
164 self.grid_size = int(self.grid_unit_px / scale_divisor)
162 self._environment["GRID_UNIT_PX"] = str(self.grid_size)
165 self._environment["GRID_UNIT_PX"] = str(self.grid_size)
tests/autopilot/unity8/shell/tests/test_helpers.py+2−1
@@ -129,7 +129,8 @@ class DashAppsHelperTestCase(tests.DashBaseTestCase):
129 available_applications = [
129 available_applications = [
130 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
130 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
131 'Title.2.5', 'Title.2.6', 'Title.2.7', 'Title.2.8', 'Title.2.9',
131 'Title.2.5', 'Title.2.6', 'Title.2.7', 'Title.2.8', 'Title.2.9',
132− 'Title.2.10', 'Title.2.11', 'Title.2.12']
132+ 'Title.2.10', 'Title.2.11', 'Title.2.12', 'Title.2.13', 'Title.2.14',
133+ 'Title.2.15', 'Title.2.16', 'Title.2.17', 'Title.2.18']
133
134
134 def setUp(self):
135 def setUp(self):
135 # Set up the fake scopes before launching unity.
136 # Set up the fake scopes before launching unity.
tests/autopilot/unity8/shell/tests/test_notifications.py+9−9
@@ -143,7 +143,7 @@ class InteractiveNotificationBase(NotificationsBase):
143 )
143 )
144
144
145 get_notification = lambda: notify_list.wait_select_single(
145 get_notification = lambda: notify_list.wait_select_single(
146− 'Notification', objectName='notification1')
146+ 'Notification', objectName='notification0')
147 notification = get_notification()
147 notification = get_notification()
148
148
149 notification.pointing_device.click_object(
149 notification.pointing_device.click_object(
@@ -185,7 +185,7 @@ class InteractiveNotificationBase(NotificationsBase):
185 # verify and interact with the triggered snap-decision notification
185 # verify and interact with the triggered snap-decision notification
186 notify_list = self._get_notifications_list()
186 notify_list = self._get_notifications_list()
187 get_notification = lambda: notify_list.wait_select_single(
187 get_notification = lambda: notify_list.wait_select_single(
188− 'Notification', objectName='notification1')
188+ 'Notification', objectName='notification0')
189 notification = get_notification()
189 notification = get_notification()
190 self._assert_notification(
190 self._assert_notification(
191 notification, summary, body, False, False, 1.0)
191 notification, summary, body, False, False, 1.0)
@@ -234,7 +234,7 @@ class InteractiveNotificationBase(NotificationsBase):
234 # verify and interact with the triggered snap-decision notification
234 # verify and interact with the triggered snap-decision notification
235 notify_list = self._get_notifications_list()
235 notify_list = self._get_notifications_list()
236 get_notification = lambda: notify_list.wait_select_single(
236 get_notification = lambda: notify_list.wait_select_single(
237− 'Notification', objectName='notification1')
237+ 'Notification', objectName='notification0')
238 notification = get_notification()
238 notification = get_notification()
239 self._assert_notification(
239 self._assert_notification(
240 notification, summary, body, True, False, 1.0)
240 notification, summary, body, True, False, 1.0)
@@ -282,7 +282,7 @@ class InteractiveNotificationBase(NotificationsBase):
282 # verify and interact with the triggered snap-decision notification
282 # verify and interact with the triggered snap-decision notification
283 notify_list = self._get_notifications_list()
283 notify_list = self._get_notifications_list()
284 get_notification = lambda: notify_list.wait_select_single(
284 get_notification = lambda: notify_list.wait_select_single(
285− 'Notification', objectName='notification1')
285+ 'Notification', objectName='notification0')
286 notification = get_notification()
286 notification = get_notification()
287 self._assert_notification(
287 self._assert_notification(
288 notification, summary, body, True, False, 1.0)
288 notification, summary, body, True, False, 1.0)
@@ -445,7 +445,7 @@ class EphemeralNotificationsTests(NotificationsBase):
445 notification.show()
445 notification.show()
446
446
447 notification = lambda: notify_list.wait_select_single(
447 notification = lambda: notify_list.wait_select_single(
448− 'Notification', objectName='notification1')
448+ 'Notification', objectName='notification0')
449 self._assert_notification(
449 self._assert_notification(
450 notification(),
450 notification(),
451 summary,
451 summary,
@@ -478,7 +478,7 @@ class EphemeralNotificationsTests(NotificationsBase):
478 notification.show()
478 notification.show()
479
479
480 notification = lambda: notify_list.wait_select_single(
480 notification = lambda: notify_list.wait_select_single(
481− 'Notification', objectName='notification1')
481+ 'Notification', objectName='notification0')
482 self._assert_notification(
482 self._assert_notification(
483 notification(),
483 notification(),
484 summary,
484 summary,
@@ -590,7 +590,7 @@ class EphemeralNotificationsTests(NotificationsBase):
590 notification.show()
590 notification.show()
591
591
592 notification = notify_list.wait_select_single(
592 notification = notify_list.wait_select_single(
593− 'Notification', objectName='notification1')
593+ 'Notification', objectName='notification0')
594
594
595 self._assert_notification(
595 self._assert_notification(
596 notification,
596 notification,
@@ -614,7 +614,7 @@ class EphemeralNotificationsTests(NotificationsBase):
614 notification.show()
614 notification.show()
615
615
616 notification = notify_list.wait_select_single(
616 notification = notify_list.wait_select_single(
617− 'Notification', objectName='notification1')
617+ 'Notification', objectName='notification0')
618
618
619 self._assert_notification(notification, summary, '', False, False, 1.0)
619 self._assert_notification(notification, summary, '', False, False, 1.0)
620
620
@@ -683,7 +683,7 @@ class EphemeralNotificationsTests(NotificationsBase):
683 notification.show()
683 notification.show()
684
684
685 get_notification = lambda: notify_list.wait_select_single(
685 get_notification = lambda: notify_list.wait_select_single(
686− 'Notification', objectName='notification1')
686+ 'Notification', objectName='notification0')
687
687
688 self._assert_notification(
688 self._assert_notification(
689 get_notification(),
689 get_notification(),
tests/mocks/GSettings.1.0/fake_gsettings.cpp+33
@@ -28,6 +28,7 @@ GSettingsControllerQml::GSettingsControllerQml()
28 , m_launcherWidth(8)
28 , m_launcherWidth(8)
29 , m_edgeDragWidth(2)
29 , m_edgeDragWidth(2)
30 , m_enableLauncher(true)
30 , m_enableLauncher(true)
31+ , m_enableIndicatorMenu(true)
31{
32{
32}
33}
33
34
@@ -159,6 +160,19 @@ bool GSettingsControllerQml::enableLauncher() const
159 return m_enableLauncher;
160 return m_enableLauncher;
160}
161}
161
162
163+bool GSettingsControllerQml::enableIndicatorMenu() const
164+{
165+ return m_enableIndicatorMenu;
166+}
167+
168+void GSettingsControllerQml::setEnableIndicatorMenu(bool enableIndicatorMenu)
169+{
170+ if (m_enableIndicatorMenu != enableIndicatorMenu) {
171+ m_enableIndicatorMenu = enableIndicatorMenu;
172+ Q_EMIT enableIndicatorMenuChanged(enableIndicatorMenu);
173+ }
174+}
175+
162GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
176GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
163}
177}
164
178
@@ -225,6 +239,8 @@ void GSettingsQml::componentComplete()
225 this, &GSettingsQml::edgeDragWidthChanged);
239 this, &GSettingsQml::edgeDragWidthChanged);
226 connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::enableLauncherChanged,
240 connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::enableLauncherChanged,
227 this, &GSettingsQml::enableLauncherChanged);
241 this, &GSettingsQml::enableLauncherChanged);
242+ connect(GSettingsControllerQml::instance(), &GSettingsControllerQml::enableIndicatorMenuChanged,
243+ this, &GSettingsQml::enableIndicatorMenuChanged);
228
244
229 Q_EMIT disableHeightChanged();
245 Q_EMIT disableHeightChanged();
230 Q_EMIT pictureUriChanged();
246 Q_EMIT pictureUriChanged();
@@ -235,6 +251,7 @@ void GSettingsQml::componentComplete()
235 Q_EMIT launcherWidthChanged();
251 Q_EMIT launcherWidthChanged();
236 Q_EMIT edgeDragWidthChanged();
252 Q_EMIT edgeDragWidthChanged();
237 Q_EMIT enableLauncherChanged();
253 Q_EMIT enableLauncherChanged();
254+ Q_EMIT enableIndicatorMenuChanged();
238}
255}
239
256
240GSettingsSchemaQml * GSettingsQml::schema() const {
257GSettingsSchemaQml * GSettingsQml::schema() const {
@@ -350,6 +367,15 @@ QVariant GSettingsQml::enableLauncher() const
350 }
367 }
351}
368}
352
369
370+QVariant GSettingsQml::enableIndicatorMenu() const
371+{
372+ if (m_valid && m_schema->id() == "com.canonical.Unity8") {
373+ return GSettingsControllerQml::instance()->enableIndicatorMenu();
374+ } else {
375+ return QVariant();
376+ }
377+}
378+
353void GSettingsQml::setLifecycleExemptAppids(const QVariant &appIds)
379void GSettingsQml::setLifecycleExemptAppids(const QVariant &appIds)
354{
380{
355 if (m_valid && m_schema->id() == "com.canonical.qtmir") {
381 if (m_valid && m_schema->id() == "com.canonical.qtmir") {
@@ -384,3 +410,10 @@ void GSettingsQml::setEnableLauncher(const QVariant &enableLauncher)
384 GSettingsControllerQml::instance()->setEnableLauncher(enableLauncher.toBool());
410 GSettingsControllerQml::instance()->setEnableLauncher(enableLauncher.toBool());
385 }
411 }
386}
412}
413+
414+void GSettingsQml::setEnableIndicatorMenu(const QVariant &enableIndicatorMenu)
415+{
416+ if (m_valid && m_schema->id() == "com.canonical.Unity8") {
417+ GSettingsControllerQml::instance()->setEnableIndicatorMenu(enableIndicatorMenu.toBool());
418+ }
419+}
tests/mocks/GSettings.1.0/fake_gsettings.h+9
@@ -58,6 +58,7 @@ class GSettingsQml: public QObject, public QQmlParserStatus
58 Q_PROPERTY(QVariant launcherWidth READ launcherWidth WRITE setLauncherWidth NOTIFY launcherWidthChanged)
58 Q_PROPERTY(QVariant launcherWidth READ launcherWidth WRITE setLauncherWidth NOTIFY launcherWidthChanged)
59 Q_PROPERTY(QVariant edgeDragWidth READ edgeDragWidth WRITE setEdgeDragWidth NOTIFY edgeDragWidthChanged)
59 Q_PROPERTY(QVariant edgeDragWidth READ edgeDragWidth WRITE setEdgeDragWidth NOTIFY edgeDragWidthChanged)
60 Q_PROPERTY(QVariant enableLauncher READ enableLauncher WRITE setEnableLauncher NOTIFY enableLauncherChanged)
60 Q_PROPERTY(QVariant enableLauncher READ enableLauncher WRITE setEnableLauncher NOTIFY enableLauncherChanged)
61+ Q_PROPERTY(QVariant enableIndicatorMenu READ enableIndicatorMenu WRITE setEnableIndicatorMenu NOTIFY enableIndicatorMenuChanged)
61
62
62public:
63public:
63 GSettingsQml(QObject *parent = nullptr);
64 GSettingsQml(QObject *parent = nullptr);
@@ -75,6 +76,7 @@ public:
75 QVariant launcherWidth() const;
76 QVariant launcherWidth() const;
76 QVariant edgeDragWidth() const;
77 QVariant edgeDragWidth() const;
77 QVariant enableLauncher() const;
78 QVariant enableLauncher() const;
79+ QVariant enableIndicatorMenu() const;
78
80
79 void setDisableHeight(const QVariant &val);
81 void setDisableHeight(const QVariant &val);
80 void setPictureUri(const QVariant &str);
82 void setPictureUri(const QVariant &str);
@@ -85,6 +87,7 @@ public:
85 void setLauncherWidth(const QVariant &launcherWidth);
87 void setLauncherWidth(const QVariant &launcherWidth);
86 void setEdgeDragWidth(const QVariant &edgeDragWidth);
88 void setEdgeDragWidth(const QVariant &edgeDragWidth);
87 void setEnableLauncher(const QVariant &enableLauncher);
89 void setEnableLauncher(const QVariant &enableLauncher);
90+ void setEnableIndicatorMenu(const QVariant &enableIndicatorMenu);
88
91
89Q_SIGNALS:
92Q_SIGNALS:
90 void disableHeightChanged();
93 void disableHeightChanged();
@@ -97,6 +100,7 @@ Q_SIGNALS:
97 void launcherWidthChanged();
100 void launcherWidthChanged();
98 void edgeDragWidthChanged();
101 void edgeDragWidthChanged();
99 void enableLauncherChanged();
102 void enableLauncherChanged();
103+ void enableIndicatorMenuChanged();
100
104
101private:
105private:
102 GSettingsSchemaQml* m_schema;
106 GSettingsSchemaQml* m_schema;
@@ -140,6 +144,9 @@ public:
140 bool enableLauncher() const;
144 bool enableLauncher() const;
141 Q_INVOKABLE void setEnableLauncher(bool enableLauncher);
145 Q_INVOKABLE void setEnableLauncher(bool enableLauncher);
142
146
147+ bool enableIndicatorMenu() const;
148+ Q_INVOKABLE void setEnableIndicatorMenu(bool enableIndicatorMenu);
149+
143Q_SIGNALS:
150Q_SIGNALS:
144 void disableHeightChanged();
151 void disableHeightChanged();
145 void pictureUriChanged(const QString&);
152 void pictureUriChanged(const QString&);
@@ -150,6 +157,7 @@ Q_SIGNALS:
150 void launcherWidthChanged(int launcherWidth);
157 void launcherWidthChanged(int launcherWidth);
151 void edgeDragWidthChanged(uint edgeDragWidth);
158 void edgeDragWidthChanged(uint edgeDragWidth);
152 void enableLauncherChanged(bool enableLauncher);
159 void enableLauncherChanged(bool enableLauncher);
160+ void enableIndicatorMenuChanged(bool enableIndicatorMenu);
153
161
154private:
162private:
155 GSettingsControllerQml();
163 GSettingsControllerQml();
@@ -163,6 +171,7 @@ private:
163 int m_launcherWidth;
171 int m_launcherWidth;
164 uint m_edgeDragWidth;
172 uint m_edgeDragWidth;
165 bool m_enableLauncher;
173 bool m_enableLauncher;
174+ bool m_enableIndicatorMenu;
166
175
167 static GSettingsControllerQml* s_controllerInstance;
176 static GSettingsControllerQml* s_controllerInstance;
168 QList<GSettingsQml *> m_registeredGSettings;
177 QList<GSettingsQml *> m_registeredGSettings;
tests/mocks/Unity/Application/CMakeLists.txt+1
@@ -5,6 +5,7 @@ set(FakeUnityApplicationQml_SOURCES
5 MirSurface.cpp
5 MirSurface.cpp
6 MirSurfaceItem.cpp
6 MirSurfaceItem.cpp
7 MirSurfaceListModel.cpp
7 MirSurfaceListModel.cpp
8+ MirMock.cpp
8 ObjectListModel.h
9 ObjectListModel.h
9 SurfaceManager.cpp
10 SurfaceManager.cpp
10 VirtualKeyboard.cpp
11 VirtualKeyboard.cpp
tests/mocks/Unity/Application/MirMock.cppnew file+49
@@ -0,0 +1,49 @@
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+#include "MirMock.h"
18+
19+MirMock *MirMock::the_mir = nullptr;
20+
21+MirMock *MirMock::instance()
22+{
23+ return the_mir;
24+}
25+
26+MirMock::MirMock()
27+{
28+ Q_ASSERT(the_mir == nullptr);
29+ the_mir = this;
30+}
31+
32+MirMock::~MirMock()
33+{
34+ Q_ASSERT(the_mir == this);
35+ the_mir = nullptr;
36+}
37+
38+void MirMock::setCursorName(const QString &cursorName)
39+{
40+ if (cursorName != m_cursorName) {
41+ m_cursorName = cursorName;
42+ Q_EMIT cursorNameChanged(m_cursorName);
43+ }
44+}
45+
46+QString MirMock::cursorName() const
47+{
48+ return m_cursorName;
49+}
tests/mocks/Unity/Application/MirMock.hnew file+39
@@ -0,0 +1,39 @@
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+#ifndef MIR_MOCK_H
18+#define MIR_MOCK_H
19+
20+#include <unity/shell/application/Mir.h>
21+
22+class MirMock : public ::Mir
23+{
24+ Q_OBJECT
25+public:
26+ explicit MirMock();
27+ virtual ~MirMock();
28+
29+ static MirMock *instance();
30+
31+ void setCursorName(const QString &cursorName) override;
32+ QString cursorName() const override;
33+
34+private:
35+ static MirMock *the_mir;
36+ QString m_cursorName;
37+};
38+
39+#endif
tests/mocks/Unity/Application/plugin.cpp+11−2
@@ -17,6 +17,7 @@
17#include "plugin.h"
17#include "plugin.h"
18#include "ApplicationInfo.h"
18#include "ApplicationInfo.h"
19#include "ApplicationManager.h"
19#include "ApplicationManager.h"
20+#include "MirMock.h"
20#include "MirSurfaceItem.h"
21#include "MirSurfaceItem.h"
21#include "SurfaceManager.h"
22#include "SurfaceManager.h"
22
23
@@ -38,6 +39,9 @@ void createUnityApplicationSharedSingletons()
38 if (!SurfaceManager::instance()) {
39 if (!SurfaceManager::instance()) {
39 new SurfaceManager;
40 new SurfaceManager;
40 }
41 }
42+ if (!MirMock::instance()) {
43+ new MirMock;
44+ }
41}
45}
42
46
43QObject* applicationManagerSingleton(QQmlEngine*, QJSEngine*)
47QObject* applicationManagerSingleton(QQmlEngine*, QJSEngine*)
@@ -46,6 +50,12 @@ QObject* applicationManagerSingleton(QQmlEngine*, QJSEngine*)
46 return new ApplicationManager;
50 return new ApplicationManager;
47}
51}
48
52
53+QObject* mirSingleton(QQmlEngine*, QJSEngine*)
54+{
55+ createUnityApplicationSharedSingletons();
56+ return MirMock::instance();
57+}
58+
49QObject* surfaceManagerSingleton(QQmlEngine*, QJSEngine*)
59QObject* surfaceManagerSingleton(QQmlEngine*, QJSEngine*)
50{
60{
51 createUnityApplicationSharedSingletons();
61 createUnityApplicationSharedSingletons();
@@ -78,9 +88,8 @@ void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
78 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
88 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
79
89
80 qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
90 qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
91+ qmlRegisterSingletonType<MirMock>(uri, 0, 1, "Mir", mirSingleton);
81 qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
92 qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
82−
83− qmlRegisterUncreatableType<Mir>(uri, 0, 1, "Mir", "Mir provides enum values, it can't be instantiated");
84}
93}
85
94
86void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
95void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
tests/mocks/Unity/Launcher/MockQuickListModel.cpp+2
@@ -37,6 +37,8 @@ QVariant MockQuickListModel::data(const QModelIndex &index, int role) const
37 return QLatin1String("copy.png");
37 return QLatin1String("copy.png");
38 case RoleClickable:
38 case RoleClickable:
39 return index.row() == 1 ? false : true;
39 return index.row() == 1 ? false : true;
40+ case RoleHasSeparator:
41+ return index.row() <= 1 ? true : false;
40 }
42 }
41 return QVariant();
43 return QVariant();
42}
44}
tests/mocks/Unity/Screens/CMakeLists.txt+1−1
@@ -11,4 +11,4 @@ add_library(MockScreensPlugin MODULE ${MockScreens_SOURCES})
11
11
12qt5_use_modules(MockScreensPlugin Gui Qml)
12qt5_use_modules(MockScreensPlugin Gui Qml)
13
13
14−add_unity8_mock(Unity.Screens 0.1 Unity/Screens TARGETS MockScreensPlugin)
14+add_unity8_mock(Unity.Screens 0.1 Unity/Screens PREFIX mocks TARGETS MockScreensPlugin)
tests/mocks/Unity/fake_categories.cpp+4
@@ -69,6 +69,10 @@ Categories::data(const QModelIndex& index, int role) const
69 } else {
69 } else {
70 map["category-layout"] = "carousel";
70 map["category-layout"] = "carousel";
71 }
71 }
72+ if (index.row() == 16) {
73+ map["expandable"] = false;
74+ map["collapsed-rows"] = 1;
75+ }
72 if (index.row() == 18) {
76 if (index.row() == 18) {
73 map["category-layout"] = "horizontal-list";
77 map["category-layout"] = "horizontal-list";
74 }
78 }
tests/plugins/Dash/cardcreator/4.res+1−1
@@ -34,7 +34,7 @@ Loader {
34 visible: showHeader && active && status === Loader.Ready;
34 visible: showHeader && active && status === Loader.Ready;
35 width: units.gu(6);
35 width: units.gu(6);
36 height: units.gu(5.625);
36 height: units.gu(5.625);
37− sourceComponent: UbuntuShape { image: mascotImage }
37+ sourceComponent: UbuntuShape { aspect: UbuntuShape.Flat; image: mascotImage }
38 anchors { verticalCenter: parent.verticalCenter; }
38 anchors { verticalCenter: parent.verticalCenter; }
39 }
39 }
40
40
tests/plugins/Dash/cardcreator/4.res.cardcreator+1−1
@@ -32,7 +32,7 @@ Loader {
32 visible: showHeader && active && status === Loader.Ready;
32 visible: showHeader && active && status === Loader.Ready;
33 width: units.gu(6);
33 width: units.gu(6);
34 height: units.gu(5.625);
34 height: units.gu(5.625);
35− sourceComponent: UbuntuShape { image: mascotImage }
35+ sourceComponent: UbuntuShape { aspect: UbuntuShape.Flat; image: mascotImage }
36 anchors { verticalCenter: parent.verticalCenter; }
36 anchors { verticalCenter: parent.verticalCenter; }
37 }
37 }
38
38
tests/qmltests/Dash/tst_GenericScopeView.qml+26
@@ -168,6 +168,32 @@ Item {
168 tryCompare(genericScopeView.scope, "searchQuery", "test")
168 tryCompare(genericScopeView.scope, "searchQuery", "test")
169 }
169 }
170
170
171+ function test_forceNotExpandable() {
172+ // wait for the item to be there
173+ tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader14", 0 /* timeout */) != null; }, true);
174+
175+ var category14 = findChild(genericScopeView, "dashCategory14")
176+ var seeAll14 = findChild(category14, "seeAll")
177+
178+ compare(category14.forceNotExpandable, false);
179+ waitForRendering(seeAll14);
180+ verify(category14.expandable);
181+ verify(!category14.expanded);
182+ compare(seeAll14.visible, true);
183+
184+ // wait for the item to be there
185+ tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader16", 0 /* timeout */) != null; }, true);
186+
187+ var category16 = findChild(genericScopeView, "dashCategory16")
188+ var seeAll16 = findChild(category16, "seeAll")
189+
190+ compare(category16.forceNotExpandable, true);
191+ waitForRendering(seeAll16);
192+ verify(!category16.expandable);
193+ verify(!category16.expanded);
194+ compare(seeAll16.visible, false);
195+ }
196+
171 function test_expand_collapse() {
197 function test_expand_collapse() {
172 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0", 0 /* timeout */) != null; }, true);
198 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0", 0 /* timeout */) != null; }, true);
173
199
tests/qmltests/Launcher/tst_Launcher.qml+89
@@ -1369,6 +1369,95 @@ Rectangle {
1369 tryCompare(clickThroughSpy, "count", 0);
1369 tryCompare(clickThroughSpy, "count", 0);
1370 }
1370 }
1371
1371
1372+ function test_tooltip() {
1373+ launcher.lockedVisible = true;
1374+ revealByEdgePush();
1375+
1376+ var item = findChild(launcher, "launcherDelegate0");
1377+ var tooltipShape = findChild(launcher, "tooltipShape");
1378+
1379+ // Initial state
1380+ tryCompare(tooltipShape, "visible", false);
1381+ tryCompare(tooltipShape, "opacity", .0);
1382+
1383+ // Move the mouse on the launcher icon
1384+ mouseMove(item, item.width / 2, item.height / 2, 10);
1385+ mouseMove(item, item.width / 2 + 1, item.height / 2, 10);
1386+ tryCompare(tooltipShape, "visible", true);
1387+ tryCompare(tooltipShape, "opacity", .95);
1388+
1389+ // Move the mouse away
1390+ mouseMove(root, root.width, root.height / 2, 10);
1391+ tryCompare(tooltipShape, "visible", false);
1392+ tryCompare(tooltipShape, "opacity", .0);
1393+ }
1394+
1395+ function test_quicklist_dismisses_tooltip() {
1396+ launcher.lockedVisible = true;
1397+ revealByEdgePush();
1398+
1399+ var item = findChild(launcher, "launcherDelegate0");
1400+ var tooltipShape = findChild(launcher, "tooltipShape");
1401+ var quickListShape = findChild(launcher, "quickListShape");
1402+
1403+ // Initial state
1404+ tryCompare(tooltipShape, "visible", false);
1405+ tryCompare(tooltipShape, "opacity", .0);
1406+
1407+ // Move the mouse on the launcher icon
1408+ mouseMove(item, item.width / 2, item.height / 2, 10);
1409+ mouseMove(item, item.width / 2 + 1, item.height / 2, 10);
1410+ tryCompare(tooltipShape, "visible", true);
1411+ tryCompare(tooltipShape, "opacity", .95);
1412+
1413+ // Right click to show the quicklist
1414+ mouseClick(item, item.width / 2, item.height / 2, Qt.RightButton);
1415+ tryCompare(quickListShape, "visible", true);
1416+ tryCompare(tooltipShape, "visible", false);
1417+ tryCompare(tooltipShape, "opacity", .0);
1418+
1419+ // Left click hides the quicklist, tooltip is still dismissed
1420+ mouseClick(item, item.width / 2, item.height / 2, Qt.LefftButton);
1421+ tryCompare(quickListShape, "visible", false);
1422+ tryCompare(tooltipShape, "visible", false);
1423+ tryCompare(tooltipShape, "opacity", .0);
1424+
1425+ // Mouse motion should should show tooltip again
1426+ mouseMove(item, item.width / 2, item.height / 2, 10);
1427+ mouseMove(item, item.width / 2 + 1, item.height / 2, 10);
1428+ tryCompare(tooltipShape, "visible", true);
1429+ tryCompare(tooltipShape, "opacity", .95);
1430+ }
1431+
1432+ function test_click_dismisses_tooltip() {
1433+ launcher.lockedVisible = true;
1434+ revealByEdgePush();
1435+
1436+ var item = findChild(launcher, "launcherDelegate0");
1437+ var tooltipShape = findChild(launcher, "tooltipShape");
1438+
1439+ // Initial state
1440+ tryCompare(tooltipShape, "visible", false);
1441+ tryCompare(tooltipShape, "opacity", .0);
1442+
1443+ // Move the mouse on the launcher icon
1444+ mouseMove(item, item.width / 2, item.height / 2, 10);
1445+ mouseMove(item, item.width / 2 + 1, item.height / 2, 10);
1446+ tryCompare(tooltipShape, "visible", true);
1447+ tryCompare(tooltipShape, "opacity", .95);
1448+
1449+ // Left click should dismiss the tooltip
1450+ mouseClick(item, item.width / 2 + 1, item.height / 2, Qt.LeftButton);
1451+ tryCompare(tooltipShape, "visible", false);
1452+ tryCompare(tooltipShape, "opacity", .0);
1453+
1454+ // Mouse motion should should show tooltip again
1455+ mouseMove(item, item.width / 2, item.height / 2, 10);
1456+ mouseMove(item, item.width / 2 + 1, item.height / 2, 10);
1457+ tryCompare(tooltipShape, "visible", true);
1458+ tryCompare(tooltipShape, "opacity", .95);
1459+ }
1460+
1372 function test_launcherEnabledSetting() {
1461 function test_launcherEnabledSetting() {
1373 launcher.available = true;
1462 launcher.available = true;
1374
1463
tests/qmltests/Panel/tst_IndicatorsMenu.qml+17
@@ -286,5 +286,22 @@ IndicatorTest {
286 mouseClick(indicatorsMenu, indicatorsMenu.width/2, indicatorsMenu.height/2, Qt.RightButton);
286 mouseClick(indicatorsMenu, indicatorsMenu.width/2, indicatorsMenu.height/2, Qt.RightButton);
287 tryCompare(clickThroughSpy, "count", 0);
287 tryCompare(clickThroughSpy, "count", 0);
288 }
288 }
289+
290+ function test_enableMenuSetting_data() {
291+ return [
292+ {tag: "menu enabled", enabled: true},
293+ {tag: "menu disabled", enabled: false}
294+ ]
295+ }
296+
297+ function test_enableMenuSetting(data) {
298+ indicatorsMenu.available = data.enabled;
299+
300+ indicatorsMenu.show();
301+ tryCompare(indicatorsMenu, data.enabled ? "fullyOpened" : "fullyClosed", true);
302+
303+ indicatorsMenu.available = true;
304+ indicatorsMenu.hide();
305+ }
289 }
306 }
290}
307}
tests/qmltests/Stage/tst_DesktopStage.qml+16
@@ -789,5 +789,21 @@ Item {
789
789
790 tryCompare(dialerAppDelegate, "state", "maximized");
790 tryCompare(dialerAppDelegate, "state", "maximized");
791 }
791 }
792+
793+ function test_grabbingCursorOnDecorationPress() {
794+ var appDelegate = startApplication("dialer-app");
795+ verify(appDelegate);
796+ var decoration = findChild(appDelegate, "appWindowDecoration");
797+ verify(decoration);
798+
799+ mousePress(decoration, decoration.width/2, decoration.height/2, Qt.LeftButton);
800+ tryCompare(Mir, "cursorName", "grabbing");
801+
802+ mouseMove(decoration, decoration.width/2 + 1, decoration.height/2 + 1);
803+ tryCompare(Mir, "cursorName", "grabbing");
804+
805+ mouseRelease(decoration);
806+ tryCompare(Mir, "cursorName", "");
807+ }
792 }
808 }
793}
809}
tests/qmltests/tst_Shell.qml+64
@@ -2638,5 +2638,69 @@ Rectangle {
2638
2638
2639 GSettingsController.setEnableLauncher(true);
2639 GSettingsController.setEnableLauncher(true);
2640 }
2640 }
2641+
2642+ function test_indicatorMenuEnabledSetting_data() {
2643+ return [
2644+ {tag: "indicator menu enabled", enabled: true},
2645+ {tag: "indicator menu disabled", enabled: false}
2646+ ]
2647+ }
2648+
2649+ function test_indicatorMenuEnabledSetting(data) {
2650+ loadShell("phone");
2651+
2652+ GSettingsController.setEnableIndicatorMenu(data.enabled);
2653+
2654+ var panel = findChild(shell, "panel");
2655+ compare(panel.indicators.available, data.enabled);
2656+
2657+ GSettingsController.setEnableIndicatorMenu(true);
2658+ }
2659+
2660+ function test_spreadDisabled_data() {
2661+ return [
2662+ { tag: "enabled", spreadEnabled: true },
2663+ { tag: "disabled", spreadEnabled: false }
2664+ ];
2665+ }
2666+
2667+ function test_spreadDisabled(data) {
2668+ loadShell("phone");
2669+ swipeAwayGreeter();
2670+ var stage = findChild(shell, "stage");
2671+ stage.spreadEnabled = data.spreadEnabled;
2672+
2673+ // Try swiping
2674+ touchFlick(shell, shell.width - 2, shell.height / 2, units.gu(1), shell.height / 2);
2675+ tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2676+
2677+ stage.closeSpread();
2678+ tryCompare(stage, "state", "staged");
2679+
2680+ // Try by edge push
2681+ mouseMove(stage, stage.width - 1, units.gu(10));
2682+ for (var i = 0; i < units.gu(10); i++) {
2683+ stage.pushRightEdge(1);
2684+ }
2685+ mouseMove(stage, stage.width - units.gu(5), units.gu(10));
2686+ tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2687+
2688+ stage.closeSpread();
2689+ tryCompare(stage, "state", "staged");
2690+
2691+ // Try by alt+tab
2692+ keyPress(Qt.Key_Alt);
2693+ keyClick(Qt.Key_Tab);
2694+ tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2695+ keyRelease(Qt.Key_Alt);
2696+
2697+ stage.closeSpread();
2698+ tryCompare(stage, "state", "staged");
2699+
2700+ // Try by Super+W
2701+ keyPress(Qt.Key_W, Qt.MetaModifier)
2702+ tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2703+ keyRelease(Qt.Key_W, Qt.MetaModifier)
2704+ }
2641 }
2705 }
2642}
2706}