on xenial help sign in
merge trunk
commitc26643bf6d14570c61adb72d29037a3e8211d7e9 authorLukáš Tinkl <lukas.tinkl@canonical.com> dateMon 3 Apr 2017, 12:56 (10 years ago) parentbbf518a40d0568
73 files changed+929−950
CMakeLists.txt+5 debian/changelog+44 debian/control+4 plugins/Ubuntu/CMakeLists.txt−1 plugins/Ubuntu/SystemImage/CMakeLists.txt−15 plugins/Ubuntu/SystemImage/SystemImage.cpp−155 plugins/Ubuntu/SystemImage/SystemImage.h−84 plugins/Ubuntu/SystemImage/plugin.cpp−28 plugins/Ubuntu/SystemImage/plugin.h−31 plugins/Ubuntu/SystemImage/qmldir−3 plugins/Unity/Launcher/launchermodel.cpp+19−16 plugins/Unity/Platform/platform.cpp+16−2 plugins/Unity/Session/plugin.cpp+1 plugins/Utils/quicklistproxymodel.h+1−1 plugins/Utils/windowstatestorage.cpp+10−3 plugins/Utils/windowstatestorage.h+2 plugins/WindowManager/AvailableDesktopArea.cpp+50 plugins/WindowManager/AvailableDesktopArea.h+38 plugins/WindowManager/CMakeLists.txt+7 plugins/WindowManager/WindowManagerPlugin.cpp+5−1 plugins/WindowManager/WindowMargins.cpp+74 plugins/WindowManager/WindowMargins.h+59 po/unity8.pot+54−76 qml/ApplicationMenus/MenuBar.qml+22−6 qml/ApplicationMenus/MenuPopup.qml+10−1 qml/Components/KeyboardShortcutsOverlay.qml+13 qml/Greeter/Greeter.qml−11 qml/Greeter/NarrowView.qml−14 qml/Greeter/WideView.qml−4 qml/Launcher/Drawer.qml−2 qml/Launcher/LauncherPanel.qml+24−6 qml/Shell.qml+8−1 qml/Stage/ChildWindow.qml+18−3 qml/Stage/ChildWindowRepeater.qml+12−1 qml/Stage/ChildWindowTree.qml+17−2 qml/Stage/DecoratedWindow.qml+14−7 qml/Stage/Stage.qml+88−48 qml/Wizard/Pages/30-wifi.qml−4 qml/Wizard/Pages/77-system-update.qml−156 src/CMakeLists.txt−1 src/Panel/CMakeLists.txt−3 src/Panel/Indicators/CMakeLists.txt−1 tests/CMakeLists.txt+1 tests/mocks/Ubuntu/CMakeLists.txt−1 tests/mocks/Ubuntu/SystemImage/CMakeLists.txt−10 tests/mocks/Ubuntu/SystemImage/MockSystemImage.cpp−50 tests/mocks/Ubuntu/SystemImage/MockSystemImage.h−56 tests/mocks/Ubuntu/SystemImage/plugin.cpp−34 tests/mocks/Ubuntu/SystemImage/plugin.h−31 tests/mocks/Ubuntu/SystemImage/qmldir−3 tests/mocks/Unity/Application/ApplicationManager.cpp+5−7 tests/mocks/Unity/Application/ApplicationManager.h+1−6 tests/mocks/Unity/Application/MirSurface.cpp+5 tests/plugins/Unity/CMakeLists.txt+1 tests/plugins/Unity/Platform/CMakeLists.txt+30 tests/plugins/Unity/Platform/platformtest.cpp+142 tests/plugins/Utils/WindowStateStorageTest.cpp+9 tests/plugins/WindowManager/UnityApplicationMocks.h+8−1 tests/qmltests/ApplicationMenus/tst_MenuBar.qml+33 tests/qmltests/Greeter/TestView.qml−5 tests/qmltests/Greeter/tst_Greeter.qml−7 tests/qmltests/Launcher/tst_Launcher.qml+32−6 tests/qmltests/Stage/tst_DesktopStage.qml+17 tests/qmltests/Stage/tst_PhoneStage.qml+5 tests/qmltests/Stage/tst_TabletStage.qml+5 tests/qmltests/Wizard/tst_Wizard.qml−6 tests/qmltests/tst_Shell.qml+19 tests/qmltests/tst_ShellWithPin.qml−40 tools/CMakeLists.txt+1 src/Panel/Indicators/client/CMakeLists.txt → tools/indicatorsclient/CMakeLists.txt src/Panel/Indicators/client/indicatorsclient.cpp → tools/indicatorsclient/indicatorsclient.cpp src/Panel/Indicators/client/indicatorsclient.h → tools/indicatorsclient/indicatorsclient.h src/Panel/Indicators/client/main.cpp → tools/indicatorsclient/main.cpp
CMakeLists.txt+5
@@ -69,6 +69,7 @@ find_package(Qt5Gui 5.6 REQUIRED)
6969find_package(Qt5DBus 5.6 REQUIRED)
7070find_package(Qt5Concurrent 5.6 REQUIRED)
7171find_package(Qt5Sql 5.6 REQUIRED)
72+find_package(Qt5Test 5.6 REQUIRED)
7273
7374pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=27)
7475pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
@@ -79,6 +80,10 @@ pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
7980pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
8081pkg_check_modules(UAL REQUIRED ubuntu-app-launch-3)
8182pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
83+pkg_check_modules(QTDBUSTEST REQUIRED
84+ libqtdbustest-1
85+ libqtdbusmock-1
86+ )
8287
8388### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
8489find_path(UBUNTUGESTUREPRIV
debian/changelog+44
@@ -1,3 +1,47 @@
1+unity8 (8.15+17.04.20170328.3-0ubuntu1) zesty; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * mock: Remove empty property and move invokable
5+ * Tune quicklist item selection
6+ * Fix unminimizing going to the wrong position the second time (LP:
7+ #1671458)
8+ * Remove unclickable gaps on the menubar (LP: #1672722)
9+ * indicators client is a tool
10+ * Make sure we destroy the popups when the item goes away (LP:
11+ #1670338)
12+ * UnityApplicationMocks: Initialize m_state and m_requestedState
13+ * Don't use appInfo after checking it if is null
14+ * Initialize m_privateMode
15+ * Hook up aboutToShow for overflow menus (LP: #1676016)
16+
17+ [ Daniel d'Andrada ]
18+ * Give active focus to child surface qml items (LP: #1671072)
19+ * Satellite child windows (LP: #1673415)
20+ * Tell qtmir/miral about the available desktop area
21+
22+ [ Florian Boucault ]
23+ * WindowStateStorage: use a private QThreadPool to ensure that
24+ WindowStateStorage::saveValue always has a thread available to
25+ execute the query in. (LP: #1675424)
26+
27+ [ Lukáš Tinkl ]
28+ * Protect against loading invalid window geometry (LP: #1674262)
29+ * Remove usage of the deprecated (and non-functional) system-image-
30+ dbus service.
31+ * Implement Ctrl+Alt+T to launch the terminal app (LP: #1673500)
32+ * Only take normal and dialog surface types into account for launcher
33+ items (LP: #1669047)
34+ * Fix the shutdown dialog after recent refactoring in
35+ DBusUnitySessionService (LP: #1676426)
36+
37+ [ Michael Zanetti ]
38+ * drop the grey background behind icons in the drawer (LP: #1675688)
39+
40+ [ Pete Woods ]
41+ * Fix Unity/Platform::isPC, and add tests (LP: #1670657)
42+
43+ -- Michał Sawicz <michal.sawicz@canonical.com> Tue, 28 Mar 2017 21:50:20 +0000
44+
145unity8 (8.15+17.04.20170321-0ubuntu1) zesty; urgency=medium
246
347 [ Albert Astals Cid ]
debian/control+4
@@ -29,6 +29,8 @@ Build-Depends: cmake,
2929 libpam0g-dev,
3030 libpulse-dev,
3131 libqmenumodel-dev (>= 0.2.12),
32+ libqtdbusmock1-dev (>= 0.7),
33+ libqtdbustest1-dev,
3234 libqt5svg5-dev,
3335 libqt5xmlpatterns5-dev,
3436 libsystemsettings-dev,
@@ -48,6 +50,7 @@ Build-Depends: cmake,
4850 pkg-config,
4951 python3-all:any,
5052 python3-setuptools,
53+ qtdbustest-runner,
5154 qml-module-qt-labs-folderlistmodel,
5255 qml-module-qt-labs-settings,
5356 qml-module-qtqml-statemachine,
@@ -205,6 +208,7 @@ Multi-Arch: same
205208Pre-Depends: ${misc:Pre-Depends},
206209Depends: dbus-test-runner,
207210 parallel,
211+ qtdbustest-runner,
208212 qt5-default,
209213 qtdeclarative5-dev-tools,
210214 unity8 (= ${source:Version}),
plugins/Ubuntu/CMakeLists.txt−1
@@ -1,3 +1,2 @@
11add_subdirectory(Gestures)
22add_subdirectory(DownloadDaemonListener)
3−add_subdirectory(SystemImage)
plugins/Ubuntu/SystemImage/CMakeLists.txtdeleted−15
@@ -1,15 +0,0 @@
1−include_directories(
2− ${GLIB_INCLUDE_DIRS}
3−)
4−
5−set(SYSTEMIMAGE_SOURCES
6− plugin.cpp
7− SystemImage.cpp
8−)
9−
10−add_library(SystemImage MODULE ${SYSTEMIMAGE_SOURCES})
11−
12−qt5_use_modules(SystemImage Qml DBus Core)
13−target_link_libraries(SystemImage ${GLIB_LIBRARIES})
14−
15−add_unity8_plugin(Ubuntu.SystemImage 0.1 Ubuntu/SystemImage TARGETS SystemImage)
plugins/Ubuntu/SystemImage/SystemImage.cppdeleted−155
@@ -1,155 +0,0 @@
1−/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include <QDBusConnection>
18−#include <QDBusPendingCall>
19−#include <QDBusReply>
20−#include <QDebug>
21−
22−#include <glib.h>
23−
24−#include "SystemImage.h"
25−
26−#define SYSTEMIMAGE_SERVICE QStringLiteral("com.canonical.SystemImage")
27−#define SYSTEMIMAGE_PATH QStringLiteral("/Service")
28−#define SYSTEMIMAGE_IFACE QStringLiteral("com.canonical.SystemImage")
29−
30−Q_LOGGING_CATEGORY(SYSTEMIMAGEPLUGIN, "unity8.systemimage", QtWarningMsg)
31−
32−#define DEBUG_MSG qCDebug(SYSTEMIMAGEPLUGIN).nospace().noquote() << Q_FUNC_INFO
33−#define WARNING_MSG qCWarning(SYSTEMIMAGEPLUGIN).nospace().noquote() << Q_FUNC_INFO
34−
35−SystemImage::SystemImage(QObject *parent)
36− : QObject(parent)
37−{
38− QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateAvailableStatus"),
39− this, SLOT(onUpdateAvailableStatus(bool,bool,QString,int,QString,QString)));
40− QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateDownloaded"),
41− this, SLOT(onUpdateDownloaded()));
42− QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateFailed"),
43− this, SLOT(onUpdateFailed(int,QString)));
44− QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("Applied"),
45− this, SLOT(onUpdateApplied(bool)));
46− QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("Rebooting"),
47− this, SLOT(onRebooting(bool)));
48−}
49−
50−void SystemImage::checkForUpdate()
51−{
52− DEBUG_MSG << "Checking for update";
53− const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
54− QStringLiteral("CheckForUpdate"));
55− QDBusConnection::systemBus().asyncCall(msg);
56−}
57−
58−void SystemImage::applyUpdate()
59−{
60− DEBUG_MSG << "Applying update";
61− setUpdateApplying(true);
62−
63− const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
64− QStringLiteral("ApplyUpdate"));
65− QDBusConnection::systemBus().asyncCall(msg);
66−}
67−
68−void SystemImage::factoryReset()
69−{
70− const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
71− QStringLiteral("FactoryReset"));
72− QDBusConnection::systemBus().asyncCall(msg);
73−}
74−
75−void SystemImage::onUpdateAvailableStatus(bool is_available, bool downloading, const QString &available_version, int update_size,
76− const QString &last_update_date, const QString &error_reason)
77−{
78− DEBUG_MSG << "A new update is " << (is_available ? "" : "NOT") << "available";
79−
80− if (is_available == m_updateAvailable) {
81− return;
82− }
83−
84− m_updateAvailable = is_available;
85− m_downloading = downloading;
86− m_availableVersion = available_version;
87− m_updateSize = formatSize(update_size);
88− m_lastUpdateDate = last_update_date;
89− m_errorReason = error_reason;
90− Q_EMIT updateAvailableStatus();
91−
92− DEBUG_MSG << "Downloading: " << downloading << ", version: " << available_version << ", last update: " << last_update_date <<
93− ", size: " << m_updateSize;
94−}
95−
96−void SystemImage::onUpdateDownloaded()
97−{
98− DEBUG_MSG << "Update downloaded";
99−
100− m_downloaded = true;
101− Q_EMIT updateDownloadedChanged();
102−}
103−
104−void SystemImage::onUpdateFailed(int /*consecutive_failure_count*/, const QString &last_reason)
105−{
106− WARNING_MSG << "System Update failed: " << last_reason;
107− setUpdateApplying(false);
108−}
109−
110−void SystemImage::onUpdateApplied(bool applied)
111−{
112− DEBUG_MSG << "System Update applied with status: " << applied;
113− setUpdateApplying(false);
114− if (applied) {
115− resetUpdateStatus();
116− Q_EMIT updateAvailableStatus();
117− }
118−}
119−
120−void SystemImage::onRebooting(bool status)
121−{
122− setUpdateApplying(false);
123− DEBUG_MSG << "Rebooting: " << status;
124−}
125−
126−void SystemImage::setUpdateApplying(bool status)
127−{
128− if (status != m_updateApplying) {
129− m_updateApplying = status;
130− Q_EMIT updateApplyingChanged();
131− }
132−}
133−
134−void SystemImage::resetUpdateStatus()
135−{
136− m_updateAvailable = false;
137− m_updateApplying = false;
138− m_downloading = false;
139− m_downloaded = false;
140− m_availableVersion.clear();
141− m_updateSize.clear();
142− m_lastUpdateDate.clear();
143− m_errorReason.clear();
144−}
145−
146−QString SystemImage::formatSize(quint64 size) const
147−{
148− guint64 g_size = size;
149−
150− gchar * formatted_size = g_format_size(g_size);
151− QString q_formatted_size = QString::fromLocal8Bit(formatted_size);
152− g_free(formatted_size);
153−
154− return q_formatted_size;
155−}
plugins/Ubuntu/SystemImage/SystemImage.hdeleted−84
@@ -1,84 +0,0 @@
1−/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef SYSTEMIMAGE_H
18−#define SYSTEMIMAGE_H
19−
20−#include <QObject>
21−#include <QLoggingCategory>
22−
23−Q_DECLARE_LOGGING_CATEGORY(SYSTEMIMAGEPLUGIN)
24−
25−class SystemImage : public QObject
26−{
27− Q_OBJECT
28− Q_DISABLE_COPY(SystemImage)
29−
30− Q_PROPERTY(bool updateAvailable READ updateAvailable NOTIFY updateAvailableStatus)
31− Q_PROPERTY(bool updateDownloading READ updateDownloading NOTIFY updateAvailableStatus)
32− Q_PROPERTY(QString availableVersion READ availableVersion NOTIFY updateAvailableStatus)
33− Q_PROPERTY(QString updateSize READ updateSize NOTIFY updateAvailableStatus)
34− Q_PROPERTY(bool updateApplying READ updateApplying NOTIFY updateApplyingChanged)
35− Q_PROPERTY(bool updateDownloaded READ updateDownloaded NOTIFY updateDownloadedChanged)
36−
37−public:
38− explicit SystemImage(QObject *parent = nullptr);
39− ~SystemImage() = default;
40−
41− bool updateAvailable() const { return m_updateAvailable; }
42− bool updateDownloading() const { return m_downloading; }
43− QString availableVersion() const { return m_availableVersion; }
44− QString updateSize() const { return m_updateSize; }
45− bool updateApplying() const { return m_updateApplying; }
46− bool updateDownloaded() const { return m_downloaded; }
47−
48−public Q_SLOTS:
49− Q_INVOKABLE void checkForUpdate();
50− Q_INVOKABLE void applyUpdate();
51− Q_INVOKABLE void factoryReset();
52−
53−private Q_SLOTS:
54− void onUpdateAvailableStatus(bool is_available, bool updateDownloading, const QString &available_version,
55− int update_size, const QString &last_update_date, const QString &error_reason);
56− void onUpdateDownloaded();
57− void onUpdateFailed(int consecutive_failure_count, const QString & last_reason);
58− void onUpdateApplied(bool applied);
59− void onRebooting(bool status);
60−
61−Q_SIGNALS:
62− void updateAvailableStatus();
63− void updateDownloadedChanged();
64− void updateApplyingChanged();
65−
66−private Q_SLOTS:
67− void setUpdateApplying(bool status);
68−
69−private:
70− void resetUpdateStatus();
71− QString formatSize(quint64 size) const;
72−
73−private:
74− bool m_updateAvailable = false;
75− bool m_updateApplying = false;
76− bool m_downloading = false;
77− bool m_downloaded = false;
78− QString m_availableVersion;
79− QString m_updateSize;
80− QString m_lastUpdateDate;
81− QString m_errorReason;
82−};
83−
84−#endif // SYSTEMIMAGE_H
plugins/Ubuntu/SystemImage/plugin.cppdeleted−28
@@ -1,28 +0,0 @@
1−/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "plugin.h"
18−#include "SystemImage.h"
19−
20−#include <QtQml>
21−
22−void BackendPlugin::registerTypes(const char *uri)
23−{
24− Q_ASSERT(uri == QLatin1String("Ubuntu.SystemImage"));
25−
26− qmlRegisterSingletonType<SystemImage>(uri, 0, 1, "SystemImage",
27− [](QQmlEngine*, QJSEngine*) -> QObject* { return new SystemImage; });
28−}
plugins/Ubuntu/SystemImage/plugin.hdeleted−31
@@ -1,31 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef SYSTEMIMAGE_PLUGIN_H
18−#define SYSTEMIMAGE_PLUGIN_H
19−
20−#include <QQmlExtensionPlugin>
21−
22−class BackendPlugin : public QQmlExtensionPlugin
23−{
24− Q_OBJECT
25− Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
26−
27−public:
28− void registerTypes(const char *uri) override;
29−};
30−
31−#endif // SYSTEMIMAGE_PLUGIN_H
plugins/Ubuntu/SystemImage/qmldirdeleted−3
@@ -1,3 +0,0 @@
1−module Ubuntu.SystemImage
2−plugin SystemImage
3−typeinfo SystemImage.qmltypes
plugins/Unity/Launcher/launchermodel.cpp+19−16
@@ -207,16 +207,17 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
207207 }
208208 } else if (actionId.startsWith(QStringLiteral("surface_"))){
209209 ApplicationInfoInterface *appInfo = m_appManager->findApplication(appId);
210− if (!appInfo) {
211− qWarning() << "App for" << appId << "not found in launcher. Cannot invoke quicklist action";
212− }
213− for (int i = 0; i < appInfo->surfaceList()->count(); ++i) {
214− MirSurfaceInterface *iface = appInfo->surfaceList()->get(i);
215− QString id = actionId;
216− id.remove(QRegExp("^surface_"));
217− if (id == iface->persistentId()) {
218− iface->activate();
210+ if (appInfo) {
211+ for (int i = 0; i < appInfo->surfaceList()->count(); ++i) {
212+ MirSurfaceInterface *iface = appInfo->surfaceList()->get(i);
213+ QString id = actionId;
214+ id.remove(QRegExp("^surface_"));
215+ if (id == iface->persistentId()) {
216+ iface->activate();
217+ }
219218 }
219+ } else {
220+ qWarning() << "App for" << appId << "not found in launcher. Cannot invoke quicklist action";
220221 }
221222 // Nope, we don't know this action, let the backend forward it to the application
222223 } else {
@@ -573,14 +574,16 @@ void LauncherModel::updateSurfaceListForApp(ApplicationInfoInterface* app)
573574 QList<QPair<QString, QString> > surfaces;
574575 for (int i = 0; i < app->surfaceList()->count(); ++i) {
575576 MirSurfaceInterface* iface = app->surfaceList()->get(i);
576− // Avoid duplicate connections, so let's just disconnect first to be sure
577− disconnect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
578− connect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
579− QString name = iface->name();
580− if (name.isEmpty()) {
581− name = app->name();
577+ if (iface->type() == Mir::NormalType || iface->type() == Mir::DialogType) {
578+ // Avoid duplicate connections, so let's just disconnect first to be sure
579+ disconnect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
580+ connect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
581+ QString name = iface->name();
582+ if (name.isEmpty()) {
583+ name = app->name();
584+ }
585+ surfaces.append({iface->persistentId(), name});
582586 }
583− surfaces.append({iface->persistentId(), name});
584587 }
585588 item->setSurfaces(surfaces);
586589 Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
plugins/Unity/Platform/platform.cpp+16−2
@@ -17,9 +17,11 @@
1717#include "platform.h"
1818
1919#include <QDBusConnection>
20+#include <QSet>
21+#include <QString>
2022
2123Platform::Platform(QObject *parent)
22− : QObject(parent)
24+ : QObject(parent), m_isPC(true), m_isMultiSession(true)
2325{
2426 QMetaObject::invokeMethod(this, "init");
2527}
@@ -31,8 +33,20 @@ void Platform::init()
3133 QDBusInterface seatIface("org.freedesktop.login1", "/org/freedesktop/login1/seat/self", "org.freedesktop.login1.Seat",
3234 QDBusConnection::systemBus(), this);
3335
36+ // From the source at https://cgit.freedesktop.org/systemd/systemd/tree/src/hostname/hostnamed.c#n130
37+ // "vm\0"
38+ // "container\0"
39+ // "desktop\0"
40+ // "laptop\0"
41+ // "server\0"
42+ // "tablet\0"
43+ // "handset\0"
44+ // "watch\0"
45+ // "embedded\0",
3446 m_chassis = iface.property("Chassis").toString();
35− m_isPC = (m_chassis == "desktop" || m_chassis == "laptop" || m_chassis == "server");
47+
48+ // A PC is not a handset, tablet or watch.
49+ m_isPC = !QSet<QString>{"handset", "tablet", "watch"}.contains(m_chassis);
3650 m_isMultiSession = seatIface.property("CanMultiSession").toBool() && seatIface.property("CanGraphical").toBool();
3751}
3852
plugins/Unity/Session/plugin.cpp+1
@@ -26,6 +26,7 @@
2626
2727static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
2828{
29+ new DBusGnomeSessionManagerDialogWrapper();
2930 new DBusGnomeSessionManagerWrapper();
3031 new DBusGnomeScreensaverWrapper();
3132 new DBusScreensaverWrapper();
plugins/Utils/quicklistproxymodel.h+1−1
@@ -48,5 +48,5 @@ Q_SIGNALS:
4848
4949private:
5050 QAbstractItemModel* m_source = nullptr;
51− bool m_privateMode;
51+ bool m_privateMode = false;
5252};
plugins/Utils/windowstatestorage.cpp+10−3
@@ -133,8 +133,15 @@ QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defa
133133 if (!query.first()) {
134134 return defaultValue;
135135 }
136− return QRect(query.value(QStringLiteral("x")).toInt(), query.value(QStringLiteral("y")).toInt(),
137− query.value(QStringLiteral("width")).toInt(), query.value(QStringLiteral("height")).toInt());
136+
137+ const QRect result(query.value(QStringLiteral("x")).toInt(), query.value(QStringLiteral("y")).toInt(),
138+ query.value(QStringLiteral("width")).toInt(), query.value(QStringLiteral("height")).toInt());
139+
140+ if (result.isValid()) {
141+ return result;
142+ }
143+
144+ return defaultValue;
138145}
139146
140147void WindowStateStorage::initdb()
@@ -165,7 +172,7 @@ void WindowStateStorage::saveValue(const QString &queryString)
165172{
166173 QMutexLocker mutexLocker(&s_mutex);
167174
168− QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
175+ QFuture<void> future = QtConcurrent::run(&m_threadPool, executeAsyncQuery, queryString);
169176 m_asyncQueries.append(future);
170177
171178 QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
plugins/Utils/windowstatestorage.h+2
@@ -18,6 +18,7 @@
1818#include <QSqlDatabase>
1919#include <QMutex>
2020#include <QFuture>
21+#include <QThreadPool>
2122
2223// unity-api
2324#include <unity/shell/application/Mir.h>
@@ -72,4 +73,5 @@ private:
7273 QSqlDatabase m_db;
7374
7475 QList<QFuture<void>> m_asyncQueries;
76+ QThreadPool m_threadPool;
7577};
plugins/WindowManager/AvailableDesktopArea.cppnew file+50
@@ -0,0 +1,50 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "AvailableDesktopArea.h"
18+
19+#include <QGuiApplication>
20+#include <QQuickWindow>
21+#include <qpa/qplatformnativeinterface.h>
22+
23+AvailableDesktopArea::AvailableDesktopArea(QQuickItem *parent)
24+ : QQuickItem(parent)
25+{
26+ connect(this, &QQuickItem::xChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
27+ connect(this, &QQuickItem::yChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
28+ connect(this, &QQuickItem::widthChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
29+ connect(this, &QQuickItem::heightChanged, this, &AvailableDesktopArea::updatePlatformWindowProperty);
30+}
31+
32+void AvailableDesktopArea::updatePlatformWindowProperty()
33+{
34+ if (!window()) {
35+ return;
36+ }
37+
38+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
39+
40+ QRect rect(x(), y(), width(), height());
41+
42+ nativeInterface->setWindowProperty(window()->handle(), "availableDesktopArea", QVariant(rect));
43+}
44+
45+void AvailableDesktopArea::itemChange(ItemChange change, const ItemChangeData &)
46+{
47+ if (change == ItemSceneChange) {
48+ updatePlatformWindowProperty();
49+ }
50+}
plugins/WindowManager/AvailableDesktopArea.hnew file+38
@@ -0,0 +1,38 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef AVAILABLEDESKTOPAREA_H
18+#define AVAILABLEDESKTOPAREA_H
19+
20+#include <QQuickItem>
21+
22+/**
23+ @brief Used to inform qtmir/miral about the available desktop area of shell
24+
25+ So that qtmir/miral can take correct window management decisions.
26+ */
27+class AvailableDesktopArea : public QQuickItem
28+{
29+ Q_OBJECT
30+public:
31+ AvailableDesktopArea(QQuickItem *parent = nullptr);
32+protected:
33+ void itemChange(ItemChange change, const ItemChangeData &value) override;
34+private Q_SLOTS:
35+ void updatePlatformWindowProperty();
36+};
37+
38+#endif // AVAILABLEDESKTOPAREA_H
plugins/WindowManager/CMakeLists.txt+7
@@ -1,7 +1,9 @@
11set(WINDOWMANAGER_SRC
2+ AvailableDesktopArea.cpp
23 TopLevelWindowModel.cpp
34 Window.cpp
45 WindowManagerPlugin.cpp
6+ WindowMargins.cpp
57 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
68 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
79 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
@@ -11,6 +13,11 @@ set(WINDOWMANAGER_SRC
1113
1214add_definitions(-DWINDOWMANAGERQML_LIBRARY)
1315
16+include_directories(
17+ SYSTEM
18+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
19+)
20+
1421add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
1522
1623qt5_use_modules(windowmanager-qml Qml Quick Gui)
plugins/WindowManager/WindowManagerPlugin.cpp+5−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -16,14 +16,18 @@
1616
1717#include "WindowManagerPlugin.h"
1818
19+#include "AvailableDesktopArea.h"
1920#include "TopLevelWindowModel.h"
2021#include "Window.h"
22+#include "WindowMargins.h"
2123
2224#include <QtQml>
2325
2426void WindowManagerPlugin::registerTypes(const char *uri)
2527{
28+ qmlRegisterType<AvailableDesktopArea>(uri, 1, 0, "AvailableDesktopArea");
2629 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
30+ qmlRegisterType<WindowMargins>(uri, 1, 0, "WindowMargins");
2731
2832 qRegisterMetaType<Window*>("Window*");
2933
plugins/WindowManager/WindowMargins.cppnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "WindowMargins.h"
18+
19+#include <QGuiApplication>
20+#include <QQuickWindow>
21+#include <qpa/qplatformnativeinterface.h>
22+
23+void WindowMargins::setNormal(QRectF value)
24+{
25+ if (m_normal == value) {
26+ return;
27+ }
28+
29+ m_normal = value;
30+
31+ if (window()) {
32+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
33+ nativeInterface->setWindowProperty(window()->handle(), "normalWindowMargins", QVariant(m_normal.toRect()));
34+ }
35+
36+ Q_EMIT normalChanged();
37+}
38+
39+QRectF WindowMargins::normal() const
40+{
41+ return m_normal;
42+}
43+
44+void WindowMargins::setDialog(QRectF value)
45+{
46+ if (m_dialog == value) {
47+ return;
48+ }
49+
50+ m_dialog = value;
51+
52+ if (window()) {
53+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
54+ nativeInterface->setWindowProperty(window()->handle(), "dialogWindowMargins", QVariant(m_dialog.toRect()));
55+ }
56+
57+ Q_EMIT dialogChanged();
58+}
59+
60+QRectF WindowMargins::dialog() const
61+{
62+ return m_dialog;
63+}
64+
65+void WindowMargins::itemChange(ItemChange change, const ItemChangeData &data)
66+{
67+ if (change == ItemSceneChange && data.window != nullptr) {
68+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
69+ if (!m_normal.isNull()) {
70+ nativeInterface->setWindowProperty(data.window->handle(), "normalWindowMargins", QVariant(m_normal.toRect()));
71+ nativeInterface->setWindowProperty(data.window->handle(), "dialogWindowMargins", QVariant(m_dialog.toRect()));
72+ }
73+ }
74+}
plugins/WindowManager/WindowMargins.hnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2017 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef WINDOWMARGINS_H
18+#define WINDOWMARGINS_H
19+
20+#include <QQuickItem>
21+#include <QRectF>
22+
23+/*
24+ * Specifies window margins for different Mir window types
25+ *
26+ * Used to inform MirAL so that it can take window management decisions that match
27+ * the visuals drawn by Unity.
28+ */
29+class WindowMargins : public QQuickItem
30+{
31+ Q_OBJECT
32+
33+ // Margins for windows of normal type
34+ Q_PROPERTY(QRectF normal READ normal WRITE setNormal NOTIFY normalChanged)
35+
36+ // Margins for windows of dialog type
37+ Q_PROPERTY(QRectF dialog READ dialog WRITE setDialog NOTIFY dialogChanged)
38+
39+ // TODO: Add margins for other window types as needed
40+
41+public:
42+ QRectF normal() const;
43+ void setNormal(QRectF value);
44+
45+ QRectF dialog() const;
46+ void setDialog(QRectF value);
47+
48+protected:
49+ void itemChange(ItemChange change, const ItemChangeData &value) override;
50+
51+Q_SIGNALS:
52+ void normalChanged();
53+ void dialogChanged();
54+private:
55+ QRectF m_normal;
56+ QRectF m_dialog;
57+};
58+
59+#endif // WINDOWMARGINS_H
po/unity8.pot+54−76
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2017-03-21 10:58+0000\n"
11+"POT-Creation-Date: 2017-03-28 21:50+0000\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -83,7 +83,7 @@ msgid "Log Out"
8383msgstr ""
8484
8585#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:264
86−#: qml/Dash/DashPageHeader.qml:324 qml/Greeter/NarrowView.qml:222
86+#: qml/Dash/DashPageHeader.qml:324 qml/Greeter/NarrowView.qml:208
8787#: qml/Wizard/Pages/passcode-confirm.qml:32
8888#: qml/Wizard/Pages/passcode-set.qml:32
8989msgid "Cancel"
@@ -167,135 +167,143 @@ msgstr ""
167167msgid "Switches to previous keyboard layout."
168168msgstr ""
169169
170−#: qml/Components/KeyboardShortcutsOverlay.qml:118
170+#: qml/Components/KeyboardShortcutsOverlay.qml:114
171+msgid "Ctrl + Alt + T"
172+msgstr ""
173+
174+#: qml/Components/KeyboardShortcutsOverlay.qml:119
175+msgid "Starts the Terminal application."
176+msgstr ""
177+
178+#: qml/Components/KeyboardShortcutsOverlay.qml:131
171179msgid "Launcher"
172180msgstr ""
173181
174−#: qml/Components/KeyboardShortcutsOverlay.qml:125
182+#: qml/Components/KeyboardShortcutsOverlay.qml:138
175183msgid "Super (Hold)"
176184msgstr ""
177185
178−#: qml/Components/KeyboardShortcutsOverlay.qml:130
186+#: qml/Components/KeyboardShortcutsOverlay.qml:143
179187msgid "Opens the launcher, displays shortcuts."
180188msgstr ""
181189
182−#: qml/Components/KeyboardShortcutsOverlay.qml:138
190+#: qml/Components/KeyboardShortcutsOverlay.qml:151
183191msgid "Alt + F1"
184192msgstr ""
185193
186−#: qml/Components/KeyboardShortcutsOverlay.qml:143
194+#: qml/Components/KeyboardShortcutsOverlay.qml:156
187195msgid "Opens launcher keyboard navigation mode."
188196msgstr ""
189197
190−#: qml/Components/KeyboardShortcutsOverlay.qml:151
198+#: qml/Components/KeyboardShortcutsOverlay.qml:164
191199msgid "Super + Tab"
192200msgstr ""
193201
194−#: qml/Components/KeyboardShortcutsOverlay.qml:156
202+#: qml/Components/KeyboardShortcutsOverlay.qml:169
195203msgid "Switches applications via the launcher."
196204msgstr ""
197205
198−#: qml/Components/KeyboardShortcutsOverlay.qml:164
206+#: qml/Components/KeyboardShortcutsOverlay.qml:177
199207msgid "Super + 1 to 0"
200208msgstr ""
201209
202−#: qml/Components/KeyboardShortcutsOverlay.qml:169
210+#: qml/Components/KeyboardShortcutsOverlay.qml:182
203211msgid "Same as clicking on a launcher icon."
204212msgstr ""
205213
206−#: qml/Components/KeyboardShortcutsOverlay.qml:177
214+#: qml/Components/KeyboardShortcutsOverlay.qml:190
207215msgid "Super + A"
208216msgstr ""
209217
210−#: qml/Components/KeyboardShortcutsOverlay.qml:182
218+#: qml/Components/KeyboardShortcutsOverlay.qml:195
211219msgid "Opens the Application Drawer."
212220msgstr ""
213221
214−#: qml/Components/KeyboardShortcutsOverlay.qml:194
222+#: qml/Components/KeyboardShortcutsOverlay.qml:207
215223msgid "Scopes"
216224msgstr ""
217225
218−#: qml/Components/KeyboardShortcutsOverlay.qml:201
226+#: qml/Components/KeyboardShortcutsOverlay.qml:214
219227msgid "Super (Tap)"
220228msgstr ""
221229
222−#: qml/Components/KeyboardShortcutsOverlay.qml:206
230+#: qml/Components/KeyboardShortcutsOverlay.qml:219
223231msgid "Opens the Scopes home."
224232msgstr ""
225233
226−#: qml/Components/KeyboardShortcutsOverlay.qml:222
234+#: qml/Components/KeyboardShortcutsOverlay.qml:235
227235msgid "Switching"
228236msgstr ""
229237
230−#: qml/Components/KeyboardShortcutsOverlay.qml:229
238+#: qml/Components/KeyboardShortcutsOverlay.qml:242
231239msgid "Alt + Tab"
232240msgstr ""
233241
234−#: qml/Components/KeyboardShortcutsOverlay.qml:234
242+#: qml/Components/KeyboardShortcutsOverlay.qml:247
235243msgid "Switches between applications."
236244msgstr ""
237245
238−#: qml/Components/KeyboardShortcutsOverlay.qml:242
246+#: qml/Components/KeyboardShortcutsOverlay.qml:255
239247msgid "Super + W"
240248msgstr ""
241249
242−#: qml/Components/KeyboardShortcutsOverlay.qml:247
250+#: qml/Components/KeyboardShortcutsOverlay.qml:260
243251msgid "Opens the desktop spread."
244252msgstr ""
245253
246−#: qml/Components/KeyboardShortcutsOverlay.qml:255
254+#: qml/Components/KeyboardShortcutsOverlay.qml:268
247255msgid "Cursor Left or Right"
248256msgstr ""
249257
250−#: qml/Components/KeyboardShortcutsOverlay.qml:260
258+#: qml/Components/KeyboardShortcutsOverlay.qml:273
251259msgid "Moves the focus."
252260msgstr ""
253261
254−#: qml/Components/KeyboardShortcutsOverlay.qml:272
262+#: qml/Components/KeyboardShortcutsOverlay.qml:285
255263msgid "Windows"
256264msgstr ""
257265
258−#: qml/Components/KeyboardShortcutsOverlay.qml:279
266+#: qml/Components/KeyboardShortcutsOverlay.qml:292
259267msgid "Ctrl + Super + D"
260268msgstr ""
261269
262−#: qml/Components/KeyboardShortcutsOverlay.qml:284
270+#: qml/Components/KeyboardShortcutsOverlay.qml:297
263271msgid "Minimizes all windows."
264272msgstr ""
265273
266−#: qml/Components/KeyboardShortcutsOverlay.qml:292
274+#: qml/Components/KeyboardShortcutsOverlay.qml:305
267275msgid "Ctrl + Super + Up"
268276msgstr ""
269277
270−#: qml/Components/KeyboardShortcutsOverlay.qml:297
278+#: qml/Components/KeyboardShortcutsOverlay.qml:310
271279msgid "Maximizes the current window."
272280msgstr ""
273281
274−#: qml/Components/KeyboardShortcutsOverlay.qml:305
282+#: qml/Components/KeyboardShortcutsOverlay.qml:318
275283msgid "Ctrl + Super + Down"
276284msgstr ""
277285
278−#: qml/Components/KeyboardShortcutsOverlay.qml:310
286+#: qml/Components/KeyboardShortcutsOverlay.qml:323
279287msgid "Minimizes or restores the current window."
280288msgstr ""
281289
282−#: qml/Components/KeyboardShortcutsOverlay.qml:318
290+#: qml/Components/KeyboardShortcutsOverlay.qml:331
283291msgid "Ctrl + Super + Left or Right"
284292msgstr ""
285293
286−#: qml/Components/KeyboardShortcutsOverlay.qml:323
294+#: qml/Components/KeyboardShortcutsOverlay.qml:336
287295msgid "Semi-maximizes the current window."
288296msgstr ""
289297
290−#: qml/Components/KeyboardShortcutsOverlay.qml:331
298+#: qml/Components/KeyboardShortcutsOverlay.qml:344
291299msgid "Alt + F4"
292300msgstr ""
293301
294−#: qml/Components/KeyboardShortcutsOverlay.qml:336
302+#: qml/Components/KeyboardShortcutsOverlay.qml:349
295303msgid "Closes the current window."
296304msgstr ""
297305
298−#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:242
306+#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:228
299307msgid "Return to Call"
300308msgstr ""
301309
@@ -489,19 +497,19 @@ msgid_plural "Please wait %1 minutes and then try again…"
489497msgstr[0] ""
490498msgstr[1] ""
491499
492−#: qml/Greeter/Greeter.qml:561
500+#: qml/Greeter/Greeter.qml:550
493501msgid "Try again"
494502msgstr ""
495503
496−#: qml/Greeter/Greeter.qml:562
504+#: qml/Greeter/Greeter.qml:551
497505msgid "Enter passphrase to unlock"
498506msgstr ""
499507
500−#: qml/Greeter/Greeter.qml:563
508+#: qml/Greeter/Greeter.qml:552
501509msgid "Enter passcode to unlock"
502510msgstr ""
503511
504−#: qml/Greeter/NarrowView.qml:242
512+#: qml/Greeter/NarrowView.qml:228
505513msgid "Emergency"
506514msgstr ""
507515
@@ -655,7 +663,7 @@ msgid "Language"
655663msgstr ""
656664
657665#: qml/Wizard/Pages/10-welcome.qml:173 qml/Wizard/Pages/20-keyboard.qml:152
658−#: qml/Wizard/Pages/30-wifi.qml:207 qml/Wizard/Pages/40-location.qml:271
666+#: qml/Wizard/Pages/30-wifi.qml:206 qml/Wizard/Pages/40-location.qml:271
659667#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
660668#: qml/Wizard/Pages/70-passwd-type.qml:145
661669#: qml/Wizard/Pages/75-report-check.qml:84
@@ -676,25 +684,24 @@ msgstr ""
676684msgid "Keyboard layout"
677685msgstr ""
678686
679−#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:207
680−#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/77-system-update.qml:152
681−#: qml/Wizard/Pages/sim.qml:101
687+#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:206
688+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/sim.qml:101
682689msgid "Skip"
683690msgstr ""
684691
685−#: qml/Wizard/Pages/30-wifi.qml:31
692+#: qml/Wizard/Pages/30-wifi.qml:30
686693msgid "Connect to Wi‑Fi"
687694msgstr ""
688695
689−#: qml/Wizard/Pages/30-wifi.qml:132
696+#: qml/Wizard/Pages/30-wifi.qml:131
690697msgid "Connected"
691698msgstr ""
692699
693−#: qml/Wizard/Pages/30-wifi.qml:165
700+#: qml/Wizard/Pages/30-wifi.qml:164
694701msgid "Available Wi-Fi networks"
695702msgstr ""
696703
697−#: qml/Wizard/Pages/30-wifi.qml:166
704+#: qml/Wizard/Pages/30-wifi.qml:165
698705msgid "No available Wi-Fi networks"
699706msgstr ""
700707
@@ -781,35 +788,6 @@ msgstr ""
781788msgid "Privacy policy"
782789msgstr ""
783790
784−#: qml/Wizard/Pages/77-system-update.qml:28
785−msgid "Update Device"
786−msgstr ""
787−
788−#: qml/Wizard/Pages/77-system-update.qml:55
789−msgid ""
790−"There is a system update available and ready to install. Afterwards, the "
791−"device will automatically restart."
792−msgstr ""
793−
794−#: qml/Wizard/Pages/77-system-update.qml:76
795−msgctxt "string identifying name of the update"
796−msgid "Ubuntu system"
797−msgstr ""
798−
799−#: qml/Wizard/Pages/77-system-update.qml:83
800−#, qt-format
801−msgctxt "version of the system update"
802−msgid "Version %1"
803−msgstr ""
804−
805−#: qml/Wizard/Pages/77-system-update.qml:102
806−msgid "This could take a few minutes..."
807−msgstr ""
808−
809−#: qml/Wizard/Pages/77-system-update.qml:116
810−msgid "Install and restart now"
811−msgstr ""
812−
813791#: qml/Wizard/Pages/80-finished.qml:89
814792msgid "Welcome to Ubuntu"
815793msgstr ""
qml/ApplicationMenus/MenuBar.qml+22−6
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2016 Canonical Ltd.
2+ * Copyright 2016, 2017 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -90,7 +90,7 @@ Item {
9090
9191 Row {
9292 id: row
93− spacing: units.gu(2)
93+ spacing: 0
9494 height: parent.height
9595
9696 ActionContext {
@@ -125,7 +125,11 @@ Item {
125125 readonly property bool shouldDisplay: x + width + ((__ownIndex < rowRepeater.count-1) ? units.gu(2) : 0) <
126126 root.overflowWidth - ((__ownIndex < rowRepeater.count-1) ? overflowButton.width : 0)
127127
128− implicitWidth: column.implicitWidth
128+ // First item is not centered, it has 0 gu on the left and 1 on the right
129+ // so needs different width and anchors
130+ readonly property bool isFirstItem: __ownIndex == 0
131+
132+ implicitWidth: column.implicitWidth + (isFirstItem ? units.gu(1) : units.gu(2))
129133 implicitHeight: row.height
130134 enabled: (model.sensitive === true) && shouldDisplay
131135 opacity: shouldDisplay ? 1 : 0
@@ -189,7 +193,9 @@ Item {
189193 id: column
190194 spacing: units.gu(1)
191195 anchors {
192− centerIn: parent
196+ verticalCenter: parent.verticalCenter
197+ horizontalCenter: !visualItem.isFirstItem ? parent.horizontalCenter : undefined
198+ left: visualItem.isFirstItem ? parent.left : undefined
193199 }
194200
195201 Icon {
@@ -224,6 +230,13 @@ Item {
224230 }
225231 }
226232 }
233+
234+ Component.onDestruction: {
235+ if (__popup) {
236+ __popup.destroy();
237+ __popup = null;
238+ }
239+ }
227240 } // Item ( delegate )
228241 } // Repeater
229242 } // Row
@@ -370,6 +383,9 @@ Item {
370383 function activate(index) {
371384 return sourceModel.activate(mapRowToSource(index));
372385 }
386+ function aboutToShow(index) {
387+ return sourceModel.aboutToShow(mapRowToSource(index));
388+ }
373389 }
374390
375391 Connections {
@@ -385,8 +401,8 @@ Item {
385401 anchors {
386402 bottom: row.bottom
387403 }
388− x: d.currentItem ? row.x + d.currentItem.x - units.gu(1) : 0
389− width: d.currentItem ? d.currentItem.width + units.gu(2) : 0
404+ x: d.currentItem ? row.x + d.currentItem.x : 0
405+ width: d.currentItem ? d.currentItem.width : 0
390406 height: units.dp(4)
391407 color: UbuntuColors.orange
392408 visible: d.currentItem
qml/ApplicationMenus/MenuPopup.qml+10−1
@@ -297,6 +297,8 @@ UbuntuShape {
297297
298298 width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
299299
300+ property Item popup: null
301+
300302 action.onTriggered: {
301303 submenuHoverTimer.stop();
302304
@@ -351,6 +353,13 @@ UbuntuShape {
351353 }
352354 }
353355 }
356+
357+ Component.onDestruction: {
358+ if (popup) {
359+ popup.destroy();
360+ popup = null;
361+ }
362+ }
354363 }
355364 }
356365
@@ -373,7 +382,7 @@ UbuntuShape {
373382 id: loader
374383 objectName: root.objectName + "-item" + __ownIndex
375384
376− property Item popup: null
385+ readonly property var popup: item ? item.popup : null
377386 property var __menuData: model
378387 property int __ownIndex: index
379388 property bool __isSeparator: model.isSeparator
qml/Components/KeyboardShortcutsOverlay.qml+13
@@ -110,6 +110,19 @@ Rectangle {
110110 Layout.maximumWidth: maxTextSize
111111 }
112112
113+ Label {
114+ text: i18n.tr("Ctrl + Alt + T")
115+ fontSize: "small"
116+ font.weight: Font.Medium
117+ }
118+ Label {
119+ text: i18n.tr("Starts the Terminal application.")
120+ fontSize: "small"
121+ font.weight: Font.Light
122+ wrapMode: Text.Wrap
123+ Layout.maximumWidth: maxTextSize
124+ }
125+
113126
114127 // Launcher section
115128 Item { Layout.columnSpan: 2; height: units.gu(2) }
qml/Greeter/Greeter.qml−11
@@ -20,7 +20,6 @@ import Biometryd 0.0
2020import GSettings 1.0
2121import Powerd 0.1
2222import Ubuntu.Components 1.3
23−import Ubuntu.SystemImage 0.1
2423import Unity.Launcher 0.1
2524import Unity.Session 0.1
2625
@@ -56,7 +55,6 @@ Showable {
5655 property bool tabletMode
5756 property url viewSource // only used for testing
5857
59− property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
6058 property int failedLoginsDelayAttempts: 7 // number of failed logins
6159 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
6260 property int failedFingerprintLoginsDisableAttempts: 3 // number of failed fingerprint logins
@@ -469,15 +467,6 @@ Showable {
469467 if (!automatic) {
470468 AccountsService.failedLogins++;
471469
472− // Check if we should initiate a factory reset
473− if (maxFailedLogins >= 2) { // require at least a warning
474− if (AccountsService.failedLogins === maxFailedLogins - 1) {
475− loader.item.showLastChance();
476− } else if (AccountsService.failedLogins >= maxFailedLogins) {
477− SystemImage.factoryReset(); // Ouch!
478− }
479− }
480−
481470 // Check if we should initiate a forced login delay
482471 if (failedLoginsDelayAttempts > 0
483472 && AccountsService.failedLogins > 0
qml/Greeter/NarrowView.qml−14
@@ -48,20 +48,6 @@ FocusScope {
4848 signal tease()
4949 signal emergencyCall()
5050
51− function showLastChance() {
52− /* TODO: when we finish support for resetting device after too many
53− failed logins, we should re-add this popup.
54− var title = lockscreen.alphaNumeric ?
55− i18n.tr("Sorry, incorrect passphrase.") :
56− i18n.tr("Sorry, incorrect passcode.");
57− var text = i18n.tr("This will be your last attempt.") + " " +
58− (lockscreen.alphaNumeric ?
59− i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
60− i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."));
61− lockscreen.showInfoPopup(title, text);
62− */
63− }
64−
6551 function hide() {
6652 lockscreen.hide();
6753 coverPage.hide();
qml/Greeter/WideView.qml−4
@@ -80,10 +80,6 @@ FocusScope {
8080 loginList.showFakePassword();
8181 }
8282
83− function showLastChance() {
84− // TODO
85− }
86−
8783 Rectangle {
8884 anchors.fill: parent
8985 color: "black"
qml/Launcher/Drawer.qml−2
@@ -364,8 +364,6 @@ FocusScope {
364364 width: units.gu(6)
365365 height: 7.5 / 8 * width
366366 anchors.horizontalCenter: parent.horizontalCenter
367− backgroundMode: UbuntuShape.SolidColor
368− backgroundColor: UbuntuColors.lightGrey
369367 radius: "medium"
370368 borderSource: 'undefined'
371369 source: Image {
qml/Launcher/LauncherPanel.qml+24−6
@@ -751,16 +751,18 @@ Rectangle {
751751 Keys.onPressed: {
752752 switch (event.key) {
753753 case Qt.Key_Down:
754− selectedIndex++;
755− if (selectedIndex >= popoverRepeater.count) {
756− selectedIndex = 0;
754+ var prevIndex = selectedIndex;
755+ selectedIndex = (selectedIndex + 1 < popoverRepeater.count) ? selectedIndex + 1 : 0;
756+ while (!popoverRepeater.itemAt(selectedIndex).clickable && selectedIndex != prevIndex) {
757+ selectedIndex = (selectedIndex + 1 < popoverRepeater.count) ? selectedIndex + 1 : 0;
757758 }
758759 event.accepted = true;
759760 break;
760761 case Qt.Key_Up:
761− selectedIndex--;
762− if (selectedIndex < 0) {
763− selectedIndex = popoverRepeater.count - 1;
762+ var prevIndex = selectedIndex;
763+ selectedIndex = (selectedIndex > 0) ? selectedIndex - 1 : popoverRepeater.count - 1;
764+ while (!popoverRepeater.itemAt(selectedIndex).clickable && selectedIndex != prevIndex) {
765+ selectedIndex = (selectedIndex > 0) ? selectedIndex - 1 : popoverRepeater.count - 1;
764766 }
765767 event.accepted = true;
766768 break;
@@ -806,6 +808,19 @@ Rectangle {
806808 width: parent.width
807809 height: quickListColumn.height
808810
811+ MouseArea {
812+ anchors.fill: parent
813+ hoverEnabled: true
814+ onPositionChanged: {
815+ var item = quickListColumn.childAt(mouseX, mouseY);
816+ if (item.clickable) {
817+ quickList.selectedIndex = item.index;
818+ } else {
819+ quickList.selectedIndex = -1;
820+ }
821+ }
822+ }
823+
809824 Column {
810825 id: quickListColumn
811826 width: parent.width
@@ -820,6 +835,9 @@ Rectangle {
820835 }
821836
822837 ListItem {
838+ readonly property bool clickable: model.clickable
839+ readonly property int index: model.index
840+
823841 objectName: "quickListEntry" + index
824842 selected: index === quickList.selectedIndex
825843 height: label.implicitHeight + label.anchors.topMargin + label.anchors.bottomMargin
qml/Shell.qml+8−1
@@ -255,6 +255,13 @@ StyledItem {
255255 }
256256 }
257257
258+ AvailableDesktopArea {
259+ id: availableDesktopAreaItem
260+ anchors.fill: parent
261+ anchors.topMargin: panel.fullscreenMode ? 0 : panel.minimizedPanelHeight
262+ anchors.leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
263+ }
264+
258265 GSettings {
259266 id: settings
260267 schema.id: "com.canonical.Unity8"
@@ -290,6 +297,7 @@ StyledItem {
290297 topLevelSurfaceList: topLevelSurfaceList
291298 inputMethodRect: inputMethod.visibleRect
292299 rightEdgePushProgress: rightEdgeBarrier.progress
300+ availableDesktopArea: availableDesktopAreaItem
293301
294302 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
295303 ? "phone"
@@ -311,7 +319,6 @@ StyledItem {
311319
312320 onInteractiveChanged: { if (interactive) { focus = true; } }
313321
314− leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
315322 suspended: greeter.shown
316323 altTabPressed: physicalKeysMapper.altTabPressed
317324 oskEnabled: shell.oskEnabled
qml/Stage/ChildWindow.qml+18−3
@@ -18,8 +18,9 @@ import QtQuick 2.4
1818import Ubuntu.Components 1.3
1919import Unity.Application 0.1
2020
21−Item {
21+FocusScope {
2222 id: root
23+ objectName: "childWindow"
2324
2425 // Set from outside.
2526 property var surface
@@ -27,6 +28,7 @@ Item {
2728 property Item target
2829 property alias requestedWidth: surfaceContainer.requestedWidth
2930 property alias requestedHeight: surfaceContainer.requestedHeight
31+ property real decorationHeight
3032
3133 width: surface ? surface.size.width : 0
3234 height: surface ? surface.size.height : 0
@@ -43,6 +45,7 @@ Item {
4345 readonly property bool decorated: surface ? surface.type === Mir.UtilityType
4446 || surface.type === Mir.DialogType
4547 || surface.type === Mir.NormalType
48+ || surface.type === Mir.SatelliteType
4649 : false
4750
4851 readonly property bool moveable: decorated
@@ -97,10 +100,14 @@ Item {
97100
98101 sourceComponent: Component {
99102 WindowDecoration {
100− height: units.gu(3)
103+ id: windowDecoration
104+ height: root.decorationHeight
101105 title: root.surface ? root.surface.name : ""
102106 active: root.surface ? root.surface.focused : false
103− closeButtonVisible: false
107+ closeButtonVisible: root.surface ? root.surface.type === Mir.SatelliteType
108+ || root.surface.type === Mir.NormalType
109+ || root.surface.type === Mir.UtilityType
110+ : false
104111 minimizeButtonVisible: false
105112 maximizeButtonShown: false
106113 onPressed: root.surface.activate();
@@ -109,6 +116,12 @@ Item {
109116 d.moveHandler.handlePositionChanged(mouse);
110117 }
111118 onReleased: if (d.moveHandler) { d.moveHandler.handleReleased(); }
119+ onCloseClicked: root.surface.close();
120+ Binding {
121+ target: root.surface
122+ property: "topMargin"
123+ value: windowDecoration.height
124+ }
112125 }
113126 }
114127 }
@@ -141,6 +154,8 @@ Item {
141154 // TODO ChildWindow parent will probably want to control those
142155 interactive: true
143156 consumesInput: true
157+
158+ focus: true
144159 }
145160
146161 Loader {
qml/Stage/ChildWindowRepeater.qml+12−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -21,8 +21,19 @@ Repeater {
2121 id: root
2222 property Item boundsItem
2323 delegate: ChildWindowTree {
24+ id: childWindowTree
2425 surface: model.surface
2526 z: root.count - model.index
2627 boundsItem: root.boundsItem
28+ Connections {
29+ target: childWindowTree.surface
30+ onFocusedChanged: {
31+ if (childWindowTree.surface.focused) {
32+ childWindowTree.focus = true;
33+ // focus the Loader
34+ childWindowTree.parent.focus = true;
35+ }
36+ }
37+ }
2738 }
2839}
qml/Stage/ChildWindowTree.qml+17−2
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -18,13 +18,14 @@ import QtQuick 2.4
1818import Ubuntu.Components 1.3
1919import Unity.Application 0.1
2020
21−Item {
21+FocusScope {
2222 id: root
2323
2424 property alias surface: childWindow.surface
2525 property real displacementX: 0
2626 property real displacementY: 0
2727 property alias boundsItem: childWindow.boundsItem
28+ property alias decorationHeight: childWindow.decorationHeight
2829
2930 x: surface ? surface.position.x + displacementX : 0
3031 y: surface ? surface.position.y + displacementY : 0
@@ -100,6 +101,13 @@ Item {
100101 onFocusRequested: {
101102 root.surface.activate();
102103 }
104+ onFocusedChanged: {
105+ if (root.surface.focused) {
106+ childWindow.focus = true;
107+ // Propagate
108+ root.focus = true;
109+ }
110+ }
103111 }
104112
105113 // Using a loader here mainly to circunvent the "ChildWindowTree is instantiated recursively" error from the QML engine
@@ -119,5 +127,12 @@ Item {
119127 property: "boundsItem"
120128 value: root.boundsItem
121129 }
130+ onFocusChanged: {
131+ if (focus) {
132+ // A surface in some ChildWindowTree got focused.
133+ // Propagate
134+ root.focus = true;
135+ }
136+ }
122137 }
123138}
qml/Stage/DecoratedWindow.qml+14−7
@@ -43,6 +43,7 @@ FocusScope {
4343 property bool hasDecoration: true
4444 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
4545 property real showDecoration: 1
46+ property alias decorationHeight: decoration.height
4647 property bool animateDecoration: false
4748 property bool showHighlight: false
4849 property int highlightSize: units.gu(1)
@@ -55,11 +56,15 @@ FocusScope {
5556 property int scaleToPreviewSize: units.gu(30)
5657
5758 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
58− readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
59+
60+ // Height of the decoration that's actually being displayed at this moment. Will match decorationHeight
61+ // when the decoration is being fully displayed
62+ readonly property real actualDecorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
63+
5964 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
6065
6166 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
62− readonly property int minimumHeight: decorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
67+ readonly property int minimumHeight: actualDecorationHeight + (!counterRotate ? applicationWindow.minimumHeight : applicationWindow.minimumWidth)
6368 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
6469 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
6570 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
@@ -74,6 +79,8 @@ FocusScope {
7479
7580 property alias altDragEnabled: altDragHandler.enabled
7681
82+ property Item windowMargins
83+
7784 signal closeClicked()
7885 signal maximizeClicked()
7986 signal maximizeHorizontallyClicked()
@@ -102,7 +109,7 @@ FocusScope {
102109 PropertyChanges {
103110 target: root
104111 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
105− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
112+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
106113 }
107114 },
108115 State {
@@ -111,7 +118,7 @@ FocusScope {
111118 PropertyChanges {
112119 target: root
113120 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
114− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
121+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
115122 }
116123 },
117124 State {
@@ -150,7 +157,7 @@ FocusScope {
150157 margins: active ? -units.gu(2) : -units.gu(1.5)
151158 }
152159 height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
153− + root.decorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
160+ + root.actualDecorationHeight * Math.min(1, root.showDecoration) + (active ? units.gu(4) : units.gu(3))
154161 source: "../graphics/dropshadow2gu.sci"
155162 opacity: root.shadowOpacity
156163 }
@@ -159,7 +166,7 @@ FocusScope {
159166 id: applicationWindow
160167 objectName: "appWindow"
161168 anchors.top: parent.top
162− anchors.topMargin: root.decorationHeight * Math.min(1, root.showDecoration)
169+ anchors.topMargin: root.actualDecorationHeight * Math.min(1, root.showDecoration)
163170 anchors.left: parent.left
164171 width: implicitWidth
165172 height: implicitHeight
@@ -207,7 +214,7 @@ FocusScope {
207214 objectName: "appWindowDecoration"
208215
209216 anchors { left: parent.left; top: parent.top; right: parent.right }
210− height: units.gu(3)
217+ height: units.gu(3) // a default value. overwritten by root.decorationHeight
211218
212219 title: applicationWindow.title
213220 windowMoving: moveHandler.moving && !altDragHandler.dragging
qml/Stage/Stage.qml+88−48
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
2+ * Copyright (C) 2014-2017 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ import GlobalShortcut 1.0
2525import GSettings 1.0
2626import "Spread"
2727import "Spread/MathUtils.js" as MathUtils
28+import WindowManager 1.0
2829
2930FocusScope {
3031 id: root
@@ -43,10 +44,10 @@ FocusScope {
4344 property int shellOrientationAngle
4445 property bool spreadEnabled: true // If false, animations and right edge will be disabled
4546 property bool suspended
46− property int leftMargin: 0
4747 property bool oskEnabled: false
4848 property rect inputMethodRect
4949 property real rightEdgePushProgress: 0
50+ property Item availableDesktopArea
5051
5152 // Configuration
5253 property string mode: "staged"
@@ -120,6 +121,12 @@ FocusScope {
120121 }
121122 }
122123
124+ // For MirAL window management
125+ WindowMargins {
126+ normal: Qt.rect(0, root.mode === "windowed" ? priv.windowDecorationHeight : 0, 0, 0)
127+ dialog: normal
128+ }
129+
123130 property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
124131 priv.focusedAppDelegate.clientAreaItem : null;
125132
@@ -224,10 +231,30 @@ FocusScope {
224231 active: priv.focusedAppDelegate !== null
225232 }
226233
234+ GlobalShortcut {
235+ shortcut: Qt.ControlModifier|Qt.AltModifier|Qt.Key_T
236+ onTriggered: {
237+ // try in this order: snap pkg, new deb name, old deb name
238+ var candidates = ["ubuntu-terminal-app_ubuntu-terminal-app", "ubuntu-terminal-app", "com.ubuntu.terminal"];
239+ for (var i = 0; i < candidates.length; i++) {
240+ if (priv.startApp(candidates[i]))
241+ break;
242+ }
243+ }
244+ }
245+
227246 QtObject {
228247 id: priv
229248 objectName: "DesktopStagePrivate"
230249
250+ function startApp(appId) {
251+ if (root.applicationManager.findApplication(appId)) {
252+ return root.applicationManager.requestFocusApplication(appId);
253+ } else {
254+ return root.applicationManager.startApplication(appId) !== null;
255+ }
256+ }
257+
231258 property var focusedAppDelegate: null
232259 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
233260
@@ -347,6 +374,8 @@ FocusScope {
347374 }
348375
349376 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
377+
378+ readonly property real windowDecorationHeight: units.gu(3)
350379 }
351380
352381 Component.onCompleted: priv.updateMainAndSideStageIndexes();
@@ -567,7 +596,7 @@ FocusScope {
567596 id: spreadItem
568597 objectName: "spreadItem"
569598 anchors.fill: appContainer
570− leftMargin: root.leftMargin
599+ leftMargin: root.availableDesktopArea.x
571600 model: root.topLevelSurfaceList
572601 spreadFlickable: floatingFlickable
573602 z: 10
@@ -675,13 +704,6 @@ FocusScope {
675704 }
676705 }
677706
678− Item {
679− id: boundariesForWindowPlacement
680− anchors.fill: parent
681− anchors.topMargin: PanelState.panelHeight
682− visible: false
683− }
684−
685707 Repeater {
686708 id: appRepeater
687709 model: topLevelSurfaceList
@@ -779,7 +801,7 @@ FocusScope {
779801 target: appDelegate
780802 property: "y"
781803 value: appDelegate.requestedY -
782− Math.min(appDelegate.requestedY - PanelState.panelHeight,
804+ Math.min(appDelegate.requestedY - root.availableDesktopArea.y,
783805 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
784806 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
785807 && root.inputMethodRect.height > 0
@@ -797,8 +819,8 @@ FocusScope {
797819 angleDiff = (360 + angleDiff) % 360;
798820 if (angleDiff === 90 || angleDiff === 270) {
799821 var aux = decoratedWindow.requestedHeight;
800− decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
801− decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
822+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.actualDecorationHeight;
823+ decoratedWindow.requestedWidth = aux - decoratedWindow.actualDecorationHeight;
802824 }
803825 }
804826 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -899,12 +921,13 @@ FocusScope {
899921 priv.updateMainAndSideStageIndexes();
900922 }
901923 appDelegate.focus = true;
924+ priv.focusedAppDelegate = appDelegate;
902925 }
903926
904927 function updateQmlFocusFromMirSurfaceFocus() {
905928 if (model.window.focused) {
906929 claimFocus();
907− priv.focusedAppDelegate = appDelegate;
930+ decoratedWindow.focus = true;
908931 }
909932 }
910933
@@ -913,8 +936,8 @@ FocusScope {
913936 target: appDelegate
914937 screenWidth: appContainer.width
915938 screenHeight: appContainer.height
916− leftMargin: root.leftMargin
917− minimumY: boundariesForWindowPlacement.y
939+ leftMargin: root.availableDesktopArea.x
940+ minimumY: root.availableDesktopArea.y
918941 }
919942
920943 Connections {
@@ -1166,7 +1189,7 @@ FocusScope {
11661189
11671190 StagedRightEdgeMaths {
11681191 id: stagedRightEdgeMaths
1169− sceneWidth: appContainer.width - root.leftMargin
1192+ sceneWidth: root.availableDesktopArea.width
11701193 sceneHeight: appContainer.height
11711194 isMainStageApp: priv.mainStageDelegate == appDelegate
11721195 isSideStageApp: priv.sideStageDelegate == appDelegate
@@ -1177,7 +1200,7 @@ FocusScope {
11771200 progress: 0
11781201 targetHeight: spreadItem.stackHeight
11791202 targetX: spreadMaths.targetX
1180− startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1203+ startY: appDelegate.fullscreen ? 0 : root.availableDesktopArea.y
11811204 targetY: spreadMaths.targetY
11821205 targetAngle: spreadMaths.targetAngle
11831206 targetScale: spreadMaths.targetScale
@@ -1298,9 +1321,9 @@ FocusScope {
12981321 PropertyChanges {
12991322 target: appDelegate
13001323 x: stageMaths.itemX
1301− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1324+ y: root.availableDesktopArea.y
13021325 requestedWidth: appContainer.width
1303− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1326+ requestedHeight: root.availableDesktopArea.height
13041327 visuallyMaximized: true
13051328 visible: appDelegate.x < root.width
13061329 }
@@ -1330,10 +1353,10 @@ FocusScope {
13301353 PropertyChanges {
13311354 target: appDelegate
13321355 x: stageMaths.itemX
1333− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1356+ y: root.availableDesktopArea.y
13341357 z: stageMaths.itemZ
13351358 requestedWidth: stageMaths.itemWidth
1336− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1359+ requestedHeight: root.availableDesktopArea.height
13371360 visuallyMaximized: true
13381361 visible: appDelegate.x < root.width
13391362 }
@@ -1354,11 +1377,11 @@ FocusScope {
13541377 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
13551378 PropertyChanges {
13561379 target: appDelegate;
1357− requestedX: root.leftMargin;
1380+ requestedX: root.availableDesktopArea.x;
13581381 requestedY: 0;
13591382 visuallyMinimized: false;
13601383 visuallyMaximized: true
1361− requestedWidth: appContainer.width - root.leftMargin;
1384+ requestedWidth: root.availableDesktopArea.width;
13621385 requestedHeight: appContainer.height;
13631386 }
13641387 PropertyChanges { target: touchControls; enabled: true }
@@ -1391,6 +1414,7 @@ FocusScope {
13911414 when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
13921415 extend: "normal"
13931416 PropertyChanges {
1417+ restoreEntryValues: false
13941418 target: appDelegate;
13951419 windowedX: restoredX;
13961420 windowedY: restoredY;
@@ -1401,10 +1425,10 @@ FocusScope {
14011425 extend: "normal"
14021426 PropertyChanges {
14031427 target: appDelegate
1404− windowedX: root.leftMargin
1405− windowedY: PanelState.panelHeight
1406− windowedWidth: (appContainer.width - root.leftMargin)/2
1407− windowedHeight: appContainer.height - PanelState.panelHeight
1428+ windowedX: root.availableDesktopArea.x
1429+ windowedY: root.availableDesktopArea.y
1430+ windowedWidth: root.availableDesktopArea.width / 2
1431+ windowedHeight: root.availableDesktopArea.height
14081432 }
14091433 },
14101434 State {
@@ -1412,7 +1436,7 @@ FocusScope {
14121436 extend: "maximizedLeft"
14131437 PropertyChanges {
14141438 target: appDelegate;
1415− windowedX: (appContainer.width + root.leftMargin)/2
1439+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
14161440 }
14171441 },
14181442 State {
@@ -1420,10 +1444,10 @@ FocusScope {
14201444 extend: "normal"
14211445 PropertyChanges {
14221446 target: appDelegate
1423− windowedX: root.leftMargin
1424− windowedY: PanelState.panelHeight
1425− windowedWidth: (appContainer.width - root.leftMargin)/2
1426− windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1447+ windowedX: root.availableDesktopArea.x
1448+ windowedY: root.availableDesktopArea.y
1449+ windowedWidth: root.availableDesktopArea.width / 2
1450+ windowedHeight: root.availableDesktopArea.height / 2
14271451 }
14281452 },
14291453 State {
@@ -1431,7 +1455,7 @@ FocusScope {
14311455 extend: "maximizedTopLeft"
14321456 PropertyChanges {
14331457 target: appDelegate
1434− windowedX: (appContainer.width + root.leftMargin)/2
1458+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
14351459 }
14361460 },
14371461 State {
@@ -1439,10 +1463,10 @@ FocusScope {
14391463 extend: "normal"
14401464 PropertyChanges {
14411465 target: appDelegate
1442− windowedX: root.leftMargin
1443− windowedY: (appContainer.height + PanelState.panelHeight)/2
1444− windowedWidth: (appContainer.width - root.leftMargin)/2
1445− windowedHeight: appContainer.height/2
1466+ windowedX: root.availableDesktopArea.x
1467+ windowedY: root.availableDesktopArea.y + (root.availableDesktopArea.height / 2)
1468+ windowedWidth: root.availableDesktopArea.width / 2
1469+ windowedHeight: root.availableDesktopArea.height / 2
14461470 }
14471471 },
14481472 State {
@@ -1450,20 +1474,26 @@ FocusScope {
14501474 extend: "maximizedBottomLeft"
14511475 PropertyChanges {
14521476 target: appDelegate
1453− windowedX: (appContainer.width + root.leftMargin)/2
1477+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
14541478 }
14551479 },
14561480 State {
14571481 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
14581482 extend: "normal"
1459− PropertyChanges { target: appDelegate; windowedX: root.leftMargin; windowedY: windowedY;
1460− windowedWidth: appContainer.width - root.leftMargin; windowedHeight: windowedHeight }
1483+ PropertyChanges {
1484+ target: appDelegate
1485+ windowedX: root.availableDesktopArea.x; windowedY: windowedY
1486+ windowedWidth: root.availableDesktopArea.width; windowedHeight: windowedHeight
1487+ }
14611488 },
14621489 State {
14631490 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
14641491 extend: "normal"
1465− PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: PanelState.panelHeight;
1466− windowedWidth: windowedWidth; windowedHeight: appContainer.height - PanelState.panelHeight }
1492+ PropertyChanges {
1493+ target: appDelegate
1494+ windowedX: windowedX; windowedY: root.availableDesktopArea.y
1495+ windowedWidth: windowedWidth; windowedHeight: root.availableDesktopArea.height
1496+ }
14671497 },
14681498 State {
14691499 name: "minimized"; when: appDelegate.minimized
@@ -1591,7 +1621,7 @@ FocusScope {
15911621 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
15921622
15931623 target: appDelegate
1594− boundsItem: boundariesForWindowPlacement
1624+ boundsItem: root.availableDesktopArea
15951625 minWidth: units.gu(10)
15961626 minHeight: units.gu(10)
15971627 borderThickness: units.gu(2)
@@ -1614,13 +1644,14 @@ FocusScope {
16141644 focus: true
16151645 interactive: root.interactive
16161646 showDecoration: 1
1647+ decorationHeight: priv.windowDecorationHeight
16171648 maximizeButtonShown: appDelegate.canBeMaximized
16181649 overlayShown: touchControls.overlayShown
16191650 width: implicitWidth
16201651 height: implicitHeight
16211652 highlightSize: windowInfoItem.iconMargin / 2
1622− boundsItem: boundariesForWindowPlacement
16231653 altDragEnabled: root.mode == "windowed"
1654+ boundsItem: root.availableDesktopArea
16241655
16251656 requestedWidth: appDelegate.requestedWidth
16261657 requestedHeight: appDelegate.requestedHeight
@@ -1683,7 +1714,7 @@ FocusScope {
16831714 resizeArea: resizeArea
16841715 enabled: false
16851716 visible: enabled
1686− boundsItem: boundariesForWindowPlacement
1717+ boundsItem: root.availableDesktopArea
16871718
16881719 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
16891720 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
@@ -1804,9 +1835,18 @@ FocusScope {
18041835 displacementX: appDelegate.clientAreaItem.x
18051836 displacementY: appDelegate.clientAreaItem.y
18061837
1807− boundsItem: boundariesForWindowPlacement
1838+ boundsItem: root.availableDesktopArea
1839+ decorationHeight: priv.windowDecorationHeight
18081840
18091841 z: childWindowRepeater.count - model.index
1842+
1843+ onFocusChanged: {
1844+ if (focus) {
1845+ // some child surface in this tree got focus.
1846+ // Ensure we also have it at the top-level hierarchy
1847+ appDelegate.claimFocus();
1848+ }
1849+ }
18101850 }
18111851 }
18121852 }
@@ -1817,7 +1857,7 @@ FocusScope {
18171857 FakeMaximizeDelegate {
18181858 id: fakeRectangle
18191859 target: priv.focusedAppDelegate
1820− leftMargin: root.leftMargin
1860+ leftMargin: root.availableDesktopArea.x
18211861 appContainerWidth: appContainer.width
18221862 appContainerHeight: appContainer.height
18231863 }
qml/Wizard/Pages/30-wifi.qml−4
@@ -20,7 +20,6 @@ import QMenuModel 0.1 as QMenuModel
2020import Ubuntu.Components 1.3
2121import Wizard 0.1
2222import Ubuntu.Connectivity 1.0
23−import Ubuntu.SystemImage 0.1
2423import ".." as LocalComponents
2524import "../../Components"
2625
@@ -206,9 +205,6 @@ LocalComponents.Page {
206205 LocalComponents.StackButton {
207206 text: (connected || listview.count === 0) ? i18n.tr("Next") : i18n.tr("Skip")
208207 onClicked: {
209− if (connected) {
210− SystemImage.checkForUpdate(); // initiate the background check for System Update
211− }
212208 pageStack.next();
213209 }
214210 }
qml/Wizard/Pages/77-system-update.qmldeleted−156
@@ -1,156 +0,0 @@
1−/*
2− * Copyright (C) 2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import QtQuick.Layouts 1.1
19−import Ubuntu.Components 1.3
20−import Ubuntu.SystemImage 0.1
21−import Wizard 0.1
22−import ".." as LocalComponents
23−
24−LocalComponents.Page {
25− id: systemUpdatePage
26− objectName: "systemUpdatePage"
27−
28− title: i18n.tr("Update Device")
29− forwardButtonSourceComponent: forwardButton
30−
31− skip: !SystemImage.updateDownloaded // skip the page when the system update is not ready to install
32−
33− Column {
34− id: column
35− anchors {
36− fill: content
37− leftMargin: systemUpdatePage.leftMargin
38− rightMargin: systemUpdatePage.rightMargin
39− topMargin: systemUpdatePage.customMargin
40− }
41− spacing: units.gu(3)
42− opacity: spinner.running ? 0.5 : 1
43− Behavior on opacity {
44− UbuntuNumberAnimation {}
45− }
46−
47− Label {
48− anchors.left: parent.left
49− anchors.right: parent.right
50− anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
51− font.weight: Font.Light
52− color: textColor
53− wrapMode: Text.Wrap
54− fontSize: "small"
55− text: i18n.tr("There is a system update available and ready to install. Afterwards, the device will automatically restart.")
56− }
57−
58− GridLayout {
59− rows: 3
60− columns: 2
61− rowSpacing: units.gu(1)
62− columnSpacing: units.gu(2)
63−
64− Image {
65− Layout.rowSpan: 3
66− Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
67− sourceSize: Qt.size(units.gu(3), units.gu(3))
68− fillMode: Image.PreserveAspectFit
69− source: "image://theme/distributor-logo"
70− }
71−
72− Label {
73− color: textColor
74− font.weight: Font.Normal
75− fontSize: "small"
76− text: i18n.ctr("string identifying name of the update", "Ubuntu system")
77− }
78−
79− Label {
80− font.weight: Font.Light
81− fontSize: "small"
82− color: textColor
83− text: i18n.ctr("version of the system update", "Version %1").arg(SystemImage.availableVersion)
84− }
85−
86− Label {
87− font.weight: Font.Light
88− fontSize: "small"
89− color: textColor
90− text: SystemImage.updateSize
91− }
92− }
93−
94− Label {
95− anchors.left: parent.left
96− anchors.right: parent.right
97− anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
98− font.weight: Font.Light
99− color: textColor
100− wrapMode: Text.Wrap
101− fontSize: "small"
102− text: i18n.tr("This could take a few minutes...")
103− }
104−
105− Rectangle {
106− anchors.left: parent.left
107− anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
108− color: theme.palette.normal.foreground
109− radius: units.dp(4)
110− width: buttonLabel.paintedWidth + units.gu(3)
111− height: buttonLabel.paintedHeight + units.gu(1.8)
112−
113− Label {
114− id: buttonLabel
115− color: textColor
116− text: i18n.tr("Install and restart now")
117− font.weight: Font.Light
118− anchors.centerIn: parent
119− }
120−
121− AbstractButton {
122− id: button
123− objectName: "installButton"
124− anchors.fill: parent
125− onClicked: {
126− System.skipUntilFinishedPage();
127− SystemImage.applyUpdate();
128− }
129− }
130−
131− transformOrigin: Item.Top
132− scale: button.pressed ? 0.98 : 1.0
133− Behavior on scale {
134− ScaleAnimator {
135− duration: UbuntuAnimation.SnapDuration
136− easing.type: Easing.Linear
137− }
138− }
139− }
140− }
141−
142− ActivityIndicator {
143− id: spinner
144− anchors.centerIn: systemUpdatePage
145− running: SystemImage.updateApplying
146− visible: running
147− }
148−
149− Component {
150− id: forwardButton
151− LocalComponents.StackButton {
152− text: i18n.tr("Skip")
153− onClicked: pageStack.next()
154− }
155− }
156−}
src/CMakeLists.txt−1
@@ -60,5 +60,4 @@ install(TARGETS ${SHELL_APP}
6060 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
6161 )
6262
63−add_subdirectory(Panel)
6463add_subdirectory(Dash)
src/Panel/CMakeLists.txtdeleted−3
@@ -1,3 +0,0 @@
1−add_subdirectory(Indicators)
2−
3−set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
src/Panel/Indicators/CMakeLists.txtdeleted−1
@@ -1 +0,0 @@
1−add_subdirectory(client)
tests/CMakeLists.txt+1
@@ -20,6 +20,7 @@ add_subdirectory(uqmlscene)
2020# Use our custom implementation of qmlscene and import dbus-test-runner
2121add_executable(qmlscene ALIAS uqmlscene)
2222import_executables(dbus-test-runner)
23+import_executables(qdbus-simple-test-runner)
2324
2425set(UNITY_PLUGINPATH "${CMAKE_BINARY_DIR}/plugins" CACHE PATH "Path to pre-built unity8 plugin dir.")
2526set(UNITY_MOCKPATH "${CMAKE_BINARY_DIR}/tests/mocks" CACHE PATH "Path to pre-built unity8 mock dir.")
tests/mocks/Ubuntu/CMakeLists.txt−1
@@ -1,6 +1,5 @@
11add_subdirectory(Connectivity)
22add_subdirectory(DownloadDaemonListener)
3−add_subdirectory(SystemImage)
43add_subdirectory(SystemSettings)
54add_subdirectory(Telephony)
65add_subdirectory(Thumbnailer)
tests/mocks/Ubuntu/SystemImage/CMakeLists.txtdeleted−10
@@ -1,10 +0,0 @@
1−set(MOCK_SYSTEMIMAGE_SOURCES
2− plugin.cpp
3− MockSystemImage.cpp
4−)
5−
6−add_library(MockSystemImage MODULE ${MOCK_SYSTEMIMAGE_SOURCES})
7−
8−qt5_use_modules(MockSystemImage Qml Quick Core)
9−
10−add_unity8_mock(Ubuntu.SystemImage 0.1 Ubuntu/SystemImage TARGETS MockSystemImage)
tests/mocks/Ubuntu/SystemImage/MockSystemImage.cppdeleted−50
@@ -1,50 +0,0 @@
1−/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include <QDebug>
18−#include <QTimer>
19−
20−#include "MockSystemImage.h"
21−
22−MockSystemImage::MockSystemImage(QObject *parent)
23− : QObject(parent)
24−{
25−}
26−
27−void MockSystemImage::checkForUpdate()
28−{
29− qDebug() << "Doing a fake system update check";
30−}
31−
32−void MockSystemImage::applyUpdate()
33−{
34− qDebug() << "Applying a fake system update";
35− setUpdateApplying(true);
36− QTimer::singleShot(3000, [this] {setUpdateApplying(false);});
37−}
38−
39−void MockSystemImage::factoryReset()
40−{
41− Q_EMIT resettingDevice();
42−}
43−
44−void MockSystemImage::setUpdateApplying(bool status)
45−{
46− if (status != m_updateApplying) {
47− m_updateApplying = status;
48− Q_EMIT updateApplyingChanged();
49− }
50−}
tests/mocks/Ubuntu/SystemImage/MockSystemImage.hdeleted−56
@@ -1,56 +0,0 @@
1−/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef MOCK_SYSTEMIMAGE_H
18−#define MOCK_SYSTEMIMAGE_H
19−
20−#include <QObject>
21−
22−class MockSystemImage : public QObject
23−{
24− Q_OBJECT
25− Q_DISABLE_COPY(MockSystemImage)
26−
27− Q_PROPERTY(bool updateDownloaded READ updateDownloaded CONSTANT)
28− Q_PROPERTY(QString availableVersion READ availableVersion CONSTANT)
29− Q_PROPERTY(QString updateSize READ updateSize CONSTANT)
30− Q_PROPERTY(bool updateApplying READ updateApplying NOTIFY updateApplyingChanged)
31−
32−public:
33− explicit MockSystemImage(QObject *parent = nullptr);
34−
35− Q_INVOKABLE void checkForUpdate();
36− Q_INVOKABLE void applyUpdate();
37− Q_INVOKABLE void factoryReset();
38−
39− bool updateApplying() const { return m_updateApplying; }
40− // these are const only in mock
41− bool updateDownloaded() const { return true; }
42− QString availableVersion() const { return QStringLiteral("42"); }
43− QString updateSize() const { return QStringLiteral("4.2 MB"); }
44−
45−Q_SIGNALS:
46− void resettingDevice(); // only for mock
47− void updateApplyingChanged();
48−
49−private Q_SLOTS:
50− void setUpdateApplying(bool status);
51−
52−private:
53− bool m_updateApplying = false;
54−};
55−
56−#endif // MOCK_SYSTEMIMAGE_H
tests/mocks/Ubuntu/SystemImage/plugin.cppdeleted−34
@@ -1,34 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "plugin.h"
18−#include "MockSystemImage.h"
19−
20−#include <QtQml>
21−
22−static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
23−{
24− Q_UNUSED(engine)
25− Q_UNUSED(scriptEngine)
26− return new MockSystemImage();
27−}
28−
29−void BackendPlugin::registerTypes(const char *uri)
30−{
31− Q_ASSERT(uri == QLatin1String("Ubuntu.SystemImage"));
32−
33− qmlRegisterSingletonType<MockSystemImage>(uri, 0, 1, "SystemImage", service_provider);
34−}
tests/mocks/Ubuntu/SystemImage/plugin.hdeleted−31
@@ -1,31 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef MOCK_SYSTEMIMAGE_PLUGIN_H
18−#define MOCK_SYSTEMIMAGE_PLUGIN_H
19−
20−#include <QQmlExtensionPlugin>
21−
22−class BackendPlugin : public QQmlExtensionPlugin
23−{
24− Q_OBJECT
25− Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26−
27−public:
28− void registerTypes(const char *uri) override;
29−};
30−
31−#endif // MOCK_SYSTEMIMAGE_PLUGIN_H
tests/mocks/Ubuntu/SystemImage/qmldirdeleted−3
@@ -1,3 +0,0 @@
1−module Ubuntu.SystemImage
2−plugin MockSystemImage
3−typeinfo SystemImage.qmltypes
tests/mocks/Unity/Application/ApplicationManager.cpp+5−7
@@ -172,7 +172,6 @@ bool ApplicationManager::add(ApplicationInfo *application) {
172172
173173 endInsertRows();
174174 Q_EMIT countChanged();
175− if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
176175
177176 return true;
178177}
@@ -189,7 +188,6 @@ void ApplicationManager::remove(ApplicationInfo *application) {
189188 endRemoveRows();
190189 m_modelBusy = false;
191190 Q_EMIT countChanged();
192− if (isEmpty()) Q_EMIT emptyChanged(isEmpty());
193191 DEBUG_MSG(application->appId() << " after: " << qPrintable(toString()));
194192 }
195193}
@@ -476,6 +474,11 @@ void ApplicationManager::buildListOfAvailableApplications()
476474 application->setIsTouchApp(false);
477475 m_availableApplications.append(application);
478476
477+ application = new ApplicationInfo(this);
478+ application->setAppId("ubuntu-terminal-app");
479+ application->setName("Terminal");
480+ m_availableApplications.append(application);
481+
479482 application = new ApplicationInfo(this);
480483 application->setAppId("primary-oriented-app");
481484 application->setName("Primary Oriented");
@@ -502,11 +505,6 @@ QStringList ApplicationManager::availableApplications()
502505 return appIds;
503506}
504507
505−bool ApplicationManager::isEmpty() const
506−{
507− return m_runningApplications.isEmpty();
508−}
509−
510508ApplicationInfo *ApplicationManager::findApplication(MirSurface* surface)
511509{
512510 for (ApplicationInfo *app : m_runningApplications) {
tests/mocks/Unity/Application/ApplicationManager.h+1−6
@@ -40,7 +40,6 @@ using namespace unity::shell::application;
4040class ApplicationManager : public ApplicationManagerInterface {
4141 Q_OBJECT
4242
43− Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
4443 Q_PROPERTY(QStringList availableApplications READ availableApplications NOTIFY availableApplicationsChanged)
4544
4645 public:
@@ -56,8 +55,6 @@ class ApplicationManager : public ApplicationManagerInterface {
5655 Q_INVOKABLE ApplicationInfo *findApplication(const QString &appId) const override;
5756 unity::shell::application::ApplicationInfoInterface *findApplicationWithSurface(unity::shell::application::MirSurfaceInterface* surface) const override;
5857
59− Q_INVOKABLE void move(int from, int to);
60−
6158 // Application control methods
6259 Q_INVOKABLE bool requestFocusApplication(const QString &appId) override;
6360 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
@@ -71,17 +68,15 @@ class ApplicationManager : public ApplicationManagerInterface {
7168
7269 QModelIndex findIndex(ApplicationInfo* application);
7370
74− bool isEmpty() const;
75−
7671 Q_SIGNALS:
7772 void focusRequested(const QString &appId);
78− void emptyChanged(bool empty);
7973 void availableApplicationsChanged(QStringList list);
8074
8175 private Q_SLOTS:
8276 void raiseApp(const QString &appId);
8377
8478 private:
79+ void move(int from, int to);
8580 bool add(ApplicationInfo *application);
8681 void remove(ApplicationInfo* application);
8782 void buildListOfAvailableApplications();
tests/mocks/Unity/Application/MirSurface.cpp+5
@@ -452,6 +452,11 @@ void MirSurface::setHeightIncrement(int value)
452452void MirSurface::close()
453453{
454454 DEBUG_MSG("");
455+
456+ for (int i = 0; i < m_childSurfaceList->count(); ++i) {
457+ m_childSurfaceList->get(i)->close();
458+ }
459+
455460 if (!m_zombieTimer.isActive()) {
456461 m_zombieTimer.start();
457462 Q_EMIT closeRequested();
tests/plugins/Unity/CMakeLists.txt+1
@@ -1,3 +1,4 @@
11add_subdirectory(Indicators)
22add_subdirectory(Launcher)
3+add_subdirectory(Platform)
34add_subdirectory(Session)
tests/plugins/Unity/Platform/CMakeLists.txtnew file+30
@@ -0,0 +1,30 @@
1+
2+include_directories(
3+ ${Qt5Core_INCLUDE_DIRS}
4+ ${Qt5DBus_INCLUDE_DIRS}
5+ ${Qt5Test_INCLUDE_DIRS}
6+ ${QTDBUSTEST_INCLUDE_DIRS}
7+ ${CMAKE_CURRENT_BINARY_DIR}
8+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Platform
9+)
10+
11+add_executable(platformtest
12+ platformtest.cpp
13+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Platform/platform.cpp
14+ )
15+
16+target_link_libraries(platformtest
17+ Qt5::Core
18+ Qt5::DBus
19+ Qt5::Test
20+ ${QTDBUSTEST_LDFLAGS}
21+ )
22+
23+
24+install(TARGETS platformtest
25+ DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Unity/Platform"
26+)
27+
28+add_unity8_unittest(Platform qdbus-simple-test-runner
29+ ARGS $<TARGET_FILE:platformtest>
30+ )
tests/plugins/Unity/Platform/platformtest.cppnew file+142
@@ -0,0 +1,142 @@
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+ * Authors:
17+ * Pete Woods <pete.woods@canonical.com>
18+ */
19+
20+#include "platform.h"
21+
22+#include <libqtdbustest/DBusTestRunner.h>
23+#include <libqtdbusmock/DBusMock.h>
24+
25+#include <QtTest>
26+#include <QDebug>
27+
28+using namespace QtDBusTest;
29+using namespace QtDBusMock;
30+
31+class PlatformTest: public QObject
32+{
33+
34+Q_OBJECT
35+
36+private:
37+ struct TestFixture
38+ {
39+ TestFixture() :
40+ mock(dbus)
41+ {
42+ }
43+
44+ DBusTestRunner dbus;
45+ DBusMock mock;
46+ };
47+
48+ QScopedPointer<TestFixture> m_data;
49+
50+ void registerLogin1(bool canMultiSession, bool canGraphical)
51+ {
52+ m_data->mock.registerLogin1({{"DefaultSeat", QVariantMap
53+ {
54+ {"CanMultiSession", canMultiSession},
55+ {"CanGraphical", canGraphical}
56+ }}}
57+ );
58+ }
59+
60+ void registerHostname1(const QString& chassis)
61+ {
62+ m_data->mock.registerHostname1({
63+ {"Chassis", chassis}
64+ });
65+ }
66+
67+ void startServices()
68+ {
69+ m_data->dbus.startServices();
70+ }
71+
72+private Q_SLOTS:
73+
74+ void init()
75+ {
76+ m_data.reset(new TestFixture);
77+ }
78+
79+ void cleanup()
80+ {
81+ m_data.reset();
82+ }
83+
84+ void testIsPC_data()
85+ {
86+ QTest::addColumn<QString>("chassis");
87+ QTest::addColumn<bool>("result");
88+
89+ QTest::newRow("vm") << "vm" << true;
90+ QTest::newRow("container") << "container" << true;
91+ QTest::newRow("desktop") << "desktop" << true;
92+ QTest::newRow("laptop") << "laptop" << true;
93+ QTest::newRow("server") << "server" << true;
94+ QTest::newRow("tablet") << "tablet" << false;
95+ QTest::newRow("handset") << "handset" << false;
96+ QTest::newRow("watch") << "watch" << false;
97+ QTest::newRow("embedded") << "embedded" << true;
98+ }
99+
100+ void testIsPC()
101+ {
102+ QFETCH(QString, chassis);
103+ QFETCH(bool, result);
104+
105+ registerLogin1(true, true);
106+ registerHostname1(chassis);
107+ startServices();
108+
109+ Platform p;
110+ QCOMPARE(p.isPC(), result);
111+ QCOMPARE(p.chassis(), chassis);
112+ }
113+
114+ void testIsMultiSession_data()
115+ {
116+ QTest::addColumn<bool>("canMultiSession");
117+ QTest::addColumn<bool>("canGraphical");
118+ QTest::addColumn<bool>("result");
119+
120+ QTest::newRow("") << true << true << true;
121+ QTest::newRow("") << true << false << false;
122+ QTest::newRow("") << false << true << false;
123+ QTest::newRow("") << false << false << false;
124+ }
125+
126+ void testIsMultiSession()
127+ {
128+ QFETCH(bool, canMultiSession);
129+ QFETCH(bool, canGraphical);
130+ QFETCH(bool, result);
131+
132+ registerLogin1(canMultiSession, canGraphical);
133+ registerHostname1("desktop");
134+ startServices();
135+
136+ Platform p;
137+ QCOMPARE(p.isMultiSession(), result);
138+ }
139+};
140+
141+QTEST_GUILESS_MAIN(PlatformTest)
142+#include "platformtest.moc"
tests/plugins/Utils/WindowStateStorageTest.cpp+9
@@ -56,6 +56,15 @@ private Q_SLOTS:
5656 QTRY_COMPARE(storage->getStage(QTest::currentTestFunction(), 0), stage);
5757 }
5858
59+ void testProtectAgainstInvalidGeometry() {
60+ const QRect geometry{10, 20, 0, 10}; // zero-width (invalid) rectangle
61+ storage->saveGeometry(QTest::currentTestFunction(), geometry);
62+ const QRect defaultGeometry{10, 20, 30, 40};
63+ const QRect loadedGeometry = storage->getGeometry(QTest::currentTestFunction(), defaultGeometry);
64+ // ensure we don't load a broken geometry, instead we fall back to the default one
65+ QCOMPARE(loadedGeometry, defaultGeometry);
66+ }
67+
5968private:
6069 WindowStateStorage * storage{nullptr};
6170};
tests/plugins/WindowManager/UnityApplicationMocks.h+8−1
@@ -95,7 +95,14 @@ class Application : public ApplicationInfoInterface
9595{
9696 Q_OBJECT
9797public:
98− Application(QString appId) : ApplicationInfoInterface(appId, nullptr), m_appId(std::move(appId)) {}
98+ Application(QString appId)
99+ : ApplicationInfoInterface(appId, nullptr)
100+ , m_appId(std::move(appId))
101+ , m_state(Starting)
102+ , m_requestedState(RequestedRunning)
103+ {
104+
105+ }
99106
100107 void close() override {}
101108 QString appId() const override { return m_appId;}
tests/qmltests/ApplicationMenus/tst_MenuBar.qml+33
@@ -329,6 +329,14 @@ Item {
329329 return false;
330330 }, true);
331331
332+ mouseClick(overflow);
333+ verify(overflow.__popup);
334+ var menuItem = findChild(menuBar, "overflow-menu-item0-actionItem");
335+ waitForRendering(menuItem);
336+ mouseClick(menuItem);
337+
338+ verify(findChild(menuBar, "overflow-menu-item0-menu-item0-actionItem"));
339+
332340 tryCompareFunction(function() {
333341 menuBackend.removeRow(0);
334342 wait(1);
@@ -339,6 +347,31 @@ Item {
339347 }, true);
340348 }
341349
350+ function test_stray_submenus() {
351+ menuBackend.modelData = appMenuData.generateTestData(3,4,1,0,"menu");
352+ var priv = findInvisibleChild(menuBar, "d");
353+
354+ var menuItem = findChild(menuBar, "menuBar-item0");
355+ menuItem.show();
356+ compare(priv.currentItem, menuItem, "CurrentItem should be set to item 0");
357+ compare(priv.currentItem.popupVisible, true, "Popup should be visible");
358+
359+ var actionItem = findChild(menuBar, "menuBar-item0-menu-item0-actionItem");
360+ mouseClick(actionItem);
361+
362+ actionItem = findChild(menuBar, "menuBar-item0-menu-item0-menu-item0-actionItem");
363+ mouseClick(actionItem);
364+
365+ actionItem = findChild(menuBar, "menuBar-item0-menu-item0-menu-item0-menu-item0-actionItem");
366+
367+ // There's one popup
368+ tryCompareFunction(function() { return findChildsByType(root, "MenuPopup").length; }, 3);
369+
370+ menuBackend.modelData = null;
371+
372+ tryCompareFunction(function() { return findChildsByType(root, "MenuPopup").length; }, 0);
373+ }
374+
342375 function test_firstDisabled() {
343376 var data = appMenuData.generateTestData(10,5,2,3);
344377 data[0].submenu[1].submenu[0].rowData.sensitive = false;
tests/qmltests/Greeter/TestView.qml−5
@@ -46,7 +46,6 @@ Item {
4646 signal tease()
4747 signal emergencyCall()
4848
49− signal _showLastChanceCalled()
5049 signal _hideCalled()
5150 signal _showFakePasswordCalled()
5251 signal _notifyAuthenticationFailedCalled()
@@ -54,10 +53,6 @@ Item {
5453 signal _forceShowCalled()
5554 signal _tryToUnlockCalled(bool toTheRight)
5655
57− function showLastChance() {
58− _showLastChanceCalled();
59− }
60−
6156 function hide() {
6257 _hideCalled();
6358 _required = false;
tests/qmltests/Greeter/tst_Greeter.qml−7
@@ -94,12 +94,6 @@ Item {
9494 property Item greeter: loader.status === Loader.Ready ? loader.item : null
9595 property Item view
9696
97− SignalSpy {
98− id: viewShowLastChanceSpy
99− target: testCase.view
100− signalName: "_showLastChanceCalled"
101− }
102−
10397 SignalSpy {
10498 id: viewHideSpy
10599 target: testCase.view
@@ -147,7 +141,6 @@ Item {
147141 Biometryd.available = true;
148142 AccountsService.enableFingerprintIdentification = true;
149143 AccountsService.failedFingerprintLogins = 0;
150− viewShowLastChanceSpy.clear();
151144 viewHideSpy.clear();
152145 viewShowFakePasswordSpy.clear();
153146 viewAuthenticationFailedSpy.clear();
tests/qmltests/Launcher/tst_Launcher.qml+32−6
@@ -1254,14 +1254,14 @@ Rectangle {
12541254 tryCompare(quickList, "selectedIndex", 0)
12551255
12561256 // Down should move down the quicklist
1257+ // Because item 1 is not selectable
12571258 keyClick(Qt.Key_Down);
1258− tryCompare(quickList, "selectedIndex", 1)
1259+ tryCompare(quickList, "selectedIndex", 2)
12591260
12601261 // The quicklist should wrap around too
12611262 keyClick(Qt.Key_Down);
12621263 keyClick(Qt.Key_Down);
12631264 keyClick(Qt.Key_Down);
1264− keyClick(Qt.Key_Down);
12651265 tryCompare(quickList, "selectedIndex", 0)
12661266
12671267 // Left gets us back to the launcher
@@ -1286,14 +1286,14 @@ Rectangle {
12861286
12871287 keyClick(Qt.Key_Down); // Down to launcher item 0
12881288 keyClick(Qt.Key_Down); // Down to launcher item 1
1289− keyClick(Qt.Key_Right); // Into quicklist
1290− keyClick(Qt.Key_Down); // Down to quicklist item 1
1291− keyClick(Qt.Key_Down); // Down to quicklist item 2
1289+ keyClick(Qt.Key_Right); // Into quicklist, item 0 is selected
1290+ keyClick(Qt.Key_Down); // Down to quicklist item 2 (because 1 is not selectable)
1291+ keyClick(Qt.Key_Down); // Down to quicklist item 3
12921292 keyClick(Qt.Key_Enter); // Trigger it
12931293
12941294 compare(signalSpy.count, 1, "Quicklist signal wasn't triggered")
12951295 compare(signalSpy.signalArguments[0][0], LauncherModel.get(1).appId)
1296− compare(signalSpy.signalArguments[0][1], 2)
1296+ compare(signalSpy.signalArguments[0][1], 3)
12971297 assertFocusOnIndex(-2);
12981298 }
12991299
@@ -1542,5 +1542,31 @@ Rectangle {
15421542 tryCompare(launcher, "maxPanelX", 0);
15431543 launcher.panelWidth = oldSize;
15441544 }
1545+
1546+ function test_mouseHoverSelectQuickList() {
1547+ dragLauncherIntoView();
1548+ var clickedItem = findChild(launcher, "launcherDelegate5")
1549+ var quickList = findChild(launcher, "quickList")
1550+
1551+ // Initial state
1552+ tryCompare(quickList, "state", "")
1553+
1554+ // Open quickList
1555+ mouseClick(clickedItem, clickedItem.width / 2, clickedItem.height / 2, Qt.RightButton)
1556+ verify(quickList, "state", "open")
1557+ compare(quickList.selectedIndex, -1)
1558+
1559+ var qEntry = findChild(launcher, "quickListEntry0");
1560+ mouseMove(qEntry, qEntry.width / 2 , qEntry.height / 2, 10);
1561+ mouseMove(qEntry, qEntry.width / 2 + 1, qEntry.height / 2, 10);
1562+
1563+ tryCompare(quickList, "selectedIndex", 0)
1564+
1565+ qEntry = findChild(launcher, "quickListEntry1");
1566+ mouseMove(qEntry, qEntry.width / 2 , qEntry.height / 2, 10);
1567+ mouseMove(qEntry, qEntry.width / 2 + 1, qEntry.height / 2, 10);
1568+
1569+ tryCompare(quickList, "selectedIndex", -1)
1570+ }
15451571 }
15461572}
tests/qmltests/Stage/tst_DesktopStage.qml+17
@@ -100,8 +100,15 @@ Item {
100100 orientations: Orientations {}
101101 applicationManager: ApplicationManager
102102 topLevelSurfaceList: topSurfaceList
103+ availableDesktopArea: availableDesktopAreaItem
103104 interactive: true
104105 mode: "windowed"
106+
107+ Item {
108+ id: availableDesktopAreaItem
109+ anchors.fill: parent
110+ anchors.topMargin: PanelState.panelHeight
111+ }
105112 }
106113 }
107114 }
@@ -1057,5 +1064,15 @@ Item {
10571064 tap(maxButton);
10581065 tryCompare(appDelegate, "state", "maximized");
10591066 }
1067+
1068+ function test_childWindowGetsActiveFocus() {
1069+ var appDelegate = startApplication("kate");
1070+ appDelegate.surface.openDialog(units.gu(5), units.gu(5), units.gu(30), units.gu(30));
1071+ var childWindow = findChild(appDelegate, "childWindow");
1072+ verify(childWindow);
1073+ var surfaceItem = findChild(childWindow, "surfaceItem");
1074+ verify(surfaceItem);
1075+ tryCompare(surfaceItem, "activeFocus", true);
1076+ }
10601077 }
10611078}
tests/qmltests/Stage/tst_PhoneStage.qml+5
@@ -52,6 +52,11 @@ Item {
5252 applicationManager: ApplicationManager
5353 surfaceManager: sMgr
5454 }
55+ availableDesktopArea: availableDesktopAreaItem
56+ Item {
57+ id: availableDesktopAreaItem
58+ anchors.fill: parent
59+ }
5560 Component.onCompleted: {
5661 ApplicationManager.startApplication("unity8-dash");
5762 }
tests/qmltests/Stage/tst_TabletStage.qml+5
@@ -61,6 +61,11 @@ Rectangle {
6161 applicationManager: ApplicationManager
6262 surfaceManager: sMgr
6363 }
64+ availableDesktopArea: availableDesktopAreaItem
65+ Item {
66+ id: availableDesktopAreaItem
67+ anchors.fill: parent
68+ }
6469 Component.onCompleted: {
6570 ApplicationManager.startApplication("unity8-dash");
6671 }
tests/qmltests/Wizard/tst_Wizard.qml−6
@@ -336,8 +336,6 @@ Item {
336336 // now finish up
337337 page = waitForPage("reportingPage");
338338 tap(findChild(page, "forwardButton"));
339− page = waitForPage("systemUpdatePage");
340− tap(findChild(page, "forwardButton"));
341339 page = waitForPage("finishedPage");
342340 waitUntilTransitionsEnd(page);
343341 tap(findChild(page, "finishButton"));
@@ -378,8 +376,6 @@ Item {
378376 // now finish up
379377 page = waitForPage("reportingPage");
380378 tap(findChild(page, "forwardButton"));
381− page = waitForPage("systemUpdatePage");
382− tap(findChild(page, "forwardButton"));
383379 page = waitForPage("finishedPage");
384380 waitUntilTransitionsEnd(page);
385381 tap(findChild(page, "finishButton"));
@@ -398,8 +394,6 @@ Item {
398394 tap(findChild(page, "forwardButton"));
399395 page = waitForPage("reportingPage");
400396 tap(findChild(page, "forwardButton"));
401− page = waitForPage("systemUpdatePage");
402− tap(findChild(page, "forwardButton"));
403397 page = waitForPage("finishedPage");
404398 waitUntilTransitionsEnd(page);
405399 tap(findChild(page, "finishButton"));
tests/qmltests/tst_Shell.qml+19
@@ -1460,6 +1460,25 @@ Rectangle {
14601460 confirmLoggedIn(true);
14611461 }
14621462
1463+ function test_terminalShortcut() {
1464+ loadShell("desktop");
1465+ shell.usageScenario = "desktop";
1466+ waitForRendering(shell);
1467+ swipeAwayGreeter();
1468+
1469+ // not running, should start
1470+ keyClick(Qt.Key_T, Qt.ControlModifier|Qt.AltModifier);
1471+ tryCompare(ApplicationManager, "focusedApplicationId", "ubuntu-terminal-app");
1472+
1473+ // start something else
1474+ ApplicationManager.startApplication("dialer-app");
1475+ tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app");
1476+
1477+ // terminal running in background, should get focused
1478+ keyClick(Qt.Key_T, Qt.ControlModifier|Qt.AltModifier);
1479+ tryCompare(ApplicationManager, "focusedApplicationId", "ubuntu-terminal-app");
1480+ }
1481+
14631482 function test_launcherInverted_data() {
14641483 return [
14651484 {tag: "phone", formFactor: "phone", usageScenario: "phone", launcherInverted: true},
tests/qmltests/tst_ShellWithPin.qml−40
@@ -21,7 +21,6 @@ import AccountsService 0.1
2121import GSettings 1.0
2222import LightDMController 0.1
2323import LightDM.FullLightDM 0.1 as LightDM
24−import Ubuntu.SystemImage 0.1
2524import Ubuntu.Telephony 0.1 as Telephony
2625import Unity.Application 0.1
2726import Unity.Test 0.1 as UT
@@ -90,19 +89,6 @@ Item {
9089 text: "Show Greeter"
9190 onClicked: LightDM.Greeter.showGreeter()
9291 }
93−
94− Label {
95− text: "Max retries:"
96− color: "black"
97− }
98− TextField {
99− id: maxRetriesTextField
100− text: "-1"
101− onTextChanged: {
102− var greeter = testCase.findChild(shellLoader.item, "greeter");
103− greeter.maxFailedLogins = text;
104− }
105− }
10692 }
10793 }
10894 }
@@ -112,12 +98,6 @@ Item {
11298 signalName: "sessionStarted"
11399 }
114100
115− SignalSpy {
116− id: resetSpy
117− target: SystemImage
118− signalName: "resettingDevice"
119− }
120−
121101 Telephony.CallEntry {
122102 id: phoneCall
123103 phoneNumber: "+447812221111"
@@ -150,7 +130,6 @@ Item {
150130 sessionSpy.target = greeter;
151131 swipeAwayGreeter(true);
152132 greeter.failedLoginsDelayAttempts = -1;
153− greeter.maxFailedLogins = -1;
154133
155134 var launcher = findChild(shell, "launcher");
156135 var panel = findChild(launcher, "launcherPanel");
@@ -373,25 +352,6 @@ Item {
373352 tryCompare(delayedLockscreen, "delayMinutes", greeter.failedLoginsDelayMinutes);
374353 }
375354
376− function test_factoryReset() {
377− skip("Factory reset support is not finished")
378−
379− maxRetriesTextField.text = "3"
380− resetSpy.clear()
381−
382− enterPin("1111")
383− enterPin("1111")
384−
385− var dialog = findChild(root, "infoPopup")
386− var button = findChild(dialog, "infoPopupOkButton")
387− tap(button)
388− tryCompareFunction(function() {return findChild(root, "infoPopup", 0 /* timeout */)}, null)
389−
390− tryCompare(resetSpy, "count", 0)
391− enterPin("1111")
392− tryCompare(resetSpy, "count", 1)
393− }
394−
395355 function test_emergencyDialerLockOut() {
396356 // This is a theoretical attack on the lockscreen: Enter emergency
397357 // dialer mode on a phone, then plug into a larger screen,
tools/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1+add_subdirectory(indicatorsclient)
12add_subdirectory(menutool)
23add_subdirectory(scopetool)
34
src/Panel/Indicators/client/CMakeLists.txt → tools/indicatorsclient/CMakeLists.txtrenamed

The content is the same.

src/Panel/Indicators/client/indicatorsclient.cpp → tools/indicatorsclient/indicatorsclient.cpprenamed

The content is the same.

src/Panel/Indicators/client/indicatorsclient.h → tools/indicatorsclient/indicatorsclient.hrenamed

The content is the same.

src/Panel/Indicators/client/main.cpp → tools/indicatorsclient/main.cpprenamed

The content is the same.