on xenial help sign in
merge trunk, fix conflicts
4e917ffLukáš Tinkl
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+1−1
@@ -131,7 +131,7 @@ Item {
131
131
132 implicitWidth: column.implicitWidth
132 implicitWidth: column.implicitWidth
133 implicitHeight: row.height
133 implicitHeight: row.height
134− enabled: model.sensitive && shouldDisplay
134+ enabled: (model.sensitive === true) && shouldDisplay
135 opacity: shouldDisplay ? 1 : 0
135 opacity: shouldDisplay ? 1 : 0
136
136
137 function show() {
137 function show() {
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/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 switchToNextState("")
122 switchToNextState("")
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+4−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
@@ -345,12 +343,12 @@ Item {
345 objectName: identifier+"-panelItem"
343 objectName: identifier+"-panelItem"
346
344
347 property int ownIndex: index
345 property int ownIndex: index
348− property bool overflow: parent.width - x > __indicators.overFlowWidth
346+ readonly property bool overflow: parent.width - x > __indicators.overFlowWidth
349− property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
347+ readonly property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
350 // HACK for indicator-session
348 // HACK for indicator-session
351 readonly property bool hideSessionIndicator: identifier == "indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
349 readonly property bool hideSessionIndicator: identifier == "indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
352 // HACK for indicator-keyboard
350 // HACK for indicator-keyboard
353− readonly property bool hideKeyboardIndicator: identifier == "indicator-keyboard" && (AccountsService.keymaps.length < 2 || keyboardsModel.count == 0)
351+ readonly property bool hideKeyboardIndicator: identifier == "indicator-keyboard" && !hasKeyboard
354
352
355 height: parent.height
353 height: parent.height
356 expanded: indicators.expanded
354 expanded: indicators.expanded
@@ -404,11 +402,6 @@ Item {
404 }
402 }
405 }
403 }
406
404
407− InputDeviceModel {
408− id: keyboardsModel
409− deviceFilter: InputInfo.Keyboard
410− }
411−
412 IndicatorsLight {
405 IndicatorsLight {
413 id: indicatorLights
406 id: indicatorLights
414 }
407 }
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+4
@@ -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
qml/Stage/MoveHandler.qml+9
@@ -194,4 +194,13 @@ QtObject {
194 target.restoredY = target.y;
194 target.restoredY = target.y;
195 }
195 }
196 }
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+ }
197}
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/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/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
@@ -311,5 +311,22 @@ StyledItem {
311
311
312 compare(launcher.lastSelectedApplication, "calendar-app");
312 compare(launcher.lastSelectedApplication, "calendar-app");
313 }
313 }
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+ }
314 }
331 }
315}
332}
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+29−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() {
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+52−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
@@ -2690,8 +2687,8 @@ Rectangle {
2690 }
2687 }
2691
2688
2692 function test_cursorHidingWithFullscreenApp() {
2689 function test_cursorHidingWithFullscreenApp() {
2693− loadShell("desktop");
2690+ loadShell("phone");
2694− shell.usageScenario = "desktop";
2691+ shell.usageScenario = "phone";
2695 waitForRendering(shell);
2692 waitForRendering(shell);
2696 swipeAwayGreeter();
2693 swipeAwayGreeter();
2697
2694
@@ -2753,14 +2750,14 @@ Rectangle {
2753 GSettingsController.setEnableIndicatorMenu(true);
2750 GSettingsController.setEnableIndicatorMenu(true);
2754 }
2751 }
2755
2752
2756− function test_spreadDisabled_data() {
2753+ function test_spreadDisabled_WithSwipe_data() {
2757 return [
2754 return [
2758 { tag: "enabled", spreadEnabled: true },
2755 { tag: "enabled", spreadEnabled: true },
2759 { tag: "disabled", spreadEnabled: false }
2756 { tag: "disabled", spreadEnabled: false }
2760 ];
2757 ];
2761 }
2758 }
2762
2759
2763− function test_spreadDisabled(data) {
2760+ function test_spreadDisabled_WithSwipe(data) {
2764 loadShell("phone");
2761 loadShell("phone");
2765 swipeAwayGreeter();
2762 swipeAwayGreeter();
2766 var stage = findChild(shell, "stage");
2763 var stage = findChild(shell, "stage");
@@ -2769,9 +2766,20 @@ Rectangle {
2769 // Try swiping
2766 // Try swiping
2770 touchFlick(shell, shell.width - 2, shell.height / 2, units.gu(1), shell.height / 2);
2767 touchFlick(shell, shell.width - 2, shell.height / 2, units.gu(1), shell.height / 2);
2771 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2768 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2769+ }
2772
2770
2773− stage.closeSpread();
2771+ function test_spreadDisabled_WithEdgePush_data() {
2774− tryCompare(stage, "state", "staged");
2772+ return [
2773+ { tag: "enabled", spreadEnabled: true },
2774+ { tag: "disabled", spreadEnabled: false }
2775+ ];
2776+ }
2777+
2778+ function test_spreadDisabled_WithEdgePush(data) {
2779+ loadShell("phone");
2780+ swipeAwayGreeter();
2781+ var stage = findChild(shell, "stage");
2782+ stage.spreadEnabled = data.spreadEnabled;
2775
2783
2776 // Try by edge push
2784 // Try by edge push
2777 var cursor = findChild(shell, "cursor");
2785 var cursor = findChild(shell, "cursor");
@@ -2781,21 +2789,43 @@ Rectangle {
2781 }
2789 }
2782 mouseMove(stage, stage.width - units.gu(5), units.gu(10));
2790 mouseMove(stage, stage.width - units.gu(5), units.gu(10));
2783 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2791 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2792+ }
2784
2793
2785− stage.closeSpread();
2794+ function test_spreadDisabled_WithAltTab_data() {
2786− tryCompare(stage, "state", "staged");
2795+ return [
2796+ { tag: "enabled", spreadEnabled: true },
2797+ { tag: "disabled", spreadEnabled: false }
2798+ ];
2799+ }
2800+
2801+ function test_spreadDisabled_WithAltTab(data) {
2802+ loadShell("phone");
2803+ swipeAwayGreeter();
2804+ var stage = findChild(shell, "stage");
2805+ stage.spreadEnabled = data.spreadEnabled;
2787
2806
2788 // Try by alt+tab
2807 // Try by alt+tab
2789 keyPress(Qt.Key_Alt);
2808 keyPress(Qt.Key_Alt);
2790 keyClick(Qt.Key_Tab);
2809 keyClick(Qt.Key_Tab);
2791 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2810 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2792 keyRelease(Qt.Key_Alt);
2811 keyRelease(Qt.Key_Alt);
2812+ }
2793
2813
2794− stage.closeSpread();
2814+ function test_spreadDisabled_WithSuperW_data() {
2795− tryCompare(stage, "state", "staged");
2815+ return [
2816+ { tag: "enabled", spreadEnabled: true },
2817+ { tag: "disabled", spreadEnabled: false }
2818+ ];
2819+ }
2820+
2821+ function test_spreadDisabled_WithSuperW(data) {
2822+ loadShell("phone");
2823+ swipeAwayGreeter();
2824+ var stage = findChild(shell, "stage");
2825+ stage.spreadEnabled = data.spreadEnabled;
2796
2826
2797 // Try by Super+W
2827 // Try by Super+W
2798− keyPress(Qt.Key_W, Qt.MetaModifier)
2828+ keyPress(Qt.Key_W, Qt.MetaModifier, 200);
2799 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2829 tryCompare(stage, "state", data.spreadEnabled ? "spread" : "staged");
2800 keyRelease(Qt.Key_W, Qt.MetaModifier)
2830 keyRelease(Qt.Key_W, Qt.MetaModifier)
2801 }
2831 }
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