on xenial help sign in
merge trunk
db3edc9Michael Zanetti
CMakeLists.txt+5
@@ -69,6 +69,7 @@ find_package(Qt5Gui 5.6 REQUIRED)
69find_package(Qt5DBus 5.6 REQUIRED)
69find_package(Qt5DBus 5.6 REQUIRED)
70find_package(Qt5Concurrent 5.6 REQUIRED)
70find_package(Qt5Concurrent 5.6 REQUIRED)
71find_package(Qt5Sql 5.6 REQUIRED)
71find_package(Qt5Sql 5.6 REQUIRED)
72+find_package(Qt5Test 5.6 REQUIRED)
72
73
73pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=27)
74pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=27)
74pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
75pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
@@ -79,6 +80,10 @@ pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
79pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
80pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
80pkg_check_modules(UAL REQUIRED ubuntu-app-launch-3)
81pkg_check_modules(UAL REQUIRED ubuntu-app-launch-3)
81pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
82pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
83+pkg_check_modules(QTDBUSTEST REQUIRED
84+ libqtdbustest-1
85+ libqtdbusmock-1
86+ )
82
87
83### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
88### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
84find_path(UBUNTUGESTUREPRIV
89find_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+
1unity8 (8.15+17.04.20170321-0ubuntu1) zesty; urgency=medium
45unity8 (8.15+17.04.20170321-0ubuntu1) zesty; urgency=medium
2
46
3 [ Albert Astals Cid ]
47 [ Albert Astals Cid ]
debian/control+4
@@ -29,6 +29,8 @@ Build-Depends: cmake,
29 libpam0g-dev,
29 libpam0g-dev,
30 libpulse-dev,
30 libpulse-dev,
31 libqmenumodel-dev (>= 0.2.12),
31 libqmenumodel-dev (>= 0.2.12),
32+ libqtdbusmock1-dev (>= 0.7),
33+ libqtdbustest1-dev,
32 libqt5svg5-dev,
34 libqt5svg5-dev,
33 libqt5xmlpatterns5-dev,
35 libqt5xmlpatterns5-dev,
34 libsystemsettings-dev,
36 libsystemsettings-dev,
@@ -48,6 +50,7 @@ Build-Depends: cmake,
48 pkg-config,
50 pkg-config,
49 python3-all:any,
51 python3-all:any,
50 python3-setuptools,
52 python3-setuptools,
53+ qtdbustest-runner,
51 qml-module-qt-labs-folderlistmodel,
54 qml-module-qt-labs-folderlistmodel,
52 qml-module-qt-labs-settings,
55 qml-module-qt-labs-settings,
53 qml-module-qtqml-statemachine,
56 qml-module-qtqml-statemachine,
@@ -205,6 +208,7 @@ Multi-Arch: same
205Pre-Depends: ${misc:Pre-Depends},
208Pre-Depends: ${misc:Pre-Depends},
206Depends: dbus-test-runner,
209Depends: dbus-test-runner,
207 parallel,
210 parallel,
211+ qtdbustest-runner,
208 qt5-default,
212 qt5-default,
209 qtdeclarative5-dev-tools,
213 qtdeclarative5-dev-tools,
210 unity8 (= ${source:Version}),
214 unity8 (= ${source:Version}),
plugins/Ubuntu/CMakeLists.txt−1
@@ -1,3 +1,2 @@
1add_subdirectory(Gestures)
1add_subdirectory(Gestures)
2add_subdirectory(DownloadDaemonListener)
2add_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
207 }
207 }
208 } else if (actionId.startsWith(QStringLiteral("surface_"))){
208 } else if (actionId.startsWith(QStringLiteral("surface_"))){
209 ApplicationInfoInterface *appInfo = m_appManager->findApplication(appId);
209 ApplicationInfoInterface *appInfo = m_appManager->findApplication(appId);
210− if (!appInfo) {
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) {
211+ for (int i = 0; i < appInfo->surfaceList()->count(); ++i) {
214− MirSurfaceInterface *iface = appInfo->surfaceList()->get(i);
212+ MirSurfaceInterface *iface = appInfo->surfaceList()->get(i);
215− QString id = actionId;
213+ QString id = actionId;
216− id.remove(QRegExp("^surface_"));
214+ id.remove(QRegExp("^surface_"));
217− if (id == iface->persistentId()) {
215+ if (id == iface->persistentId()) {
218− iface->activate();
216+ iface->activate();
217+ }
219 }
218 }
219+ } else {
220+ qWarning() << "App for" << appId << "not found in launcher. Cannot invoke quicklist action";
220 }
221 }
221 // Nope, we don't know this action, let the backend forward it to the application
222 // Nope, we don't know this action, let the backend forward it to the application
222 } else {
223 } else {
@@ -573,14 +574,16 @@ void LauncherModel::updateSurfaceListForApp(ApplicationInfoInterface* app)
573 QList<QPair<QString, QString> > surfaces;
574 QList<QPair<QString, QString> > surfaces;
574 for (int i = 0; i < app->surfaceList()->count(); ++i) {
575 for (int i = 0; i < app->surfaceList()->count(); ++i) {
575 MirSurfaceInterface* iface = app->surfaceList()->get(i);
576 MirSurfaceInterface* iface = app->surfaceList()->get(i);
577+ if (iface->type() == Mir::NormalType || iface->type() == Mir::DialogType) {
576− // Avoid duplicate connections, so let's just disconnect first to be sure
578+ // Avoid duplicate connections, so let's just disconnect first to be sure
577− disconnect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
579+ disconnect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
578− connect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
580+ connect(iface, &MirSurfaceInterface::nameChanged, this, &LauncherModel::updateSurfaceListForSurface);
579− QString name = iface->name();
581+ QString name = iface->name();
580− if (name.isEmpty()) {
582+ if (name.isEmpty()) {
581− name = app->name();
583+ name = app->name();
584+ }
585+ surfaces.append({iface->persistentId(), name});
582 }
586 }
583− surfaces.append({iface->persistentId(), name});
584 }
587 }
585 item->setSurfaces(surfaces);
588 item->setSurfaces(surfaces);
586 Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
589 Q_EMIT dataChanged(index(idx), index(idx), {RoleSurfaceCount});
plugins/Unity/Platform/platform.cpp+16−2
@@ -17,9 +17,11 @@
17#include "platform.h"
17#include "platform.h"
18
18
19#include <QDBusConnection>
19#include <QDBusConnection>
20+#include <QSet>
21+#include <QString>
20
22
21Platform::Platform(QObject *parent)
23Platform::Platform(QObject *parent)
22− : QObject(parent)
24+ : QObject(parent), m_isPC(true), m_isMultiSession(true)
23{
25{
24 QMetaObject::invokeMethod(this, "init");
26 QMetaObject::invokeMethod(this, "init");
25}
27}
@@ -31,8 +33,20 @@ void Platform::init()
31 QDBusInterface seatIface("org.freedesktop.login1", "/org/freedesktop/login1/seat/self", "org.freedesktop.login1.Seat",
33 QDBusInterface seatIface("org.freedesktop.login1", "/org/freedesktop/login1/seat/self", "org.freedesktop.login1.Seat",
32 QDBusConnection::systemBus(), this);
34 QDBusConnection::systemBus(), this);
33
35
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",
34 m_chassis = iface.property("Chassis").toString();
46 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);
36 m_isMultiSession = seatIface.property("CanMultiSession").toBool() && seatIface.property("CanGraphical").toBool();
50 m_isMultiSession = seatIface.property("CanMultiSession").toBool() && seatIface.property("CanGraphical").toBool();
37}
51}
38
52
plugins/Unity/Session/plugin.cpp+1
@@ -26,6 +26,7 @@
26
26
27static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
27static QObject *dbusunitysessionservice_provider(QQmlEngine */*engine*/, QJSEngine */*jsEngine*/)
28{
28{
29+ new DBusGnomeSessionManagerDialogWrapper();
29 new DBusGnomeSessionManagerWrapper();
30 new DBusGnomeSessionManagerWrapper();
30 new DBusGnomeScreensaverWrapper();
31 new DBusGnomeScreensaverWrapper();
31 new DBusScreensaverWrapper();
32 new DBusScreensaverWrapper();
plugins/Utils/quicklistproxymodel.h+1−1
@@ -48,5 +48,5 @@ Q_SIGNALS:
48
48
49private:
49private:
50 QAbstractItemModel* m_source = nullptr;
50 QAbstractItemModel* m_source = nullptr;
51− bool m_privateMode;
51+ bool m_privateMode = false;
52};
52};
plugins/Utils/windowstatestorage.cpp+10−3
@@ -133,8 +133,15 @@ QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defa
133 if (!query.first()) {
133 if (!query.first()) {
134 return defaultValue;
134 return defaultValue;
135 }
135 }
136+
136− return QRect(query.value(QStringLiteral("x")).toInt(), query.value(QStringLiteral("y")).toInt(),
137+ const QRect result(query.value(QStringLiteral("x")).toInt(), query.value(QStringLiteral("y")).toInt(),
137− query.value(QStringLiteral("width")).toInt(), query.value(QStringLiteral("height")).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;
138}
145}
139
146
140void WindowStateStorage::initdb()
147void WindowStateStorage::initdb()
@@ -165,7 +172,7 @@ void WindowStateStorage::saveValue(const QString &queryString)
165{
172{
166 QMutexLocker mutexLocker(&s_mutex);
173 QMutexLocker mutexLocker(&s_mutex);
167
174
168− QFuture<void> future = QtConcurrent::run(executeAsyncQuery, queryString);
175+ QFuture<void> future = QtConcurrent::run(&m_threadPool, executeAsyncQuery, queryString);
169 m_asyncQueries.append(future);
176 m_asyncQueries.append(future);
170
177
171 QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
178 QFutureWatcher<void> *futureWatcher = new QFutureWatcher<void>();
plugins/Utils/windowstatestorage.h+2
@@ -18,6 +18,7 @@
18#include <QSqlDatabase>
18#include <QSqlDatabase>
19#include <QMutex>
19#include <QMutex>
20#include <QFuture>
20#include <QFuture>
21+#include <QThreadPool>
21
22
22// unity-api
23// unity-api
23#include <unity/shell/application/Mir.h>
24#include <unity/shell/application/Mir.h>
@@ -72,4 +73,5 @@ private:
72 QSqlDatabase m_db;
73 QSqlDatabase m_db;
73
74
74 QList<QFuture<void>> m_asyncQueries;
75 QList<QFuture<void>> m_asyncQueries;
76+ QThreadPool m_threadPool;
75};
77};
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 @@
1set(WINDOWMANAGER_SRC
1set(WINDOWMANAGER_SRC
2+ AvailableDesktopArea.cpp
2 TopLevelWindowModel.cpp
3 TopLevelWindowModel.cpp
3 Window.cpp
4 Window.cpp
4 WindowManagerPlugin.cpp
5 WindowManagerPlugin.cpp
6+ WindowMargins.cpp
5 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
7 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
6 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
8 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
7 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
9 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
@@ -11,6 +13,11 @@ set(WINDOWMANAGER_SRC
11
13
12add_definitions(-DWINDOWMANAGERQML_LIBRARY)
14add_definitions(-DWINDOWMANAGERQML_LIBRARY)
13
15
16+include_directories(
17+ SYSTEM
18+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
19+)
20+
14add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
21add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
15
22
16qt5_use_modules(windowmanager-qml Qml Quick Gui)
23qt5_use_modules(windowmanager-qml Qml Quick Gui)
plugins/WindowManager/WindowManagerPlugin.cpp+5−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -16,14 +16,18 @@
16
16
17#include "WindowManagerPlugin.h"
17#include "WindowManagerPlugin.h"
18
18
19+#include "AvailableDesktopArea.h"
19#include "TopLevelWindowModel.h"
20#include "TopLevelWindowModel.h"
20#include "Window.h"
21#include "Window.h"
22+#include "WindowMargins.h"
21
23
22#include <QtQml>
24#include <QtQml>
23
25
24void WindowManagerPlugin::registerTypes(const char *uri)
26void WindowManagerPlugin::registerTypes(const char *uri)
25{
27{
28+ qmlRegisterType<AvailableDesktopArea>(uri, 1, 0, "AvailableDesktopArea");
26 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
29 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
30+ qmlRegisterType<WindowMargins>(uri, 1, 0, "WindowMargins");
27
31
28 qRegisterMetaType<Window*>("Window*");
32 qRegisterMetaType<Window*>("Window*");
29
33
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 ""
8msgstr ""
8msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"
10"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2017-03-21 10:58+0000\n"
11+"POT-Creation-Date: 2017-03-28 21:50+0000\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -83,7 +83,7 @@ msgid "Log Out"
83msgstr ""
83msgstr ""
84
84
85#: qml/Components/Dialogs.qml:199 qml/Components/Dialogs.qml:264
85#: 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
87#: qml/Wizard/Pages/passcode-confirm.qml:32
87#: qml/Wizard/Pages/passcode-confirm.qml:32
88#: qml/Wizard/Pages/passcode-set.qml:32
88#: qml/Wizard/Pages/passcode-set.qml:32
89msgid "Cancel"
89msgid "Cancel"
@@ -167,135 +167,143 @@ msgstr ""
167msgid "Switches to previous keyboard layout."
167msgid "Switches to previous keyboard layout."
168msgstr ""
168msgstr ""
169
169
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
171msgid "Launcher"
179msgid "Launcher"
172msgstr ""
180msgstr ""
173
181
174−#: qml/Components/KeyboardShortcutsOverlay.qml:125
182+#: qml/Components/KeyboardShortcutsOverlay.qml:138
175msgid "Super (Hold)"
183msgid "Super (Hold)"
176msgstr ""
184msgstr ""
177
185
178−#: qml/Components/KeyboardShortcutsOverlay.qml:130
186+#: qml/Components/KeyboardShortcutsOverlay.qml:143
179msgid "Opens the launcher, displays shortcuts."
187msgid "Opens the launcher, displays shortcuts."
180msgstr ""
188msgstr ""
181
189
182−#: qml/Components/KeyboardShortcutsOverlay.qml:138
190+#: qml/Components/KeyboardShortcutsOverlay.qml:151
183msgid "Alt + F1"
191msgid "Alt + F1"
184msgstr ""
192msgstr ""
185
193
186−#: qml/Components/KeyboardShortcutsOverlay.qml:143
194+#: qml/Components/KeyboardShortcutsOverlay.qml:156
187msgid "Opens launcher keyboard navigation mode."
195msgid "Opens launcher keyboard navigation mode."
188msgstr ""
196msgstr ""
189
197
190−#: qml/Components/KeyboardShortcutsOverlay.qml:151
198+#: qml/Components/KeyboardShortcutsOverlay.qml:164
191msgid "Super + Tab"
199msgid "Super + Tab"
192msgstr ""
200msgstr ""
193
201
194−#: qml/Components/KeyboardShortcutsOverlay.qml:156
202+#: qml/Components/KeyboardShortcutsOverlay.qml:169
195msgid "Switches applications via the launcher."
203msgid "Switches applications via the launcher."
196msgstr ""
204msgstr ""
197
205
198−#: qml/Components/KeyboardShortcutsOverlay.qml:164
206+#: qml/Components/KeyboardShortcutsOverlay.qml:177
199msgid "Super + 1 to 0"
207msgid "Super + 1 to 0"
200msgstr ""
208msgstr ""
201
209
202−#: qml/Components/KeyboardShortcutsOverlay.qml:169
210+#: qml/Components/KeyboardShortcutsOverlay.qml:182
203msgid "Same as clicking on a launcher icon."
211msgid "Same as clicking on a launcher icon."
204msgstr ""
212msgstr ""
205
213
206−#: qml/Components/KeyboardShortcutsOverlay.qml:177
214+#: qml/Components/KeyboardShortcutsOverlay.qml:190
207msgid "Super + A"
215msgid "Super + A"
208msgstr ""
216msgstr ""
209
217
210−#: qml/Components/KeyboardShortcutsOverlay.qml:182
218+#: qml/Components/KeyboardShortcutsOverlay.qml:195
211msgid "Opens the Application Drawer."
219msgid "Opens the Application Drawer."
212msgstr ""
220msgstr ""
213
221
214−#: qml/Components/KeyboardShortcutsOverlay.qml:194
222+#: qml/Components/KeyboardShortcutsOverlay.qml:207
215msgid "Scopes"
223msgid "Scopes"
216msgstr ""
224msgstr ""
217
225
218−#: qml/Components/KeyboardShortcutsOverlay.qml:201
226+#: qml/Components/KeyboardShortcutsOverlay.qml:214
219msgid "Super (Tap)"
227msgid "Super (Tap)"
220msgstr ""
228msgstr ""
221
229
222−#: qml/Components/KeyboardShortcutsOverlay.qml:206
230+#: qml/Components/KeyboardShortcutsOverlay.qml:219
223msgid "Opens the Scopes home."
231msgid "Opens the Scopes home."
224msgstr ""
232msgstr ""
225
233
226−#: qml/Components/KeyboardShortcutsOverlay.qml:222
234+#: qml/Components/KeyboardShortcutsOverlay.qml:235
227msgid "Switching"
235msgid "Switching"
228msgstr ""
236msgstr ""
229
237
230−#: qml/Components/KeyboardShortcutsOverlay.qml:229
238+#: qml/Components/KeyboardShortcutsOverlay.qml:242
231msgid "Alt + Tab"
239msgid "Alt + Tab"
232msgstr ""
240msgstr ""
233
241
234−#: qml/Components/KeyboardShortcutsOverlay.qml:234
242+#: qml/Components/KeyboardShortcutsOverlay.qml:247
235msgid "Switches between applications."
243msgid "Switches between applications."
236msgstr ""
244msgstr ""
237
245
238−#: qml/Components/KeyboardShortcutsOverlay.qml:242
246+#: qml/Components/KeyboardShortcutsOverlay.qml:255
239msgid "Super + W"
247msgid "Super + W"
240msgstr ""
248msgstr ""
241
249
242−#: qml/Components/KeyboardShortcutsOverlay.qml:247
250+#: qml/Components/KeyboardShortcutsOverlay.qml:260
243msgid "Opens the desktop spread."
251msgid "Opens the desktop spread."
244msgstr ""
252msgstr ""
245
253
246−#: qml/Components/KeyboardShortcutsOverlay.qml:255
254+#: qml/Components/KeyboardShortcutsOverlay.qml:268
247msgid "Cursor Left or Right"
255msgid "Cursor Left or Right"
248msgstr ""
256msgstr ""
249
257
250−#: qml/Components/KeyboardShortcutsOverlay.qml:260
258+#: qml/Components/KeyboardShortcutsOverlay.qml:273
251msgid "Moves the focus."
259msgid "Moves the focus."
252msgstr ""
260msgstr ""
253
261
254−#: qml/Components/KeyboardShortcutsOverlay.qml:272
262+#: qml/Components/KeyboardShortcutsOverlay.qml:285
255msgid "Windows"
263msgid "Windows"
256msgstr ""
264msgstr ""
257
265
258−#: qml/Components/KeyboardShortcutsOverlay.qml:279
266+#: qml/Components/KeyboardShortcutsOverlay.qml:292
259msgid "Ctrl + Super + D"
267msgid "Ctrl + Super + D"
260msgstr ""
268msgstr ""
261
269
262−#: qml/Components/KeyboardShortcutsOverlay.qml:284
270+#: qml/Components/KeyboardShortcutsOverlay.qml:297
263msgid "Minimizes all windows."
271msgid "Minimizes all windows."
264msgstr ""
272msgstr ""
265
273
266−#: qml/Components/KeyboardShortcutsOverlay.qml:292
274+#: qml/Components/KeyboardShortcutsOverlay.qml:305
267msgid "Ctrl + Super + Up"
275msgid "Ctrl + Super + Up"
268msgstr ""
276msgstr ""
269
277
270−#: qml/Components/KeyboardShortcutsOverlay.qml:297
278+#: qml/Components/KeyboardShortcutsOverlay.qml:310
271msgid "Maximizes the current window."
279msgid "Maximizes the current window."
272msgstr ""
280msgstr ""
273
281
274−#: qml/Components/KeyboardShortcutsOverlay.qml:305
282+#: qml/Components/KeyboardShortcutsOverlay.qml:318
275msgid "Ctrl + Super + Down"
283msgid "Ctrl + Super + Down"
276msgstr ""
284msgstr ""
277
285
278−#: qml/Components/KeyboardShortcutsOverlay.qml:310
286+#: qml/Components/KeyboardShortcutsOverlay.qml:323
279msgid "Minimizes or restores the current window."
287msgid "Minimizes or restores the current window."
280msgstr ""
288msgstr ""
281
289
282−#: qml/Components/KeyboardShortcutsOverlay.qml:318
290+#: qml/Components/KeyboardShortcutsOverlay.qml:331
283msgid "Ctrl + Super + Left or Right"
291msgid "Ctrl + Super + Left or Right"
284msgstr ""
292msgstr ""
285
293
286−#: qml/Components/KeyboardShortcutsOverlay.qml:323
294+#: qml/Components/KeyboardShortcutsOverlay.qml:336
287msgid "Semi-maximizes the current window."
295msgid "Semi-maximizes the current window."
288msgstr ""
296msgstr ""
289
297
290−#: qml/Components/KeyboardShortcutsOverlay.qml:331
298+#: qml/Components/KeyboardShortcutsOverlay.qml:344
291msgid "Alt + F4"
299msgid "Alt + F4"
292msgstr ""
300msgstr ""
293
301
294−#: qml/Components/KeyboardShortcutsOverlay.qml:336
302+#: qml/Components/KeyboardShortcutsOverlay.qml:349
295msgid "Closes the current window."
303msgid "Closes the current window."
296msgstr ""
304msgstr ""
297
305
298−#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:242
306+#: qml/Components/Lockscreen.qml:212 qml/Greeter/NarrowView.qml:228
299msgid "Return to Call"
307msgid "Return to Call"
300msgstr ""
308msgstr ""
301
309
@@ -489,19 +497,19 @@ msgid_plural "Please wait %1 minutes and then try again…"
489msgstr[0] ""
497msgstr[0] ""
490msgstr[1] ""
498msgstr[1] ""
491
499
492−#: qml/Greeter/Greeter.qml:561
500+#: qml/Greeter/Greeter.qml:550
493msgid "Try again"
501msgid "Try again"
494msgstr ""
502msgstr ""
495
503
496−#: qml/Greeter/Greeter.qml:562
504+#: qml/Greeter/Greeter.qml:551
497msgid "Enter passphrase to unlock"
505msgid "Enter passphrase to unlock"
498msgstr ""
506msgstr ""
499
507
500−#: qml/Greeter/Greeter.qml:563
508+#: qml/Greeter/Greeter.qml:552
501msgid "Enter passcode to unlock"
509msgid "Enter passcode to unlock"
502msgstr ""
510msgstr ""
503
511
504−#: qml/Greeter/NarrowView.qml:242
512+#: qml/Greeter/NarrowView.qml:228
505msgid "Emergency"
513msgid "Emergency"
506msgstr ""
514msgstr ""
507
515
@@ -655,7 +663,7 @@ msgid "Language"
655msgstr ""
663msgstr ""
656
664
657#: qml/Wizard/Pages/10-welcome.qml:173 qml/Wizard/Pages/20-keyboard.qml:152
665#: 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
659#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
667#: qml/Wizard/Pages/50-timezone.qml:271 qml/Wizard/Pages/60-account.qml:65
660#: qml/Wizard/Pages/70-passwd-type.qml:145
668#: qml/Wizard/Pages/70-passwd-type.qml:145
661#: qml/Wizard/Pages/75-report-check.qml:84
669#: qml/Wizard/Pages/75-report-check.qml:84
@@ -676,25 +684,24 @@ msgstr ""
676msgid "Keyboard layout"
684msgid "Keyboard layout"
677msgstr ""
685msgstr ""
678
686
679−#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:207
687+#: qml/Wizard/Pages/20-keyboard.qml:152 qml/Wizard/Pages/30-wifi.qml:206
680−#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/77-system-update.qml:152
688+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/sim.qml:101
681−#: qml/Wizard/Pages/sim.qml:101
682msgid "Skip"
689msgid "Skip"
683msgstr ""
690msgstr ""
684
691
685−#: qml/Wizard/Pages/30-wifi.qml:31
692+#: qml/Wizard/Pages/30-wifi.qml:30
686msgid "Connect to Wi‑Fi"
693msgid "Connect to Wi‑Fi"
687msgstr ""
694msgstr ""
688
695
689−#: qml/Wizard/Pages/30-wifi.qml:132
696+#: qml/Wizard/Pages/30-wifi.qml:131
690msgid "Connected"
697msgid "Connected"
691msgstr ""
698msgstr ""
692
699
693−#: qml/Wizard/Pages/30-wifi.qml:165
700+#: qml/Wizard/Pages/30-wifi.qml:164
694msgid "Available Wi-Fi networks"
701msgid "Available Wi-Fi networks"
695msgstr ""
702msgstr ""
696
703
697−#: qml/Wizard/Pages/30-wifi.qml:166
704+#: qml/Wizard/Pages/30-wifi.qml:165
698msgid "No available Wi-Fi networks"
705msgid "No available Wi-Fi networks"
699msgstr ""
706msgstr ""
700
707
@@ -781,35 +788,6 @@ msgstr ""
781msgid "Privacy policy"
788msgid "Privacy policy"
782msgstr ""
789msgstr ""
783
790
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−
813#: qml/Wizard/Pages/80-finished.qml:89
791#: qml/Wizard/Pages/80-finished.qml:89
814msgid "Welcome to Ubuntu"
792msgid "Welcome to Ubuntu"
815msgstr ""
793msgstr ""
qml/ApplicationMenus/MenuBar.qml+22−6
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2016 Canonical Ltd.
2+ * Copyright 2016, 2017 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -90,7 +90,7 @@ Item {
90
90
91 Row {
91 Row {
92 id: row
92 id: row
93− spacing: units.gu(2)
93+ spacing: 0
94 height: parent.height
94 height: parent.height
95
95
96 ActionContext {
96 ActionContext {
@@ -125,7 +125,11 @@ Item {
125 readonly property bool shouldDisplay: x + width + ((__ownIndex < rowRepeater.count-1) ? units.gu(2) : 0) <
125 readonly property bool shouldDisplay: x + width + ((__ownIndex < rowRepeater.count-1) ? units.gu(2) : 0) <
126 root.overflowWidth - ((__ownIndex < rowRepeater.count-1) ? overflowButton.width : 0)
126 root.overflowWidth - ((__ownIndex < rowRepeater.count-1) ? overflowButton.width : 0)
127
127
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+
128− implicitWidth: column.implicitWidth
132+ implicitWidth: column.implicitWidth + (isFirstItem ? units.gu(1) : units.gu(2))
129 implicitHeight: row.height
133 implicitHeight: row.height
130 enabled: (model.sensitive === true) && shouldDisplay
134 enabled: (model.sensitive === true) && shouldDisplay
131 opacity: shouldDisplay ? 1 : 0
135 opacity: shouldDisplay ? 1 : 0
@@ -189,7 +193,9 @@ Item {
189 id: column
193 id: column
190 spacing: units.gu(1)
194 spacing: units.gu(1)
191 anchors {
195 anchors {
192− centerIn: parent
196+ verticalCenter: parent.verticalCenter
197+ horizontalCenter: !visualItem.isFirstItem ? parent.horizontalCenter : undefined
198+ left: visualItem.isFirstItem ? parent.left : undefined
193 }
199 }
194
200
195 Icon {
201 Icon {
@@ -224,6 +230,13 @@ Item {
224 }
230 }
225 }
231 }
226 }
232 }
233+
234+ Component.onDestruction: {
235+ if (__popup) {
236+ __popup.destroy();
237+ __popup = null;
238+ }
239+ }
227 } // Item ( delegate )
240 } // Item ( delegate )
228 } // Repeater
241 } // Repeater
229 } // Row
242 } // Row
@@ -370,6 +383,9 @@ Item {
370 function activate(index) {
383 function activate(index) {
371 return sourceModel.activate(mapRowToSource(index));
384 return sourceModel.activate(mapRowToSource(index));
372 }
385 }
386+ function aboutToShow(index) {
387+ return sourceModel.aboutToShow(mapRowToSource(index));
388+ }
373 }
389 }
374
390
375 Connections {
391 Connections {
@@ -385,8 +401,8 @@ Item {
385 anchors {
401 anchors {
386 bottom: row.bottom
402 bottom: row.bottom
387 }
403 }
388− x: d.currentItem ? row.x + d.currentItem.x - units.gu(1) : 0
404+ x: d.currentItem ? row.x + d.currentItem.x : 0
389− width: d.currentItem ? d.currentItem.width + units.gu(2) : 0
405+ width: d.currentItem ? d.currentItem.width : 0
390 height: units.dp(4)
406 height: units.dp(4)
391 color: UbuntuColors.orange
407 color: UbuntuColors.orange
392 visible: d.currentItem
408 visible: d.currentItem
qml/ApplicationMenus/MenuPopup.qml+10−1
@@ -297,6 +297,8 @@ UbuntuShape {
297
297
298 width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
298 width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
299
299
300+ property Item popup: null
301+
300 action.onTriggered: {
302 action.onTriggered: {
301 submenuHoverTimer.stop();
303 submenuHoverTimer.stop();
302
304
@@ -351,6 +353,13 @@ UbuntuShape {
351 }
353 }
352 }
354 }
353 }
355 }
356+
357+ Component.onDestruction: {
358+ if (popup) {
359+ popup.destroy();
360+ popup = null;
361+ }
362+ }
354 }
363 }
355 }
364 }
356
365
@@ -373,7 +382,7 @@ UbuntuShape {
373 id: loader
382 id: loader
374 objectName: root.objectName + "-item" + __ownIndex
383 objectName: root.objectName + "-item" + __ownIndex
375
384
376− property Item popup: null
385+ readonly property var popup: item ? item.popup : null
377 property var __menuData: model
386 property var __menuData: model
378 property int __ownIndex: index
387 property int __ownIndex: index
379 property bool __isSeparator: model.isSeparator
388 property bool __isSeparator: model.isSeparator
qml/Components/KeyboardShortcutsOverlay.qml+13
@@ -110,6 +110,19 @@ Rectangle {
110 Layout.maximumWidth: maxTextSize
110 Layout.maximumWidth: maxTextSize
111 }
111 }
112
112
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+
113
126
114 // Launcher section
127 // Launcher section
115 Item { Layout.columnSpan: 2; height: units.gu(2) }
128 Item { Layout.columnSpan: 2; height: units.gu(2) }
qml/Greeter/Greeter.qml−11
@@ -20,7 +20,6 @@ import Biometryd 0.0
20import GSettings 1.0
20import GSettings 1.0
21import Powerd 0.1
21import Powerd 0.1
22import Ubuntu.Components 1.3
22import Ubuntu.Components 1.3
23−import Ubuntu.SystemImage 0.1
24import Unity.Launcher 0.1
23import Unity.Launcher 0.1
25import Unity.Session 0.1
24import Unity.Session 0.1
26
25
@@ -56,7 +55,6 @@ Showable {
56 property bool tabletMode
55 property bool tabletMode
57 property url viewSource // only used for testing
56 property url viewSource // only used for testing
58
57
59− property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
60 property int failedLoginsDelayAttempts: 7 // number of failed logins
58 property int failedLoginsDelayAttempts: 7 // number of failed logins
61 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
59 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
62 property int failedFingerprintLoginsDisableAttempts: 3 // number of failed fingerprint logins
60 property int failedFingerprintLoginsDisableAttempts: 3 // number of failed fingerprint logins
@@ -469,15 +467,6 @@ Showable {
469 if (!automatic) {
467 if (!automatic) {
470 AccountsService.failedLogins++;
468 AccountsService.failedLogins++;
471
469
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−
481 // Check if we should initiate a forced login delay
470 // Check if we should initiate a forced login delay
482 if (failedLoginsDelayAttempts > 0
471 if (failedLoginsDelayAttempts > 0
483 && AccountsService.failedLogins > 0
472 && AccountsService.failedLogins > 0
qml/Greeter/NarrowView.qml−14
@@ -48,20 +48,6 @@ FocusScope {
48 signal tease()
48 signal tease()
49 signal emergencyCall()
49 signal emergencyCall()
50
50
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−
65 function hide() {
51 function hide() {
66 lockscreen.hide();
52 lockscreen.hide();
67 coverPage.hide();
53 coverPage.hide();
qml/Greeter/WideView.qml−4
@@ -80,10 +80,6 @@ FocusScope {
80 loginList.showFakePassword();
80 loginList.showFakePassword();
81 }
81 }
82
82
83− function showLastChance() {
84− // TODO
85− }
86−
87 Rectangle {
83 Rectangle {
88 anchors.fill: parent
84 anchors.fill: parent
89 color: "black"
85 color: "black"
qml/Launcher/Drawer.qml−2
@@ -364,8 +364,6 @@ FocusScope {
364 width: units.gu(6)
364 width: units.gu(6)
365 height: 7.5 / 8 * width
365 height: 7.5 / 8 * width
366 anchors.horizontalCenter: parent.horizontalCenter
366 anchors.horizontalCenter: parent.horizontalCenter
367− backgroundMode: UbuntuShape.SolidColor
368− backgroundColor: UbuntuColors.lightGrey
369 radius: "medium"
367 radius: "medium"
370 borderSource: 'undefined'
368 borderSource: 'undefined'
371 source: Image {
369 source: Image {
qml/Launcher/LauncherPanel.qml+24−6
@@ -751,16 +751,18 @@ Rectangle {
751 Keys.onPressed: {
751 Keys.onPressed: {
752 switch (event.key) {
752 switch (event.key) {
753 case Qt.Key_Down:
753 case Qt.Key_Down:
754− selectedIndex++;
754+ var prevIndex = selectedIndex;
755− if (selectedIndex >= popoverRepeater.count) {
755+ selectedIndex = (selectedIndex + 1 < popoverRepeater.count) ? selectedIndex + 1 : 0;
756− selectedIndex = 0;
756+ while (!popoverRepeater.itemAt(selectedIndex).clickable && selectedIndex != prevIndex) {
757+ selectedIndex = (selectedIndex + 1 < popoverRepeater.count) ? selectedIndex + 1 : 0;
757 }
758 }
758 event.accepted = true;
759 event.accepted = true;
759 break;
760 break;
760 case Qt.Key_Up:
761 case Qt.Key_Up:
761− selectedIndex--;
762+ var prevIndex = selectedIndex;
762− if (selectedIndex < 0) {
763+ selectedIndex = (selectedIndex > 0) ? selectedIndex - 1 : popoverRepeater.count - 1;
764+ while (!popoverRepeater.itemAt(selectedIndex).clickable && selectedIndex != prevIndex) {
763− selectedIndex = popoverRepeater.count - 1;
765+ selectedIndex = (selectedIndex > 0) ? selectedIndex - 1 : popoverRepeater.count - 1;
764 }
766 }
765 event.accepted = true;
767 event.accepted = true;
766 break;
768 break;
@@ -806,6 +808,19 @@ Rectangle {
806 width: parent.width
808 width: parent.width
807 height: quickListColumn.height
809 height: quickListColumn.height
808
810
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+
809 Column {
824 Column {
810 id: quickListColumn
825 id: quickListColumn
811 width: parent.width
826 width: parent.width
@@ -820,6 +835,9 @@ Rectangle {
820 }
835 }
821
836
822 ListItem {
837 ListItem {
838+ readonly property bool clickable: model.clickable
839+ readonly property int index: model.index
840+
823 objectName: "quickListEntry" + index
841 objectName: "quickListEntry" + index
824 selected: index === quickList.selectedIndex
842 selected: index === quickList.selectedIndex
825 height: label.implicitHeight + label.anchors.topMargin + label.anchors.bottomMargin
843 height: label.implicitHeight + label.anchors.topMargin + label.anchors.bottomMargin
qml/Shell.qml+8−1
@@ -255,6 +255,13 @@ StyledItem {
255 }
255 }
256 }
256 }
257
257
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+
258 GSettings {
265 GSettings {
259 id: settings
266 id: settings
260 schema.id: "com.canonical.Unity8"
267 schema.id: "com.canonical.Unity8"
@@ -290,6 +297,7 @@ StyledItem {
290 topLevelSurfaceList: topLevelSurfaceList
297 topLevelSurfaceList: topLevelSurfaceList
291 inputMethodRect: inputMethod.visibleRect
298 inputMethodRect: inputMethod.visibleRect
292 rightEdgePushProgress: rightEdgeBarrier.progress
299 rightEdgePushProgress: rightEdgeBarrier.progress
300+ availableDesktopArea: availableDesktopAreaItem
293
301
294 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
302 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
295 ? "phone"
303 ? "phone"
@@ -311,7 +319,6 @@ StyledItem {
311
319
312 onInteractiveChanged: { if (interactive) { focus = true; } }
320 onInteractiveChanged: { if (interactive) { focus = true; } }
313
321
314− leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
315 suspended: greeter.shown
322 suspended: greeter.shown
316 altTabPressed: physicalKeysMapper.altTabPressed
323 altTabPressed: physicalKeysMapper.altTabPressed
317 oskEnabled: shell.oskEnabled
324 oskEnabled: shell.oskEnabled
qml/Stage/ChildWindow.qml+18−3
@@ -18,8 +18,9 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Unity.Application 0.1
19import Unity.Application 0.1
20
20
21−Item {
21+FocusScope {
22 id: root
22 id: root
23+ objectName: "childWindow"
23
24
24 // Set from outside.
25 // Set from outside.
25 property var surface
26 property var surface
@@ -27,6 +28,7 @@ Item {
27 property Item target
28 property Item target
28 property alias requestedWidth: surfaceContainer.requestedWidth
29 property alias requestedWidth: surfaceContainer.requestedWidth
29 property alias requestedHeight: surfaceContainer.requestedHeight
30 property alias requestedHeight: surfaceContainer.requestedHeight
31+ property real decorationHeight
30
32
31 width: surface ? surface.size.width : 0
33 width: surface ? surface.size.width : 0
32 height: surface ? surface.size.height : 0
34 height: surface ? surface.size.height : 0
@@ -43,6 +45,7 @@ Item {
43 readonly property bool decorated: surface ? surface.type === Mir.UtilityType
45 readonly property bool decorated: surface ? surface.type === Mir.UtilityType
44 || surface.type === Mir.DialogType
46 || surface.type === Mir.DialogType
45 || surface.type === Mir.NormalType
47 || surface.type === Mir.NormalType
48+ || surface.type === Mir.SatelliteType
46 : false
49 : false
47
50
48 readonly property bool moveable: decorated
51 readonly property bool moveable: decorated
@@ -97,10 +100,14 @@ Item {
97
100
98 sourceComponent: Component {
101 sourceComponent: Component {
99 WindowDecoration {
102 WindowDecoration {
100− height: units.gu(3)
103+ id: windowDecoration
104+ height: root.decorationHeight
101 title: root.surface ? root.surface.name : ""
105 title: root.surface ? root.surface.name : ""
102 active: root.surface ? root.surface.focused : false
106 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
104 minimizeButtonVisible: false
111 minimizeButtonVisible: false
105 maximizeButtonShown: false
112 maximizeButtonShown: false
106 onPressed: root.surface.activate();
113 onPressed: root.surface.activate();
@@ -109,6 +116,12 @@ Item {
109 d.moveHandler.handlePositionChanged(mouse);
116 d.moveHandler.handlePositionChanged(mouse);
110 }
117 }
111 onReleased: if (d.moveHandler) { d.moveHandler.handleReleased(); }
118 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+ }
112 }
125 }
113 }
126 }
114 }
127 }
@@ -141,6 +154,8 @@ Item {
141 // TODO ChildWindow parent will probably want to control those
154 // TODO ChildWindow parent will probably want to control those
142 interactive: true
155 interactive: true
143 consumesInput: true
156 consumesInput: true
157+
158+ focus: true
144 }
159 }
145
160
146 Loader {
161 Loader {
qml/Stage/ChildWindowRepeater.qml+12−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -21,8 +21,19 @@ Repeater {
21 id: root
21 id: root
22 property Item boundsItem
22 property Item boundsItem
23 delegate: ChildWindowTree {
23 delegate: ChildWindowTree {
24+ id: childWindowTree
24 surface: model.surface
25 surface: model.surface
25 z: root.count - model.index
26 z: root.count - model.index
26 boundsItem: root.boundsItem
27 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+ }
27 }
38 }
28}
39}
qml/Stage/ChildWindowTree.qml+17−2
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -18,13 +18,14 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Unity.Application 0.1
19import Unity.Application 0.1
20
20
21−Item {
21+FocusScope {
22 id: root
22 id: root
23
23
24 property alias surface: childWindow.surface
24 property alias surface: childWindow.surface
25 property real displacementX: 0
25 property real displacementX: 0
26 property real displacementY: 0
26 property real displacementY: 0
27 property alias boundsItem: childWindow.boundsItem
27 property alias boundsItem: childWindow.boundsItem
28+ property alias decorationHeight: childWindow.decorationHeight
28
29
29 x: surface ? surface.position.x + displacementX : 0
30 x: surface ? surface.position.x + displacementX : 0
30 y: surface ? surface.position.y + displacementY : 0
31 y: surface ? surface.position.y + displacementY : 0
@@ -100,6 +101,13 @@ Item {
100 onFocusRequested: {
101 onFocusRequested: {
101 root.surface.activate();
102 root.surface.activate();
102 }
103 }
104+ onFocusedChanged: {
105+ if (root.surface.focused) {
106+ childWindow.focus = true;
107+ // Propagate
108+ root.focus = true;
109+ }
110+ }
103 }
111 }
104
112
105 // Using a loader here mainly to circunvent the "ChildWindowTree is instantiated recursively" error from the QML engine
113 // Using a loader here mainly to circunvent the "ChildWindowTree is instantiated recursively" error from the QML engine
@@ -119,5 +127,12 @@ Item {
119 property: "boundsItem"
127 property: "boundsItem"
120 value: root.boundsItem
128 value: root.boundsItem
121 }
129 }
130+ onFocusChanged: {
131+ if (focus) {
132+ // A surface in some ChildWindowTree got focused.
133+ // Propagate
134+ root.focus = true;
135+ }
136+ }
122 }
137 }
123}
138}
qml/Stage/DecoratedWindow.qml+14−7
@@ -43,6 +43,7 @@ FocusScope {
43 property bool hasDecoration: true
43 property bool hasDecoration: true
44 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
44 // This will temporarily show/hide the decoration without actually changing the surface's dimensions
45 property real showDecoration: 1
45 property real showDecoration: 1
46+ property alias decorationHeight: decoration.height
46 property bool animateDecoration: false
47 property bool animateDecoration: false
47 property bool showHighlight: false
48 property bool showHighlight: false
48 property int highlightSize: units.gu(1)
49 property int highlightSize: units.gu(1)
@@ -55,11 +56,15 @@ FocusScope {
55 property int scaleToPreviewSize: units.gu(30)
56 property int scaleToPreviewSize: units.gu(30)
56
57
57 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
58 property alias surfaceOrientationAngle: applicationWindow.surfaceOrientationAngle
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
58− readonly property real decorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
62+ readonly property real actualDecorationHeight: Math.min(d.visibleDecorationHeight, d.requestedDecorationHeight)
63+
59 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
64 readonly property bool counterRotate: surfaceOrientationAngle != 0 && surfaceOrientationAngle != 180
60
65
61 readonly property int minimumWidth: !counterRotate ? applicationWindow.minimumWidth : applicationWindow.minimumHeight
66 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)
63 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
68 readonly property int maximumWidth: !counterRotate ? applicationWindow.maximumWidth : applicationWindow.maximumHeight
64 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
69 readonly property int maximumHeight: (root.decorationShown && applicationWindow.maximumHeight > 0 ? decoration.height : 0)
65 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
70 + (!counterRotate ? applicationWindow.maximumHeight : applicationWindow.maximumWidth)
@@ -74,6 +79,8 @@ FocusScope {
74
79
75 property alias altDragEnabled: altDragHandler.enabled
80 property alias altDragEnabled: altDragHandler.enabled
76
81
82+ property Item windowMargins
83+
77 signal closeClicked()
84 signal closeClicked()
78 signal maximizeClicked()
85 signal maximizeClicked()
79 signal maximizeHorizontallyClicked()
86 signal maximizeHorizontallyClicked()
@@ -102,7 +109,7 @@ FocusScope {
102 PropertyChanges {
109 PropertyChanges {
103 target: root
110 target: root
104 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
111 implicitWidth: counterRotate ? applicationWindow.implicitHeight : applicationWindow.implicitWidth
105− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
112+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.implicitWidth: applicationWindow.implicitHeight)
106 }
113 }
107 },
114 },
108 State {
115 State {
@@ -111,7 +118,7 @@ FocusScope {
111 PropertyChanges {
118 PropertyChanges {
112 target: root
119 target: root
113 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
120 implicitWidth: counterRotate ? applicationWindow.requestedHeight : applicationWindow.requestedWidth
114− implicitHeight: root.decorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
121+ implicitHeight: root.actualDecorationHeight + (counterRotate ? applicationWindow.requestedWidth: applicationWindow.requestedHeight)
115 }
122 }
116 },
123 },
117 State {
124 State {
@@ -150,7 +157,7 @@ FocusScope {
150 margins: active ? -units.gu(2) : -units.gu(1.5)
157 margins: active ? -units.gu(2) : -units.gu(1.5)
151 }
158 }
152 height: Math.min(applicationWindow.implicitHeight, applicationWindow.height) * applicationWindow.itemScale
159 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))
154 source: "../graphics/dropshadow2gu.sci"
161 source: "../graphics/dropshadow2gu.sci"
155 opacity: root.shadowOpacity
162 opacity: root.shadowOpacity
156 }
163 }
@@ -159,7 +166,7 @@ FocusScope {
159 id: applicationWindow
166 id: applicationWindow
160 objectName: "appWindow"
167 objectName: "appWindow"
161 anchors.top: parent.top
168 anchors.top: parent.top
162− anchors.topMargin: root.decorationHeight * Math.min(1, root.showDecoration)
169+ anchors.topMargin: root.actualDecorationHeight * Math.min(1, root.showDecoration)
163 anchors.left: parent.left
170 anchors.left: parent.left
164 width: implicitWidth
171 width: implicitWidth
165 height: implicitHeight
172 height: implicitHeight
@@ -207,7 +214,7 @@ FocusScope {
207 objectName: "appWindowDecoration"
214 objectName: "appWindowDecoration"
208
215
209 anchors { left: parent.left; top: parent.top; right: parent.right }
216 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
211
218
212 title: applicationWindow.title
219 title: applicationWindow.title
213 windowMoving: moveHandler.moving && !altDragHandler.dragging
220 windowMoving: moveHandler.moving && !altDragHandler.dragging
qml/Stage/Stage.qml+88−48
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014-2016 Canonical, Ltd.
2+ * Copyright (C) 2014-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@ import GlobalShortcut 1.0
25import GSettings 1.0
25import GSettings 1.0
26import "Spread"
26import "Spread"
27import "Spread/MathUtils.js" as MathUtils
27import "Spread/MathUtils.js" as MathUtils
28+import WindowManager 1.0
28
29
29FocusScope {
30FocusScope {
30 id: root
31 id: root
@@ -43,10 +44,10 @@ FocusScope {
43 property int shellOrientationAngle
44 property int shellOrientationAngle
44 property bool spreadEnabled: true // If false, animations and right edge will be disabled
45 property bool spreadEnabled: true // If false, animations and right edge will be disabled
45 property bool suspended
46 property bool suspended
46− property int leftMargin: 0
47 property bool oskEnabled: false
47 property bool oskEnabled: false
48 property rect inputMethodRect
48 property rect inputMethodRect
49 property real rightEdgePushProgress: 0
49 property real rightEdgePushProgress: 0
50+ property Item availableDesktopArea
50
51
51 // Configuration
52 // Configuration
52 property string mode: "staged"
53 property string mode: "staged"
@@ -120,6 +121,12 @@ FocusScope {
120 }
121 }
121 }
122 }
122
123
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+
123 property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
130 property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
124 priv.focusedAppDelegate.clientAreaItem : null;
131 priv.focusedAppDelegate.clientAreaItem : null;
125
132
@@ -224,10 +231,30 @@ FocusScope {
224 active: priv.focusedAppDelegate !== null
231 active: priv.focusedAppDelegate !== null
225 }
232 }
226
233
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+
227 QtObject {
246 QtObject {
228 id: priv
247 id: priv
229 objectName: "DesktopStagePrivate"
248 objectName: "DesktopStagePrivate"
230
249
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+
231 property var focusedAppDelegate: null
258 property var focusedAppDelegate: null
232 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
259 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
233
260
@@ -347,6 +374,8 @@ FocusScope {
347 }
374 }
348
375
349 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
376 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
377+
378+ readonly property real windowDecorationHeight: units.gu(3)
350 }
379 }
351
380
352 Component.onCompleted: priv.updateMainAndSideStageIndexes();
381 Component.onCompleted: priv.updateMainAndSideStageIndexes();
@@ -568,7 +597,7 @@ FocusScope {
568 id: spreadItem
597 id: spreadItem
569 objectName: "spreadItem"
598 objectName: "spreadItem"
570 anchors.fill: appContainer
599 anchors.fill: appContainer
571− leftMargin: root.leftMargin
600+ leftMargin: root.availableDesktopArea.x
572 model: root.topLevelSurfaceList
601 model: root.topLevelSurfaceList
573 spreadFlickable: floatingFlickable
602 spreadFlickable: floatingFlickable
574 z: 10
603 z: 10
@@ -676,13 +705,6 @@ FocusScope {
676 }
705 }
677 }
706 }
678
707
679− Item {
680− id: boundariesForWindowPlacement
681− anchors.fill: parent
682− anchors.topMargin: PanelState.panelHeight
683− visible: false
684− }
685−
686 Repeater {
708 Repeater {
687 id: appRepeater
709 id: appRepeater
688 model: topLevelSurfaceList
710 model: topLevelSurfaceList
@@ -780,7 +802,7 @@ FocusScope {
780 target: appDelegate
802 target: appDelegate
781 property: "y"
803 property: "y"
782 value: appDelegate.requestedY -
804 value: appDelegate.requestedY -
783− Math.min(appDelegate.requestedY - PanelState.panelHeight,
805+ Math.min(appDelegate.requestedY - root.availableDesktopArea.y,
784 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
806 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
785 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
807 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
786 && root.inputMethodRect.height > 0
808 && root.inputMethodRect.height > 0
@@ -798,8 +820,8 @@ FocusScope {
798 angleDiff = (360 + angleDiff) % 360;
820 angleDiff = (360 + angleDiff) % 360;
799 if (angleDiff === 90 || angleDiff === 270) {
821 if (angleDiff === 90 || angleDiff === 270) {
800 var aux = decoratedWindow.requestedHeight;
822 var aux = decoratedWindow.requestedHeight;
801− decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.decorationHeight;
823+ decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.actualDecorationHeight;
802− decoratedWindow.requestedWidth = aux - decoratedWindow.decorationHeight;
824+ decoratedWindow.requestedWidth = aux - decoratedWindow.actualDecorationHeight;
803 }
825 }
804 }
826 }
805 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
827 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
@@ -900,12 +922,13 @@ FocusScope {
900 priv.updateMainAndSideStageIndexes();
922 priv.updateMainAndSideStageIndexes();
901 }
923 }
902 appDelegate.focus = true;
924 appDelegate.focus = true;
925+ priv.focusedAppDelegate = appDelegate;
903 }
926 }
904
927
905 function updateQmlFocusFromMirSurfaceFocus() {
928 function updateQmlFocusFromMirSurfaceFocus() {
906 if (model.window.focused) {
929 if (model.window.focused) {
907 claimFocus();
930 claimFocus();
908− priv.focusedAppDelegate = appDelegate;
931+ decoratedWindow.focus = true;
909 }
932 }
910 }
933 }
911
934
@@ -914,8 +937,8 @@ FocusScope {
914 target: appDelegate
937 target: appDelegate
915 screenWidth: appContainer.width
938 screenWidth: appContainer.width
916 screenHeight: appContainer.height
939 screenHeight: appContainer.height
917− leftMargin: root.leftMargin
940+ leftMargin: root.availableDesktopArea.x
918− minimumY: boundariesForWindowPlacement.y
941+ minimumY: root.availableDesktopArea.y
919 }
942 }
920
943
921 Connections {
944 Connections {
@@ -1167,7 +1190,7 @@ FocusScope {
1167
1190
1168 StagedRightEdgeMaths {
1191 StagedRightEdgeMaths {
1169 id: stagedRightEdgeMaths
1192 id: stagedRightEdgeMaths
1170− sceneWidth: appContainer.width - root.leftMargin
1193+ sceneWidth: root.availableDesktopArea.width
1171 sceneHeight: appContainer.height
1194 sceneHeight: appContainer.height
1172 isMainStageApp: priv.mainStageDelegate == appDelegate
1195 isMainStageApp: priv.mainStageDelegate == appDelegate
1173 isSideStageApp: priv.sideStageDelegate == appDelegate
1196 isSideStageApp: priv.sideStageDelegate == appDelegate
@@ -1178,7 +1201,7 @@ FocusScope {
1178 progress: 0
1201 progress: 0
1179 targetHeight: spreadItem.stackHeight
1202 targetHeight: spreadItem.stackHeight
1180 targetX: spreadMaths.targetX
1203 targetX: spreadMaths.targetX
1181− startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1204+ startY: appDelegate.fullscreen ? 0 : root.availableDesktopArea.y
1182 targetY: spreadMaths.targetY
1205 targetY: spreadMaths.targetY
1183 targetAngle: spreadMaths.targetAngle
1206 targetAngle: spreadMaths.targetAngle
1184 targetScale: spreadMaths.targetScale
1207 targetScale: spreadMaths.targetScale
@@ -1299,9 +1322,9 @@ FocusScope {
1299 PropertyChanges {
1322 PropertyChanges {
1300 target: appDelegate
1323 target: appDelegate
1301 x: stageMaths.itemX
1324 x: stageMaths.itemX
1302− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1325+ y: root.availableDesktopArea.y
1303 requestedWidth: appContainer.width
1326 requestedWidth: appContainer.width
1304− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1327+ requestedHeight: root.availableDesktopArea.height
1305 visuallyMaximized: true
1328 visuallyMaximized: true
1306 visible: appDelegate.x < root.width
1329 visible: appDelegate.x < root.width
1307 }
1330 }
@@ -1331,10 +1354,10 @@ FocusScope {
1331 PropertyChanges {
1354 PropertyChanges {
1332 target: appDelegate
1355 target: appDelegate
1333 x: stageMaths.itemX
1356 x: stageMaths.itemX
1334− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1357+ y: root.availableDesktopArea.y
1335 z: stageMaths.itemZ
1358 z: stageMaths.itemZ
1336 requestedWidth: stageMaths.itemWidth
1359 requestedWidth: stageMaths.itemWidth
1337− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1360+ requestedHeight: root.availableDesktopArea.height
1338 visuallyMaximized: true
1361 visuallyMaximized: true
1339 visible: appDelegate.x < root.width
1362 visible: appDelegate.x < root.width
1340 }
1363 }
@@ -1355,11 +1378,11 @@ FocusScope {
1355 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1378 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1356 PropertyChanges {
1379 PropertyChanges {
1357 target: appDelegate;
1380 target: appDelegate;
1358− requestedX: root.leftMargin;
1381+ requestedX: root.availableDesktopArea.x;
1359 requestedY: 0;
1382 requestedY: 0;
1360 visuallyMinimized: false;
1383 visuallyMinimized: false;
1361 visuallyMaximized: true
1384 visuallyMaximized: true
1362− requestedWidth: appContainer.width - root.leftMargin;
1385+ requestedWidth: root.availableDesktopArea.width;
1363 requestedHeight: appContainer.height;
1386 requestedHeight: appContainer.height;
1364 }
1387 }
1365 PropertyChanges { target: touchControls; enabled: true }
1388 PropertyChanges { target: touchControls; enabled: true }
@@ -1392,6 +1415,7 @@ FocusScope {
1392 when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
1415 when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
1393 extend: "normal"
1416 extend: "normal"
1394 PropertyChanges {
1417 PropertyChanges {
1418+ restoreEntryValues: false
1395 target: appDelegate;
1419 target: appDelegate;
1396 windowedX: restoredX;
1420 windowedX: restoredX;
1397 windowedY: restoredY;
1421 windowedY: restoredY;
@@ -1402,10 +1426,10 @@ FocusScope {
1402 extend: "normal"
1426 extend: "normal"
1403 PropertyChanges {
1427 PropertyChanges {
1404 target: appDelegate
1428 target: appDelegate
1405− windowedX: root.leftMargin
1429+ windowedX: root.availableDesktopArea.x
1406− windowedY: PanelState.panelHeight
1430+ windowedY: root.availableDesktopArea.y
1407− windowedWidth: (appContainer.width - root.leftMargin)/2
1431+ windowedWidth: root.availableDesktopArea.width / 2
1408− windowedHeight: appContainer.height - PanelState.panelHeight
1432+ windowedHeight: root.availableDesktopArea.height
1409 }
1433 }
1410 },
1434 },
1411 State {
1435 State {
@@ -1413,7 +1437,7 @@ FocusScope {
1413 extend: "maximizedLeft"
1437 extend: "maximizedLeft"
1414 PropertyChanges {
1438 PropertyChanges {
1415 target: appDelegate;
1439 target: appDelegate;
1416− windowedX: (appContainer.width + root.leftMargin)/2
1440+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1417 }
1441 }
1418 },
1442 },
1419 State {
1443 State {
@@ -1421,10 +1445,10 @@ FocusScope {
1421 extend: "normal"
1445 extend: "normal"
1422 PropertyChanges {
1446 PropertyChanges {
1423 target: appDelegate
1447 target: appDelegate
1424− windowedX: root.leftMargin
1448+ windowedX: root.availableDesktopArea.x
1425− windowedY: PanelState.panelHeight
1449+ windowedY: root.availableDesktopArea.y
1426− windowedWidth: (appContainer.width - root.leftMargin)/2
1450+ windowedWidth: root.availableDesktopArea.width / 2
1427− windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1451+ windowedHeight: root.availableDesktopArea.height / 2
1428 }
1452 }
1429 },
1453 },
1430 State {
1454 State {
@@ -1432,7 +1456,7 @@ FocusScope {
1432 extend: "maximizedTopLeft"
1456 extend: "maximizedTopLeft"
1433 PropertyChanges {
1457 PropertyChanges {
1434 target: appDelegate
1458 target: appDelegate
1435− windowedX: (appContainer.width + root.leftMargin)/2
1459+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1436 }
1460 }
1437 },
1461 },
1438 State {
1462 State {
@@ -1440,10 +1464,10 @@ FocusScope {
1440 extend: "normal"
1464 extend: "normal"
1441 PropertyChanges {
1465 PropertyChanges {
1442 target: appDelegate
1466 target: appDelegate
1443− windowedX: root.leftMargin
1467+ windowedX: root.availableDesktopArea.x
1444− windowedY: (appContainer.height + PanelState.panelHeight)/2
1468+ windowedY: root.availableDesktopArea.y + (root.availableDesktopArea.height / 2)
1445− windowedWidth: (appContainer.width - root.leftMargin)/2
1469+ windowedWidth: root.availableDesktopArea.width / 2
1446− windowedHeight: appContainer.height/2
1470+ windowedHeight: root.availableDesktopArea.height / 2
1447 }
1471 }
1448 },
1472 },
1449 State {
1473 State {
@@ -1451,20 +1475,26 @@ FocusScope {
1451 extend: "maximizedBottomLeft"
1475 extend: "maximizedBottomLeft"
1452 PropertyChanges {
1476 PropertyChanges {
1453 target: appDelegate
1477 target: appDelegate
1454− windowedX: (appContainer.width + root.leftMargin)/2
1478+ windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1455 }
1479 }
1456 },
1480 },
1457 State {
1481 State {
1458 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
1482 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
1459 extend: "normal"
1483 extend: "normal"
1484+ PropertyChanges {
1485+ target: appDelegate
1460− PropertyChanges { target: appDelegate; windowedX: root.leftMargin; windowedY: windowedY;
1486+ windowedX: root.availableDesktopArea.x; windowedY: windowedY
1461− windowedWidth: appContainer.width - root.leftMargin; windowedHeight: windowedHeight }
1487+ windowedWidth: root.availableDesktopArea.width; windowedHeight: windowedHeight
1488+ }
1462 },
1489 },
1463 State {
1490 State {
1464 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1491 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1465 extend: "normal"
1492 extend: "normal"
1493+ PropertyChanges {
1494+ target: appDelegate
1466− PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: PanelState.panelHeight;
1495+ windowedX: windowedX; windowedY: root.availableDesktopArea.y
1467− windowedWidth: windowedWidth; windowedHeight: appContainer.height - PanelState.panelHeight }
1496+ windowedWidth: windowedWidth; windowedHeight: root.availableDesktopArea.height
1497+ }
1468 },
1498 },
1469 State {
1499 State {
1470 name: "minimized"; when: appDelegate.minimized
1500 name: "minimized"; when: appDelegate.minimized
@@ -1592,7 +1622,7 @@ FocusScope {
1592 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1622 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1593
1623
1594 target: appDelegate
1624 target: appDelegate
1595− boundsItem: boundariesForWindowPlacement
1625+ boundsItem: root.availableDesktopArea
1596 minWidth: units.gu(10)
1626 minWidth: units.gu(10)
1597 minHeight: units.gu(10)
1627 minHeight: units.gu(10)
1598 borderThickness: units.gu(2)
1628 borderThickness: units.gu(2)
@@ -1615,13 +1645,14 @@ FocusScope {
1615 focus: true
1645 focus: true
1616 interactive: root.interactive
1646 interactive: root.interactive
1617 showDecoration: 1
1647 showDecoration: 1
1648+ decorationHeight: priv.windowDecorationHeight
1618 maximizeButtonShown: appDelegate.canBeMaximized
1649 maximizeButtonShown: appDelegate.canBeMaximized
1619 overlayShown: touchControls.overlayShown
1650 overlayShown: touchControls.overlayShown
1620 width: implicitWidth
1651 width: implicitWidth
1621 height: implicitHeight
1652 height: implicitHeight
1622 highlightSize: windowInfoItem.iconMargin / 2
1653 highlightSize: windowInfoItem.iconMargin / 2
1623− boundsItem: boundariesForWindowPlacement
1624 altDragEnabled: root.mode == "windowed"
1654 altDragEnabled: root.mode == "windowed"
1655+ boundsItem: root.availableDesktopArea
1625
1656
1626 requestedWidth: appDelegate.requestedWidth
1657 requestedWidth: appDelegate.requestedWidth
1627 requestedHeight: appDelegate.requestedHeight
1658 requestedHeight: appDelegate.requestedHeight
@@ -1684,7 +1715,7 @@ FocusScope {
1684 resizeArea: resizeArea
1715 resizeArea: resizeArea
1685 enabled: false
1716 enabled: false
1686 visible: enabled
1717 visible: enabled
1687− boundsItem: boundariesForWindowPlacement
1718+ boundsItem: root.availableDesktopArea
1688
1719
1689 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1720 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1690 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
1721 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
@@ -1805,9 +1836,18 @@ FocusScope {
1805 displacementX: appDelegate.clientAreaItem.x
1836 displacementX: appDelegate.clientAreaItem.x
1806 displacementY: appDelegate.clientAreaItem.y
1837 displacementY: appDelegate.clientAreaItem.y
1807
1838
1808− boundsItem: boundariesForWindowPlacement
1839+ boundsItem: root.availableDesktopArea
1840+ decorationHeight: priv.windowDecorationHeight
1809
1841
1810 z: childWindowRepeater.count - model.index
1842 z: childWindowRepeater.count - model.index
1843+
1844+ onFocusChanged: {
1845+ if (focus) {
1846+ // some child surface in this tree got focus.
1847+ // Ensure we also have it at the top-level hierarchy
1848+ appDelegate.claimFocus();
1849+ }
1850+ }
1811 }
1851 }
1812 }
1852 }
1813 }
1853 }
@@ -1818,7 +1858,7 @@ FocusScope {
1818 FakeMaximizeDelegate {
1858 FakeMaximizeDelegate {
1819 id: fakeRectangle
1859 id: fakeRectangle
1820 target: priv.focusedAppDelegate
1860 target: priv.focusedAppDelegate
1821− leftMargin: root.leftMargin
1861+ leftMargin: root.availableDesktopArea.x
1822 appContainerWidth: appContainer.width
1862 appContainerWidth: appContainer.width
1823 appContainerHeight: appContainer.height
1863 appContainerHeight: appContainer.height
1824 }
1864 }
qml/Wizard/Pages/30-wifi.qml−4
@@ -20,7 +20,6 @@ import QMenuModel 0.1 as QMenuModel
20import Ubuntu.Components 1.3
20import Ubuntu.Components 1.3
21import Wizard 0.1
21import Wizard 0.1
22import Ubuntu.Connectivity 1.0
22import Ubuntu.Connectivity 1.0
23−import Ubuntu.SystemImage 0.1
24import ".." as LocalComponents
23import ".." as LocalComponents
25import "../../Components"
24import "../../Components"
26
25
@@ -206,9 +205,6 @@ LocalComponents.Page {
206 LocalComponents.StackButton {
205 LocalComponents.StackButton {
207 text: (connected || listview.count === 0) ? i18n.tr("Next") : i18n.tr("Skip")
206 text: (connected || listview.count === 0) ? i18n.tr("Next") : i18n.tr("Skip")
208 onClicked: {
207 onClicked: {
209− if (connected) {
210− SystemImage.checkForUpdate(); // initiate the background check for System Update
211− }
212 pageStack.next();
208 pageStack.next();
213 }
209 }
214 }
210 }
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}
60 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
60 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
61 )
61 )
62
62
63−add_subdirectory(Panel)
64add_subdirectory(Dash)
63add_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)
20# Use our custom implementation of qmlscene and import dbus-test-runner
20# Use our custom implementation of qmlscene and import dbus-test-runner
21add_executable(qmlscene ALIAS uqmlscene)
21add_executable(qmlscene ALIAS uqmlscene)
22import_executables(dbus-test-runner)
22import_executables(dbus-test-runner)
23+import_executables(qdbus-simple-test-runner)
23
24
24set(UNITY_PLUGINPATH "${CMAKE_BINARY_DIR}/plugins" CACHE PATH "Path to pre-built unity8 plugin dir.")
25set(UNITY_PLUGINPATH "${CMAKE_BINARY_DIR}/plugins" CACHE PATH "Path to pre-built unity8 plugin dir.")
25set(UNITY_MOCKPATH "${CMAKE_BINARY_DIR}/tests/mocks" CACHE PATH "Path to pre-built unity8 mock dir.")
26set(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 @@
1add_subdirectory(Connectivity)
1add_subdirectory(Connectivity)
2add_subdirectory(DownloadDaemonListener)
2add_subdirectory(DownloadDaemonListener)
3−add_subdirectory(SystemImage)
4add_subdirectory(SystemSettings)
3add_subdirectory(SystemSettings)
5add_subdirectory(Telephony)
4add_subdirectory(Telephony)
6add_subdirectory(Thumbnailer)
5add_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) {
172
172
173 endInsertRows();
173 endInsertRows();
174 Q_EMIT countChanged();
174 Q_EMIT countChanged();
175− if (count() == 1) Q_EMIT emptyChanged(isEmpty()); // was empty but not anymore
176
175
177 return true;
176 return true;
178}
177}
@@ -189,7 +188,6 @@ void ApplicationManager::remove(ApplicationInfo *application) {
189 endRemoveRows();
188 endRemoveRows();
190 m_modelBusy = false;
189 m_modelBusy = false;
191 Q_EMIT countChanged();
190 Q_EMIT countChanged();
192− if (isEmpty()) Q_EMIT emptyChanged(isEmpty());
193 DEBUG_MSG(application->appId() << " after: " << qPrintable(toString()));
191 DEBUG_MSG(application->appId() << " after: " << qPrintable(toString()));
194 }
192 }
195}
193}
@@ -476,6 +474,11 @@ void ApplicationManager::buildListOfAvailableApplications()
476 application->setIsTouchApp(false);
474 application->setIsTouchApp(false);
477 m_availableApplications.append(application);
475 m_availableApplications.append(application);
478
476
477+ application = new ApplicationInfo(this);
478+ application->setAppId("ubuntu-terminal-app");
479+ application->setName("Terminal");
480+ m_availableApplications.append(application);
481+
479 application = new ApplicationInfo(this);
482 application = new ApplicationInfo(this);
480 application->setAppId("primary-oriented-app");
483 application->setAppId("primary-oriented-app");
481 application->setName("Primary Oriented");
484 application->setName("Primary Oriented");
@@ -502,11 +505,6 @@ QStringList ApplicationManager::availableApplications()
502 return appIds;
505 return appIds;
503}
506}
504
507
505−bool ApplicationManager::isEmpty() const
506−{
507− return m_runningApplications.isEmpty();
508−}
509−
510ApplicationInfo *ApplicationManager::findApplication(MirSurface* surface)
508ApplicationInfo *ApplicationManager::findApplication(MirSurface* surface)
511{
509{
512 for (ApplicationInfo *app : m_runningApplications) {
510 for (ApplicationInfo *app : m_runningApplications) {
tests/mocks/Unity/Application/ApplicationManager.h+1−6
@@ -40,7 +40,6 @@ using namespace unity::shell::application;
40class ApplicationManager : public ApplicationManagerInterface {
40class ApplicationManager : public ApplicationManagerInterface {
41 Q_OBJECT
41 Q_OBJECT
42
42
43− Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
44 Q_PROPERTY(QStringList availableApplications READ availableApplications NOTIFY availableApplicationsChanged)
43 Q_PROPERTY(QStringList availableApplications READ availableApplications NOTIFY availableApplicationsChanged)
45
44
46 public:
45 public:
@@ -56,8 +55,6 @@ class ApplicationManager : public ApplicationManagerInterface {
56 Q_INVOKABLE ApplicationInfo *findApplication(const QString &appId) const override;
55 Q_INVOKABLE ApplicationInfo *findApplication(const QString &appId) const override;
57 unity::shell::application::ApplicationInfoInterface *findApplicationWithSurface(unity::shell::application::MirSurfaceInterface* surface) const override;
56 unity::shell::application::ApplicationInfoInterface *findApplicationWithSurface(unity::shell::application::MirSurfaceInterface* surface) const override;
58
57
59− Q_INVOKABLE void move(int from, int to);
60−
61 // Application control methods
58 // Application control methods
62 Q_INVOKABLE bool requestFocusApplication(const QString &appId) override;
59 Q_INVOKABLE bool requestFocusApplication(const QString &appId) override;
63 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
60 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
@@ -71,17 +68,15 @@ class ApplicationManager : public ApplicationManagerInterface {
71
68
72 QModelIndex findIndex(ApplicationInfo* application);
69 QModelIndex findIndex(ApplicationInfo* application);
73
70
74− bool isEmpty() const;
75−
76 Q_SIGNALS:
71 Q_SIGNALS:
77 void focusRequested(const QString &appId);
72 void focusRequested(const QString &appId);
78− void emptyChanged(bool empty);
79 void availableApplicationsChanged(QStringList list);
73 void availableApplicationsChanged(QStringList list);
80
74
81 private Q_SLOTS:
75 private Q_SLOTS:
82 void raiseApp(const QString &appId);
76 void raiseApp(const QString &appId);
83
77
84 private:
78 private:
79+ void move(int from, int to);
85 bool add(ApplicationInfo *application);
80 bool add(ApplicationInfo *application);
86 void remove(ApplicationInfo* application);
81 void remove(ApplicationInfo* application);
87 void buildListOfAvailableApplications();
82 void buildListOfAvailableApplications();
tests/mocks/Unity/Application/MirSurface.cpp+5
@@ -452,6 +452,11 @@ void MirSurface::setHeightIncrement(int value)
452void MirSurface::close()
452void MirSurface::close()
453{
453{
454 DEBUG_MSG("");
454 DEBUG_MSG("");
455+
456+ for (int i = 0; i < m_childSurfaceList->count(); ++i) {
457+ m_childSurfaceList->get(i)->close();
458+ }
459+
455 if (!m_zombieTimer.isActive()) {
460 if (!m_zombieTimer.isActive()) {
456 m_zombieTimer.start();
461 m_zombieTimer.start();
457 Q_EMIT closeRequested();
462 Q_EMIT closeRequested();
tests/plugins/Unity/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1add_subdirectory(Indicators)
1add_subdirectory(Indicators)
2add_subdirectory(Launcher)
2add_subdirectory(Launcher)
3+add_subdirectory(Platform)
3add_subdirectory(Session)
4add_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:
56 QTRY_COMPARE(storage->getStage(QTest::currentTestFunction(), 0), stage);
56 QTRY_COMPARE(storage->getStage(QTest::currentTestFunction(), 0), stage);
57 }
57 }
58
58
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+
59private:
68private:
60 WindowStateStorage * storage{nullptr};
69 WindowStateStorage * storage{nullptr};
61};
70};
tests/plugins/WindowManager/UnityApplicationMocks.h+8−1
@@ -95,7 +95,14 @@ class Application : public ApplicationInfoInterface
95{
95{
96 Q_OBJECT
96 Q_OBJECT
97public:
97public:
98+ Application(QString appId)
98− Application(QString appId) : ApplicationInfoInterface(appId, nullptr), m_appId(std::move(appId)) {}
99+ : ApplicationInfoInterface(appId, nullptr)
100+ , m_appId(std::move(appId))
101+ , m_state(Starting)
102+ , m_requestedState(RequestedRunning)
103+ {
104+
105+ }
99
106
100 void close() override {}
107 void close() override {}
101 QString appId() const override { return m_appId;}
108 QString appId() const override { return m_appId;}
tests/qmltests/ApplicationMenus/tst_MenuBar.qml+33
@@ -329,6 +329,14 @@ Item {
329 return false;
329 return false;
330 }, true);
330 }, true);
331
331
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+
332 tryCompareFunction(function() {
340 tryCompareFunction(function() {
333 menuBackend.removeRow(0);
341 menuBackend.removeRow(0);
334 wait(1);
342 wait(1);
@@ -339,6 +347,31 @@ Item {
339 }, true);
347 }, true);
340 }
348 }
341
349
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+
342 function test_firstDisabled() {
375 function test_firstDisabled() {
343 var data = appMenuData.generateTestData(10,5,2,3);
376 var data = appMenuData.generateTestData(10,5,2,3);
344 data[0].submenu[1].submenu[0].rowData.sensitive = false;
377 data[0].submenu[1].submenu[0].rowData.sensitive = false;
tests/qmltests/Greeter/TestView.qml−5
@@ -46,7 +46,6 @@ Item {
46 signal tease()
46 signal tease()
47 signal emergencyCall()
47 signal emergencyCall()
48
48
49− signal _showLastChanceCalled()
50 signal _hideCalled()
49 signal _hideCalled()
51 signal _showFakePasswordCalled()
50 signal _showFakePasswordCalled()
52 signal _notifyAuthenticationFailedCalled()
51 signal _notifyAuthenticationFailedCalled()
@@ -54,10 +53,6 @@ Item {
54 signal _forceShowCalled()
53 signal _forceShowCalled()
55 signal _tryToUnlockCalled(bool toTheRight)
54 signal _tryToUnlockCalled(bool toTheRight)
56
55
57− function showLastChance() {
58− _showLastChanceCalled();
59− }
60−
61 function hide() {
56 function hide() {
62 _hideCalled();
57 _hideCalled();
63 _required = false;
58 _required = false;
tests/qmltests/Greeter/tst_Greeter.qml−7
@@ -94,12 +94,6 @@ Item {
94 property Item greeter: loader.status === Loader.Ready ? loader.item : null
94 property Item greeter: loader.status === Loader.Ready ? loader.item : null
95 property Item view
95 property Item view
96
96
97− SignalSpy {
98− id: viewShowLastChanceSpy
99− target: testCase.view
100− signalName: "_showLastChanceCalled"
101− }
102−
103 SignalSpy {
97 SignalSpy {
104 id: viewHideSpy
98 id: viewHideSpy
105 target: testCase.view
99 target: testCase.view
@@ -147,7 +141,6 @@ Item {
147 Biometryd.available = true;
141 Biometryd.available = true;
148 AccountsService.enableFingerprintIdentification = true;
142 AccountsService.enableFingerprintIdentification = true;
149 AccountsService.failedFingerprintLogins = 0;
143 AccountsService.failedFingerprintLogins = 0;
150− viewShowLastChanceSpy.clear();
151 viewHideSpy.clear();
144 viewHideSpy.clear();
152 viewShowFakePasswordSpy.clear();
145 viewShowFakePasswordSpy.clear();
153 viewAuthenticationFailedSpy.clear();
146 viewAuthenticationFailedSpy.clear();
tests/qmltests/Launcher/tst_Launcher.qml+32−6
@@ -1254,14 +1254,14 @@ Rectangle {
1254 tryCompare(quickList, "selectedIndex", 0)
1254 tryCompare(quickList, "selectedIndex", 0)
1255
1255
1256 // Down should move down the quicklist
1256 // Down should move down the quicklist
1257+ // Because item 1 is not selectable
1257 keyClick(Qt.Key_Down);
1258 keyClick(Qt.Key_Down);
1258− tryCompare(quickList, "selectedIndex", 1)
1259+ tryCompare(quickList, "selectedIndex", 2)
1259
1260
1260 // The quicklist should wrap around too
1261 // The quicklist should wrap around too
1261 keyClick(Qt.Key_Down);
1262 keyClick(Qt.Key_Down);
1262 keyClick(Qt.Key_Down);
1263 keyClick(Qt.Key_Down);
1263 keyClick(Qt.Key_Down);
1264 keyClick(Qt.Key_Down);
1264− keyClick(Qt.Key_Down);
1265 tryCompare(quickList, "selectedIndex", 0)
1265 tryCompare(quickList, "selectedIndex", 0)
1266
1266
1267 // Left gets us back to the launcher
1267 // Left gets us back to the launcher
@@ -1286,14 +1286,14 @@ Rectangle {
1286
1286
1287 keyClick(Qt.Key_Down); // Down to launcher item 0
1287 keyClick(Qt.Key_Down); // Down to launcher item 0
1288 keyClick(Qt.Key_Down); // Down to launcher item 1
1288 keyClick(Qt.Key_Down); // Down to launcher item 1
1289− keyClick(Qt.Key_Right); // Into quicklist
1289+ keyClick(Qt.Key_Right); // Into quicklist, item 0 is selected
1290− keyClick(Qt.Key_Down); // Down to quicklist item 1
1291− keyClick(Qt.Key_Down); // Down to quicklist item 2
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
1292 keyClick(Qt.Key_Enter); // Trigger it
1292 keyClick(Qt.Key_Enter); // Trigger it
1293
1293
1294 compare(signalSpy.count, 1, "Quicklist signal wasn't triggered")
1294 compare(signalSpy.count, 1, "Quicklist signal wasn't triggered")
1295 compare(signalSpy.signalArguments[0][0], LauncherModel.get(1).appId)
1295 compare(signalSpy.signalArguments[0][0], LauncherModel.get(1).appId)
1296− compare(signalSpy.signalArguments[0][1], 2)
1296+ compare(signalSpy.signalArguments[0][1], 3)
1297 assertFocusOnIndex(-2);
1297 assertFocusOnIndex(-2);
1298 }
1298 }
1299
1299
@@ -1542,5 +1542,31 @@ Rectangle {
1542 tryCompare(launcher, "maxPanelX", 0);
1542 tryCompare(launcher, "maxPanelX", 0);
1543 launcher.panelWidth = oldSize;
1543 launcher.panelWidth = oldSize;
1544 }
1544 }
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+ }
1545 }
1571 }
1546}
1572}
tests/qmltests/Stage/tst_DesktopStage.qml+17
@@ -100,8 +100,15 @@ Item {
100 orientations: Orientations {}
100 orientations: Orientations {}
101 applicationManager: ApplicationManager
101 applicationManager: ApplicationManager
102 topLevelSurfaceList: topSurfaceList
102 topLevelSurfaceList: topSurfaceList
103+ availableDesktopArea: availableDesktopAreaItem
103 interactive: true
104 interactive: true
104 mode: "windowed"
105 mode: "windowed"
106+
107+ Item {
108+ id: availableDesktopAreaItem
109+ anchors.fill: parent
110+ anchors.topMargin: PanelState.panelHeight
111+ }
105 }
112 }
106 }
113 }
107 }
114 }
@@ -1057,5 +1064,15 @@ Item {
1057 tap(maxButton);
1064 tap(maxButton);
1058 tryCompare(appDelegate, "state", "maximized");
1065 tryCompare(appDelegate, "state", "maximized");
1059 }
1066 }
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+ }
1060 }
1077 }
1061}
1078}
tests/qmltests/Stage/tst_PhoneStage.qml+5
@@ -52,6 +52,11 @@ Item {
52 applicationManager: ApplicationManager
52 applicationManager: ApplicationManager
53 surfaceManager: sMgr
53 surfaceManager: sMgr
54 }
54 }
55+ availableDesktopArea: availableDesktopAreaItem
56+ Item {
57+ id: availableDesktopAreaItem
58+ anchors.fill: parent
59+ }
55 Component.onCompleted: {
60 Component.onCompleted: {
56 ApplicationManager.startApplication("unity8-dash");
61 ApplicationManager.startApplication("unity8-dash");
57 }
62 }
tests/qmltests/Stage/tst_TabletStage.qml+5
@@ -61,6 +61,11 @@ Rectangle {
61 applicationManager: ApplicationManager
61 applicationManager: ApplicationManager
62 surfaceManager: sMgr
62 surfaceManager: sMgr
63 }
63 }
64+ availableDesktopArea: availableDesktopAreaItem
65+ Item {
66+ id: availableDesktopAreaItem
67+ anchors.fill: parent
68+ }
64 Component.onCompleted: {
69 Component.onCompleted: {
65 ApplicationManager.startApplication("unity8-dash");
70 ApplicationManager.startApplication("unity8-dash");
66 }
71 }
tests/qmltests/Wizard/tst_Wizard.qml−6
@@ -336,8 +336,6 @@ Item {
336 // now finish up
336 // now finish up
337 page = waitForPage("reportingPage");
337 page = waitForPage("reportingPage");
338 tap(findChild(page, "forwardButton"));
338 tap(findChild(page, "forwardButton"));
339− page = waitForPage("systemUpdatePage");
340− tap(findChild(page, "forwardButton"));
341 page = waitForPage("finishedPage");
339 page = waitForPage("finishedPage");
342 waitUntilTransitionsEnd(page);
340 waitUntilTransitionsEnd(page);
343 tap(findChild(page, "finishButton"));
341 tap(findChild(page, "finishButton"));
@@ -378,8 +376,6 @@ Item {
378 // now finish up
376 // now finish up
379 page = waitForPage("reportingPage");
377 page = waitForPage("reportingPage");
380 tap(findChild(page, "forwardButton"));
378 tap(findChild(page, "forwardButton"));
381− page = waitForPage("systemUpdatePage");
382− tap(findChild(page, "forwardButton"));
383 page = waitForPage("finishedPage");
379 page = waitForPage("finishedPage");
384 waitUntilTransitionsEnd(page);
380 waitUntilTransitionsEnd(page);
385 tap(findChild(page, "finishButton"));
381 tap(findChild(page, "finishButton"));
@@ -398,8 +394,6 @@ Item {
398 tap(findChild(page, "forwardButton"));
394 tap(findChild(page, "forwardButton"));
399 page = waitForPage("reportingPage");
395 page = waitForPage("reportingPage");
400 tap(findChild(page, "forwardButton"));
396 tap(findChild(page, "forwardButton"));
401− page = waitForPage("systemUpdatePage");
402− tap(findChild(page, "forwardButton"));
403 page = waitForPage("finishedPage");
397 page = waitForPage("finishedPage");
404 waitUntilTransitionsEnd(page);
398 waitUntilTransitionsEnd(page);
405 tap(findChild(page, "finishButton"));
399 tap(findChild(page, "finishButton"));
tests/qmltests/tst_Shell.qml+19
@@ -1460,6 +1460,25 @@ Rectangle {
1460 confirmLoggedIn(true);
1460 confirmLoggedIn(true);
1461 }
1461 }
1462
1462
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+
1463 function test_launcherInverted_data() {
1482 function test_launcherInverted_data() {
1464 return [
1483 return [
1465 {tag: "phone", formFactor: "phone", usageScenario: "phone", launcherInverted: true},
1484 {tag: "phone", formFactor: "phone", usageScenario: "phone", launcherInverted: true},
tests/qmltests/tst_ShellWithPin.qml−40
@@ -21,7 +21,6 @@ import AccountsService 0.1
21import GSettings 1.0
21import GSettings 1.0
22import LightDMController 0.1
22import LightDMController 0.1
23import LightDM.FullLightDM 0.1 as LightDM
23import LightDM.FullLightDM 0.1 as LightDM
24−import Ubuntu.SystemImage 0.1
25import Ubuntu.Telephony 0.1 as Telephony
24import Ubuntu.Telephony 0.1 as Telephony
26import Unity.Application 0.1
25import Unity.Application 0.1
27import Unity.Test 0.1 as UT
26import Unity.Test 0.1 as UT
@@ -90,19 +89,6 @@ Item {
90 text: "Show Greeter"
89 text: "Show Greeter"
91 onClicked: LightDM.Greeter.showGreeter()
90 onClicked: LightDM.Greeter.showGreeter()
92 }
91 }
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− }
106 }
92 }
107 }
93 }
108 }
94 }
@@ -112,12 +98,6 @@ Item {
112 signalName: "sessionStarted"
98 signalName: "sessionStarted"
113 }
99 }
114
100
115− SignalSpy {
116− id: resetSpy
117− target: SystemImage
118− signalName: "resettingDevice"
119− }
120−
121 Telephony.CallEntry {
101 Telephony.CallEntry {
122 id: phoneCall
102 id: phoneCall
123 phoneNumber: "+447812221111"
103 phoneNumber: "+447812221111"
@@ -150,7 +130,6 @@ Item {
150 sessionSpy.target = greeter;
130 sessionSpy.target = greeter;
151 swipeAwayGreeter(true);
131 swipeAwayGreeter(true);
152 greeter.failedLoginsDelayAttempts = -1;
132 greeter.failedLoginsDelayAttempts = -1;
153− greeter.maxFailedLogins = -1;
154
133
155 var launcher = findChild(shell, "launcher");
134 var launcher = findChild(shell, "launcher");
156 var panel = findChild(launcher, "launcherPanel");
135 var panel = findChild(launcher, "launcherPanel");
@@ -373,25 +352,6 @@ Item {
373 tryCompare(delayedLockscreen, "delayMinutes", greeter.failedLoginsDelayMinutes);
352 tryCompare(delayedLockscreen, "delayMinutes", greeter.failedLoginsDelayMinutes);
374 }
353 }
375
354
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−
395 function test_emergencyDialerLockOut() {
355 function test_emergencyDialerLockOut() {
396 // This is a theoretical attack on the lockscreen: Enter emergency
356 // This is a theoretical attack on the lockscreen: Enter emergency
397 // dialer mode on a phone, then plug into a larger screen,
357 // dialer mode on a phone, then plug into a larger screen,
tools/CMakeLists.txt+1
@@ -1,3 +1,4 @@
1+add_subdirectory(indicatorsclient)
1add_subdirectory(menutool)
2add_subdirectory(menutool)
2add_subdirectory(scopetool)
3add_subdirectory(scopetool)
3
4
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.