on xenial help sign in
merge prereq
d323b7bMichael Zanetti
build.sh+16
@@ -1,5 +1,21 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
3SETUP=false
19SETUP=false
4CLEAN=false
20CLEAN=false
5NUM_JOBS=$(( `grep -c ^processor /proc/cpuinfo` + 1 ))
21NUM_JOBS=$(( `grep -c ^processor /proc/cpuinfo` + 1 ))
data/com.canonical.Unity8.gschema.xml+11−1
@@ -33,7 +33,7 @@
33 <description>How big (in grid units) the edge-drag sensitive area should be.</description>
33 <description>How big (in grid units) the edge-drag sensitive area should be.</description>
34 </key>
34 </key>
35 <key type="b" name="autohide-launcher">
35 <key type="b" name="autohide-launcher">
36− <default>true</default>
36+ <default>false</default>
37 <summary>Autohide the launcher</summary>
37 <summary>Autohide the launcher</summary>
38 <description>This will only be applied in windowed mode. In staged mode, the launcher will always hide.</description>
38 <description>This will only be applied in windowed mode. In staged mode, the launcher will always hide.</description>
39 </key>
39 </key>
@@ -58,6 +58,16 @@
58 <summary>The uri to the app store</summary>
58 <summary>The uri to the app store</summary>
59 <description>This will be used whenever the user triggers an action to open the app store.</description>
59 <description>This will be used whenever the user triggers an action to open the app store.</description>
60 </key>
60 </key>
61+ <key type="b" name="always-show-osk">
62+ <default>false</default>
63+ <summary>Force showing/hiding the OSK</summary>
64+ <description>Toggle the visibility of the On Screen Keyboard unconditionally</description>
65+ </key>
66+ <key type="b" name="osk-switch-visible">
67+ <default>false</default>
68+ <summary>Whether the OSK switch should be visible</summary>
69+ <description>Toggle the visibility of the OSK switch</description>
70+ </key>
61 </schema>
71 </schema>
62
72
63 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
73 <schema path="/com/canonical/unity8/greeter/" id="com.canonical.Unity8.Greeter" gettext-domain="unity8">
data/unity8-greeter-wrapper+7−4
@@ -49,9 +49,12 @@ if which ubuntu-touch-session >/dev/null; then
49 TOUCH_WRAPPER=ubuntu-touch-session
49 TOUCH_WRAPPER=ubuntu-touch-session
50fi
50fi
51
51
52−# Pretend that we're in an ubuntu-touch session, so that indicator-network
52+# Advertise as a unity8 session, so that indicator-network will start.
53−# will start.
53+export XDG_SESSION_DESKTOP=unity8
54−export DESKTOP_SESSION=ubuntu-touch
54+export DESKTOP_SESSION=$XDG_SESSION_DESKTOP
55+
56+set_greeter_var QT_IM_MODULE maliitphablet
57+set_greeter_var QT_QPA_PLATFORM ubuntumirclient
55
58
56# We disable ofono using pulse. It causes problems with racing with the user's
59# We disable ofono using pulse. It causes problems with racing with the user's
57# pulse. We need to come up with a better long-term fix for this, because we
60# pulse. We need to come up with a better long-term fix for this, because we
@@ -100,7 +103,7 @@ if [ "$(id -u phablet 2>/dev/null)" = "32011" ]; then
100fi
103fi
101
104
102# And finally actually start the greeter
105# And finally actually start the greeter
103−exec env QT_QPA_PLATFORM=ubuntumirclient MIR_SERVER_FILE=$SUB_SOCKET $TOUCH_WRAPPER $@ &
106+exec env MIR_SERVER_FILE=$SUB_SOCKET $TOUCH_WRAPPER $@ &
104CMD_PID=$!
107CMD_PID=$!
105wait $CMD_PID
108wait $CMD_PID
106CMD_PID=
109CMD_PID=
data/unity8.conf+19−35
@@ -20,28 +20,32 @@ env QML_NO_TOUCH_COMPRESSION=1
20respawn
20respawn
21expect stop
21expect stop
22
22
23+# FIXME Create an autopilot test that makes sure start+stop and restart
24+# work fine at least 2 times
25+
23pre-start script
26pre-start script
24 # Tell unity-mir to raise SIGSTOP after we start
27 # Tell unity-mir to raise SIGSTOP after we start
25 initctl set-env UNITY_MIR_EMITS_SIGSTOP=1
28 initctl set-env UNITY_MIR_EMITS_SIGSTOP=1
26
29
27− if [ -n "$MIR_SOCKET" ]; then
28− # FIXME Create an autopilot test that makes sure start+stop and restart
29− # work fine at least 2 times
30− # Save original value of MIR_SOCKET in case we are stopped,
30+ # Save original value of MIR_SOCKET so that we can restore it when stopped,
31− # as we modify the variable for future jobs, including ourself.
31+ # as we modify the variable for future jobs, including ourself.
32− UNITY_MIR_SOCKET=$(initctl get-env --global MIR_SOCKET)
33− initctl set-env --global UNITY_MIR_SOCKET=$UNITY_MIR_SOCKET
32+ initctl set-env UNITY_MIR_SOCKET=$MIR_SOCKET
34
33
35− # Point unity8 at unity-system-compositor
34+ # Decide where we are going to put our own socket file
35+ if [ -n "$SNAP" ]; then
36+ # In snappy, we want to hard code our path because our apparmor profile
37+ # only lets us put the socket in one place. And consumers expect it
38+ # there.
39+ MIR_SERVER_FILE=/run/user/$(id -u)/mir_socket
40+ else
36 MIR_SERVER_FILE=$XDG_RUNTIME_DIR/mir_socket
41 MIR_SERVER_FILE=$XDG_RUNTIME_DIR/mir_socket
37− initctl set-env MIR_SERVER_FILE=$MIR_SERVER_FILE
38− initctl set-env MIR_SERVER_HOST_SOCKET=$UNITY_MIR_SOCKET
39−
40− # Point all future jobs in this session to our Mir socket instead of
41− # unity-system-compositor's socket.
42− initctl set-env --global MIR_SOCKET=$MIR_SERVER_FILE
43− gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
44 fi
42 fi
43+ initctl set-env MIR_SERVER_FILE=$MIR_SERVER_FILE
44+
45+ # Point all future jobs in this session to our Mir socket instead of
46+ # unity-system-compositor's socket.
47+ initctl set-env --global MIR_SOCKET=$MIR_SERVER_FILE
48+ gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
45
49
46 # Remove the normal and trusted sockets if still there
50 # Remove the normal and trusted sockets if still there
47 if [ -S "$MIR_SERVER_FILE" ]; then
51 if [ -S "$MIR_SERVER_FILE" ]; then
@@ -54,12 +58,6 @@ pre-start script
54
58
55 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
59 initctl set-env --global MIR_SERVER_PROMPT_FILE=1
56
60
57− #
58− # Mir's input resampling is deprecated and going away soon. Turn it off
59− # so we don't get a surprise change in behaviour when that happens.
60− #
61− initctl set-env --global MIR_CLIENT_INPUT_RATE=0
62−
63 if [ "$XDG_SESSION_DESKTOP" = "ubuntu-touch" ]; then
61 if [ "$XDG_SESSION_DESKTOP" = "ubuntu-touch" ]; then
64 # On Ubuntu Touch, we currently use a trick where we auto-login the
62 # On Ubuntu Touch, we currently use a trick where we auto-login the
65 # user without a LightDM greeter at all. In this case, we want to
63 # user without a LightDM greeter at all. In this case, we want to
@@ -74,25 +72,11 @@ end script
74exec ${BINARY:-unity8} --mode=$MODE $ARGS
72exec ${BINARY:-unity8} --mode=$MODE $ARGS
75
73
76post-start script
74post-start script
77− # If no MIR_SOCKET was defined on launch, we try to set one here
78− if [ -z "$(initctl get-env --global UNITY_MIR_SOCKET)" ]; then
79− if [ -S "$XDG_RUNTIME_DIR/mir_socket" ]; then
80− mir_socket=$XDG_RUNTIME_DIR/mir_socket
81− elif [ -S "/tmp/mir_socket" ]; then
82− mir_socket=/tmp/mir_socket
83− fi
84−
85− if [ -n "$mir_socket" ]; then
86− initctl set-env --global MIR_SOCKET="$mir_socket"
87− fi
88− fi
89−
90 initctl emit --no-wait indicator-services-start
75 initctl emit --no-wait indicator-services-start
91end script
76end script
92
77
93post-stop script
78post-stop script
94 initctl set-env --global MIR_SOCKET=$UNITY_MIR_SOCKET
79 initctl set-env --global MIR_SOCKET=$UNITY_MIR_SOCKET
95− initctl unset-env --global UNITY_MIR_SOCKET
96 initctl unset-env --global MIR_SERVER_PROMPT_FILE
80 initctl unset-env --global MIR_SERVER_PROMPT_FILE
97 initctl emit application-end
81 initctl emit application-end
98end script
82end script
debian/changelog+56
@@ -1,3 +1,59 @@
1+unity8 (8.15+17.04.20170308-0ubuntu1) zesty; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Let's follow the keyboard order
5+ * Enable the license check (LP: #1590044)
6+ * Show a barebones error message if loading the QML doesn't work
7+ * Make sure cursor is back to normal when closing the window (LP:
8+ #1666158)
9+ * Fix small warning when sensitive is undefined
10+ * Remove unused member variable
11+ * Initialize m_msecsSinceReference
12+ * Add warning if registerService fails
13+ * Move menus Component {} out of the repeater
14+ * Add tool to browse menus of a running app
15+
16+ [ Daniel d'Andrada ]
17+ * Drag child windows with Alt+LeftMouseButton (LP: #1664947)
18+
19+ [ Gerry Boland ]
20+ * TopLevelWindowModel: connect to the OSK surface to know when it goes
21+ away so we can clean up after it. (LP: #1670681)
22+
23+ [ Josh Arenson ]
24+ * Initialize sessionMode to single when mock is reset (LP: #1667463)
25+
26+ [ Lukáš Tinkl ]
27+ * Make the menu string "Back" translatable
28+ * Let the OSK be driven by a switch in indicator-keyboard (LP:
29+ #1521518)
30+ * Disable the tutorial when there's no touchscreen (LP: #1661557)
31+ * Shell chrome fixes (LP: #1658117, #1665723, #1665724, #1669010)
32+ * Cancel the drag as soon as we're entering the spread (LP: #1668642)
33+ * Fix being unable to use window control buttons or menus with touch
34+ (LP: #1667604, #1668387)
35+
36+ [ Michael Terry ]
37+ * Set QT_IM_MODULE in the greeter so that the OSK can come up. (LP:
38+ #1670383)
39+ * Simplify our startup handling of Mir environment variables and set
40+ the right socket path in snappy.
41+
42+ [ Michael Zanetti ]
43+ * Cancel the home key activation if something else is pressed along
44+ with Meta (LP: #1670678)
45+ * close the drawer when something is launched from the launcher (LP:
46+ #1660367)
47+ * use a svg instead of a png for the Launcher's BFB (LP: #1668057)
48+ * change the default setting for the launcher autohiding (LP:
49+ #1670655)
50+
51+ [ Nick Dedekind ]
52+ * Split up Shell::test_spreadDisabled to ensure initial state for each
53+ test.
54+
55+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 08 Mar 2017 09:56:46 +0000
56+
1unity8 (8.15+17.04.20170221-0ubuntu1) zesty; urgency=medium
57unity8 (8.15+17.04.20170221-0ubuntu1) zesty; urgency=medium
2
58
3 * Handle ubuntu-app-launch API/ABI break
59 * Handle ubuntu-app-launch API/ABI break
plugins/Utils/URLDispatcher.cpp+5−2
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
17#include "URLDispatcher.h"
17#include "URLDispatcher.h"
18
18
19#include <QDBusConnection>
19#include <QDBusConnection>
20+#include <QDebug>
20
21
21class URLDispatcherInterface : public QObject
22class URLDispatcherInterface : public QObject
22{
23{
@@ -63,7 +64,9 @@ void URLDispatcher::setActive(bool value)
63 connection.registerObject(QStringLiteral("/com/canonical/URLDispatcher"),
64 connection.registerObject(QStringLiteral("/com/canonical/URLDispatcher"),
64 dispatcher,
65 dispatcher,
65 QDBusConnection::ExportScriptableContents);
66 QDBusConnection::ExportScriptableContents);
66− connection.registerService(QStringLiteral("com.canonical.URLDispatcher"));
67+ if (!connection.registerService(QStringLiteral("com.canonical.URLDispatcher"))) {
68+ qWarning() << "Unable to register DBus service com.canonical.URLDispatcher";
69+ }
67 m_dispatcher = dispatcher;
70 m_dispatcher = dispatcher;
68 } else {
71 } else {
69 connection.unregisterService(QStringLiteral("com.canonical.URLDispatcher"));
72 connection.unregisterService(QStringLiteral("com.canonical.URLDispatcher"));
plugins/Utils/WindowInputMonitor.cpp+3
@@ -73,6 +73,9 @@ void WindowInputMonitor::update(QEvent *event)
73 && m_windowLastTouchedTimer->elapsed() >= msecsWithoutTouches) {
73 && m_windowLastTouchedTimer->elapsed() >= msecsWithoutTouches) {
74 m_pressedHomeKey = keyEvent->key();
74 m_pressedHomeKey = keyEvent->key();
75 m_activationTimer->start();
75 m_activationTimer->start();
76+ } else if (m_pressedHomeKey != 0 && !m_homeKeys.contains(keyEvent->key())) {
77+ // something else came in... cancel activation
78+ m_activationTimer->stop();
76 }
79 }
77
80
78 } else if (event->type() == QEvent::KeyRelease) {
81 } else if (event->type() == QEvent::KeyRelease) {
plugins/WindowManager/TopLevelWindowModel.cpp+1
@@ -341,6 +341,7 @@ void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surfac
341 });
341 });
342 } else {
342 } else {
343 if (surface->type() == Mir::InputMethodType) {
343 if (surface->type() == Mir::InputMethodType) {
344+ connectSurface(surface);
344 setInputMethodWindow(createWindow(surface));
345 setInputMethodWindow(createWindow(surface));
345 } else {
346 } else {
346 auto *application = m_applicationManager->findApplicationWithSurface(surface);
347 auto *application = m_applicationManager->findApplicationWithSurface(surface);
po/unity8.pot+7−3
@@ -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: 2017-02-21 13:23+0000\n"
11+"POT-Creation-Date: 2017-03-08 09:56+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"
@@ -196,7 +196,7 @@ msgid "Switches applications via the launcher."
196msgstr ""
196msgstr ""
197
197
198#: qml/Components/KeyboardShortcutsOverlay.qml:164
198#: qml/Components/KeyboardShortcutsOverlay.qml:164
199−msgid "Super + 0 to 9"
199+msgid "Super + 1 to 0"
200msgstr ""
200msgstr ""
201
201
202#: qml/Components/KeyboardShortcutsOverlay.qml:169
202#: qml/Components/KeyboardShortcutsOverlay.qml:169
@@ -526,7 +526,7 @@ msgctxt "Apps sorted alphabetically"
526msgid "A-Z"
526msgid "A-Z"
527msgstr ""
527msgstr ""
528
528
529−#: qml/Launcher/MoreAppsHeader.qml:39
529+#: qml/Launcher/MoreAppsHeader.qml:55
530msgid "More apps in the store"
530msgid "More apps in the store"
531msgstr ""
531msgstr ""
532
532
@@ -617,6 +617,10 @@ msgctxt "Button: Call back on phone"
617msgid "Call back"
617msgid "Call back"
618msgstr ""
618msgstr ""
619
619
620+#: qml/Panel/PanelMenuPage.qml:92
621+msgid "Back"
622+msgstr ""
623+
620#: qml/Stage/SideStage.qml:76
624#: qml/Stage/SideStage.qml:76
621msgid "Drag using 3 fingers any application from one window to the other"
625msgid "Drag using 3 fingers any application from one window to the other"
622msgstr ""
626msgstr ""
po/update-unity-pot+17
@@ -1,4 +1,21 @@
1#!/bin/sh
1#!/bin/sh
2+
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
2set -e
19set -e
3cd $(dirname $0)
20cd $(dirname $0)
4PO_DIR=$PWD
21PO_DIR=$PWD
qml/ApplicationMenus/MenuBar.qml+49−24
@@ -28,11 +28,19 @@ Item {
28 property alias unityMenuModel: rowRepeater.model
28 property alias unityMenuModel: rowRepeater.model
29 property bool enableKeyFilter: false
29 property bool enableKeyFilter: false
30 property real overflowWidth: width
30 property real overflowWidth: width
31+ property bool windowMoving: false
31
32
32 // read from outside
33 // read from outside
33 readonly property bool valid: rowRepeater.count > 0
34 readonly property bool valid: rowRepeater.count > 0
34 readonly property bool showRequested: d.longAltPressed || d.currentItem != null
35 readonly property bool showRequested: d.longAltPressed || d.currentItem != null
35
36
37+ // MoveHandler API for DecoratedWindow
38+ signal pressed(var mouse)
39+ signal pressedChangedEx(bool pressed, var pressedButtons, real mouseX, real mouseY)
40+ signal positionChanged(var mouse)
41+ signal released(var mouse)
42+ signal doubleClicked(var mouse)
43+
36 implicitWidth: row.width
44 implicitWidth: row.width
37 height: parent.height
45 height: parent.height
38
46
@@ -77,7 +85,7 @@ Item {
77 anchors.fill: parent
85 anchors.fill: parent
78 enabled: d.currentItem != null
86 enabled: d.currentItem != null
79 hoverEnabled: enabled && d.currentItem && d.currentItem.__popup != null
87 hoverEnabled: enabled && d.currentItem && d.currentItem.__popup != null
80− onPressed: d.dismissAll()
88+ onPressed: { mouse.accepted = false; d.dismissAll(); }
81 }
89 }
82
90
83 Row {
91 Row {
@@ -96,6 +104,11 @@ Item {
96 onModelReset: d.firstInvisibleIndex = undefined
104 onModelReset: d.firstInvisibleIndex = undefined
97 }
105 }
98
106
107+ Component {
108+ id: menuComponent
109+ MenuPopup { }
110+ }
111+
99 Repeater {
112 Repeater {
100 id: rowRepeater
113 id: rowRepeater
101
114
@@ -114,12 +127,19 @@ Item {
114
127
115 implicitWidth: column.implicitWidth
128 implicitWidth: column.implicitWidth
116 implicitHeight: row.height
129 implicitHeight: row.height
117− enabled: model.sensitive && shouldDisplay
130+ enabled: (model.sensitive === true) && shouldDisplay
118 opacity: shouldDisplay ? 1 : 0
131 opacity: shouldDisplay ? 1 : 0
119
132
120 function show() {
133 function show() {
121 if (!__popup) {
134 if (!__popup) {
122− __popup = menuComponent.createObject(root, { objectName: visualItem.objectName + "-menu" });
135+ __popup = menuComponent.createObject(root,
136+ {
137+ objectName: visualItem.objectName + "-menu",
138+ desiredX: Qt.binding(function() { return visualItem.x - units.gu(1); }),
139+ desiredY: Qt.binding(function() { return root.height; }),
140+ unityMenuModel: Qt.binding(function() { return root.unityMenuModel.submenu(visualItem.__ownIndex); })
141+ });
142+ __popup.reset();
123 __popup.childActivated.connect(dismiss);
143 __popup.childActivated.connect(dismiss);
124 // force the current item to be the newly popped up menu
144 // force the current item to be the newly popped up menu
125 } else {
145 } else {
@@ -162,17 +182,6 @@ Item {
162 onDismissAll: visualItem.dismiss()
182 onDismissAll: visualItem.dismiss()
163 }
183 }
164
184
165− Component {
166− id: menuComponent
167− MenuPopup {
168− desiredX: visualItem.x - units.gu(1)
169− desiredY: parent.height
170− unityMenuModel: root.unityMenuModel.submenu(visualItem.__ownIndex)
171−
172− Component.onCompleted: reset();
173− }
174− }
175−
176 RowLayout {
185 RowLayout {
177 id: column
186 id: column
178 spacing: units.gu(1)
187 spacing: units.gu(1)
@@ -217,24 +226,40 @@ Item {
217 } // Row
226 } // Row
218
227
219 MouseArea {
228 MouseArea {
220− anchors.fill: row
229+ anchors.fill: parent
221 hoverEnabled: d.currentItem
230 hoverEnabled: d.currentItem
222
231
232+ property bool moved: false
233+
223 onEntered: {
234 onEntered: {
224 if (d.currentItem) {
235 if (d.currentItem) {
225 updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
236 updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
226 }
237 }
227 }
238 }
228− onPositionChanged: {
239+
229− if (d.currentItem) {
240+ onClicked: {
241+ if (!moved) {
242+ var prevItem = d.currentItem;
230− updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
243+ updateCurrentItemFromPosition(Qt.point(mouseX, mouseY));
244+ if (prevItem && d.currentItem == prevItem) {
245+ prevItem.hide();
246+ }
231 }
247 }
248+ moved = false;
232 }
249 }
233− onClicked: {
250+
234− var prevItem = d.currentItem;
251+ // for the MoveHandler
252+ onPressed: root.pressed(mouse)
253+ onPressedChanged: root.pressedChangedEx(pressed, pressedButtons, mouseX, mouseY)
254+ onReleased: root.released(mouse)
255+ onDoubleClicked: root.doubleClicked(mouse)
256+
257+ Mouse.ignoreSynthesizedEvents: true
258+ Mouse.onPositionChanged: {
259+ root.positionChanged(mouse);
260+ moved = root.windowMoving;
261+ if (d.currentItem) {
235− updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
262+ updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
236− if (prevItem && d.currentItem == prevItem) {
237− prevItem.hide();
238 }
263 }
239 }
264 }
240
265
@@ -259,7 +284,7 @@ Item {
259 hoverEnabled: d.currentItem
284 hoverEnabled: d.currentItem
260 onEntered: d.currentItem = this
285 onEntered: d.currentItem = this
261 onPositionChanged: d.currentItem = this
286 onPositionChanged: d.currentItem = this
262− onClicked: d.currentItem = this
287+ onPressed: d.currentItem = this
263
288
264 property Item __popup: null;
289 property Item __popup: null;
265 readonly property bool popupVisible: __popup && __popup.visible
290 readonly property bool popupVisible: __popup && __popup.visible
qml/ApplicationMenus/MenuItem.qml+6−6
@@ -34,7 +34,7 @@ ActionItem {
34 val += units.gu(1) + title.contentWidth;
34 val += units.gu(1) + title.contentWidth;
35 if (hasSubmenu) {
35 if (hasSubmenu) {
36 val += units.gu(1) + chevronIcon.width;
36 val += units.gu(1) + chevronIcon.width;
37− } else if (shortcut != undefined) {
37+ } else if (menuData && menuData.shortcut != undefined) {
38 val += units.gu(3) + shortcutLabel.contentWidth;
38 val += units.gu(3) + shortcutLabel.contentWidth;
39 }
39 }
40 return val + units.gu(1);
40 return val + units.gu(1);
@@ -49,9 +49,9 @@ ActionItem {
49 enabled: root.enabled
49 enabled: root.enabled
50
50
51 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
51 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
52− text: menuData.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
52+ text: menuData ? menuData.label.replace("_", "&").replace("<u>", "&").replace("</u>", "") : ""
53− checkable: menuData.isCheck || menuData.isRadio
53+ checkable: menuData && (menuData.isCheck || menuData.isRadio)
54− checked: menuData.isToggled
54+ checked: menuData && menuData.isToggled
55 }
55 }
56
56
57 width: {
57 width: {
@@ -127,8 +127,8 @@ ActionItem {
127 color: enabled ? theme.palette.normal.overlaySecondaryText :
127 color: enabled ? theme.palette.normal.overlaySecondaryText :
128 theme.palette.disabled.overlaySecondaryText
128 theme.palette.disabled.overlaySecondaryText
129
129
130− visible: menuData.shortcut != undefined && !root.hasSubmenu && QuickUtils.keyboardAttached
130+ visible: menuData && menuData.shortcut != undefined && !root.hasSubmenu && QuickUtils.keyboardAttached
131− text: menuData.shortcut ? menuData.shortcut : ""
131+ text: menuData && menuData.shortcut ? menuData.shortcut : ""
132 }
132 }
133 }
133 }
134
134
qml/ApplicationMenus/MenuPopup.qml+75−73
@@ -276,6 +276,79 @@ UbuntuShape {
276 }
276 }
277 }
277 }
278
278
279+ Component {
280+ id: separatorComponent
281+ ListItems.ThinDivider {
282+ // Parent will be loader
283+ objectName: parent.objectName + "-separator"
284+ implicitHeight: units.dp(2)
285+ }
286+ }
287+
288+ Component {
289+ id: menuItemComponent
290+ MenuItem {
291+ // Parent will be loader
292+ id: menuItem
293+ menuData: parent.__menuData
294+ objectName: parent.objectName + "-actionItem"
295+
296+ width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
297+
298+ action.onTriggered: {
299+ submenuHoverTimer.stop();
300+
301+ d.currentItem = parent;
302+
303+ if (hasSubmenu) {
304+ if (!popup) {
305+ var model = root.unityMenuModel.submenu(__ownIndex);
306+ popup = submenuComponent.createObject(focusScope, {
307+ objectName: parent.objectName + "-",
308+ unityMenuModel: model,
309+ substractWidth: true,
310+ desiredX: Qt.binding(function() { return root.width }),
311+ desiredY: Qt.binding(function() {
312+ var dummy = listView.contentY; // force a recalc on contentY change.
313+ return mapToItem(container, 0, y).y;
314+ })
315+ });
316+ popup.retreat.connect(function() {
317+ popup.destroy();
318+ popup = null;
319+ menuItem.forceActiveFocus();
320+ });
321+ popup.childActivated.connect(function() {
322+ popup.destroy();
323+ popup = null;
324+ root.childActivated();
325+ });
326+ } else if (popup) {
327+ popup.visible = true;
328+ }
329+ } else {
330+ root.unityMenuModel.activate(__ownIndex);
331+ root.childActivated();
332+ }
333+ }
334+
335+ Connections {
336+ target: d
337+ onCurrentIndexChanged: {
338+ if (popup && d.currentIndex != __ownIndex) {
339+ popup.visible = false;
340+ }
341+ }
342+ onDismissAll: {
343+ if (popup) {
344+ popup.destroy();
345+ popup = null;
346+ }
347+ }
348+ }
349+ }
350+ }
351+
279 ColumnLayout {
352 ColumnLayout {
280 id: menuColumn
353 id: menuColumn
281 spacing: 0
354 spacing: 0
@@ -289,6 +362,8 @@ UbuntuShape {
289 id: loader
362 id: loader
290 objectName: root.objectName + "-item" + __ownIndex
363 objectName: root.objectName + "-item" + __ownIndex
291
364
365+ property Item popup: null
366+ property var __menuData: model
292 property int __ownIndex: index
367 property int __ownIndex: index
293 property bool __isSeparator: model.isSeparator
368 property bool __isSeparator: model.isSeparator
294
369
@@ -301,80 +376,7 @@ UbuntuShape {
301 return menuItemComponent;
376 return menuItemComponent;
302 }
377 }
303
378
304− property Item popup: null
305−
306 Layout.fillWidth: true
379 Layout.fillWidth: true
307−
308− Component {
309− id: menuItemComponent
310− MenuItem {
311− id: menuItem
312− menuData: model
313− objectName: loader.objectName + "-actionItem"
314−
315− width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
316−
317− action.onTriggered: {
318− submenuHoverTimer.stop();
319−
320− d.currentItem = loader;
321−
322− if (hasSubmenu) {
323− if (!popup) {
324− var model = root.unityMenuModel.submenu(__ownIndex);
325− popup = submenuComponent.createObject(focusScope, {
326− objectName: loader.objectName + "-",
327− unityMenuModel: model,
328− substractWidth: true,
329− desiredX: Qt.binding(function() { return root.width }),
330− desiredY: Qt.binding(function() {
331− var dummy = listView.contentY; // force a recalc on contentY change.
332− return mapToItem(container, 0, y).y;
333− })
334− });
335− popup.retreat.connect(function() {
336− popup.destroy();
337− popup = null;
338− menuItem.forceActiveFocus();
339− });
340− popup.childActivated.connect(function() {
341− popup.destroy();
342− popup = null;
343− root.childActivated();
344− });
345− } else if (popup) {
346− popup.visible = true;
347− }
348− } else {
349− root.unityMenuModel.activate(__ownIndex);
350− root.childActivated();
351− }
352− }
353−
354− Connections {
355− target: d
356− onCurrentIndexChanged: {
357− if (popup && d.currentIndex != __ownIndex) {
358− popup.visible = false;
359− }
360− }
361− onDismissAll: {
362− if (popup) {
363− popup.destroy();
364− popup = null;
365− }
366− }
367− }
368− }
369− }
370−
371− Component {
372− id: separatorComponent
373− ListItems.ThinDivider {
374− objectName: loader.objectName + "-separator"
375− implicitHeight: units.dp(2)
376− }
377− }
378 }
380 }
379
381
380 }
382 }
qml/Components/KeyboardShortcutsOverlay.qml+1−1
@@ -161,7 +161,7 @@ Rectangle {
161 }
161 }
162
162
163 Label {
163 Label {
164− text: i18n.tr("Super + 0 to 9")
164+ text: i18n.tr("Super + 1 to 0")
165 fontSize: "small"
165 fontSize: "small"
166 font.weight: Font.Medium
166 font.weight: Font.Medium
167 }
167 }
qml/Components/WindowControlButtons.qml−21
@@ -47,13 +47,6 @@ Row {
47 onClicked: root.closeClicked()
47 onClicked: root.closeClicked()
48 visible: root.closeButtonShown
48 visible: root.closeButtonShown
49
49
50− // We dont want touch events to fall through to parent,
51− // otherwise the containsMouse will not work.
52− MouseArea {
53− anchors.fill: parent
54− propagateComposedEvents: true
55− }
56−
57 Rectangle {
50 Rectangle {
58 anchors.fill: parent
51 anchors.fill: parent
59 anchors.margins: windowIsMaximized ? units.dp(3) : 0
52 anchors.margins: windowIsMaximized ? units.dp(3) : 0
@@ -78,13 +71,6 @@ Row {
78 onClicked: root.minimizeClicked()
71 onClicked: root.minimizeClicked()
79 visible: root.minimizeButtonVisible
72 visible: root.minimizeButtonVisible
80
73
81− // We dont want touch events to fall through to parent,
82− // otherwise the containsMouse will not work.
83− MouseArea {
84− anchors.fill: parent
85− propagateComposedEvents: true
86− }
87−
88 Rectangle {
74 Rectangle {
89 anchors.fill: parent
75 anchors.fill: parent
90 anchors.margins: windowIsMaximized ? units.dp(3) : 0
76 anchors.margins: windowIsMaximized ? units.dp(3) : 0
@@ -118,13 +104,6 @@ Row {
118 }
104 }
119 }
105 }
120
106
121− // We dont want touch events to fall through to parent,
122− // otherwise the containsMouse will not work.
123− MouseArea {
124− anchors.fill: parent
125− propagateComposedEvents: true
126− }
127−
128 Rectangle {
107 Rectangle {
129 anchors.fill: parent
108 anchors.fill: parent
130 anchors.margins: windowIsMaximized ? units.dp(3) : 0
109 anchors.margins: windowIsMaximized ? units.dp(3) : 0
qml/Greeter/GreeterPrompt.qml+29−10
@@ -16,6 +16,7 @@
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19+import GSettings 1.0
19import "../Components"
20import "../Components"
20
21
21FocusScope {
22FocusScope {
@@ -43,6 +44,11 @@ FocusScope {
43 }
44 }
44 }
45 }
45
46
47+ GSettings {
48+ id: unity8Settings
49+ schema.id: "com.canonical.Unity8"
50+ }
51+
46 StyledItem {
52 StyledItem {
47 id: d
53 id: d
48
54
@@ -154,14 +160,27 @@ FocusScope {
154 }
160 }
155
161
156 secondaryItem: [
162 secondaryItem: [
157− Icon {
163+ Row {
158− id: capsIcon
164+ id: extraIcons
165+ spacing: passwordInput.frameSpacing
166+ Icon {
159− name: "keyboard-caps-enabled"
167+ name: "keyboard-caps-enabled"
160− height: units.gu(3)
168+ height: units.gu(3)
161− width: units.gu(3)
169+ width: units.gu(3)
162− color: d.textColor
170+ color: d.textColor
163− visible: root.isSecret && false // TODO: detect when caps lock is on
171+ visible: root.isSecret && false // TODO: detect when caps lock is on
164− readonly property real visibleWidth: visible ? width + passwordInput.frameSpacing : 0
172+ }
173+ Icon {
174+ name: "input-keyboard-symbolic"
175+ height: units.gu(3)
176+ width: units.gu(3)
177+ color: d.textColor
178+ visible: !unity8Settings.alwaysShowOsk
179+ MouseArea {
180+ anchors.fill: parent
181+ onClicked: unity8Settings.alwaysShowOsk = true
182+ }
183+ }
165 }
184 }
166 ]
185 ]
167
186
@@ -199,7 +218,7 @@ FocusScope {
199 right: parent.right
218 right: parent.right
200 verticalCenter: parent.verticalCenter
219 verticalCenter: parent.verticalCenter
201 leftMargin: units.gu(1.5)
220 leftMargin: units.gu(1.5)
202− rightMargin: anchors.leftMargin + capsIcon.visibleWidth
221+ rightMargin: anchors.leftMargin + extraIcons.width
203 }
222 }
204 text: root.text
223 text: root.text
205 visible: passwordInput.text == "" && !passwordInput.inputMethodComposing
224 visible: passwordInput.text == "" && !passwordInput.inputMethodComposing
@@ -221,7 +240,7 @@ FocusScope {
221 anchors.left: parent.left
240 anchors.left: parent.left
222 anchors.right: parent.right
241 anchors.right: parent.right
223 anchors.leftMargin: passwordInput.frameSpacing * 2
242 anchors.leftMargin: passwordInput.frameSpacing * 2
224− anchors.rightMargin: passwordInput.frameSpacing * 2 + capsIcon.visibleWidth
243+ anchors.rightMargin: passwordInput.frameSpacing * 2 + extraIcons.width
225 color: d.drawColor
244 color: d.drawColor
226 text: passwordInput.displayText
245 text: passwordInput.displayText
227 visible: root.isPrompt && !root.interactive
246 visible: root.isPrompt && !root.interactive
qml/Launcher/Launcher.qml+3
@@ -114,6 +114,9 @@ FocusScope {
114
114
115 function hide(flags) {
115 function hide(flags) {
116 if ((flags & ignoreHideIfMouseOverLauncher) && Utils.Functions.itemUnderMouse(panel)) {
116 if ((flags & ignoreHideIfMouseOverLauncher) && Utils.Functions.itemUnderMouse(panel)) {
117+ if (state == "drawer") {
118+ switchToNextState("visibleTemporary");
119+ }
117 return;
120 return;
118 }
121 }
119 if (root.lockedVisible) {
122 if (root.lockedVisible) {
qml/Launcher/LauncherPanel.qml+3−1
@@ -92,8 +92,10 @@ Rectangle {
92 objectName: "dashItem"
92 objectName: "dashItem"
93 width: parent.width * .6
93 width: parent.width * .6
94 height: width
94 height: width
95+ sourceSize.width: width
96+ sourceSize.height: height
95 anchors.centerIn: parent
97 anchors.centerIn: parent
96− source: "graphics/home.png"
98+ source: "graphics/home.svg"
97 rotation: root.rotation
99 rotation: root.rotation
98 }
100 }
99 AbstractButton {
101 AbstractButton {
qml/Launcher/MoreAppsHeader.qml+16
@@ -1,3 +1,19 @@
1+/*
2+ * Copyright (C) 2017 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+
1import QtQuick 2.4
17import QtQuick 2.4
2import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
3
19
qml/Launcher/graphics/home.svgnew file+243
@@ -0,0 +1,243 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ viewBox="0 0 90 89.999999"
13+ style="enable-background:new"
14+ inkscape:export-ydpi="180"
15+ inkscape:export-xdpi="180"
16+ inkscape:export-filename="app_shape02.png"
17+ sodipodi:docname="home@18.svg"
18+ inkscape:version="0.92+devel unknown"
19+ version="1.1"
20+ id="svg3336"
21+ height="90"
22+ width="90">
23+ <sodipodi:namedview
24+ inkscape:snap-global="false"
25+ fit-margin-bottom="0"
26+ fit-margin-right="0"
27+ fit-margin-left="0"
28+ fit-margin-top="0"
29+ inkscape:snap-grids="true"
30+ inkscape:guide-bbox="true"
31+ showguides="false"
32+ inkscape:snap-center="true"
33+ inkscape:snap-object-midpoints="true"
34+ inkscape:snap-midpoints="true"
35+ inkscape:snap-smooth-nodes="true"
36+ inkscape:snap-intersection-paths="true"
37+ inkscape:object-nodes="true"
38+ inkscape:object-paths="true"
39+ inkscape:snap-bbox-midpoints="true"
40+ inkscape:snap-bbox-edge-midpoints="true"
41+ inkscape:bbox-nodes="true"
42+ inkscape:bbox-paths="true"
43+ inkscape:snap-bbox="true"
44+ showborder="true"
45+ inkscape:showpageshadow="false"
46+ inkscape:snap-page="true"
47+ inkscape:window-maximized="1"
48+ inkscape:window-y="24"
49+ inkscape:window-x="0"
50+ inkscape:window-height="1029"
51+ inkscape:window-width="1920"
52+ showgrid="false"
53+ inkscape:current-layer="layer1"
54+ inkscape:document-units="px"
55+ inkscape:cy="-8.7116629"
56+ inkscape:cx="2.9876656"
57+ inkscape:zoom="1.5625"
58+ inkscape:pageshadow="2"
59+ inkscape:pageopacity="0"
60+ borderopacity="1.0"
61+ bordercolor="#666666"
62+ pagecolor="#4f4f4f"
63+ id="base"
64+ inkscape:document-rotation="0">
65+ <inkscape:grid
66+ type="xygrid"
67+ id="grid811"
68+ originx="-211"
69+ originy="-195.00023"
70+ visible="true"
71+ enabled="true" />
72+ <sodipodi:guide
73+ orientation="1,0"
74+ position="-107,-35.000232"
75+ id="guide819"
76+ inkscape:locked="false" />
77+ <sodipodi:guide
78+ orientation="1,0"
79+ position="-91,-51.000232"
80+ id="guide821"
81+ inkscape:locked="false" />
82+ <sodipodi:guide
83+ orientation="1,0"
84+ position="181,-67.000232"
85+ id="guide823"
86+ inkscape:locked="false" />
87+ <sodipodi:guide
88+ orientation="1,0"
89+ position="197,-67.000232"
90+ id="guide825"
91+ inkscape:locked="false" />
92+ <sodipodi:guide
93+ orientation="0,1"
94+ position="117,196.99977"
95+ id="guide827"
96+ inkscape:locked="false" />
97+ <sodipodi:guide
98+ orientation="0,1"
99+ position="125,180.99977"
100+ id="guide829"
101+ inkscape:locked="false" />
102+ <sodipodi:guide
103+ orientation="0,1"
104+ position="-35,-91.000232"
105+ id="guide831"
106+ inkscape:locked="false" />
107+ <sodipodi:guide
108+ orientation="0,1"
109+ position="5.0000002,-107.00023"
110+ id="guide833"
111+ inkscape:locked="false" />
112+ <inkscape:grid
113+ type="axonomgrid"
114+ id="grid835"
115+ units="px"
116+ empspacing="60"
117+ gridanglex="42.9"
118+ gridanglez="42.9"
119+ spacingy="3.522px"
120+ enabled="false"
121+ originx="-211"
122+ originy="-194.00023" />
123+ <sodipodi:guide
124+ orientation="0,1"
125+ position="133,164.99977"
126+ id="guide4126"
127+ inkscape:locked="false" />
128+ <sodipodi:guide
129+ orientation="0,1"
130+ position="-51,-75.000232"
131+ id="guide4128"
132+ inkscape:locked="false" />
133+ <sodipodi:guide
134+ orientation="1,0"
135+ position="-75,-115.00023"
136+ id="guide4130"
137+ inkscape:locked="false" />
138+ <sodipodi:guide
139+ orientation="1,0"
140+ position="165,-75.000232"
141+ id="guide4134"
142+ inkscape:locked="false" />
143+ <sodipodi:guide
144+ orientation="-0.70710678,0.70710678"
145+ position="333,332.99977"
146+ id="guide4136"
147+ inkscape:locked="false" />
148+ <sodipodi:guide
149+ orientation="1,0"
150+ position="45,-243.00023"
151+ id="guide4138"
152+ inkscape:locked="false" />
153+ <sodipodi:guide
154+ orientation="0,1"
155+ position="333,44.999767"
156+ id="guide4140"
157+ inkscape:locked="false" />
158+ <sodipodi:guide
159+ orientation="0.70710678,0.70710678"
160+ position="333,-243.00023"
161+ id="guide4142"
162+ inkscape:locked="false" />
163+ <sodipodi:guide
164+ orientation="0,1"
165+ position="37,-195.00023"
166+ id="guide4152"
167+ inkscape:locked="false" />
168+ <sodipodi:guide
169+ orientation="0,1"
170+ position="125,284.99977"
171+ id="guide4154"
172+ inkscape:locked="false" />
173+ <sodipodi:guide
174+ position="133,-115.00023"
175+ orientation="1,0"
176+ id="guide4361"
177+ inkscape:locked="false" />
178+ <sodipodi:guide
179+ position="365,-43.000232"
180+ orientation="0,1"
181+ id="guide4363"
182+ inkscape:locked="false" />
183+ <sodipodi:guide
184+ position="-43,-19.000232"
185+ orientation="1,0"
186+ id="guide4229"
187+ inkscape:locked="false" />
188+ <sodipodi:guide
189+ position="101,132.99977"
190+ orientation="0,1"
191+ id="guide4233"
192+ inkscape:locked="false" />
193+ <sodipodi:guide
194+ position="-30.52,-307.00023"
195+ orientation="0,1"
196+ id="guide4235"
197+ inkscape:locked="false" />
198+ </sodipodi:namedview>
199+ <defs
200+ id="defs3338">
201+ <clipPath
202+ clipPathUnits="userSpaceOnUse"
203+ id="clipPath4755">
204+ <path
205+ style="color:#000000;opacity:0.24899998;fill:#5e2c73;stroke-width:5"
206+ d="M 360,50 594,284 V 215.89844 C 594,70.73665 573.2426,50 427.94531,50 Z"
207+ id="path4757"
208+ inkscape:connector-curvature="0" />
209+ </clipPath>
210+ <clipPath
211+ clipPathUnits="userSpaceOnUse"
212+ id="clipPath4767">
213+ <path
214+ style="color:#000000;fill:#f6f6f6;stroke-width:5"
215+ d="M 543.8125,454.1875 312.18945,685.81055 367.94531,681 C 512.70468,668.50896 526.55393,654.72881 539,510.10156 Z"
216+ id="path4769"
217+ inkscape:connector-curvature="0" />
218+ </clipPath>
219+ </defs>
220+ <metadata
221+ id="metadata3341">
222+ <rdf:RDF>
223+ <cc:Work
224+ rdf:about="">
225+ <dc:format>image/svg+xml</dc:format>
226+ <dc:type
227+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
228+ <dc:title></dc:title>
229+ </cc:Work>
230+ </rdf:RDF>
231+ </metadata>
232+ <g
233+ inkscape:groupmode="layer"
234+ id="layer1"
235+ inkscape:label="Pictogram"
236+ transform="translate(-243,-242.99977)">
237+ <path
238+ style="color:#000000;fill:#ffffff;stroke-width:8;stroke-linecap:square"
239+ d="m 288,243.00023 a 44.999951,44.999951 0 0 0 -45,45 44.999951,44.999951 0 0 0 45,44.99954 44.999951,44.999951 0 0 0 45,-44.99954 44.999951,44.999951 0 0 0 -45,-45 z m 14.57434,13.77039 c 1.02065,-0.0231 2.06021,0.22446 3.0092,0.77195 2.76095,1.59476 3.70514,5.12339 2.11064,7.88408 -1.59271,2.76068 -5.12109,3.70488 -7.88178,2.11064 -2.75891,-1.59271 -3.70494,-5.12125 -2.11248,-7.88041 1.04672,-1.8117 2.9259,-2.84213 4.87442,-2.88626 z m -14.5748,6.15598 c 2.32096,0 4.56584,0.32221 6.69895,0.91089 0.37619,2.31944 1.75264,4.4561 3.94752,5.7227 2.19107,1.26304 4.72599,1.38994 6.92062,0.56079 4.26774,4.19709 7.04521,9.90478 7.44987,16.26267 l -8.22457,0.12112 C 304.03344,277.89278 296.80747,271.1402 288,271.1402 c -2.53726,0 -4.9441,0.5641 -7.10161,1.56813 l -4.01059,-7.18662 c 3.34938,-1.65779 7.12182,-2.59511 11.11174,-2.59511 z m -13.90979,4.21169 4.21992,7.06779 c -4.3351,3.05147 -7.16833,8.09073 -7.16833,13.79461 0,5.70414 2.83323,10.74309 7.16833,13.79278 l -4.21992,7.06916 c -5.0519,-3.37556 -8.80916,-8.53411 -10.36858,-14.57708 1.82199,-1.48672 2.98818,-3.74984 2.98818,-6.28532 0,-2.53701 -1.16619,-4.80043 -2.98818,-6.28715 1.56145,-6.04118 5.31871,-11.19923 10.36858,-14.57479 z m -15.48569,15.08943 c 3.18747,0 5.7716,2.58397 5.7716,5.77297 0,3.18746 -2.58413,5.77114 -5.7716,5.77114 -3.18924,0 -5.77296,-2.58368 -5.77296,-5.77114 0,-3.189 2.58372,-5.77297 5.77296,-5.77297 z m 46.18604,7.2666 8.2264,0.12112 c -0.40465,6.3579 -3.18213,12.06558 -7.44987,16.26267 -2.19462,-0.82915 -4.72803,-0.70428 -6.92062,0.5608 -2.19438,1.26888 -3.57087,3.40326 -3.94706,5.72269 -2.13286,0.59047 -4.378,0.91318 -6.69895,0.91318 -3.99018,0 -7.76236,-0.93758 -11.11175,-2.5974 l 4.0106,-7.18662 c 2.15726,1.00378 4.56389,1.56859 7.10115,1.56859 8.80772,0 16.03339,-6.75074 16.7901,-15.36503 z m -1.96713,18.19415 c 1.94837,0.044 3.82782,1.0739 4.87304,2.88443 1.59449,2.76095 0.64796,6.28907 -2.11247,7.88179 -2.76069,1.5945 -6.28862,0.64822 -7.88133,-2.11247 -1.59475,-2.75917 -0.64821,-6.2873 2.11247,-7.88179 0.94829,-0.5475 1.98772,-0.795 3.00829,-0.77196 z"
240+ id="circle4206"
241+ inkscape:connector-curvature="0" />
242+ </g>
243+</svg>
qml/Launcher/graphics/home@18.pngdeleted

Binary file not shown.

qml/OrientedShell.qml+8−6
@@ -197,6 +197,12 @@ Item {
197 value: !shell.oskEnabled || shell.usageScenario == "desktop"
197 value: !shell.oskEnabled || shell.usageScenario == "desktop"
198 }
198 }
199
199
200+ Binding {
201+ target: unity8Settings
202+ property: "oskSwitchVisible"
203+ value: shell.hasKeyboard
204+ }
205+
200 readonly property int supportedOrientations: shell.supportedOrientations
206 readonly property int supportedOrientations: shell.supportedOrientations
201 & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation
207 & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation
202 ? orientations.native_
208 ? orientations.native_
@@ -268,12 +274,8 @@ Item {
268 mode: applicationArguments.mode
274 mode: applicationArguments.mode
269 hasMouse: pointerInputDevices > 0
275 hasMouse: pointerInputDevices > 0
270 hasKeyboard: keyboardsModel.count > 0
276 hasKeyboard: keyboardsModel.count > 0
271− // TODO: Factor in if the current screen is a touch screen and if the user wants to
277+ hasTouchscreen: touchScreensModel.count > 0
272− // have multiple keyboards around. For now we only enable one keyboard at a time
278+ oskEnabled: unity8Settings.alwaysShowOsk || !hasKeyboard || forceOSKEnabled
273− // thus hiding it here if there is a physical one around or if we have a second
274− // screen (the virtual touchpad & osk on the phone) attached.
275− oskEnabled: (keyboardsModel.count === 0 && screens.count === 1) ||
276− forceOSKEnabled
277
279
278 usageScenario: {
280 usageScenario: {
279 if (unity8Settings.usageMode === "Windowed") {
281 if (unity8Settings.usageMode === "Windowed") {
qml/Panel/Panel.qml+6−11
@@ -23,9 +23,6 @@ import Utils 0.1
23import Unity.ApplicationMenu 0.1
23import Unity.ApplicationMenu 0.1
24
24
25import QtQuick.Window 2.2
25import QtQuick.Window 2.2
26−// for indicator-keyboard
27−import AccountsService 0.1
28−import Unity.InputInfo 0.1
29
26
30import "../ApplicationMenus"
27import "../ApplicationMenus"
31import "../Components"
28import "../Components"
@@ -47,6 +44,7 @@ Item {
47 property bool fullscreenMode: false
44 property bool fullscreenMode: false
48 property real panelAreaShowProgress: 1.0
45 property real panelAreaShowProgress: 1.0
49 property bool greeterShown: false
46 property bool greeterShown: false
47+ property bool hasKeyboard: false
50
48
51 property string mode: "staged"
49 property string mode: "staged"
52
50
@@ -231,6 +229,8 @@ Item {
231 target: __indicators
229 target: __indicators
232 onShownChanged: bar.dismiss();
230 onShownChanged: bar.dismiss();
233 }
231 }
232+
233+ onDoubleClicked: PanelState.restoreClicked()
234 }
234 }
235 }
235 }
236 }
236 }
@@ -337,12 +337,12 @@ Item {
337 objectName: identifier+"-panelItem"
337 objectName: identifier+"-panelItem"
338
338
339 property int ownIndex: index
339 property int ownIndex: index
340− property bool overflow: parent.width - x > __indicators.overFlowWidth
340+ readonly property bool overflow: parent.width - x > __indicators.overFlowWidth
341− property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
341+ readonly property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
342 // HACK for indicator-session
342 // HACK for indicator-session
343 readonly property bool hideSessionIndicator: identifier == "indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
343 readonly property bool hideSessionIndicator: identifier == "indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
344 // HACK for indicator-keyboard
344 // HACK for indicator-keyboard
345− readonly property bool hideKeyboardIndicator: identifier == "indicator-keyboard" && (AccountsService.keymaps.length < 2 || keyboardsModel.count == 0)
345+ readonly property bool hideKeyboardIndicator: identifier == "indicator-keyboard" && !hasKeyboard
346
346
347 height: parent.height
347 height: parent.height
348 expanded: indicators.expanded
348 expanded: indicators.expanded
@@ -396,11 +396,6 @@ Item {
396 }
396 }
397 }
397 }
398
398
399− InputDeviceModel {
400− id: keyboardsModel
401− deviceFilter: InputInfo.Keyboard
402− }
403−
404 IndicatorsLight {
399 IndicatorsLight {
405 id: indicatorLights
400 id: indicatorLights
406 }
401 }
qml/Panel/PanelMenuPage.qml+1−1
@@ -89,7 +89,7 @@ PageStack {
89 leadingActionBar.actions: [
89 leadingActionBar.actions: [
90 Action {
90 Action {
91 iconName: "back"
91 iconName: "back"
92− text: "Back"
92+ text: i18n.tr("Back")
93 onTriggered: {
93 onTriggered: {
94 root.pop();
94 root.pop();
95 }
95 }
qml/Shell.qml+4−2
@@ -69,6 +69,7 @@ StyledItem {
69 }
69 }
70 property bool hasMouse: false
70 property bool hasMouse: false
71 property bool hasKeyboard: false
71 property bool hasKeyboard: false
72+ property bool hasTouchscreen: false
72
73
73 // to be read from outside
74 // to be read from outside
74 readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
75 readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
@@ -533,6 +534,7 @@ StyledItem {
533 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0 && !stage.spreadShown)
534 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0 && !stage.spreadShown)
534 || greeter.hasLockedApp
535 || greeter.hasLockedApp
535 greeterShown: greeter && greeter.shown
536 greeterShown: greeter && greeter.shown
537+ hasKeyboard: shell.hasKeyboard
536 }
538 }
537
539
538 Launcher {
540 Launcher {
@@ -627,8 +629,8 @@ StyledItem {
627 objectName: "tutorial"
629 objectName: "tutorial"
628 anchors.fill: parent
630 anchors.fill: parent
629
631
630− paused: callManager.hasCalls || !greeter || greeter.active ||
632+ paused: callManager.hasCalls || !greeter || greeter.active || wizard.active
631− wizard.active
633+ || !hasTouchscreen // TODO #1661557 something better for no touchscreen
632 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
634 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
633 inputMethod.visible ||
635 inputMethod.visible ||
634 (launcher.shown && !launcher.lockedVisible) ||
636 (launcher.shown && !launcher.lockedVisible) ||
qml/Stage/ApplicationWindow.qml+1
@@ -28,6 +28,7 @@ FocusScope {
28 property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
28 property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
29 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
29 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
30 readonly property QtObject focusedSurface: d.focusedSurface.surface
30 readonly property QtObject focusedSurface: d.focusedSurface.surface
31+ readonly property alias surfaceInitialized: d.surfaceInitialized
31
32
32 // to be set from outside
33 // to be set from outside
33 property QtObject surface
34 property QtObject surface
qml/Stage/ChildWindow.qml+34−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -143,6 +143,39 @@ Item {
143 consumesInput: true
143 consumesInput: true
144 }
144 }
145
145
146+ Loader {
147+ active: d.moveable
148+ anchors.fill: parent
149+ sourceComponent: Component {
150+ MouseArea {
151+ acceptedButtons: Qt.LeftButton
152+ property bool dragging: false
153+ cursorShape: undefined // don't interfere with the cursor shape set by the underlying MirSurfaceItem
154+ onPressed: {
155+ if (mouse.button == Qt.LeftButton && mouse.modifiers == Qt.AltModifier) {
156+ d.moveHandler.handlePressedChanged(true, Qt.LeftButton, mouse.x, mouse.y);
157+ dragging = true;
158+ mouse.accepted = true;
159+ } else {
160+ mouse.accepted = false;
161+ }
162+ }
163+ onPositionChanged: {
164+ if (dragging) {
165+ d.moveHandler.handlePositionChanged(mouse);
166+ }
167+ }
168+ onReleased: {
169+ if (dragging) {
170+ d.moveHandler.handlePressedChanged(false, Qt.LeftButton);
171+ d.moveHandler.handleReleased();
172+ dragging = false;
173+ }
174+ }
175+ }
176+ }
177+ }
178+
146 Loader {
179 Loader {
147 id: touchOverlayLoader
180 id: touchOverlayLoader
148 active: d.resizeable || d.moveable
181 active: d.resizeable || d.moveable
qml/Stage/DecoratedWindow.qml+7
@@ -80,6 +80,10 @@ FocusScope {
80 signal decorationPressed()
80 signal decorationPressed()
81 signal decorationReleased()
81 signal decorationReleased()
82
82
83+ function cancelDrag() {
84+ moveHandler.cancelDrag();
85+ }
86+
83 QtObject {
87 QtObject {
84 id: d
88 id: d
85 property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
89 property int requestedDecorationHeight: root.hasDecoration ? decoration.height : 0
@@ -204,12 +208,14 @@ FocusScope {
204 height: units.gu(3)
208 height: units.gu(3)
205
209
206 title: applicationWindow.title
210 title: applicationWindow.title
211+ windowMoving: moveHandler.moving && !altDragHandler.dragging
207
212
208 opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
213 opacity: root.hasDecoration ? Math.min(1, root.showDecoration) : 0
209 Behavior on opacity { UbuntuNumberAnimation { } }
214 Behavior on opacity { UbuntuNumberAnimation { } }
210
215
211 onPressed: root.decorationPressed();
216 onPressed: root.decorationPressed();
212 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
217 onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
218+ onPressedChangedEx: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
213 onPositionChanged: moveHandler.handlePositionChanged(mouse)
219 onPositionChanged: moveHandler.handlePositionChanged(mouse)
214 onReleased: {
220 onReleased: {
215 root.decorationReleased();
221 root.decorationReleased();
@@ -255,6 +261,7 @@ FocusScope {
255 }
261 }
256
262
257 MouseArea {
263 MouseArea {
264+ id: altDragHandler
258 anchors.fill: applicationWindow
265 anchors.fill: applicationWindow
259 acceptedButtons: Qt.LeftButton
266 acceptedButtons: Qt.LeftButton
260 property bool dragging: false
267 property bool dragging: false
qml/Stage/MoveHandler.qml+13
@@ -29,6 +29,7 @@ QtObject {
29 property real boundsTopMargin: 0
29 property real boundsTopMargin: 0
30
30
31 readonly property bool dragging: priv.dragging
31 readonly property bool dragging: priv.dragging
32+ readonly property bool moving: priv.moving
32
33
33 signal fakeMaximizeAnimationRequested(real amount)
34 signal fakeMaximizeAnimationRequested(real amount)
34 signal fakeMaximizeLeftAnimationRequested(real amount)
35 signal fakeMaximizeLeftAnimationRequested(real amount)
@@ -43,6 +44,7 @@ QtObject {
43 property real distanceX
44 property real distanceX
44 property real distanceY
45 property real distanceY
45 property bool dragging
46 property bool dragging
47+ property bool moving
46
48
47 readonly property int triggerArea: units.gu(8)
49 readonly property int triggerArea: units.gu(8)
48 property bool nearLeftEdge: target.maximizedLeft
50 property bool nearLeftEdge: target.maximizedLeft
@@ -110,6 +112,7 @@ QtObject {
110
112
111 function handlePositionChanged(mouse, sensingPoints) {
113 function handlePositionChanged(mouse, sensingPoints) {
112 if (priv.dragging) {
114 if (priv.dragging) {
115+ priv.moving = true;
113 priv.mouseDownTimer.stop();
116 priv.mouseDownTimer.stop();
114 Mir.cursorName = "grabbing";
117 Mir.cursorName = "grabbing";
115
118
@@ -180,6 +183,7 @@ QtObject {
180 }
183 }
181
184
182 function handleReleased(touchMode) {
185 function handleReleased(touchMode) {
186+ priv.moving = false;
183 if (touchMode) {
187 if (touchMode) {
184 priv.progress = 0;
188 priv.progress = 0;
185 priv.resetEdges();
189 priv.resetEdges();
@@ -190,4 +194,13 @@ QtObject {
190 target.restoredY = target.y;
194 target.restoredY = target.y;
191 }
195 }
192 }
196 }
197+
198+ function cancelDrag() {
199+ priv.dragging = false;
200+ root.stopFakeAnimation();
201+ priv.mouseDownTimer.stop();
202+ Mir.cursorName = "";
203+ priv.progress = 0;
204+ priv.resetEdges();
205+ }
193}
206}
qml/Stage/Stage.qml+23−11
@@ -470,7 +470,7 @@ FocusScope {
470 extend: "stagedRightEdge"
470 extend: "stagedRightEdge"
471 PropertyChanges {
471 PropertyChanges {
472 target: sideStage
472 target: sideStage
473− opacity: priv.sideStageDelegate.x === sideStage.x ? 1 : 0
473+ opacity: priv.sideStageDelegate && priv.sideStageDelegate.x === sideStage.x ? 1 : 0
474 visible: true
474 visible: true
475 }
475 }
476 },
476 },
@@ -723,6 +723,7 @@ FocusScope {
723 // miral doesn't know about our window decorations. So we have to deduct them
723 // miral doesn't know about our window decorations. So we have to deduct them
724 value: Qt.point(appDelegate.requestedX + appDelegate.clientAreaItem.x,
724 value: Qt.point(appDelegate.requestedX + appDelegate.clientAreaItem.x,
725 appDelegate.requestedY + appDelegate.clientAreaItem.y)
725 appDelegate.requestedY + appDelegate.clientAreaItem.y)
726+ when: root.mode == "windowed"
726 }
727 }
727
728
728 // In those are for windowed mode. Those values basically store the window's properties
729 // In those are for windowed mode. Those values basically store the window's properties
@@ -768,7 +769,6 @@ FocusScope {
768 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
769 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
769 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
770 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
770 && root.inputMethodRect.height > 0
771 && root.inputMethodRect.height > 0
771−
772 }
772 }
773
773
774 Behavior on x { id: xBehavior; enabled: priv.closingIndex >= 0; UbuntuNumberAnimation { onRunningChanged: if (!running) priv.closingIndex = -1} }
774 Behavior on x { id: xBehavior; enabled: priv.closingIndex >= 0; UbuntuNumberAnimation { onRunningChanged: if (!running) priv.closingIndex = -1} }
@@ -933,7 +933,8 @@ FocusScope {
933 } else if (model.window.state === Mir.MaximizedBottomRightState) {
933 } else if (model.window.state === Mir.MaximizedBottomRightState) {
934 appDelegate.maximizeBottomRight();
934 appDelegate.maximizeBottomRight();
935 } else if (model.window.state === Mir.RestoredState) {
935 } else if (model.window.state === Mir.RestoredState) {
936− if (appDelegate.fullscreen && appDelegate.prevWindowState != WindowStateStorage.WindowStateRestored) {
936+ if (appDelegate.fullscreen && appDelegate.prevWindowState != WindowStateStorage.WindowStateRestored
937+ && appDelegate.prevWindowState != WindowStateStorage.WindowStateNormal) {
937 model.window.requestState(WindowStateStorage.toMirState(appDelegate.prevWindowState));
938 model.window.requestState(WindowStateStorage.toMirState(appDelegate.prevWindowState));
938 } else {
939 } else {
939 appDelegate.restore();
940 appDelegate.restore();
@@ -945,6 +946,21 @@ FocusScope {
945 }
946 }
946 }
947 }
947
948
949+ readonly property bool windowReady: clientAreaItem.surfaceInitialized
950+ onWindowReadyChanged: {
951+ if (windowReady) {
952+ var loadedMirState = WindowStateStorage.toMirState(windowStateSaver.loadedState);
953+ // need to apply the shell chrome policy on top the saved window state
954+ var policy;
955+ if (root.mode == "windowed") {
956+ policy = windowedFullscreenPolicy;
957+ } else {
958+ policy = stagedFullscreenPolicy
959+ }
960+ window.requestState(policy.applyPolicy(loadedMirState, surface.shellChrome));
961+ }
962+ }
963+
948 Component.onCompleted: {
964 Component.onCompleted: {
949 if (application && application.rotatesWindowContents) {
965 if (application && application.rotatesWindowContents) {
950 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
966 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -957,7 +973,6 @@ FocusScope {
957 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
973 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
958 // Now load any saved state. This needs to happen *after* the cascading!
974 // Now load any saved state. This needs to happen *after* the cascading!
959 windowStateSaver.load();
975 windowStateSaver.load();
960− model.window.requestState(WindowStateStorage.toMirState(windowState));
961
976
962 updateQmlFocusFromMirSurfaceFocus();
977 updateQmlFocusFromMirSurfaceFocus();
963
978
@@ -1173,6 +1188,7 @@ FocusScope {
1173 states: [
1188 states: [
1174 State {
1189 State {
1175 name: "spread"; when: root.state == "spread"
1190 name: "spread"; when: root.state == "spread"
1191+ StateChangeScript { script: { decoratedWindow.cancelDrag(); } }
1176 PropertyChanges {
1192 PropertyChanges {
1177 target: decoratedWindow;
1193 target: decoratedWindow;
1178 showDecoration: false;
1194 showDecoration: false;
@@ -1199,6 +1215,7 @@ FocusScope {
1199 }
1215 }
1200 PropertyChanges { target: dragArea; enabled: true }
1216 PropertyChanges { target: dragArea; enabled: true }
1201 PropertyChanges { target: windowInfoItem; opacity: spreadMaths.tileInfoOpacity; visible: spreadMaths.itemVisible }
1217 PropertyChanges { target: windowInfoItem; opacity: spreadMaths.tileInfoOpacity; visible: spreadMaths.itemVisible }
1218+ PropertyChanges { target: touchControls; enabled: false }
1202 },
1219 },
1203 State {
1220 State {
1204 name: "stagedRightEdge"
1221 name: "stagedRightEdge"
@@ -1441,7 +1458,7 @@ FocusScope {
1441 ]
1458 ]
1442 transitions: [
1459 transitions: [
1443 Transition {
1460 Transition {
1444− from: "staged,stagedWithSideStage"; to: "normal"
1461+ from: "staged,stagedWithSideStage"
1445 enabled: appDelegate.animationsEnabled
1462 enabled: appDelegate.animationsEnabled
1446 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1463 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1447 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,opacity,requestedWidth,requestedHeight,scale"; duration: priv.animationDuration }
1464 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,opacity,requestedWidth,requestedHeight,scale"; duration: priv.animationDuration }
@@ -1462,8 +1479,7 @@ FocusScope {
1462 },
1479 },
1463 Transition {
1480 Transition {
1464 from: "normal,staged"; to: "stagedWithSideStage"
1481 from: "normal,staged"; to: "stagedWithSideStage"
1465− UbuntuNumberAnimation { target: appDelegate; properties: "x,y"; duration: priv.animationDuration }
1466− UbuntuNumberAnimation { target: appDelegate; properties: "requestedWidth,requestedHeight"; duration: priv.animationDuration }
1482+ UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedWidth,requestedHeight"; duration: priv.animationDuration }
1467 },
1483 },
1468 Transition {
1484 Transition {
1469 to: "windowedRightEdge"
1485 to: "windowedRightEdge"
@@ -1503,7 +1519,6 @@ FocusScope {
1503 from: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1519 from: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1504 to: "minimized"
1520 to: "minimized"
1505 SequentialAnimation {
1521 SequentialAnimation {
1506− ScriptAction { script: print("transitioning:", appDelegate.x, appDelegate.y, appDelegate.scale) }
1507 ScriptAction { script: { fakeRectangle.stop(); } }
1522 ScriptAction { script: { fakeRectangle.stop(); } }
1508 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1523 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1509 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,scale,opacity"; duration: priv.animationDuration }
1524 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,scale,opacity"; duration: priv.animationDuration }
@@ -1514,7 +1529,6 @@ FocusScope {
1514 from: "minimized"
1529 from: "minimized"
1515 to: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1530 to: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1516 SequentialAnimation {
1531 SequentialAnimation {
1517− ScriptAction { script: print("transitioning:", appDelegate.x, appDelegate.y, appDelegate.scale) }
1518 PropertyAction { target: appDelegate; property: "visuallyMinimized,z" }
1532 PropertyAction { target: appDelegate; property: "visuallyMinimized,z" }
1519 ParallelAnimation {
1533 ParallelAnimation {
1520 UbuntuNumberAnimation { target: appDelegate; properties: "x"; from: -appDelegate.width / 2; duration: priv.animationDuration }
1534 UbuntuNumberAnimation { target: appDelegate; properties: "x"; from: -appDelegate.width / 2; duration: priv.animationDuration }
@@ -1661,8 +1675,6 @@ FocusScope {
1661
1675
1662 WindowedFullscreenPolicy {
1676 WindowedFullscreenPolicy {
1663 id: windowedFullscreenPolicy
1677 id: windowedFullscreenPolicy
1664− active: root.mode == "windowed"
1665− surface: model.window.surface
1666 }
1678 }
1667 StagedFullscreenPolicy {
1679 StagedFullscreenPolicy {
1668 id: stagedFullscreenPolicy
1680 id: stagedFullscreenPolicy
qml/Stage/StageMaths.qml+16
@@ -1,3 +1,19 @@
1+/*
2+ * Copyright (C) 2017 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+
1import QtQuick 2.4
17import QtQuick 2.4
2import Unity.Application 0.1
18import Unity.Application 0.1
3import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
qml/Stage/StagedFullscreenPolicy.qml+5−11
@@ -28,14 +28,14 @@ import Unity.Application 0.1
28QtObject {
28QtObject {
29 property bool active: true
29 property bool active: true
30
30
31− property var surface: null
31+ function applyPolicy(surfaceState, surfaceChrome) {
32− onSurfaceChanged: {
33− if (!active || !surface) return;
34− if (surface.shellChrome === Mir.LowChrome) {
32+ if (surfaceChrome === Mir.LowChrome) {
35− surface.requestState(Mir.FullscreenState);
33+ return Mir.FullscreenState;
36 }
34 }
35+ return surfaceState;
37 }
36 }
38
37
38+ property var surface: null
39 property var _connections: Connections {
39 property var _connections: Connections {
40 target: surface
40 target: surface
41 onShellChromeChanged: {
41 onShellChromeChanged: {
@@ -46,11 +46,5 @@ QtObject {
46 surface.requestState(Mir.RestoredState);
46 surface.requestState(Mir.RestoredState);
47 }
47 }
48 }
48 }
49− onStateChanged: {
50− if (!active) return;
51− if (surface.state === Mir.RestoredState && surface.shellChrome === Mir.LowChrome) {
52− surface.requestState(Mir.FullscreenState);
53− }
54− }
55 }
49 }
56}
50}
qml/Stage/WindowDecoration.qml+12−14
@@ -33,23 +33,21 @@ MouseArea {
33 property alias overlayShown: buttons.overlayShown
33 property alias overlayShown: buttons.overlayShown
34 property var menu: undefined
34 property var menu: undefined
35 property bool enableMenus: true
35 property bool enableMenus: true
36+ property bool windowMoving: false
36
37
37 readonly property real buttonsWidth: buttons.width + row.spacing
38 readonly property real buttonsWidth: buttons.width + row.spacing
38
39
39 acceptedButtons: Qt.AllButtons // prevent leaking unhandled mouse events
40 acceptedButtons: Qt.AllButtons // prevent leaking unhandled mouse events
40 hoverEnabled: true
41 hoverEnabled: true
41
42
42− drag.target: Item {}
43− drag.filterChildren: true
44− drag.threshold: 0
45−
46 signal closeClicked()
43 signal closeClicked()
47 signal minimizeClicked()
44 signal minimizeClicked()
48 signal maximizeClicked()
45 signal maximizeClicked()
49 signal maximizeHorizontallyClicked()
46 signal maximizeHorizontallyClicked()
50 signal maximizeVerticallyClicked()
47 signal maximizeVerticallyClicked()
51
48
52− onClicked: mouse.accepted = true // propogated event
49+ signal pressedChangedEx(bool pressed, var pressedButtons, real mouseX, real mouseY)
50+
53 onDoubleClicked: {
51 onDoubleClicked: {
54 if (mouse.button == Qt.LeftButton) {
52 if (mouse.button == Qt.LeftButton) {
55 root.maximizeClicked();
53 root.maximizeClicked();
@@ -69,13 +67,6 @@ MouseArea {
69 (menuBar.showRequested || root.containsMouse)
67 (menuBar.showRequested || root.containsMouse)
70 }
68 }
71
69
72− // We dont want touch events to fall through to parent as it expect some child MouseArea to have them
73− // If not some MouseArea in the menu bar, it will be this one.
74− MouseArea {
75− anchors.fill: parent
76− propagateComposedEvents: true
77− }
78−
79 Rectangle {
70 Rectangle {
80 id: background
71 id: background
81 anchors.fill: parent
72 anchors.fill: parent
@@ -136,7 +127,7 @@ MouseArea {
136 fontSize: "medium"
127 fontSize: "medium"
137 font.weight: root.active ? Font.Light : Font.Medium
128 font.weight: root.active ? Font.Light : Font.Medium
138 elide: Text.ElideRight
129 elide: Text.ElideRight
139− opacity: overlayShown || priv.shouldShowMenus ? 0 : 1
130+ opacity: overlayShown || menuBarLoader.visible ? 0 : 1
140 visible: opacity != 0
131 visible: opacity != 0
141 Behavior on opacity { UbuntuNumberAnimation {} }
132 Behavior on opacity { UbuntuNumberAnimation {} }
142 }
133 }
@@ -154,9 +145,16 @@ MouseArea {
154 height: menuBarLoader.height
145 height: menuBarLoader.height
155 enableKeyFilter: valid && root.active && root.enableMenus
146 enableKeyFilter: valid && root.active && root.enableMenus
156 unityMenuModel: root.menu
147 unityMenuModel: root.menu
148+ windowMoving: root.windowMoving
149+
150+ onPressed: root.onPressed(mouse)
151+ onPressedChangedEx: root.pressedChangedEx(pressed, pressedButtons, mouseX, mouseY)
152+ onPositionChanged: root.onPositionChanged(mouse)
153+ onReleased: root.onReleased(mouse)
154+ onDoubleClicked: root.onDoubleClicked(mouse)
157 }
155 }
158
156
159− opacity: !overlayShown && priv.shouldShowMenus ? 1 : 0
157+ opacity: (!overlayShown && priv.shouldShowMenus) || (active && priv.menuBar.valid && root.windowMoving) ? 1 : 0
160 visible: opacity == 1
158 visible: opacity == 1
161 Behavior on opacity { UbuntuNumberAnimation {} }
159 Behavior on opacity { UbuntuNumberAnimation {} }
162 }
160 }
qml/Stage/WindowInfoItem.qml+16
@@ -1,3 +1,19 @@
1+/*
2+ * Copyright (C) 2017 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+
1import QtQuick 2.4
17import QtQuick 2.4
2import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
3
19
qml/Stage/WindowResizeArea.qml+12
@@ -152,6 +152,18 @@ MouseArea {
152 onCursorNameChanged: {
152 onCursorNameChanged: {
153 Mir.cursorName = cursorName;
153 Mir.cursorName = cursorName;
154 }
154 }
155+ Component.onDestruction: {
156+ // TODO Qt 5.8 has fixed the problem with containsMouse
157+ // not being updated when the MouseArea that had containsMouse
158+ // is hidden/removed. When we start using Qt 5.8 we should
159+ // try to fix this scenario
160+ // two windows side by side
161+ // cursor in the resize left area of the right one
162+ // close window by Alt+F4
163+ // cursor should change to resize right of the left one
164+ // currently changes to ""
165+ Mir.cursorName = "";
166+ }
155
167
156 function updateBorders() {
168 function updateBorders() {
157 leftBorder = mouseX <= borderThickness;
169 leftBorder = mouseX <= borderThickness;
qml/Stage/WindowStateSaver.qml+4−3
@@ -28,6 +28,8 @@ QtObject {
28 property int leftMargin: 0
28 property int leftMargin: 0
29 property int minimumY: 0
29 property int minimumY: 0
30
30
31+ property int loadedState
32+
31 function load() {
33 function load() {
32 var defaultWidth = units.gu(60);
34 var defaultWidth = units.gu(60);
33 var defaultHeight = units.gu(50);
35 var defaultHeight = units.gu(50);
@@ -41,14 +43,13 @@ QtObject {
41 (target.fullscreen ? 0 : root.leftMargin)); });
43 (target.fullscreen ? 0 : root.leftMargin)); });
42 target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, screenHeight - target.windowedHeight), minimumY); });
44 target.windowedY = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, screenHeight - target.windowedHeight), minimumY); });
43
45
44− var windowState = WindowStateStorage.getState(target.appId, WindowStateStorage.WindowStateNormal)
45− target.restore(false /* animated */, windowState);
46−
47 target.updateNormalGeometry();
46 target.updateNormalGeometry();
48
47
49 // initialize the x/y to restore to
48 // initialize the x/y to restore to
50 target.restoredX = target.normalX;
49 target.restoredX = target.normalX;
51 target.restoredY = target.normalY;
50 target.restoredY = target.normalY;
51+
52+ loadedState = WindowStateStorage.getState(target.appId, WindowStateStorage.WindowStateNormal);
52 }
53 }
53
54
54 function save() {
55 function save() {
qml/Stage/WindowedFullscreenPolicy.qml+4−12
@@ -22,18 +22,10 @@ import Unity.Application 0.1
22// On first surface load; if the surface is set to low chrome & fullscreen, the
22// On first surface load; if the surface is set to low chrome & fullscreen, the
23// state of the window is returned to restored.
23// state of the window is returned to restored.
24QtObject {
24QtObject {
25− property bool active: true
25+ function applyPolicy(surfaceState, surfaceChrome) {
26− property QtObject surface: null
27−
28− property bool _firstTimeSurface: true
29−
30− onSurfaceChanged: {
31− if (!active || !surface) return;
32− if (!_firstTimeSurface) return;
33− _firstTimeSurface = false;
34−
35− if (surface.state === Mir.FullscreenState && surface.shellChrome === Mir.LowChrome) {
26+ if (surfaceState === Mir.FullscreenState && surfaceChrome === Mir.LowChrome) {
36− surface.requestState(Mir.RestoredState);
27+ return Mir.RestoredState;
37 }
28 }
29+ return surfaceState;
38 }
30 }
39}
31}
src/ShellView.cpp+22
@@ -19,6 +19,9 @@
19// Qt
19// Qt
20#include <QQmlContext>
20#include <QQmlContext>
21#include <QQuickItem>
21#include <QQuickItem>
22+#include <QtQuick/private/qquickitem_p.h>
23+#include <QtQuick/private/qquickrectangle_p.h>
24+#include <QtQuick/private/qquicktext_p.h>
22
25
23// local
26// local
24#include <paths.h>
27#include <paths.h>
@@ -32,6 +35,25 @@ ShellView::ShellView(QQmlEngine *engine, QObject *qmlArgs)
32
35
33 rootContext()->setContextProperty(QStringLiteral("applicationArguments"), qmlArgs);
36 rootContext()->setContextProperty(QStringLiteral("applicationArguments"), qmlArgs);
34
37
38+ connect(this, &QQuickView::statusChanged, this, [this] {
39+ if (status() == QQuickView::Error) {
40+ QQuickRectangle *rect = new QQuickRectangle(contentItem());
41+ rect->setColor(Qt::white);
42+ QQuickItemPrivate::get(rect)->anchors()->setFill(contentItem());
43+
44+ QString errorsString;
45+ for(const QQmlError &e: errors()) {
46+ errorsString += e.toString() + "\n";
47+ }
48+ QQuickText *text = new QQuickText(rect);
49+ text->setColor(Qt::black);
50+ text->setWrapMode(QQuickText::Wrap);
51+ text->setText(QString("There was an error loading Unity8:\n%1").arg(errorsString));
52+ QQuickItemPrivate::get(text)->anchors()->setFill(rect);
53+ }
54+ }
55+ );
56+
35 QUrl source(::qmlDirectory() + "/OrientedShell.qml");
57 QUrl source(::qmlDirectory() + "/OrientedShell.qml");
36 setSource(source);
58 setSource(source);
37
59
tests/CMakeLists.txt+1
@@ -143,3 +143,4 @@ add_subdirectory(plugins)
143add_subdirectory(qmltests)
143add_subdirectory(qmltests)
144add_subdirectory(whitespace)
144add_subdirectory(whitespace)
145add_subdirectory(imports)
145add_subdirectory(imports)
146+add_subdirectory(copyright)
tests/copyright/check_copyright.sh+33−4
@@ -1,7 +1,7 @@
1#!/bin/sh
1#!/bin/sh
2
2
3#
3#
4−# Copyright (C) 2013 Canonical Ltd
4+# Copyright (C) 2017 Canonical Ltd
5#
5#
6# This program is free software: you can redistribute it and/or modify
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3 as
7# it under the terms of the GNU General Public License version 3 as
@@ -15,8 +15,6 @@
15# You should have received a copy of the GNU General Public License
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17#
17#
18−# Authored by: Michi Henning <michi.henning@canonical.com>
19−#
20
18
21#
19#
22# Check that, somewhere in the first 30 lines of each file, the string "Copyright" (case independent) appears.
20# Check that, somewhere in the first 30 lines of each file, the string "Copyright" (case independent) appears.
@@ -33,7 +31,38 @@ usage()
33[ $# -lt 1 ] && usage
31[ $# -lt 1 ] && usage
34[ $# -gt 2 ] && usage
32[ $# -gt 2 ] && usage
35
33
34+# image files
36−ignore_pat="\\.sci$"
35+ignore_pat="\\.sci$|\\.svg$|\\.png$|\\.jpg$"
36+# git/bzr files
37+ignore_pat="$ignore_pat|/\\.bzr/|\\.bzrignore$|\\.gitignore$|/\\.bazaar/Makefile$|/\\.bzr-builddeb/default\\.conf$"
38+# info files
39+ignore_pat="$ignore_pat|/README$|/CODING$|/LGPL_EXCEPTION\\.txt$"
40+# cmake files
41+ignore_pat="$ignore_pat|/CMakeLists\\.txt$|\\.cmake$"
42+# card creator test files
43+ignore_pat="$ignore_pat|/cardcreator/.*\\.res$|/cardcreator/.*\\.res\\.cardcreator$|/cardcreator/.*\\.tst$"
44+# project files
45+ignore_pat="$ignore_pat|/\\.project$|/\\.pydevproject$|/\\.settings/|/\\.crossbuilder/"
46+# test desktop files
47+ignore_pat="$ignore_pat|/tests/.*/.*\\.desktop$"
48+# xml files
49+ignore_pat="$ignore_pat|\\.xml$"
50+# /data/ files
51+ignore_pat="$ignore_pat|/data/.*\\.conf$|/data/.*\\.in|/data/.*\\.url-dispatcher$|/data/.*\\.pkla$"
52+# polkit files
53+ignore_pat="$ignore_pat|\\.pkla$"
54+# /debian/ files
55+ignore_pat="$ignore_pat|/debian/"
56+# qmldir files
57+ignore_pat="$ignore_pat|/qmldir$"
58+# Doxygen files
59+ignore_pat="$ignore_pat|/Doxyfile.in$"
60+# Wizard license files
61+ignore_pat="$ignore_pat|/Wizard/licenses/.*\\.html$"
62+# qrc files
63+ignore_pat="$ignore_pat|\\.qrc$"
64+# the doc devices.conf file
65+ignore_pat="$ignore_pat|/doc/devices\\.conf$"
37
66
38#
67#
39# We don't use the -i option of licensecheck to add ignore_dir to the pattern because Jenkins creates directories
68# We don't use the -i option of licensecheck to add ignore_dir to the pattern because Jenkins creates directories
tests/mocks/Biometryd/MockOperation.h−1
@@ -40,7 +40,6 @@ Q_SIGNALS:
40
40
41private:
41private:
42 QObject *m_observer;
42 QObject *m_observer;
43− bool m_running;
44};
43};
45
44
46Q_DECLARE_METATYPE(MockOperation*)
45Q_DECLARE_METATYPE(MockOperation*)
tests/mocks/Unity/Application/ApplicationManager.cpp+1
@@ -337,6 +337,7 @@ void ApplicationManager::buildListOfAvailableApplications()
337 application->setScreenshotId("camera");
337 application->setScreenshotId("camera");
338 application->setIconId("camera");
338 application->setIconId("camera");
339 application->setFullscreen(true);
339 application->setFullscreen(true);
340+ application->setShellChrome(Mir::LowChrome);
340 application->setSupportedOrientations(Qt::PortraitOrientation
341 application->setSupportedOrientations(Qt::PortraitOrientation
341 | Qt::LandscapeOrientation
342 | Qt::LandscapeOrientation
342 | Qt::InvertedPortraitOrientation
343 | Qt::InvertedPortraitOrientation
tests/mocks/Unity/Indicators/fakeindicatorsmodeldata.js+16
@@ -1,3 +1,19 @@
1+/*
2+ * Copyright (C) 2017 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+
1var usageScenario = (typeof shell != 'undefined') ? shell.usageScenario : "desktop";
17var usageScenario = (typeof shell != 'undefined') ? shell.usageScenario : "desktop";
2
18
3var fakeMenuData = {
19var fakeMenuData = {
tests/mocks/liblightdm/MockController.cpp+2−1
@@ -25,6 +25,7 @@ MockController::MockController(QObject *parent)
25 : QObject(parent)
25 : QObject(parent)
26 , m_selectGuestHint(false)
26 , m_selectGuestHint(false)
27 , m_hasGuestAccountHint(false)
27 , m_hasGuestAccountHint(false)
28+ , m_sessionMode("single")
28 , m_fullSessions(
29 , m_fullSessions(
29 {
30 {
30 {"ubuntu", "Ubuntu"},
31 {"ubuntu", "Ubuntu"},
@@ -68,7 +69,7 @@ void MockController::reset()
68 setSelectGuestHint(false);
69 setSelectGuestHint(false);
69 setHasGuestAccountHint(false);
70 setHasGuestAccountHint(false);
70 setUserMode(userMode);
71 setUserMode(userMode);
71− setSessionMode("full");
72+ setSessionMode("single");
72 setNumSessions(numFullSessions());
73 setNumSessions(numFullSessions());
73 setShowManualLoginHint(false);
74 setShowManualLoginHint(false);
74 setHideUsersHint(false);
75 setHideUsersHint(false);
tests/plugins/Utils/WindowInputMonitorTest.cpp+31−1
@@ -32,7 +32,7 @@ public:
32 qint64 elapsed() const override { return m_valid ? msecsSinceEpoch - m_msecsSinceReference : qrand(); }
32 qint64 elapsed() const override { return m_valid ? msecsSinceEpoch - m_msecsSinceReference : qrand(); }
33
33
34private:
34private:
35− qint64 m_msecsSinceReference;
35+ qint64 m_msecsSinceReference{0};
36 bool m_valid{false};
36 bool m_valid{false};
37};
37};
38qint64 FakeElapsedTimer::msecsSinceEpoch = 0;
38qint64 FakeElapsedTimer::msecsSinceEpoch = 0;
@@ -89,6 +89,8 @@ private Q_SLOTS:
89 void tapWhileTouching();
89 void tapWhileTouching();
90 void multipleHomeKeys();
90 void multipleHomeKeys();
91
91
92+ void keyComboInvolvingHome();
93+
92 void repeatedSuperPress();
94 void repeatedSuperPress();
93
95
94private:
96private:
@@ -197,6 +199,34 @@ void WindowInputMonitorTest::touchTapTouch()
197 QCOMPARE(activatedSpy.count(), expectedActivatedCount);
199 QCOMPARE(activatedSpy.count(), expectedActivatedCount);
198}
200}
199
201
202+void WindowInputMonitorTest::keyComboInvolvingHome()
203+{
204+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
205+ QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
206+ QVERIFY(activatedSpy.isValid());
207+
208+ passTime(1000);
209+ {
210+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
211+ homeKeyWatcher.update(&keyEvent);
212+ }
213+ {
214+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
215+ homeKeyWatcher.update(&keyEvent);
216+ }
217+ {
218+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::NoModifier);
219+ homeKeyWatcher.update(&keyEvent);
220+ }
221+ {
222+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
223+ homeKeyWatcher.update(&keyEvent);
224+ }
225+ passTime(1000);
226+
227+ QCOMPARE(activatedSpy.count(), 0);
228+}
229+
200void WindowInputMonitorTest::tapWhileTouching()
230void WindowInputMonitorTest::tapWhileTouching()
201{
231{
202 WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
232 WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(this), new FakeElapsedTimer);
tests/qmltests/ApplicationMenuDataLoader.qml+16
@@ -1,3 +1,19 @@
1+/*
2+ * Copyright 2017 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+
1import QtQuick 2.4
17import QtQuick 2.4
2import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
3import Unity.Application 0.1
19import Unity.Application 0.1
tests/qmltests/ApplicationMenus/tst_MenuBar.qml+3
@@ -85,6 +85,7 @@ Item {
85 menuBar.dismiss();
85 menuBar.dismiss();
86 menuBackend.modelData = appMenuData.generateTestData(5,5,2,3, "menu")
86 menuBackend.modelData = appMenuData.generateTestData(5,5,2,3, "menu")
87 activatedSpy.clear();
87 activatedSpy.clear();
88+ waitForRendering(menuBar);
88 }
89 }
89
90
90 function test_mouseNavigation() {
91 function test_mouseNavigation() {
@@ -97,6 +98,7 @@ Item {
97 var menuItem2 = findChild(menuBar, "menuBar-item2"); verify(menuItem2);
98 var menuItem2 = findChild(menuBar, "menuBar-item2"); verify(menuItem2);
98
99
99 menuItem0.show();
100 menuItem0.show();
101+ mouseMove(menuItem0, menuItem0.width/2, menuItem0.height/2);
100 compare(priv.currentItem, menuItem0, "CurrentItem should be set to item 0");
102 compare(priv.currentItem, menuItem0, "CurrentItem should be set to item 0");
101 compare(priv.currentItem.popupVisible, true, "Popup should be visible");
103 compare(priv.currentItem.popupVisible, true, "Popup should be visible");
102
104
@@ -178,6 +180,7 @@ Item {
178
180
179 keyPress(data.tag, Qt.AltModifier, 100);
181 keyPress(data.tag, Qt.AltModifier, 100);
180 tryCompare(priv, "currentItem", menuItem);
182 tryCompare(priv, "currentItem", menuItem);
183+ keyRelease(data.tag, Qt.AltModifier, 100);
181 }
184 }
182
185
183 function test_menuActivateClosesMenu() {
186 function test_menuActivateClosesMenu() {
tests/qmltests/Greeter/tst_WideView.qml+4
@@ -355,6 +355,7 @@ StyledItem {
355 loader.active = true;
355 loader.active = true;
356 tryCompare(loader, "status", Loader.Ready);
356 tryCompare(loader, "status", Loader.Ready);
357 removeTimeConstraintsFromSwipeAreas(loader.item);
357 removeTimeConstraintsFromSwipeAreas(loader.item);
358+ LightDMController.sessionMode = "single";
358 }
359 }
359
360
360 function getIndexOf(name) {
361 function getIndexOf(name) {
@@ -418,6 +419,7 @@ StyledItem {
418 }
419 }
419
420
420 function test_sessionIconsAreValid() {
421 function test_sessionIconsAreValid() {
422+ LightDMController.sessionMode = "full";
421 selectUser("has-password");
423 selectUser("has-password");
422
424
423 // Test the login list icon is valid
425 // Test the login list icon is valid
@@ -439,6 +441,7 @@ StyledItem {
439 // Ensure the default session is selected (Ubuntu)
441 // Ensure the default session is selected (Ubuntu)
440 cleanup();
442 cleanup();
441
443
444+ LightDMController.sessionMode = "full";
442 selectUser("has-password");
445 selectUser("has-password");
443
446
444 var sessionChooserButton = findChild(view, "sessionChooserButton");
447 var sessionChooserButton = findChild(view, "sessionChooserButton");
@@ -484,6 +487,7 @@ StyledItem {
484 }
487 }
485
488
486 function test_sessionIconShownWithMultipleSessions() {
489 function test_sessionIconShownWithMultipleSessions() {
490+ LightDMController.sessionMode = "full";
487 selectUser("has-password");
491 selectUser("has-password");
488
492
489 var sessionChooserButton = findChild(view, "sessionChooserButton");
493 var sessionChooserButton = findChild(view, "sessionChooserButton");
tests/qmltests/Launcher/tst_Drawer.qml+17
@@ -312,6 +312,23 @@ StyledItem {
312 compare(launcher.lastSelectedApplication, "calendar-app");
312 compare(launcher.lastSelectedApplication, "calendar-app");
313 }
313 }
314
314
315+ function test_focusAppFromLauncherWhileDrawerIsOpen() {
316+ // FIXME: Skipping this test because of a bug in Qt. Please enable
317+ // once https://codereview.qt-project.org/#/c/184942/ is accepted
318+ skip();
319+
320+ launcher.openDrawer(true);
321+ waitForRendering(launcher);
322+ waitUntilTransitionsEnd(launcher);
323+
324+ var appIcon = findChild(launcher, "launcherDelegate4")
325+
326+ mouseMove(launcher, units.gu(4), launcher.height / 2)
327+ mouseClick(appIcon, appIcon.width / 2, appIcon.height / 2);
328+
329+ tryCompare(launcher, "state", "visibleTemporary");
330+ }
331+
315 function test_focusMovesCorrectlyBetweenLauncherAndDrawer() {
332 function test_focusMovesCorrectlyBetweenLauncherAndDrawer() {
316 var panel = findChild(launcher, "launcherPanel");
333 var panel = findChild(launcher, "launcherPanel");
317 var drawer = findChild(launcher, "drawer");
334 var drawer = findChild(launcher, "drawer");
tests/qmltests/Panel/tst_Panel.qml+6−3
@@ -272,6 +272,7 @@ PanelTest {
272 }
272 }
273
273
274 function cleanup() {
274 function cleanup() {
275+ panel.hasKeyboard = false;
275 panel.indicators.hide();
276 panel.indicators.hide();
276 panel.applicationMenus.hide();
277 panel.applicationMenus.hide();
277 waitForAllAnimationToComplete("initial");
278 waitForAllAnimationToComplete("initial");
@@ -713,8 +714,8 @@ PanelTest {
713 { tag: "No keyboard, no keymap", keyboard: false, keymaps: [], hidden: true },
714 { tag: "No keyboard, no keymap", keyboard: false, keymaps: [], hidden: true },
714 { tag: "No keyboard, one keymap", keyboard: false, keymaps: ["us"], hidden: true },
715 { tag: "No keyboard, one keymap", keyboard: false, keymaps: ["us"], hidden: true },
715 { tag: "No keyboard, 2 keymaps", keyboard: false, keymaps: ["us", "cs"], hidden: true },
716 { tag: "No keyboard, 2 keymaps", keyboard: false, keymaps: ["us", "cs"], hidden: true },
716− { tag: "Keyboard, no keymap", keyboard: true, keymaps: [], hidden: true },
717+ { tag: "Keyboard, no keymap", keyboard: true, keymaps: [], hidden: false },
717− { tag: "Keyboard, one keymap", keyboard: true, keymaps: ["us"], hidden: true },
718+ { tag: "Keyboard, one keymap", keyboard: true, keymaps: ["us"], hidden: false },
718 { tag: "Keyboard, 2 keymaps", keyboard: true, keymaps: ["us", "cs"], hidden: false }
719 { tag: "Keyboard, 2 keymaps", keyboard: true, keymaps: ["us", "cs"], hidden: false }
719 ];
720 ];
720 }
721 }
@@ -722,6 +723,7 @@ PanelTest {
722 function test_hidingKeyboardIndicator(data) {
723 function test_hidingKeyboardIndicator(data) {
723 var item = findChild(panel, "indicator-keyboard-panelItem");
724 var item = findChild(panel, "indicator-keyboard-panelItem");
724 AccountsService.keymaps = data.keymaps;
725 AccountsService.keymaps = data.keymaps;
726+ panel.hasKeyboard = data.keyboard;
725 if (data.keyboard) {
727 if (data.keyboard) {
726 MockInputDeviceBackend.addMockDevice("/indicator_kbd0", InputInfo.Keyboard);
728 MockInputDeviceBackend.addMockDevice("/indicator_kbd0", InputInfo.Keyboard);
727 } else {
729 } else {
@@ -734,11 +736,12 @@ PanelTest {
734 function test_visibleIndicators_data() {
736 function test_visibleIndicators_data() {
735 return [
737 return [
736 { visible: [true, false, true, false, true, true, false, true] },
738 { visible: [true, false, true, false, true, true, false, true] },
737− { visible: [false, false, false, false, false, false, true, false] }
739+ { visible: [true, false, false, false, false, false, true, false] }
738 ];
740 ];
739 }
741 }
740
742
741 function test_visibleIndicators(data) {
743 function test_visibleIndicators(data) {
744+ panel.hasKeyboard = true;
742 for (var i = 0; i < data.visible.length; i++) {
745 for (var i = 0; i < data.visible.length; i++) {
743 var visible = data.visible[i];
746 var visible = data.visible[i];
744 root.setIndicatorVisible(i, visible);
747 root.setIndicatorVisible(i, visible);
tests/qmltests/Stage/tst_DesktopStage.qml+47−3
@@ -321,7 +321,7 @@ Item {
321 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
321 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
322 verify(maximizeButton);
322 verify(maximizeButton);
323 mouseClick(maximizeButton);
323 mouseClick(maximizeButton);
324− tryCompare(appDelegate, "visuallyMaximized", true);
324+ tryCompare(appDelegate, "maximized", true);
325 }
325 }
326
326
327 function test_tappingOnDecorationFocusesApplication(data) {
327 function test_tappingOnDecorationFocusesApplication(data) {
@@ -637,7 +637,7 @@ Item {
637 var dialerAppDelegate = startApplication("dialer-app");
637 var dialerAppDelegate = startApplication("dialer-app");
638
638
639 // verify the drop shadow becomes visible
639 // verify the drop shadow becomes visible
640− verify(PanelState.dropShadow == true);
640+ tryCompareFunction(function() { return PanelState.dropShadow; }, true);
641
641
642 // close the maximized app
642 // close the maximized app
643 ApplicationManager.stopApplication("facebook-webapp");
643 ApplicationManager.stopApplication("facebook-webapp");
@@ -771,6 +771,32 @@ Item {
771 tryCompareFunction(function(){return posBefore == posAfter;}, data.button !== Qt.LeftButton ? true : false);
771 tryCompareFunction(function(){return posBefore == posAfter;}, data.button !== Qt.LeftButton ? true : false);
772 }
772 }
773
773
774+ function test_spreadDisablesWindowDrag() {
775+ var appDelegate = startApplication("dialer-app");
776+ verify(appDelegate);
777+ var decoration = findChild(appDelegate, "appWindowDecoration");
778+ verify(decoration);
779+
780+ // grab the decoration
781+ mousePress(decoration);
782+
783+ // enter the spread
784+ keyPress(Qt.Key_W, Qt.MetaModifier)
785+ tryCompare(stage, "state", "spread");
786+
787+ // try to drag the window
788+ mouseMove(decoration, 10, 10, 200);
789+
790+ // verify it's not moving even before we release the decoration drag
791+ tryCompare(appDelegate, "dragging", false);
792+
793+ // cleanup
794+ mouseRelease(decoration);
795+ keyRelease(Qt.Key_W, Qt.MetaModifier);
796+ stage.closeSpread();
797+ tryCompare(stage, "state", "windowed");
798+ }
799+
774 // regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1627281
800 // regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1627281
775 function test_doubleTapToMaximizeWindow() {
801 function test_doubleTapToMaximizeWindow() {
776 var dialerAppDelegate = startApplication("dialer-app");
802 var dialerAppDelegate = startApplication("dialer-app");
@@ -785,7 +811,7 @@ Item {
785 waitUntilTransitionsEnd(dialerAppDelegate);
811 waitUntilTransitionsEnd(dialerAppDelegate);
786 waitUntilTransitionsEnd(stage);
812 waitUntilTransitionsEnd(stage);
787
813
788− tryCompare(dialerAppDelegate, "state", "maximized");
814+ tryCompare(dialerAppDelegate, "maximized", true);
789 }
815 }
790
816
791 function test_saveRestoreSize() {
817 function test_saveRestoreSize() {
@@ -1013,5 +1039,23 @@ Item {
1013 expectFail("", "Hovering the window controls should be ignored when the menu is open");
1039 expectFail("", "Hovering the window controls should be ignored when the menu is open");
1014 tryCompare(closeButton, "containsMouse", true);
1040 tryCompare(closeButton, "containsMouse", true);
1015 }
1041 }
1042+
1043+ function test_windowControlsTouchInteractionWithMenu() {
1044+ var appDelegate = startApplication("gmail-webapp");
1045+
1046+ var wd = findChild(appDelegate, "appWindowDecoration");
1047+ var maxButton = findChild(wd, "maximizeWindowButton");
1048+ var menuBarLoader = findChild(wd, "menuBarLoader");
1049+ var menuNav = findInvisibleChild(menuBarLoader, "d");
1050+
1051+ // make the menubar active and visible, select first item
1052+ menuBarLoader.active = true;
1053+ menuNav.select(0);
1054+ tryCompare(menuBarLoader.item, "visible", true);
1055+
1056+ // verify the maximized button can still be tapped
1057+ tap(maxButton);
1058+ tryCompare(appDelegate, "state", "maximized");
1059+ }
1016 }
1060 }
1017}
1061}
tests/qmltests/Tutorial/tst_Tutorial.qml+1
@@ -149,6 +149,7 @@ Rectangle {
149 native_: shellLoader.nativeOrientation
149 native_: shellLoader.nativeOrientation
150 primary: shellLoader.primaryOrientation
150 primary: shellLoader.primaryOrientation
151 }
151 }
152+ hasTouchscreen: true
152
153
153 Component.onDestruction: {
154 Component.onDestruction: {
154 shellLoader.itemDestroyed = true;
155 shellLoader.itemDestroyed = true;
tests/qmltests/tst_OrientedShell.qml+17−3
@@ -695,9 +695,11 @@ Rectangle {
695 // false -> true -> false
695 // false -> true -> false
696 compare(transitionSpy.count, 2);
696 compare(transitionSpy.count, 2);
697
697
698+ if (!data.windowed) { // subject to shell-chrome policies
698− // It should retain native dimensions regardless of its rotation/orientation
699+ // It should retain native dimensions regardless of its rotation/orientation
699− compare(cameraSurface.width, orientedShell.width);
700+ compare(cameraSurface.width, orientedShell.width);
700− compare(cameraSurface.height, orientedShell.height);
701+ compare(cameraSurface.height, orientedShell.height);
702+ }
701
703
702 // Surface focus shouldn't have been touched because of the rotation
704 // Surface focus shouldn't have been touched because of the rotation
703 compare(focusChangedSpy.count, 0);
705 compare(focusChangedSpy.count, 0);
@@ -1641,5 +1643,17 @@ Rectangle {
1641 tryCompare(dialogLoader, "item", null);
1643 tryCompare(dialogLoader, "item", null);
1642 compare(window.activeFocusItem, surfaceItem);
1644 compare(window.activeFocusItem, surfaceItem);
1643 }
1645 }
1646+
1647+ function test_tutorialDisabledWithNoTouchscreen() {
1648+ loadShell("desktop");
1649+ usageModeSelector.selectWindowed();
1650+
1651+ MockInputDeviceBackend.addMockDevice("/touchscreen", InputInfo.TouchScreen);
1652+ var tutorial = findChild(shell, "tutorial");
1653+ tryCompare(tutorial, "paused", false);
1654+
1655+ MockInputDeviceBackend.removeDevice("/touchscreen");
1656+ tryCompare(tutorial, "paused", true);
1657+ }
1644 }
1658 }
1645}
1659}
tests/qmltests/tst_Shell.qml+76−22
@@ -137,6 +137,7 @@ Rectangle {
137 primary: shellLoader.primaryOrientation
137 primary: shellLoader.primaryOrientation
138 }
138 }
139 mode: shellLoader.mode
139 mode: shellLoader.mode
140+ hasTouchscreen: true
140 Component.onCompleted: {
141 Component.onCompleted: {
141 ApplicationManager.startApplication("unity8-dash");
142 ApplicationManager.startApplication("unity8-dash");
142 }
143 }
@@ -334,7 +335,7 @@ Rectangle {
334
335
335 Row {
336 Row {
336 CheckBox {
337 CheckBox {
337− id: fullscreeAppCheck
338+ id: fullscreenAppCheck
338 activeFocusOnPress: false
339 activeFocusOnPress: false
339 activeFocusOnTab: false
340 activeFocusOnTab: false
340
341
@@ -348,13 +349,10 @@ Rectangle {
348 }
349 }
349
350
350 Binding {
351 Binding {
351− target: fullscreeAppCheck
352+ target: fullscreenAppCheck
352 when: topLevelSurfaceList && topLevelSurfaceList.focusedWindow
353 when: topLevelSurfaceList && topLevelSurfaceList.focusedWindow
353 property: "checked"
354 property: "checked"
354− value: {
355− if (!topLevelSurfaceList || !topLevelSurfaceList.focusedWindow) return false;
356− return topLevelSurfaceList.focusedWindow.state === Mir.FullscreenState
355+ value: topLevelSurfaceList.focusedWindow.state === Mir.FullscreenState
357− }
358 }
356 }
359 }
357 }
360 Label {
358 Label {
@@ -365,6 +363,8 @@ Rectangle {
365 Row {
363 Row {
366 CheckBox {
364 CheckBox {
367 id: chromeAppCheck
365 id: chromeAppCheck
366+ activeFocusOnPress: false
367+ activeFocusOnTab: false
368
368
369 onTriggered: {
369 onTriggered: {
370 if (!topLevelSurfaceList.focusedWindow || !topLevelSurfaceList.focusedWindow.surface) return;
370 if (!topLevelSurfaceList.focusedWindow || !topLevelSurfaceList.focusedWindow.surface) return;
@@ -380,10 +380,8 @@ Rectangle {
380 target: chromeAppCheck
380 target: chromeAppCheck
381 when: topLevelSurfaceList && topLevelSurfaceList.focusedWindow !== null && topLevelSurfaceList.focusedWindow.surface !== null
381 when: topLevelSurfaceList && topLevelSurfaceList.focusedWindow !== null && topLevelSurfaceList.focusedWindow.surface !== null
382 property: "checked"
382 property: "checked"
383− value: {
384− if (!topLevelSurfaceList || !topLevelSurfaceList.focusedWindow || !topLevelSurfaceList.focusedWindow.surface) return false;
383+ value: topLevelSurfaceList.focusedWindow.surface &&
385− topLevelSurfaceList.focusedWindow.surface.shellChrome === Mir.LowChrome
384+ topLevelSurfaceList.focusedWindow.surface.shellChrome === Mir.LowChrome
386− }
387 }
385 }
388 }
386 }
389 Label {
387 Label {
@@ -2294,7 +2292,6 @@ Rectangle {
2294 return [
2292 return [
2295 { tag: "phone" },
2293 { tag: "phone" },
2296 { tag: "tablet" },
2294 { tag: "tablet" },
2297− { tag: "desktop" },
2298 ]
2295 ]
2299 }
2296 }
2300
2297
@@ -2674,8 +2671,8 @@ Rectangle {
2674 }
2671 }
2675
2672
2676 function test_cursorHidingWithFullscreenApp() {
2673 function test_cursorHidingWithFullscreenApp() {
2677− loadShell("desktop");
2674+ loadShell("phone");
2678− shell.usageScenario = "desktop";
2675+ shell.usageScenario = "phone";
2679 waitForRendering(shell);
2676 waitForRendering(shell);
2680 swipeAwayGreeter();
2677 swipeAwayGreeter();
2681
2678
@@ -2737,14 +2734,14 @@ Rectangle {
2737 GSettingsController.setEnableIndicatorMenu(true);
2734 GSettingsController.setEnableIndicatorMenu(true);
2738 }
2735 }
2739
2736
2740− function test_spreadDisabled_data() {
2737+ function test_spreadDisabled_WithSwipe_data() {
2741 return [
2738 return [
2742 { tag: "enabled", spreadEnabled: true },
2739 { tag: "enabled", spreadEnabled: true },
2743 { tag: "disabled", spreadEnabled: false }
2740 { tag: "disabled", spreadEnabled: false }
2744 ];
2741 ];
2745 }
2742 }
2746
2743
2747− function test_spreadDisabled(data) {
2744+ function test_spreadDisabled_WithSwipe(data) {
2748 loadShell("phone");
2745 loadShell("phone");
2749 swipeAwayGreeter();
2746 swipeAwayGreeter();
2750 var stage = findChild(shell, "stage");
2747 var stage = findChild(shell, "stage");
@@ -2753,9 +2750,20 @@ Rectangle {
2753 // Try swiping
2750 // Try swiping
2754 touchFlick(shell, shell.width - 2, shell.height / 2, units.gu(1), shell.height / 2);
2751 touchFlick(shell, shell.width - 2, shell.height / 2, units.gu(1), shell.height / 2);
2755 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2752 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2753+ }
2754+
2755+ function test_spreadDisabled_WithEdgePush_data() {
2756+ return [
2757+ { tag: "enabled", spreadEnabled: true },
2758+ { tag: "disabled", spreadEnabled: false }
2759+ ];
2760+ }
2756
2761
2757− stage.closeSpread();
2762+ function test_spreadDisabled_WithEdgePush(data) {
2758− tryCompare(stage, "state", "staged");
2763+ loadShell("phone");
2764+ swipeAwayGreeter();
2765+ var stage = findChild(shell, "stage");
2766+ stage.spreadEnabled = data.spreadEnabled;
2759
2767
2760 // Try by edge push
2768 // Try by edge push
2761 var cursor = findChild(shell, "cursor");
2769 var cursor = findChild(shell, "cursor");
@@ -2765,21 +2773,43 @@ Rectangle {
2765 }
2773 }
2766 mouseMove(stage, stage.width - units.gu(5), units.gu(10));
2774 mouseMove(stage, stage.width - units.gu(5), units.gu(10));
2767 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2775 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2776+ }
2768
2777
2769− stage.closeSpread();
2778+ function test_spreadDisabled_WithAltTab_data() {
2770− tryCompare(stage, "state", "staged");
2779+ return [
2780+ { tag: "enabled", spreadEnabled: true },
2781+ { tag: "disabled", spreadEnabled: false }
2782+ ];
2783+ }
2784+
2785+ function test_spreadDisabled_WithAltTab(data) {
2786+ loadShell("phone");
2787+ swipeAwayGreeter();
2788+ var stage = findChild(shell, "stage");
2789+ stage.spreadEnabled = data.spreadEnabled;
2771
2790
2772 // Try by alt+tab
2791 // Try by alt+tab
2773 keyPress(Qt.Key_Alt);
2792 keyPress(Qt.Key_Alt);
2774 keyClick(Qt.Key_Tab);
2793 keyClick(Qt.Key_Tab);
2775 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2794 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2776 keyRelease(Qt.Key_Alt);
2795 keyRelease(Qt.Key_Alt);
2796+ }
2777
2797
2778− stage.closeSpread();
2798+ function test_spreadDisabled_WithSuperW_data() {
2779− tryCompare(stage, "state", "staged");
2799+ return [
2800+ { tag: "enabled", spreadEnabled: true },
2801+ { tag: "disabled", spreadEnabled: false }
2802+ ];
2803+ }
2804+
2805+ function test_spreadDisabled_WithSuperW(data) {
2806+ loadShell("phone");
2807+ swipeAwayGreeter();
2808+ var stage = findChild(shell, "stage");
2809+ stage.spreadEnabled = data.spreadEnabled;
2780
2810
2781 // Try by Super+W
2811 // Try by Super+W
2782− keyPress(Qt.Key_W, Qt.MetaModifier)
2812+ keyPress(Qt.Key_W, Qt.MetaModifier, 200);
2783 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2813 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2784 keyRelease(Qt.Key_W, Qt.MetaModifier)
2814 keyRelease(Qt.Key_W, Qt.MetaModifier)
2785 }
2815 }
@@ -2910,5 +2940,29 @@ Rectangle {
2910 tryCompare(topLevelSurfaceList.focusedWindow, "surface", appDelegate.surface);
2940 tryCompare(topLevelSurfaceList.focusedWindow, "surface", appDelegate.surface);
2911 tryCompare(topLevelSurfaceList.applicationAt(0), "appId", "dialer-app");
2941 tryCompare(topLevelSurfaceList.applicationAt(0), "appId", "dialer-app");
2912 }
2942 }
2943+
2944+ function test_doubleClickPanelRestoresWindow() {
2945+ loadShell("desktop");
2946+ shell.usageScenario = "desktop";
2947+ waitForRendering(shell);
2948+ swipeAwayGreeter();
2949+
2950+ // start dialer
2951+ var appDelegate = startApplication("dialer-app")
2952+ verify(appDelegate);
2953+ tryCompare(appDelegate, "state", "normal");
2954+
2955+ // maximize dialer
2956+ var decoration = findChild(appDelegate, "appWindowDecoration");
2957+ verify(decoration);
2958+ mouseDoubleClickSequence(decoration);
2959+ tryCompare(appDelegate, "state", "maximized");
2960+
2961+ // double click the panel
2962+ var panel = findChild(shell, "panel");
2963+ verify(panel);
2964+ mouseDoubleClickSequence(panel, panel.width/2, PanelState.panelHeight/2, Qt.LeftButton, Qt.NoModifier, 300);
2965+ tryCompare(appDelegate, "state", "restored");
2966+ }
2913 }
2967 }
2914}
2968}
tests/qmltests/tst_ShellWithPin.qml+1
@@ -69,6 +69,7 @@ Item {
69 property bool itemDestroyed: false
69 property bool itemDestroyed: false
70 sourceComponent: Component {
70 sourceComponent: Component {
71 Shell {
71 Shell {
72+ hasTouchscreen: true
72 Component.onDestruction: {
73 Component.onDestruction: {
73 shellLoader.itemDestroyed = true
74 shellLoader.itemDestroyed = true
74 }
75 }
tests/scripts/alert-launcher-icon.sh+16
@@ -1,3 +1,19 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
3qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 com.canonical.Unity.Launcher.Item.Alert
19qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 com.canonical.Unity.Launcher.Item.Alert
tests/scripts/get-progress.sh+16
@@ -1,3 +1,19 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
3qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Get com.canonical.Unity.Launcher.Item progress
19qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Get com.canonical.Unity.Launcher.Item progress
tests/scripts/list-launcher-icons.sh+16
@@ -1,3 +1,19 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
3qdbus com.canonical.Unity | grep Launcher | cut -f6 -d/
19qdbus com.canonical.Unity | grep Launcher | cut -f6 -d/
tests/scripts/set-count-visible.sh+16
@@ -1,3 +1,19 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
3qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item countVisible $2
19qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item countVisible $2
tests/scripts/set-count.sh+16
@@ -1,3 +1,19 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
3qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item count $2
19qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item count $2
tests/scripts/set-progress.sh+16
@@ -1,3 +1,19 @@
1#!/bin/sh
1#!/bin/sh
2
2
3+#
4+# Copyright (C) 2017 Canonical Ltd
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License version 3 as
8+# published by the Free Software Foundation.
9+#
10+# This program is distributed in the hope that it will be useful,
11+# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+# GNU General Public License for more details.
14+#
15+# You should have received a copy of the GNU General Public License
16+# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#
18+
3qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item progress $2
19qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item progress $2
tools/CMakeLists.txt+2−12
@@ -1,14 +1,4 @@
1−add_executable(${SCOPE_TOOL}
1+add_subdirectory(menutool)
2− scopetool.cpp
2+add_subdirectory(scopetool)
3− registry-tracker.cpp
4− ../src/UnixSignalHandler.cpp
5− )
6−
7−qt5_use_modules(${SCOPE_TOOL} Qml Quick)
8−
9−# install binaries
10−install(TARGETS ${SCOPE_TOOL}
11− RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
12− )
13
3
14install(FILES unlock-device DESTINATION ${SHELL_APP_DIR})
4install(FILES unlock-device DESTINATION ${SHELL_APP_DIR})
tools/menutool/CMakeLists.txtnew file+5
@@ -0,0 +1,5 @@
1+add_executable(menutool
2+ menutool.cpp
3+ )
4+
5+qt5_use_modules(menutool Qml Quick)
tools/menutool/READMEnew file+11
@@ -0,0 +1,11 @@
1+This tool can be used to browse the menus of another application
2+
3+How to use:
4+ * Start application that exports menus
5+ e.g. QT_QPA_PLATFORMTHEME=ubuntuappmenu kate
6+ * Figure out which is the dbus address
7+ * This is a bit tricky, but using qdbusviewer to see the addresses
8+ that appear when starting the app and looking for one that
9+ contains com/Ubuntu/Menu/0 should be enough
10+ * Start tool passing the dbus address
11+ builddir/menutool/menutool :1.293
tools/menutool/menutool.cppnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (C) 2017 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+// Qt
18+#include <QDebug>
19+#include <QCommandLineParser>
20+#include <QGuiApplication>
21+#include <QQmlContext>
22+#include <QQmlEngine>
23+#include <QQuickView>
24+
25+// local
26+#include <paths.h>
27+
28+int main(int argc, char *argv[])
29+{
30+ QGuiApplication::setApplicationName("Menu Test Tool");
31+ QGuiApplication *application = new QGuiApplication(argc, argv);
32+
33+ QCommandLineParser parser;
34+ parser.parse(application->arguments());
35+ const QStringList args = parser.positionalArguments();
36+
37+ if (args.count() != 1) {
38+ qWarning() << "You need to pass the dbus address";
39+ return 1;
40+ }
41+
42+ QQuickView* view = new QQuickView();
43+ view->setResizeMode(QQuickView::SizeRootObjectToView);
44+ view->setTitle(QGuiApplication::applicationName());
45+ view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
46+ view->rootContext()->setContextProperty("contextBusName", args[0]);
47+
48+ QUrl source(::sourceDirectory() + "/tools/menutool/menutool.qml");
49+ prependImportPaths(view->engine(), ::overrideImportPaths());
50+ prependImportPaths(view->engine(), ::nonMirImportPaths());
51+
52+ view->setSource(source);
53+
54+ view->show();
55+
56+ int result = application->exec();
57+
58+ delete view;
59+ delete application;
60+
61+ return result;
62+}
tools/menutool/menutool.qmlnew file+118
@@ -0,0 +1,118 @@
1+/*
2+* Copyright (C) 2017 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+import "../../qml/ApplicationMenus"
21+import "../../qml/Panel"
22+import "../../qml/Components/PanelState"
23+
24+import QMenuModel 0.1
25+import Unity.Indicators 0.1 as Indicators
26+
27+Item {
28+ width: units.gu(180)
29+ height: units.gu(120)
30+
31+ UnityMenuModel {
32+ id: menuModel
33+ busName: contextBusName
34+ menuObjectPath: "/com/ubuntu/Menu/0"
35+ actions: { "unity": "/com/ubuntu/Menu/0" }
36+ }
37+
38+ readonly property bool hasMenus: repeater.count > 0
39+ Repeater {
40+ id: repeater
41+ model: menuModel
42+ delegate: Item {}
43+ }
44+
45+ Panel {
46+ id: panel
47+
48+ height: parent.height
49+ width: parent.width / 2
50+ minimizedPanelHeight: units.gu(6)
51+ visible: hasMenus
52+
53+ mode: "windowed"
54+
55+ applicationMenus {
56+ model: menuModel
57+ }
58+
59+ Rectangle {
60+ width: 50
61+ height: 50
62+ anchors.centerIn: parent
63+ color: "gray"
64+ rotation: 45
65+ Timer {
66+ interval: 20
67+ running: true
68+ repeat: true
69+ onTriggered: parent.rotation = parent.rotation+1
70+ }
71+ }
72+
73+ Rectangle {
74+ color: "green"
75+ anchors.bottom: parent.bottom
76+ anchors.right: parent.right
77+ Label {
78+ id: label
79+ anchors.centerIn: parent
80+ text: "Click here to open touch menu manually"
81+ }
82+ width: label.width + units.gu(2)
83+ height: label.height + units.gu(2)
84+ MouseArea {
85+ anchors.fill: parent
86+ onClicked: panel.applicationMenus.show();
87+ }
88+ visible: !panel.applicationMenus.shown
89+ }
90+ }
91+
92+ Rectangle {
93+ color: "blue"
94+ height: parent.height
95+ width: parent.width / 2
96+ x: width
97+ visible: hasMenus
98+
99+ MenuBar {
100+ id: menuBar
101+ height: units.gu(3)
102+ width: parent.width
103+ enableKeyFilter: true
104+ unityMenuModel: menuModel
105+ }
106+ }
107+
108+ Component.onCompleted: {
109+ theme.name = "Ubuntu.Components.Themes.SuruDark";
110+ PanelState.title = "Drag here to open touch menu";
111+ }
112+
113+ Text {
114+ anchors.centerIn: parent
115+ text: "The dbus address you gave has no menus. Make sure you read the README file."
116+ visible: !hasMenus
117+ }
118+}
tools/scopetool/CMakeLists.txtnew file+12
@@ -0,0 +1,12 @@
1+add_executable(${SCOPE_TOOL}
2+ scopetool.cpp
3+ registry-tracker.cpp
4+ ../../src/UnixSignalHandler.cpp
5+ )
6+
7+qt5_use_modules(${SCOPE_TOOL} Qml Quick)
8+
9+# install binaries
10+install(TARGETS ${SCOPE_TOOL}
11+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
12+ )
tools/registry-tracker.cpp → tools/scopetool/registry-tracker.cpprenamed

The content is the same.

tools/registry-tracker.h → tools/scopetool/registry-tracker.hrenamed

The content is the same.

tools/scopetool.cpp → tools/scopetool/scopetool.cpprenamed

The content is the same.

tools/unlock-device+16
@@ -1,6 +1,22 @@
1#!/bin/bash
1#!/bin/bash
2# -*- Mode: sh; indent-tabs-mode: nil; tab-width: 4 -*-
2# -*- Mode: sh; indent-tabs-mode: nil; tab-width: 4 -*-
3
3
4+#
5+# Copyright (C) 2017 Canonical Ltd
6+#
7+# This program is free software: you can redistribute it and/or modify
8+# it under the terms of the GNU General Public License version 3 as
9+# published by the Free Software Foundation.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
4# Our goal here is to get an Ubuntu Touch device into a testable unlocked state.
20# Our goal here is to get an Ubuntu Touch device into a testable unlocked state.
5# This will include a reboot.
21# This will include a reboot.
6
22