on df345d2 help sign in
debian/unity8.install+4
since splitsnapshots
unifiedsplit
@@ -16,7 +16,11 @@ usr/share/unity8/Rotation
16usr/share/unity8/DeviceConfiguration.qml
16usr/share/unity8/DeviceConfiguration.qml
17usr/share/unity8/OrientedShell.qml
17usr/share/unity8/OrientedShell.qml
18usr/share/unity8/DisabledScreenNotice.qml
18usr/share/unity8/DisabledScreenNotice.qml
19+usr/share/unity8/qmldir
19usr/share/unity8/Shell.qml
20usr/share/unity8/Shell.qml
21+usr/share/unity8/ShellApplication.qml
22+usr/share/unity8/ShellNotifier.qml
23+usr/share/unity8/ShellScreen.qml
20usr/share/unity8/Stage
24usr/share/unity8/Stage
21usr/share/unity8/Tutorial
25usr/share/unity8/Tutorial
22usr/share/unity8/Wizard
26usr/share/unity8/Wizard
plugins/Cursor/CMakeLists.txt+1
@@ -15,6 +15,7 @@ set(QMLPLUGIN_SRC
15 CursorImageInfo.cpp
15 CursorImageInfo.cpp
16 CursorImageProvider.cpp
16 CursorImageProvider.cpp
17 MousePointer.cpp
17 MousePointer.cpp
18+ InputDispatcherFilter.cpp
18 # We need to run moc on this header
19 # We need to run moc on this header
19 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h
20 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h
20 )
21 )
plugins/Cursor/InputDispatcherFilter.cppnew file+175
@@ -0,0 +1,175 @@
1+/*
2+ * Copyright (C) 2016 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 "InputDispatcherFilter.h"
18+#include "MousePointer.h"
19+
20+#include <QEvent>
21+#include <QGuiApplication>
22+#include <QQuickWindow>
23+#include <QScreen>
24+#include <QtMath>
25+#include <qpa/qplatformnativeinterface.h>
26+#include <qpa/qplatformscreen.h>
27+
28+InputDispatcherFilter *InputDispatcherFilter::instance()
29+{
30+ static InputDispatcherFilter filter;
31+ return &filter;
32+}
33+
34+InputDispatcherFilter::InputDispatcherFilter(QObject *parent)
35+ : QObject(parent)
36+ , m_pushing(false)
37+{
38+ QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface();
39+ m_inputDispatcher = static_cast<QObject*>(ni->nativeResourceForIntegration("InputDispatcher"));
40+ if (m_inputDispatcher) {
41+ m_inputDispatcher->installEventFilter(this);
42+ }
43+}
44+
45+void InputDispatcherFilter::registerPointer(MousePointer *pointer)
46+{
47+ // allow first registered pointer to be visible.
48+ m_pointers.insert(pointer);
49+}
50+
51+void InputDispatcherFilter::unregisterPointer(MousePointer *pointer)
52+{
53+ m_pointers.remove(pointer);
54+}
55+
56+bool InputDispatcherFilter::eventFilter(QObject *o, QEvent *e)
57+{
58+ if (o != m_inputDispatcher) return false;
59+
60+ switch (e->type()) {
61+ case QEvent::MouseMove:
62+ case QEvent::MouseButtonPress:
63+ case QEvent::MouseButtonRelease:
64+ {
65+ // if we don't have any pointers, filter all mouse events.
66+ auto pointer = currentPointer();
67+ if (!pointer) return true;
68+
69+ QMouseEvent* me = static_cast<QMouseEvent*>(e);
70+
71+ // Local position gives relative change of mouse pointer.
72+ QPointF movement = me->localPos();
73+
74+ // Adjust the position
75+ QPointF oldPos = pointer->window()->geometry().topLeft() + pointer->position();
76+ QPointF newPos = adjustedPositionForMovement(oldPos, movement);
77+
78+ QScreen* currentScreen = screenAt(newPos);
79+ if (currentScreen) {
80+ QRect screenRect = currentScreen->geometry();
81+ qreal newX = (oldPos + movement).x();
82+ qreal newY = (oldPos + movement).y();
83+
84+ if (newX <= screenRect.left() && newY < screenRect.top() + pointer->topBoundaryOffset()) { // top left corner
85+ const auto distance = qSqrt(qPow(newX, 2) + qPow(newY- screenRect.top() - pointer->topBoundaryOffset(), 2));
86+ Q_EMIT pushedTopLeftCorner(currentScreen, qAbs(distance), me->buttons());
87+ m_pushing = true;
88+ } else if (newX >= screenRect.right()-1 && newY < screenRect.top() + pointer->topBoundaryOffset()) { // top right corner
89+ const auto distance = qSqrt(qPow(newX-screenRect.right(), 2) + qPow(newY - screenRect.top() - pointer->topBoundaryOffset(), 2));
90+ Q_EMIT pushedTopRightCorner(currentScreen, qAbs(distance), me->buttons());
91+ m_pushing = true;
92+ } else if (newX < 0 && newY >= screenRect.bottom()-1) { // bottom left corner
93+ const auto distance = qSqrt(qPow(newX, 2) + qPow(newY-screenRect.bottom(), 2));
94+ Q_EMIT pushedBottomLeftCorner(currentScreen, qAbs(distance), me->buttons());
95+ m_pushing = true;
96+ } else if (newX >= screenRect.right()-1 && newY >= screenRect.bottom()-1) { // bottom right corner
97+ const auto distance = qSqrt(qPow(newX-screenRect.right(), 2) + qPow(newY-screenRect.bottom(), 2));
98+ Q_EMIT pushedBottomRightCorner(currentScreen, qAbs(distance), me->buttons());
99+ m_pushing = true;
100+ } else if (newX < screenRect.left()) { // left edge
101+ Q_EMIT pushedLeftBoundary(currentScreen, qAbs(newX), me->buttons());
102+ m_pushing = true;
103+ } else if (newX >= screenRect.right()) { // right edge
104+ Q_EMIT pushedRightBoundary(currentScreen, newX - (screenRect.right() - 1), me->buttons());
105+ m_pushing = true;
106+ } else if (newY < screenRect.top() + pointer->topBoundaryOffset()) { // top edge
107+ Q_EMIT pushedTopBoundary(currentScreen, qAbs(newY - screenRect.top() - pointer->topBoundaryOffset()), me->buttons());
108+ m_pushing = true;
109+ } else if (Q_LIKELY(newX > 0 && newX < screenRect.right()-1 && newY > 0 && newY < screenRect.bottom()-1)) { // normal pos, not pushing
110+ if (m_pushing) {
111+ Q_EMIT pushStopped(currentScreen);
112+ m_pushing = false;
113+ }
114+ }
115+ }
116+
117+ // Send the event
118+ QMouseEvent eCopy(me->type(), me->localPos(), newPos, me->button(), me->buttons(), me->modifiers());
119+ eCopy.setTimestamp(me->timestamp());
120+ o->event(&eCopy);
121+ return true;
122+ }
123+ default:
124+ break;
125+ }
126+ return false;
127+}
128+
129+QPointF InputDispatcherFilter::adjustedPositionForMovement(const QPointF &pt, const QPointF &movement) const
130+{
131+ QPointF adjusted = pt + movement;
132+
133+ auto screen = screenAt(adjusted); // first check if our move was to a screen with an enabled pointer.
134+ if (screen) {
135+ return adjusted;
136+ } else if ((screen = screenAt(pt))) { // then check if our old position was valid
137+ QRectF screenBounds = screen->geometry();
138+ // bound the new position to the old screen geometry
139+ adjusted.rx() = qMax(screenBounds.left(), qMin(adjusted.x(), screenBounds.right()-1));
140+ adjusted.ry() = qMax(screenBounds.top(), qMin(adjusted.y(), screenBounds.bottom()-1));
141+ } else {
142+ auto screens = QGuiApplication::screens();
143+
144+ // center of first screen with a pointer.
145+ Q_FOREACH(QScreen* screen, screens) {
146+ Q_FOREACH(MousePointer* pointer, m_pointers) {
147+ if (pointer->isEnabled() && pointer->screen() == screen) {
148+ return screen->geometry().center();
149+ }
150+ }
151+ }
152+ }
153+ return adjusted;
154+}
155+
156+QScreen *InputDispatcherFilter::screenAt(const QPointF &pt) const
157+{
158+ Q_FOREACH(MousePointer* pointer, m_pointers) {
159+ if (!pointer->isEnabled()) continue;
160+
161+ QScreen* screen = pointer->screen();
162+ if (screen && screen->geometry().contains(pt.toPoint()))
163+ return screen;
164+ }
165+ return nullptr;
166+}
167+
168+MousePointer *InputDispatcherFilter::currentPointer() const
169+{
170+ Q_FOREACH(MousePointer* pointer, m_pointers) {
171+ if (!pointer->isEnabled()) continue;
172+ return pointer;
173+ }
174+ return nullptr;
175+}
plugins/Cursor/InputDispatcherFilter.hnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (C) 2016 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 INPUTDISPATCHERFILTER_H
18+#define INPUTDISPATCHERFILTER_H
19+
20+#include <QObject>
21+#include <QPointF>
22+#include <QSet>
23+
24+class MousePointer;
25+class QScreen;
26+
27+class InputDispatcherFilter : public QObject
28+{
29+ Q_OBJECT
30+public:
31+ static InputDispatcherFilter *instance();
32+
33+ void registerPointer(MousePointer* pointer);
34+ void unregisterPointer(MousePointer* pointer);
35+
36+Q_SIGNALS:
37+ void pushedLeftBoundary(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
38+ void pushedRightBoundary(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
39+ void pushedTopBoundary(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
40+ void pushedTopLeftCorner(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
41+ void pushedTopRightCorner(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
42+ void pushedBottomLeftCorner(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
43+ void pushedBottomRightCorner(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
44+ void pushStopped(QScreen* screen);
45+
46+protected:
47+ InputDispatcherFilter(QObject* parent = nullptr);
48+
49+ bool eventFilter(QObject *o, QEvent *e) override;
50+
51+ QPointF adjustedPositionForMovement(const QPointF& pt, const QPointF& movement) const;
52+ QScreen* screenAt(const QPointF& pt) const;
53+
54+ MousePointer* currentPointer() const;
55+
56+private:
57+ QObject* m_inputDispatcher;
58+ QSet<MousePointer*> m_pointers;
59+ bool m_pushing;
60+};
61+
62+#endif // INPUTDISPATCHERFILTER_H
plugins/Cursor/MousePointer.cpp+64−78
@@ -16,84 +16,74 @@
16
16
17#include "MousePointer.h"
17#include "MousePointer.h"
18#include "CursorImageProvider.h"
18#include "CursorImageProvider.h"
19−
19+#include "InputDispatcherFilter.h"
20−// Unity API
21−#include <unity/shell/application/MirPlatformCursor.h>
22
20
23#include <QQuickWindow>
21#include <QQuickWindow>
24−#include <QGuiApplication>
25−#include <QtMath>
26
22
27−#include <qpa/qwindowsysteminterface.h>
23+// Unity API
24+#include <unity/shell/application/MirPlatformCursor.h>
28
25
29MousePointer::MousePointer(QQuickItem *parent)
26MousePointer::MousePointer(QQuickItem *parent)
30 : MirMousePointerInterface(parent)
27 : MirMousePointerInterface(parent)
31 , m_cursorName(QStringLiteral("left_ptr"))
28 , m_cursorName(QStringLiteral("left_ptr"))
32 , m_themeName(QStringLiteral("default"))
29 , m_themeName(QStringLiteral("default"))
33{
30{
34−}
31+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedLeftBoundary,
35−
32+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
36−void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
33+ if (window() && window()->screen() == screen) {
37− Qt::KeyboardModifiers modifiers)
34+ Q_EMIT pushedLeftBoundary(amount, buttons);
38−{
39− if (!parentItem()) {
40− return;
41− }
42−
43− if (!movement.isNull()) {
44− Q_EMIT mouseMoved();
45− }
35+ }
46−
36+ });
47− m_accumulatedMovement += movement;
37+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedRightBoundary,
48− // don't apply the fractional part
38+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
49− QPointF appliedMovement(int(m_accumulatedMovement.x()), int(m_accumulatedMovement.y()));
39+ if (window() && window()->screen() == screen) {
50− m_accumulatedMovement -= appliedMovement;
40+ Q_EMIT pushedRightBoundary(amount, buttons);
51−
41+ }
52− qreal newX = x() + appliedMovement.x();
42+ });
53− qreal newY = y() + appliedMovement.y();
43+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedTopBoundary,
54− const qreal sceneWidth = parentItem()->width();
44+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
55− const qreal sceneHeight = parentItem()->height();
45+ if (window() && window()->screen() == screen) {
56−
46+ Q_EMIT pushedTopBoundary(amount, buttons);
57− if (newX <= 0 && newY < m_topBoundaryOffset) { // top left corner
47+ }
58− const auto distance = qSqrt(qPow(newX, 2) + qPow(newY-m_topBoundaryOffset, 2));
48+ });
59− Q_EMIT pushedTopLeftCorner(qAbs(distance), buttons);
49+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedTopLeftCorner,
60− m_pushing = true;
50+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
61− } else if (newX >= sceneWidth-1 && newY < m_topBoundaryOffset) { // top right corner
51+ if (window() && window()->screen() == screen) {
62− const auto distance = qSqrt(qPow(newX-sceneWidth, 2) + qPow(newY-m_topBoundaryOffset, 2));
52+ Q_EMIT pushedTopLeftCorner(amount, buttons);
63− Q_EMIT pushedTopRightCorner(qAbs(distance), buttons);
53+ }
64− m_pushing = true;
54+ });
65− } else if (newX < 0 && newY >= sceneHeight-1) { // bottom left corner
55+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedTopRightCorner,
66− const auto distance = qSqrt(qPow(newX, 2) + qPow(newY-sceneHeight, 2));
56+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
67− Q_EMIT pushedBottomLeftCorner(qAbs(distance), buttons);
57+ if (window() && window()->screen() == screen) {
68− m_pushing = true;
58+ Q_EMIT pushedTopRightCorner(amount, buttons);
69− } else if (newX >= sceneWidth-1 && newY >= sceneHeight-1) { // bottom right corner
59+ }
70− const auto distance = qSqrt(qPow(newX-sceneWidth, 2) + qPow(newY-sceneHeight, 2));
60+ });
71− Q_EMIT pushedBottomRightCorner(qAbs(distance), buttons);
61+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedBottomLeftCorner,
72− m_pushing = true;
62+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
73− } else if (newX < 0) { // left edge
63+ if (window() && window()->screen() == screen) {
74− Q_EMIT pushedLeftBoundary(qAbs(newX), buttons);
64+ Q_EMIT pushedBottomLeftCorner(amount, buttons);
75− m_pushing = true;
65+ }
76− } else if (newX >= sceneWidth) { // right edge
66+ });
77− Q_EMIT pushedRightBoundary(newX - (sceneWidth - 1), buttons);
67+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedBottomRightCorner,
78− m_pushing = true;
68+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
79− } else if (newY < m_topBoundaryOffset) { // top edge
69+ if (window() && window()->screen() == screen) {
80− Q_EMIT pushedTopBoundary(qAbs(newY - m_topBoundaryOffset), buttons);
70+ Q_EMIT pushedBottomRightCorner(amount, buttons);
81− m_pushing = true;
71+ }
82− } else if (Q_LIKELY(newX > 0 && newX < sceneWidth-1 && newY > 0 && newY < sceneHeight-1)) { // normal pos, not pushing
72+ });
83− if (m_pushing) {
73+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushStopped,
74+ this, [this](QScreen* screen) {
75+ if (window() && window()->screen() == screen) {
84 Q_EMIT pushStopped();
76 Q_EMIT pushStopped();
85− m_pushing = false;
86 }
77 }
87− }
78+ });
88−
89− applyItemConfinement(newX, newY);
90
79
91− setX(qBound(0.0, newX, sceneWidth - 1));
80+ InputDispatcherFilter::instance()->registerPointer(this);
92− setY(qBound(0.0, newY, sceneHeight - 1));
81+}
93
82
94− QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0));
83+MousePointer::~MousePointer()
95− QWindowSystemInterface::handleMouseEvent(window(), timestamp, scenePosition /*local*/, scenePosition /*global*/,
84+{
96− buttons, modifiers);
85+ registerScreen(nullptr);
86+ InputDispatcherFilter::instance()->unregisterPointer(this);
97}
87}
98
88
99void MousePointer::applyItemConfinement(qreal &newX, qreal &newY)
89void MousePointer::applyItemConfinement(qreal &newX, qreal &newY)
@@ -121,17 +111,6 @@ void MousePointer::applyItemConfinement(qreal &newX, qreal &newY)
121 }
111 }
122}
112}
123
113
124−void MousePointer::handleWheelEvent(ulong timestamp, QPoint angleDelta, Qt::KeyboardModifiers modifiers)
125−{
126− if (!parentItem()) {
127− return;
128− }
129−
130− QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0));
131− QWindowSystemInterface::handleWheelEvent(window(), timestamp, scenePosition /* local */, scenePosition /* global */,
132− QPoint() /* pixelDelta */, angleDelta, modifiers, Qt::ScrollUpdate);
133−}
134−
135int MousePointer::topBoundaryOffset() const
114int MousePointer::topBoundaryOffset() const
136{
115{
137 return m_topBoundaryOffset;
116 return m_topBoundaryOffset;
@@ -182,7 +161,7 @@ void MousePointer::registerScreen(QScreen *screen)
182 if (m_registeredScreen) {
161 if (m_registeredScreen) {
183 auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
162 auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
184 if (previousCursor) {
163 if (previousCursor) {
185− previousCursor->setMousePointer(nullptr);
164+ previousCursor->unregisterMousePointer(this);
186 } else {
165 } else {
187 qCritical("QPlatformCursor is not a MirPlatformCursor! Cursor module only works in a Mir server.");
166 qCritical("QPlatformCursor is not a MirPlatformCursor! Cursor module only works in a Mir server.");
188 }
167 }
@@ -193,7 +172,7 @@ void MousePointer::registerScreen(QScreen *screen)
193 if (m_registeredScreen) {
172 if (m_registeredScreen) {
194 auto cursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
173 auto cursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
195 if (cursor) {
174 if (cursor) {
196− cursor->setMousePointer(this);
175+ cursor->registerMousePointer(this);
197 } else {
176 } else {
198 qCritical("QPlaformCursor is not a MirPlatformCursor! Cursor module only works in Mir.");
177 qCritical("QPlaformCursor is not a MirPlatformCursor! Cursor module only works in Mir.");
199 }
178 }
@@ -216,6 +195,12 @@ void MousePointer::setThemeName(const QString &themeName)
216 }
195 }
217}
196}
218
197
198+void MousePointer::moveTo(const QPoint &position)
199+{
200+ setPosition(position);
201+ Q_EMIT mouseMoved();
202+}
203+
219void MousePointer::setCustomCursor(const QCursor &customCursor)
204void MousePointer::setCustomCursor(const QCursor &customCursor)
220{
205{
221 CursorImageProvider::instance()->setCustomCursor(customCursor);
206 CursorImageProvider::instance()->setCustomCursor(customCursor);
@@ -233,3 +218,4 @@ void MousePointer::setConfiningItem(QQuickItem *item)
233 Q_EMIT confiningItemChanged();
218 Q_EMIT confiningItemChanged();
234 }
219 }
235}
220}
221+
plugins/Cursor/MousePointer.h+5−4
@@ -31,6 +31,7 @@ class MousePointer : public MirMousePointerInterface {
31 Q_PROPERTY(int topBoundaryOffset READ topBoundaryOffset WRITE setTopBoundaryOffset NOTIFY topBoundaryOffsetChanged)
31 Q_PROPERTY(int topBoundaryOffset READ topBoundaryOffset WRITE setTopBoundaryOffset NOTIFY topBoundaryOffsetChanged)
32public:
32public:
33 MousePointer(QQuickItem *parent = nullptr);
33 MousePointer(QQuickItem *parent = nullptr);
34+ ~MousePointer();
34
35
35 void setCursorName(const QString &qtCursorName) override;
36 void setCursorName(const QString &qtCursorName) override;
36 QString cursorName() const override { return m_cursorName; }
37 QString cursorName() const override { return m_cursorName; }
@@ -38,6 +39,8 @@ public:
38 void setThemeName(const QString &themeName) override;
39 void setThemeName(const QString &themeName) override;
39 QString themeName() const override { return m_themeName; }
40 QString themeName() const override { return m_themeName; }
40
41
42+ void moveTo(const QPoint& position) override;
43+
41 void setCustomCursor(const QCursor &) override;
44 void setCustomCursor(const QCursor &) override;
42
45
43 QQuickItem* confiningItem() const;
46 QQuickItem* confiningItem() const;
@@ -46,10 +49,7 @@ public:
46 int topBoundaryOffset() const;
49 int topBoundaryOffset() const;
47 void setTopBoundaryOffset(int topBoundaryOffset);
50 void setTopBoundaryOffset(int topBoundaryOffset);
48
51
49−public Q_SLOTS:
52+ QScreen* screen() const { return m_registeredScreen; }
50− void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
51− Qt::KeyboardModifiers modifiers) override;
52− void handleWheelEvent(ulong timestamp, QPoint angleDelta, Qt::KeyboardModifiers modifiers) override;
53
53
54Q_SIGNALS:
54Q_SIGNALS:
55 void pushedLeftBoundary(qreal amount, Qt::MouseButtons buttons);
55 void pushedLeftBoundary(qreal amount, Qt::MouseButtons buttons);
@@ -79,6 +79,7 @@ private:
79 QPointer<QScreen> m_registeredScreen;
79 QPointer<QScreen> m_registeredScreen;
80 QString m_cursorName;
80 QString m_cursorName;
81 QString m_themeName;
81 QString m_themeName;
82+ bool m_active;
82
83
83 // Accumulated, unapplied, mouse movement.
84 // Accumulated, unapplied, mouse movement.
84 QPointF m_accumulatedMovement;
85 QPointF m_accumulatedMovement;
plugins/UInput/plugin.cpp+7−1
@@ -19,8 +19,14 @@
19
19
20#include <QtQml/qqml.h>
20#include <QtQml/qqml.h>
21
21
22+
23+QObject* uinputSingleton(QQmlEngine*, QJSEngine*)
24+{
25+ return new UInput;
26+}
27+
22void UInputPlugin::registerTypes(const char *uri)
28void UInputPlugin::registerTypes(const char *uri)
23{
29{
24 Q_ASSERT(uri == QLatin1String("UInput"));
30 Q_ASSERT(uri == QLatin1String("UInput"));
25− qmlRegisterType<UInput>(uri, 0, 1, "UInput");
31+ qmlRegisterSingletonType<UInput>(uri, 0, 1, "UInput", uinputSingleton);
26}
32}
plugins/Unity/CMakeLists.txt+1
@@ -1,5 +1,6 @@
1add_subdirectory(ApplicationMenu)
1add_subdirectory(ApplicationMenu)
2add_subdirectory(Connectivity)
2add_subdirectory(Connectivity)
3+add_subdirectory(Debug)
3add_subdirectory(Indicators)
4add_subdirectory(Indicators)
4add_subdirectory(Launcher)
5add_subdirectory(Launcher)
5add_subdirectory(Session)
6add_subdirectory(Session)
plugins/Unity/Debug/CMakeLists.txtnew file+30
@@ -0,0 +1,30 @@
1+include_directories(
2+ ${CMAKE_CURRENT_SOURCE_DIR}
3+ ${CMAKE_CURRENT_BINARY_DIR}
4+)
5+
6+include_directories(
7+ SYSTEM
8+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
9+ ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
10+ ${GIO_INCLUDE_DIRS}
11+)
12+
13+set(QMLPLUGIN_SRC
14+ consolelog.cpp
15+ plugin.cpp
16+ )
17+
18+add_library(Debug-qml SHARED
19+ ${QMLPLUGIN_SRC}
20+ )
21+
22+# Because this is an internal support library, we want
23+# to expose all symbols in it. Consider changing this
24+# either to a static library or just using the
25+# files directly in targets.
26+set_target_properties(Debug-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
27+
28+qt5_use_modules(Debug-qml Qml Quick Concurrent)
29+
30+add_unity8_plugin(Unity.Debug 0.1 Unity/Debug TARGETS Debug-qml)
plugins/Unity/Debug/consolelog.cppnew file+221
@@ -0,0 +1,221 @@
1+/*
2+ * Copyright 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 Lesser 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 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 "consolelog.h"
18+
19+#include <unistd.h>
20+#include <stdio.h>
21+#include <thread>
22+#include <iostream>
23+#include <sys/ioctl.h>
24+
25+#include <functional>
26+
27+namespace
28+{
29+
30+int wait_fd(std::function<int(void)> fn)
31+{
32+ int ret = -1;
33+ bool fd_blocked = false;
34+ do
35+ {
36+ ret = fn();
37+ fd_blocked = (errno == EINTR || errno == EBUSY);
38+ if (fd_blocked)
39+ QThread::msleep(10);
40+ }
41+ while (ret < 0);
42+ return ret;
43+}
44+
45+#define PIPE_WAIT(val) wait_fd(std::bind(pipe, val))
46+#define DUP_WAIT(fd) wait_fd(std::bind(dup, fd))
47+#define DUP2_WAIT(fd1, fd2) wait_fd(std::bind(dup2, fd1, fd2))
48+#define CLOSE_WAIT(fd) wait_fd(std::bind(close, fd))
49+
50+}
51+
52+LogRedirector::LogRedirector()
53+ : m_ref(0)
54+ , m_stop(false)
55+{
56+ setObjectName("ConsoleLog");
57+
58+ // make stdout & stderr streams unbuffered
59+ // so that we don't need to flush the streams
60+ // before capture and after capture
61+ // (fflush can cause a deadlock if the stream is currently being used)
62+ setvbuf(stdout,NULL,_IONBF,0);
63+ setvbuf(stderr,NULL,_IONBF,0);
64+}
65+
66+void LogRedirector::run()
67+{
68+ PIPE_WAIT(m_pipe);
69+
70+ int oldStdOut = DUP_WAIT(fileno(stdout));
71+ int oldStdErr = DUP_WAIT(fileno(stderr));
72+
73+ DUP2_WAIT(m_pipe[WRITE], fileno(stdout));
74+ DUP2_WAIT(m_pipe[WRITE], fileno(stderr));
75+ CLOSE_WAIT(m_pipe[WRITE]);
76+
77+ while(true) {
78+ {
79+ QMutexLocker lock(&m_mutex);
80+ if (m_stop) break;
81+ }
82+ checkLog();
83+ QThread::msleep(50);
84+ }
85+
86+ DUP2_WAIT(oldStdOut, fileno(stdout));
87+ DUP2_WAIT(oldStdErr, fileno(stderr));
88+
89+ CLOSE_WAIT(oldStdOut);
90+ CLOSE_WAIT(oldStdErr);
91+ CLOSE_WAIT(m_pipe[READ]);
92+}
93+
94+
95+void LogRedirector::checkLog()
96+{
97+ // Do not allow read to block with no data.
98+ // If we stop the thread while waiting a read,
99+ // it will block the main thread waiting for this thread to stop.
100+ int count = 0;
101+ ioctl(m_pipe[READ], FIONREAD, &count);
102+ if (count <= 0) return;
103+
104+ std::string captured;
105+ std::string buf;
106+ const int bufSize = 1024;
107+ buf.resize(bufSize);
108+ int bytesRead = 0;
109+ bytesRead = read(m_pipe[READ], &(*buf.begin()), bufSize);
110+ while(bytesRead == bufSize)
111+ {
112+ captured += buf;
113+ bytesRead = 0;
114+ bytesRead = read(m_pipe[READ], &(*buf.begin()), bufSize);
115+ }
116+ if (bytesRead > 0)
117+ {
118+ buf.resize(bytesRead);
119+ captured += buf;
120+ }
121+
122+ if (!captured.empty()) {
123+ Q_EMIT log(QString::fromStdString(captured));
124+ }
125+}
126+
127+LogRedirector *LogRedirector::instance()
128+{
129+ static LogRedirector* log = nullptr;
130+ if (!log) {
131+ log = new LogRedirector();
132+ }
133+ return log;
134+}
135+
136+void LogRedirector::add(ConsoleLog* logger)
137+{
138+ QMutexLocker lock(&m_mutex);
139+ connect(this, &LogRedirector::log, logger, &ConsoleLog::logged, Qt::UniqueConnection);
140+
141+ m_ref++;
142+ if (!LogRedirector::instance()->isRunning()) {
143+ m_stop = false;
144+ LogRedirector::instance()->start();
145+ }
146+}
147+
148+void LogRedirector::remove(ConsoleLog* logger)
149+{
150+ QMutexLocker lock(&m_mutex);
151+ disconnect(this, &LogRedirector::log, logger, &ConsoleLog::logged);
152+
153+ m_ref = qMax(m_ref-1, 0);
154+ if (m_ref == 0 && LogRedirector::instance()->isRunning()) {
155+ m_stop = true;
156+ lock.unlock();
157+ LogRedirector::instance()->wait();
158+ }
159+}
160+
161+ConsoleLog::ConsoleLog(QObject *parent)
162+ : QObject(parent)
163+ , m_enabled(false)
164+ , m_maxLines(60)
165+{
166+ auto updateEnabled = [this]() {
167+ if (m_enabled) {
168+ LogRedirector::instance()->add(this);
169+ } else {
170+ LogRedirector::instance()->remove(this);
171+ }
172+ };
173+ connect(this, &ConsoleLog::enabledChanged, this, updateEnabled);
174+}
175+
176+ConsoleLog::~ConsoleLog()
177+{
178+ if (m_enabled) {
179+ LogRedirector::instance()->remove(this);
180+ }
181+}
182+
183+void ConsoleLog::setEnabled(bool enabled)
184+{
185+ if (m_enabled == enabled) {
186+ return;
187+ }
188+
189+ m_enabled = enabled;
190+ Q_EMIT enabledChanged();
191+}
192+
193+QString ConsoleLog::out() const
194+{
195+ return m_out.join("\n");
196+}
197+
198+void ConsoleLog::setMaxLines(int maxLines)
199+{
200+ if (m_maxLines == maxLines) {
201+ return;
202+ }
203+
204+ m_maxLines = maxLines;
205+ while (m_out.count() > m_maxLines) {
206+ m_out.removeLast();
207+ }
208+ Q_EMIT outChanged();
209+ Q_EMIT maxLinesChanged();
210+}
211+
212+void ConsoleLog::logged(QString captured)
213+{
214+ QStringList li = captured.split("\n", QString::SkipEmptyParts);
215+ li << m_out;
216+ m_out = li;
217+ while (m_out.count() > m_maxLines) {
218+ m_out.removeLast();
219+ }
220+ Q_EMIT outChanged();
221+}
plugins/Unity/Debug/consolelog.hnew file+87
@@ -0,0 +1,87 @@
1+/*
2+ * Copyright 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 Lesser 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 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 CONSOLELOG_H
18+#define CONSOLELOG_H
19+
20+#include <QThread>
21+#include <QMutex>
22+#include <QSet>
23+
24+class ConsoleLog;
25+
26+class LogRedirector : public QThread
27+{
28+ Q_OBJECT
29+public:
30+ static LogRedirector *instance();
31+
32+ void add(ConsoleLog* logger);
33+ void remove(ConsoleLog* logger);
34+
35+private Q_SLOTS:
36+ void checkLog();
37+
38+Q_SIGNALS:
39+ void log(QString log);
40+
41+private:
42+ LogRedirector();
43+ void run() Q_DECL_OVERRIDE;
44+
45+ QMutex m_mutex;
46+ int m_pipe[2];
47+ int m_ref;
48+ bool m_stop;
49+
50+ enum PIPES { READ, WRITE };
51+};
52+
53+class ConsoleLog : public QObject
54+{
55+ Q_OBJECT
56+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
57+ Q_PROPERTY(QString out READ out NOTIFY outChanged)
58+ Q_PROPERTY(int maxLines READ maxLines WRITE setMaxLines NOTIFY maxLinesChanged)
59+public:
60+ explicit ConsoleLog(QObject *parent = 0);
61+ ~ConsoleLog();
62+
63+ bool isEnabled() const { return m_enabled; }
64+ void setEnabled(bool enabled);
65+
66+ QString out() const;
67+
68+ int maxLines() const { return m_maxLines; }
69+ void setMaxLines(int maxLines);
70+
71+public Q_SLOTS:
72+ void logged(QString captured);
73+
74+Q_SIGNALS:
75+ void enabledChanged();
76+ void outChanged();
77+ void maxLinesChanged();
78+
79+private:
80+ void updateEnabled();
81+
82+ QStringList m_out;
83+ bool m_enabled;
84+ int m_maxLines;
85+};
86+
87+#endif // CONSOLELOG_H
plugins/Unity/Debug/plugin.cppnew file+31
@@ -0,0 +1,31 @@
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+// Qt
18+#include <QtQml/qqml.h>
19+
20+// self
21+#include "plugin.h"
22+
23+// local
24+#include "consolelog.h"
25+
26+void UnityDebugPlugin::registerTypes(const char *uri)
27+{
28+ Q_ASSERT(uri == QLatin1String("Unity.Debug"));
29+
30+ qmlRegisterType<ConsoleLog>(uri, 0, 1, "ConsoleLog");
31+}
src/ShellView.h → plugins/Unity/Debug/plugin.hrenamed+9−11
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2016 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
@@ -14,21 +14,19 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef UNITY_SHELL_VIEW_H
17+#ifndef UNITYDEBUG_PLUGIN_H
18−#define UNITY_SHELL_VIEW_H
18+#define UNITYDEBUG_PLUGIN_H
19
19
20−#include <QQuickView>
20+#include <QtQml/QQmlEngine>
21+#include <QtQml/QQmlExtensionPlugin>
21
22
22−class ShellView : public QQuickView
23+class UnityDebugPlugin : public QQmlExtensionPlugin
23{
24{
24 Q_OBJECT
25 Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25
27
26public:
28public:
27− ShellView(QQmlEngine *engine, QObject *qmlArgs);
29+ void registerTypes(const char *uri) override;
28−
29−private Q_SLOTS:
30− void onWidthChanged(int);
31− void onHeightChanged(int);
32};
30};
33
31
34−#endif // UNITY_SHELL_VIEW_H
32+#endif
plugins/Unity/Debug/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Unity.Debug
2+plugin Debug-qml
3+typeinfo Debug.qmltypes
qml/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−file(GLOB QML_JS_FILES *.qml *.js)
1+file(GLOB QML_JS_FILES *.qml *.js qmldir)
2
2
3install(FILES ${QML_JS_FILES}
3install(FILES ${QML_JS_FILES}
4 DESTINATION ${SHELL_APP_DIR}
4 DESTINATION ${SHELL_APP_DIR}
qml/Components/PanelState/PanelState.qml−1
@@ -14,7 +14,6 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−pragma Singleton
18import QtQuick 2.4
17import QtQuick 2.4
19
18
20QtObject {
19QtObject {
qml/Components/PanelState/qmldir+1−1
@@ -1 +1 @@
1−singleton PanelState 1.0 PanelState.qml
1+PanelState 1.0 PanelState.qml
qml/Components/VirtualTouchPad.qml+13−19
@@ -24,16 +24,14 @@ import "../Components"
24
24
25Item {
25Item {
26 id: root
26 id: root
27− property var uinput: UInput {
28− Component.onCompleted: createMouse();
29− Component.onDestruction: removeMouse();
30− }
31
27
32 Component.onCompleted: {
28 Component.onCompleted: {
29+ UInput.createMouse();
33 if (!settings.touchpadTutorialHasRun) {
30 if (!settings.touchpadTutorialHasRun) {
34 root.runTutorial()
31 root.runTutorial()
35 }
32 }
36 }
33 }
34+ Component.onDestruction: UInput.removeMouse()
37
35
38 function runTutorial() {
36 function runTutorial() {
39 // If the tutorial animation is started too early, e.g. in Component.onCompleted,
37 // If the tutorial animation is started too early, e.g. in Component.onCompleted,
@@ -85,7 +83,7 @@ Item {
85 if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))
83 if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))
86 && clickTimer.running) {
84 && clickTimer.running) {
87 clickTimer.stop();
85 clickTimer.stop();
88− uinput.pressMouse(UInput.ButtonLeft)
86+ UInput.pressMouse(UInput.ButtonLeft)
89 isDoubleClick = true;
87 isDoubleClick = true;
90 }
88 }
91 isClick = true;
89 isClick = true;
@@ -104,7 +102,7 @@ Item {
104
102
105 onReleased: {
103 onReleased: {
106 if (isDoubleClick || isDrag) {
104 if (isDoubleClick || isDrag) {
107− uinput.releaseMouse(UInput.ButtonLeft)
105+ UInput.releaseMouse(UInput.ButtonLeft)
108 isDoubleClick = false;
106 isDoubleClick = false;
109 }
107 }
110 if (isClick) {
108 if (isClick) {
@@ -120,8 +118,8 @@ Item {
120 interval: 200
118 interval: 200
121 property int button: UInput.ButtonLeft
119 property int button: UInput.ButtonLeft
122 onTriggered: {
120 onTriggered: {
123− uinput.pressMouse(button);
121+ UInput.pressMouse(button);
124− uinput.releaseMouse(button);
122+ UInput.releaseMouse(button);
125 }
123 }
126 function scheduleClick(button) {
124 function scheduleClick(button) {
127 clickTimer.button = button;
125 clickTimer.button = button;
@@ -138,7 +136,7 @@ Item {
138 isDrag = true;
136 isDrag = true;
139 }
137 }
140
138
141− uinput.moveMouse(tp.x - tp.previousX, tp.y - tp.previousY);
139+ UInput.moveMouse(tp.x - tp.previousX, tp.y - tp.previousY);
142 }
140 }
143
141
144 function scroll(touchPoints) {
142 function scroll(touchPoints) {
@@ -166,7 +164,7 @@ Item {
166 dh /= 2;
164 dh /= 2;
167 dv /= 2;
165 dv /= 2;
168
166
169− uinput.scrollMouse(dh, dv);
167+ UInput.scrollMouse(dh, dv);
170 }
168 }
171
169
172 touchPoints: [
170 touchPoints: [
@@ -189,8 +187,8 @@ Item {
189 objectName: "leftButton"
187 objectName: "leftButton"
190 Layout.fillWidth: true
188 Layout.fillWidth: true
191 Layout.fillHeight: true
189 Layout.fillHeight: true
192− onPressed: uinput.pressMouse(UInput.ButtonLeft);
190+ onPressed: UInput.pressMouse(UInput.ButtonLeft);
193− onReleased: uinput.releaseMouse(UInput.ButtonLeft);
191+ onReleased: UInput.releaseMouse(UInput.ButtonLeft);
194 property bool highlight: false
192 property bool highlight: false
195 UbuntuShape {
193 UbuntuShape {
196 anchors.fill: parent
194 anchors.fill: parent
@@ -204,8 +202,8 @@ Item {
204 objectName: "rightButton"
202 objectName: "rightButton"
205 Layout.fillWidth: true
203 Layout.fillWidth: true
206 Layout.fillHeight: true
204 Layout.fillHeight: true
207− onPressed: uinput.pressMouse(UInput.ButtonRight);
205+ onPressed: UInput.pressMouse(UInput.ButtonRight);
208− onReleased: uinput.releaseMouse(UInput.ButtonRight);
206+ onReleased: UInput.releaseMouse(UInput.ButtonRight);
209 property bool highlight: false
207 property bool highlight: false
210 UbuntuShape {
208 UbuntuShape {
211 anchors.fill: parent
209 anchors.fill: parent
@@ -239,14 +237,10 @@ Item {
239 }
237 }
240 }
238 }
241
239
242− Screens {
243− id: screens
244− }
245−
246 InputMethod {
240 InputMethod {
247 id: inputMethod
241 id: inputMethod
248 // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
242 // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
249− enabled: screens.count > 1 && settings.oskEnabled && !tutorial.running
243+ enabled: Screens.count > 1 && settings.oskEnabled && !tutorial.running
250 objectName: "inputMethod"
244 objectName: "inputMethod"
251 anchors.fill: parent
245 anchors.fill: parent
252 }
246 }
qml/DisabledScreenNotice.qml+2−1
@@ -28,8 +28,9 @@ Item {
28 property var screen: Screen
28 property var screen: Screen
29 property var orientationLock: OrientationLock
29 property var orientationLock: OrientationLock
30
30
31+ property alias deviceConfiguration: _deviceConfiguration
31 DeviceConfiguration {
32 DeviceConfiguration {
32− id: deviceConfiguration
33+ id: _deviceConfiguration
33 name: applicationArguments.deviceName
34 name: applicationArguments.deviceName
34 }
35 }
35
36
qml/Greeter/Greeter.qml+21−3
@@ -25,6 +25,7 @@ import Unity.Launcher 0.1
25import Unity.Session 0.1
25import Unity.Session 0.1
26
26
27import "." 0.1
27import "." 0.1
28+import ".." 0.1
28import "../Components"
29import "../Components"
29
30
30Showable {
31Showable {
@@ -234,7 +235,7 @@ Showable {
234 if (forcedUnlock && shown) {
235 if (forcedUnlock && shown) {
235 hideView();
236 hideView();
236 if (hideNow) {
237 if (hideNow) {
237− root.hideNow(); // skip hide animation
238+ ShellNotifier.greeter.hide(true); // skip hide animation
238 }
239 }
239 }
240 }
240 }
241 }
@@ -397,7 +398,7 @@ Showable {
397 onEmergencyCall: root.emergencyCall()
398 onEmergencyCall: root.emergencyCall()
398 onRequiredChanged: {
399 onRequiredChanged: {
399 if (!loader.item.required) {
400 if (!loader.item.required) {
400− root.hide();
401+ ShellNotifier.greeter.hide(false);
401 }
402 }
402 }
403 }
403 }
404 }
@@ -529,12 +530,29 @@ Showable {
529 onRequestAuthenticationUser: d.selectUser(d.getUserIndex(user), true)
530 onRequestAuthenticationUser: d.selectUser(d.getUserIndex(user), true)
530 }
531 }
531
532
533+ Connections {
534+ target: ShellNotifier.greeter
535+ onHide: {
536+ if (now) {
537+ root.hideNow(); // skip hide animation
538+ } else {
539+ root.hide();
540+ }
541+ }
542+ }
543+
544+ Binding {
545+ target: ShellNotifier.greeter
546+ property: "shown"
547+ value: root.shown
548+ }
549+
532 Connections {
550 Connections {
533 target: DBusUnitySessionService
551 target: DBusUnitySessionService
534 onLockRequested: root.forceShow()
552 onLockRequested: root.forceShow()
535 onUnlocked: {
553 onUnlocked: {
536 root.forcedUnlock = true;
554 root.forcedUnlock = true;
537− root.hideNow();
555+ ShellNotifier.greeter.hide(true);
538 }
556 }
539 }
557 }
540
558
qml/Greeter/SecondaryGreeter.qmlnew file+75
@@ -0,0 +1,75 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+
20+import "../Components"
21+import ".." 0.1
22+
23+Showable {
24+ id: root
25+
26+ readonly property bool active: required || hasLockedApp
27+
28+ readonly property bool hasLockedApp: lockedApp !== ""
29+ readonly property bool locked: false
30+ readonly property bool waiting: false
31+ readonly property bool fullyShown: shown
32+
33+ property string lockedApp: ""
34+
35+ function forceShow() { show(); }
36+ property var notifyAppFocusRequested: (function(appId) { return; })
37+ property var notifyUserRequestedApp: (function(appId) { return; })
38+ property var notifyShowingDashFromDrag: (function(appId) { return false; })
39+
40+ showAnimation: StandardAnimation { property: "opacity"; to: 1 }
41+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
42+
43+ shown: ShellNotifier.greeter.shown
44+ Component.onCompleted: opacity = shown ? 1 : 0
45+ visible: opacity != 0
46+
47+ Rectangle {
48+ anchors.fill: parent
49+ color: UbuntuColors.purple
50+ }
51+
52+ MouseArea {
53+ anchors.fill: parent
54+ acceptedButtons: Qt.AllButtons
55+ onWheel: wheel.accepted = true
56+ }
57+
58+ Connections {
59+ target: ShellNotifier.greeter
60+ onHide: {
61+ if (now) {
62+ root.hideNow(); // skip hide animation
63+ } else {
64+ root.hide();
65+ }
66+ }
67+ onShownChanged: {
68+ if (ShellNotifier.greeter.shown) {
69+ root.show();
70+ } else {
71+ root.hide();
72+ }
73+ }
74+ }
75+}
qml/OrientedShell.qml+7−9
@@ -32,15 +32,17 @@ Item {
32 implicitWidth: units.gu(40)
32 implicitWidth: units.gu(40)
33 implicitHeight: units.gu(71)
33 implicitHeight: units.gu(71)
34
34
35+ property alias deviceConfiguration: _deviceConfiguration
36+ property alias orientations: d.orientations
37+ property alias surfaceManager: shell.surfaceManager
38+
35 onWidthChanged: calculateUsageMode();
39 onWidthChanged: calculateUsageMode();
36
40
37 DeviceConfiguration {
41 DeviceConfiguration {
38− id: deviceConfiguration
42+ id: _deviceConfiguration
39 name: applicationArguments.deviceName
43 name: applicationArguments.deviceName
40 }
44 }
41
45
42− property alias orientations: d.orientations
43−
44 Item {
46 Item {
45 id: d
47 id: d
46
48
@@ -157,10 +159,6 @@ Item {
157 return false;
159 return false;
158 }
160 }
159
161
160− Screens {
161− id: screens
162− }
163−
164 property int orientation
162 property int orientation
165 onPhysicalOrientationChanged: {
163 onPhysicalOrientationChanged: {
166 if (!orientationLocked) {
164 if (!orientationLocked) {
@@ -258,7 +256,7 @@ Item {
258
256
259 Shell {
257 Shell {
260 id: shell
258 id: shell
261− objectName: "shell"
259+ objectName: "shell-"+screenWindow.objectName
262 width: root.width
260 width: root.width
263 height: root.height
261 height: root.height
264 orientation: root.angleToOrientation(orientationAngle)
262 orientation: root.angleToOrientation(orientationAngle)
@@ -271,7 +269,7 @@ Item {
271 // have multiple keyboards around. For now we only enable one keyboard at a time
269 // have multiple keyboards around. For now we only enable one keyboard at a time
272 // thus hiding it here if there is a physical one around or if we have a second
270 // thus hiding it here if there is a physical one around or if we have a second
273 // screen (the virtual touchpad & osk on the phone) attached.
271 // screen (the virtual touchpad & osk on the phone) attached.
274− oskEnabled: (keyboardsModel.count === 0 && screens.count === 1) ||
272+ oskEnabled: (keyboardsModel.count === 0 && Screens.count === 1) ||
275 forceOSKEnabled
273 forceOSKEnabled
276
274
277 usageScenario: {
275 usageScenario: {
qml/Panel/Panel.qml+14−14
@@ -47,8 +47,8 @@ Item {
47 property bool fullscreenMode: false
47 property bool fullscreenMode: false
48 property real panelAreaShowProgress: 1.0
48 property real panelAreaShowProgress: 1.0
49 property bool greeterShown: false
49 property bool greeterShown: false
50−
51 property string mode: "staged"
50 property string mode: "staged"
51+ property PanelState panelState
52
52
53 MouseArea {
53 MouseArea {
54 id: backMouseEater
54 id: backMouseEater
@@ -65,14 +65,14 @@ Item {
65 }
65 }
66
66
67 Binding {
67 Binding {
68− target: PanelState
68+ target: panelState
69 property: "panelHeight"
69 property: "panelHeight"
70 value: minimizedPanelHeight
70 value: minimizedPanelHeight
71 }
71 }
72
72
73 RegisteredApplicationMenuModel {
73 RegisteredApplicationMenuModel {
74 id: registeredMenuModel
74 id: registeredMenuModel
75− persistentSurfaceId: PanelState.focusedPersistentSurfaceId
75+ persistentSurfaceId: panelState.focusedPersistentSurfaceId
76 }
76 }
77
77
78 QtObject {
78 QtObject {
@@ -83,11 +83,11 @@ Item {
83 !indicators.shown &&
83 !indicators.shown &&
84 (decorationMouseArea.containsMouse || menuBarLoader.menusRequested)
84 (decorationMouseArea.containsMouse || menuBarLoader.menusRequested)
85
85
86− property bool showWindowDecorationControls: (revealControls && PanelState.decorationsVisible) ||
86+ property bool showWindowDecorationControls: (revealControls && panelState.decorationsVisible) ||
87− PanelState.decorationsAlwaysVisible
87+ panelState.decorationsAlwaysVisible
88
88
89 property bool showPointerMenu: revealControls &&
89 property bool showPointerMenu: revealControls &&
90− (PanelState.decorationsVisible || mode == "staged")
90+ (panelState.decorationsVisible || mode == "staged")
91
91
92 property bool enablePointerMenu: revealControls &&
92 property bool enablePointerMenu: revealControls &&
93 applicationMenus.available &&
93 applicationMenus.available &&
@@ -139,7 +139,7 @@ Item {
139 fill: panelAreaBackground
139 fill: panelAreaBackground
140 bottomMargin: -units.gu(1)
140 bottomMargin: -units.gu(1)
141 }
141 }
142− visible: PanelState.dropShadow
142+ visible: panelState.dropShadow
143 source: "graphics/rectangular_dropshadow.sci"
143 source: "graphics/rectangular_dropshadow.sci"
144 }
144 }
145
145
@@ -192,12 +192,12 @@ Item {
192 visible: opacity != 0
192 visible: opacity != 0
193 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
193 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
194
194
195− active: PanelState.decorationsVisible || PanelState.decorationsAlwaysVisible
195+ active: panelState.decorationsVisible || panelState.decorationsAlwaysVisible
196 windowIsMaximized: true
196 windowIsMaximized: true
197− onCloseClicked: PanelState.closeClicked()
197+ onCloseClicked: panelState.closeClicked()
198− onMinimizeClicked: PanelState.minimizeClicked()
198+ onMinimizeClicked: panelState.minimizeClicked()
199− onMaximizeClicked: PanelState.restoreClicked()
199+ onMaximizeClicked: panelState.restoreClicked()
200− closeButtonShown: PanelState.closeButtonShown
200+ closeButtonShown: panelState.closeButtonShown
201 }
201 }
202
202
203 Loader {
203 Loader {
@@ -217,7 +217,7 @@ Item {
217 anchors.left: parent.left
217 anchors.left: parent.left
218 anchors.margins: units.gu(1)
218 anchors.margins: units.gu(1)
219 height: menuBarLoader.height
219 height: menuBarLoader.height
220− enableKeyFilter: valid && PanelState.decorationsVisible
220+ enableKeyFilter: valid && panelState.decorationsVisible
221 unityMenuModel: __applicationMenus.model
221 unityMenuModel: __applicationMenus.model
222
222
223 Connections {
223 Connections {
@@ -265,7 +265,7 @@ Item {
265 }
265 }
266
266
267 showRowTitle: !expanded
267 showRowTitle: !expanded
268− rowTitle: PanelState.title
268+ rowTitle: panelState.title
269 rowItemDelegate: ActionItem {
269 rowItemDelegate: ActionItem {
270 id: actionItem
270 id: actionItem
271 property int ownIndex: index
271 property int ownIndex: index
qml/Shell.qml+48−12
@@ -1,4 +1,4 @@
1−/*
1+/*
2 * Copyright (C) 2013-2016 Canonical, Ltd.
2 * Copyright (C) 2013-2016 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
@@ -38,12 +38,14 @@ import "Notifications"
38import "Stage"
38import "Stage"
39import "Tutorial"
39import "Tutorial"
40import "Wizard"
40import "Wizard"
41+import "Components/PanelState"
41import Unity.Notifications 1.0 as NotificationBackend
42import Unity.Notifications 1.0 as NotificationBackend
42import Unity.Session 0.1
43import Unity.Session 0.1
43import Unity.DashCommunicator 0.1
44import Unity.DashCommunicator 0.1
44import Unity.Indicators 0.1 as Indicators
45import Unity.Indicators 0.1 as Indicators
45import Cursor 1.1
46import Cursor 1.1
46import WindowManager 1.0
47import WindowManager 1.0
48+import Unity.Debug 0.1 as Debug
47
49
48
50
49StyledItem {
51StyledItem {
@@ -52,6 +54,7 @@ StyledItem {
52 theme.name: "Ubuntu.Components.Themes.SuruDark"
54 theme.name: "Ubuntu.Components.Themes.SuruDark"
53
55
54 // to be set from outside
56 // to be set from outside
57+ property alias surfaceManager: topLevelSurfaceList.surfaceManager
55 property int orientationAngle: 0
58 property int orientationAngle: 0
56 property int orientation
59 property int orientation
57 property Orientations orientations
60 property Orientations orientations
@@ -258,21 +261,21 @@ StyledItem {
258 schema.id: "com.canonical.Unity8"
261 schema.id: "com.canonical.Unity8"
259 }
262 }
260
263
264+ PanelState {
265+ id: panelState
266+ objectName: "panelState"
267+ }
268+
261 Item {
269 Item {
262 id: stages
270 id: stages
263 objectName: "stages"
271 objectName: "stages"
264 width: parent.width
272 width: parent.width
265 height: parent.height
273 height: parent.height
266
274
267− SurfaceManager {
268− id: surfaceMan
269− objectName: "surfaceManager"
270− }
271 TopLevelWindowModel {
275 TopLevelWindowModel {
272 id: topLevelSurfaceList
276 id: topLevelSurfaceList
273 objectName: "topLevelSurfaceList"
277 objectName: "topLevelSurfaceList"
274 applicationManager: ApplicationManager // it's a singleton
278 applicationManager: ApplicationManager // it's a singleton
275− surfaceManager: surfaceMan
276 }
279 }
277
280
278 Stage {
281 Stage {
@@ -313,6 +316,7 @@ StyledItem {
313 altTabPressed: physicalKeysMapper.altTabPressed
316 altTabPressed: physicalKeysMapper.altTabPressed
314 oskEnabled: shell.oskEnabled
317 oskEnabled: shell.oskEnabled
315 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
318 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
319+ panelState: panelState
316
320
317 onSpreadShownChanged: {
321 onSpreadShownChanged: {
318 panel.indicators.hide();
322 panel.indicators.hide();
@@ -338,8 +342,13 @@ StyledItem {
338 objectName: "greeterLoader"
342 objectName: "greeterLoader"
339 anchors.fill: parent
343 anchors.fill: parent
340 anchors.topMargin: panel.panelHeight
344 anchors.topMargin: panel.panelHeight
341− sourceComponent: shell.mode != "shell" ? integratedGreeter :
345+ sourceComponent: {
346+ if (shell.mode != "shell") {
347+ if (screenWindow.primary) return integratedGreeter;
348+ return secondaryGreeter;
349+ }
342− Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
350+ return Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
351+ }
343 onLoaded: {
352 onLoaded: {
344 item.objectName = "greeter"
353 item.objectName = "greeter"
345 }
354 }
@@ -379,6 +388,13 @@ StyledItem {
379 }
388 }
380 }
389 }
381
390
391+ Component {
392+ id: secondaryGreeter
393+ SecondaryGreeter {
394+ hides: [launcher, panel.indicators]
395+ }
396+ }
397+
382 Timer {
398 Timer {
383 // See powerConnection for why this is useful
399 // See powerConnection for why this is useful
384 id: showGreeterDelayed
400 id: showGreeterDelayed
@@ -489,6 +505,7 @@ StyledItem {
489 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
505 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
490 || greeter.hasLockedApp
506 || greeter.hasLockedApp
491 greeterShown: greeter && greeter.shown
507 greeterShown: greeter && greeter.shown
508+ panelState: panelState
492 }
509 }
493
510
494 Launcher {
511 Launcher {
@@ -699,12 +716,13 @@ StyledItem {
699
716
700 Cursor {
717 Cursor {
701 id: cursor
718 id: cursor
702− objectName: "cursor"
719+ objectName: "Pointer-"+screenWindow.objectName
703− visible: shell.hasMouse
720+
704 z: itemGrabber.z + 1
721 z: itemGrabber.z + 1
722+ opacity: 0
705 topBoundaryOffset: panel.panelHeight
723 topBoundaryOffset: panel.panelHeight
706−
724+ enabled: shell.hasMouse && screenWindow.active
707− confiningItem: stage.itemConfiningMouseCursor
725+ visible: enabled
708
726
709 property bool mouseNeverMoved: true
727 property bool mouseNeverMoved: true
710 Binding {
728 Binding {
@@ -716,6 +734,8 @@ StyledItem {
716 when: cursor.mouseNeverMoved && cursor.visible
734 when: cursor.mouseNeverMoved && cursor.visible
717 }
735 }
718
736
737+ confiningItem: stage.itemConfiningMouseCursor
738+
719 height: units.gu(3)
739 height: units.gu(3)
720
740
721 readonly property var previewRectangle: stage.previewRectangle.target &&
741 readonly property var previewRectangle: stage.previewRectangle.target &&
@@ -802,4 +822,20 @@ StyledItem {
802 }
822 }
803 }
823 }
804 }
824 }
825+
826+ Loader {
827+ z: shutdownFadeOutRectangle.z + 1
828+ active: DebuggingController.logOverlay
829+
830+ sourceComponent: Text {
831+ width: shell.width
832+ height: shell.height
833+
834+ text: consoleLog.out
835+ Debug.ConsoleLog {
836+ id: consoleLog
837+ enabled: true
838+ }
839+ }
840+ }
805}
841}
qml/ShellApplication.qmlnew file+51
@@ -0,0 +1,51 @@
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.Window 2.2
19+import Unity.Screens 0.1
20+import Unity.Application 0.1
21+
22+Instantiator {
23+ id: root
24+ model: Screens
25+
26+ property QtObject surfaceMan: SurfaceManager {}
27+
28+ ShellScreen {
29+ id: screen
30+ objectName: "screen"+index
31+ screen: model.screen
32+ visibility: applicationArguments.hasFullscreen ? Window.FullScreen : Window.Windowed
33+ flags: applicationArguments.hasFrameless ? Qt.FramelessWindowHint : 0
34+ surfaceManager: surfaceMan
35+
36+ Binding {
37+ when: applicationArguments.hasGeometry
38+ target: screen
39+ property: "width"
40+ value: applicationArguments.windowGeometry.width
41+ }
42+ Binding {
43+ when: applicationArguments.hasGeometry
44+ target: screen
45+ property: "height"
46+ value: applicationArguments.windowGeometry.height
47+ }
48+
49+ primary: index == 0
50+ }
51+}
src/SecondaryWindow.h → qml/ShellNotifier.qmlrenamed+12−12
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2016 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
@@ -14,17 +14,17 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef UNITY_SECONDARY_WINDOW_H
17+/*
18−#define UNITY_SECONDARY_WINDOW_H
18+ Shared signals & properties on multi-window desktop
19−
19+ */
20−#include <QQuickView>
21
20
22−class SecondaryWindow : public QQuickView
21+pragma Singleton
23−{
22+import QtQuick 2.4
24− Q_OBJECT
25
23
26−public:
24+QtObject {
27− SecondaryWindow(QQmlEngine *engine);
25+ property var greeter: QtObject {
28−};
26+ signal hide(bool now)
29
27
30−#endif // UNITY_SECONDARY_WINDOW_H
28+ property bool shown: true
29+ }
30+}
qml/ShellScreen.qmlnew file+65
@@ -0,0 +1,65 @@
1+/*
2+* Copyright (C) 2016 Canonical, Ltd.
3+*
4+* This program is free software; you can redistribute it and/or modify
5+* it under the terms of the GNU General Public License as published by
6+* the Free Software Foundation; version 3.
7+*
8+* This program is distributed in the hope that it will be useful,
9+* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+* GNU General Public License for more details.
12+*
13+* You should have received a copy of the GNU General Public License
14+* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Unity.Screens 0.1
20+import Cursor 1.1
21+import "Components"
22+
23+ScreenWindow {
24+ id: screenWindow
25+
26+ color: "black"
27+ title: "Unity8 Shell"
28+ property bool primary: false
29+ property QtObject surfaceManager: null
30+
31+ DeviceConfiguration {
32+ id: deviceConfiguration
33+ name: applicationArguments.deviceName
34+ }
35+
36+ Loader {
37+ width: screenWindow.width
38+ height: screenWindow.height
39+
40+ sourceComponent: {
41+ if (Screens.count > 1 && primary && deviceConfiguration.category !== "desktop") {
42+ return disabledScreenComponent;
43+ }
44+ return shellComponent;
45+ }
46+ }
47+
48+ Component {
49+ id: shellComponent
50+ OrientedShell {
51+ implicitWidth: screenWindow.width
52+ implicitHeight: screenWindow.height
53+ surfaceManager: screenWindow.surfaceManager
54+
55+ deviceConfiguration {
56+ name: Screens.count > 1 ? "desktop" : applicationArguments.deviceName
57+ }
58+ }
59+ }
60+
61+ Component {
62+ id: disabledScreenComponent
63+ DisabledScreenNotice {}
64+ }
65+}
qml/Stage/DecoratedWindow.qml+4−1
@@ -73,6 +73,8 @@ FocusScope {
73
73
74 readonly property Item clientAreaItem: applicationWindow
74 readonly property Item clientAreaItem: applicationWindow
75
75
76+ property PanelState panelState
77+
76 signal closeClicked()
78 signal closeClicked()
77 signal maximizeClicked()
79 signal maximizeClicked()
78 signal maximizeHorizontallyClicked()
80 signal maximizeHorizontallyClicked()
@@ -232,7 +234,7 @@ FocusScope {
232 enableMenus: {
234 enableMenus: {
233 return active &&
235 return active &&
234 surface &&
236 surface &&
235− (PanelState.focusedPersistentSurfaceId === surface.persistentId && !PanelState.decorationsVisible)
237+ (panelState.focusedPersistentSurfaceId === surface.persistentId && !panelState.decorationsVisible)
236 }
238 }
237 menu: sharedAppModel.model
239 menu: sharedAppModel.model
238
240
@@ -297,6 +299,7 @@ FocusScope {
297 objectName: "moveHandler"
299 objectName: "moveHandler"
298 target: root.parent
300 target: root.parent
299 buttonsWidth: decoration.buttonsWidth
301 buttonsWidth: decoration.buttonsWidth
302+ panelState: root.panelState
300 }
303 }
301
304
302 Rectangle {
305 Rectangle {
qml/Stage/FakeMaximizeDelegate.qml+12−11
@@ -35,6 +35,7 @@ Rectangle {
35 property int leftMargin
35 property int leftMargin
36 property real appContainerWidth
36 property real appContainerWidth
37 property real appContainerHeight
37 property real appContainerHeight
38+ property PanelState panelState
38
39
39 readonly property real hintThreshold: 0.1
40 readonly property real hintThreshold: 0.1
40
41
@@ -178,7 +179,7 @@ Rectangle {
178 ParallelAnimation {
179 ParallelAnimation {
179 id: fakeMaximizeAnimation
180 id: fakeMaximizeAnimation
180 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
181 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
181− UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: PanelState.panelHeight }
182+ UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: panelState.panelHeight }
182 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: appContainerWidth - leftMargin }
183 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: appContainerWidth - leftMargin }
183 UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight }
184 UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight }
184 }
185 }
@@ -186,39 +187,39 @@ Rectangle {
186 ParallelAnimation {
187 ParallelAnimation {
187 id: fakeMaximizeLeftAnimation
188 id: fakeMaximizeLeftAnimation
188 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
189 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
189− UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: PanelState.panelHeight }
190+ UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: panelState.panelHeight }
190 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
191 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
191− UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight - PanelState.panelHeight }
192+ UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight - panelState.panelHeight }
192 }
193 }
193
194
194 ParallelAnimation {
195 ParallelAnimation {
195 id: fakeMaximizeRightAnimation
196 id: fakeMaximizeRightAnimation
196 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth + leftMargin)/2 }
197 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth + leftMargin)/2 }
197− UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: PanelState.panelHeight }
198+ UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: panelState.panelHeight }
198 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
199 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
199− UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight - PanelState.panelHeight }
200+ UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight - panelState.panelHeight }
200 }
201 }
201
202
202 ParallelAnimation {
203 ParallelAnimation {
203 id: fakeMaximizeTopLeftAnimation
204 id: fakeMaximizeTopLeftAnimation
204 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
205 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
205− UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: PanelState.panelHeight }
206+ UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: panelState.panelHeight }
206 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
207 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
207− UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight - PanelState.panelHeight)/2 }
208+ UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight - panelState.panelHeight)/2 }
208 }
209 }
209
210
210 ParallelAnimation {
211 ParallelAnimation {
211 id: fakeMaximizeTopRightAnimation
212 id: fakeMaximizeTopRightAnimation
212 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth + leftMargin)/2 }
213 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth + leftMargin)/2 }
213− UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: PanelState.panelHeight }
214+ UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: panelState.panelHeight }
214 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
215 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
215− UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight - PanelState.panelHeight)/2 }
216+ UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight - panelState.panelHeight)/2 }
216 }
217 }
217
218
218 ParallelAnimation {
219 ParallelAnimation {
219 id: fakeMaximizeBottomLeftAnimation
220 id: fakeMaximizeBottomLeftAnimation
220 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
221 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: leftMargin }
221− UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight + PanelState.panelHeight)/2 }
222+ UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight + panelState.panelHeight)/2 }
222 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
223 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
223 UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight/2 }
224 UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight/2 }
224 }
225 }
@@ -226,7 +227,7 @@ Rectangle {
226 ParallelAnimation {
227 ParallelAnimation {
227 id: fakeMaximizeBottomRightAnimation
228 id: fakeMaximizeBottomRightAnimation
228 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth + leftMargin)/2 }
229 UbuntuNumberAnimation { target: fakeRectangle; properties: "x"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth + leftMargin)/2 }
229− UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight + PanelState.panelHeight)/2 }
230+ UbuntuNumberAnimation { target: fakeRectangle; properties: "y"; duration: UbuntuAnimation.BriskDuration; to: (appContainerHeight + panelState.panelHeight)/2 }
230 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
231 UbuntuNumberAnimation { target: fakeRectangle; properties: "width"; duration: UbuntuAnimation.BriskDuration; to: (appContainerWidth - leftMargin)/2 }
231 UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight/2 }
232 UbuntuNumberAnimation { target: fakeRectangle; properties: "height"; duration: UbuntuAnimation.BriskDuration; to: appContainerHeight/2 }
232 }
233 }
qml/Stage/MoveHandler.qml+8−7
@@ -28,6 +28,7 @@ QtObject {
28 property int stageWidth
28 property int stageWidth
29 property int stageHeight
29 property int stageHeight
30 property real buttonsWidth: 0
30 property real buttonsWidth: 0
31+ property PanelState panelState
31
32
32 readonly property bool dragging: priv.dragging
33 readonly property bool dragging: priv.dragging
33
34
@@ -122,18 +123,18 @@ QtObject {
122 // position. Mouse movement could have subpixel precision, yielding a fractional
123 // position. Mouse movement could have subpixel precision, yielding a fractional
123 // mouse position.
124 // mouse position.
124 target.windowedX = Math.round(pos.x - priv.distanceX);
125 target.windowedX = Math.round(pos.x - priv.distanceX);
125− target.windowedY = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
126+ target.windowedY = Math.round(Math.max(pos.y - priv.distanceY, panelState.panelHeight));
126
127
127 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
128 if (sensingPoints) { // edge/corner detection when dragging via the touch overlay
128− if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < PanelState.panelHeight + priv.triggerArea
129+ if (sensingPoints.topLeft.x < priv.triggerArea && sensingPoints.topLeft.y < panelState.panelHeight + priv.triggerArea
129 && target.canBeCornerMaximized) { // top left
130 && target.canBeCornerMaximized) { // top left
130− priv.progress = priv.progressInCorner(0, PanelState.panelHeight, sensingPoints.topLeft.x, sensingPoints.topLeft.y);
131+ priv.progress = priv.progressInCorner(0, panelState.panelHeight, sensingPoints.topLeft.x, sensingPoints.topLeft.y);
131 priv.resetEdges();
132 priv.resetEdges();
132 priv.nearTopLeftCorner = true;
133 priv.nearTopLeftCorner = true;
133 root.fakeMaximizeTopLeftAnimationRequested(priv.progress);
134 root.fakeMaximizeTopLeftAnimationRequested(priv.progress);
134− } else if (sensingPoints.topRight.x > stageWidth - priv.triggerArea && sensingPoints.topRight.y < PanelState.panelHeight + priv.triggerArea
135+ } else if (sensingPoints.topRight.x > stageWidth - priv.triggerArea && sensingPoints.topRight.y < panelState.panelHeight + priv.triggerArea
135 && target.canBeCornerMaximized) { // top right
136 && target.canBeCornerMaximized) { // top right
136− priv.progress = priv.progressInCorner(stageWidth, PanelState.panelHeight, sensingPoints.topRight.x, sensingPoints.topRight.y);
137+ priv.progress = priv.progressInCorner(stageWidth, panelState.panelHeight, sensingPoints.topRight.x, sensingPoints.topRight.y);
137 priv.resetEdges();
138 priv.resetEdges();
138 priv.nearTopRightCorner = true;
139 priv.nearTopRightCorner = true;
139 root.fakeMaximizeTopRightAnimationRequested(priv.progress);
140 root.fakeMaximizeTopRightAnimationRequested(priv.progress);
@@ -159,8 +160,8 @@ QtObject {
159 priv.resetEdges();
160 priv.resetEdges();
160 priv.nearRightEdge = true;
161 priv.nearRightEdge = true;
161 root.fakeMaximizeRightAnimationRequested(priv.progress);
162 root.fakeMaximizeRightAnimationRequested(priv.progress);
162− } else if (sensingPoints.top.y < PanelState.panelHeight + priv.triggerArea && target.canBeMaximized) { // top
163+ } else if (sensingPoints.top.y < panelState.panelHeight + priv.triggerArea && target.canBeMaximized) { // top
163− priv.progress = MathUtils.clampAndProject(sensingPoints.top.y, PanelState.panelHeight + priv.triggerArea, 0, 0, 1);
164+ priv.progress = MathUtils.clampAndProject(sensingPoints.top.y, panelState.panelHeight + priv.triggerArea, 0, 0, 1);
164 priv.resetEdges();
165 priv.resetEdges();
165 priv.nearTopEdge = true;
166 priv.nearTopEdge = true;
166 root.fakeMaximizeAnimationRequested(priv.progress);
167 root.fakeMaximizeAnimationRequested(priv.progress);
qml/Stage/Stage.qml+29−25
@@ -46,6 +46,7 @@ FocusScope {
46 property int leftMargin: 0
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 PanelState panelState
49
50
50 // Configuration
51 // Configuration
51 property string mode: "staged"
52 property string mode: "staged"
@@ -348,20 +349,20 @@ FocusScope {
348 Component.onCompleted: priv.updateMainAndSideStageIndexes();
349 Component.onCompleted: priv.updateMainAndSideStageIndexes();
349
350
350 Connections {
351 Connections {
351− target: PanelState
352+ target: panelState
352 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
353 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
353 onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestMinimize(); } }
354 onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestMinimize(); } }
354 onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestRestore(); } }
355 onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestRestore(); } }
355 }
356 }
356
357
357 Binding {
358 Binding {
358− target: PanelState
359+ target: panelState
359 property: "decorationsVisible"
360 property: "decorationsVisible"
360 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
361 value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
361 }
362 }
362
363
363 Binding {
364 Binding {
364− target: PanelState
365+ target: panelState
365 property: "title"
366 property: "title"
366 value: {
367 value: {
367 if (priv.focusedAppDelegate !== null) {
368 if (priv.focusedAppDelegate !== null) {
@@ -376,7 +377,7 @@ FocusScope {
376 }
377 }
377
378
378 Binding {
379 Binding {
379− target: PanelState
380+ target: panelState
380 property: "focusedPersistentSurfaceId"
381 property: "focusedPersistentSurfaceId"
381 value: {
382 value: {
382 if (priv.focusedAppDelegate !== null) {
383 if (priv.focusedAppDelegate !== null) {
@@ -390,21 +391,21 @@ FocusScope {
390 }
391 }
391
392
392 Binding {
393 Binding {
393− target: PanelState
394+ target: panelState
394 property: "dropShadow"
395 property: "dropShadow"
395 value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
396 value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
396 }
397 }
397
398
398 Binding {
399 Binding {
399− target: PanelState
400+ target: panelState
400 property: "closeButtonShown"
401 property: "closeButtonShown"
401 value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
402 value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
402 }
403 }
403
404
404 Component.onDestruction: {
405 Component.onDestruction: {
405− PanelState.title = "";
406+ panelState.title = "";
406− PanelState.decorationsVisible = false;
407+ panelState.decorationsVisible = false;
407− PanelState.dropShadow = false;
408+ panelState.dropShadow = false;
408 }
409 }
409
410
410 Instantiator {
411 Instantiator {
@@ -753,7 +754,7 @@ FocusScope {
753 target: appDelegate
754 target: appDelegate
754 property: "y"
755 property: "y"
755 value: appDelegate.requestedY -
756 value: appDelegate.requestedY -
756− Math.min(appDelegate.requestedY - PanelState.panelHeight,
757+ Math.min(appDelegate.requestedY - panelState.panelHeight,
757 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
758 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
758 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
759 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
759 && root.inputMethodRect.height > 0
760 && root.inputMethodRect.height > 0
@@ -890,7 +891,7 @@ FocusScope {
890 screenWidth: appContainer.width
891 screenWidth: appContainer.width
891 screenHeight: appContainer.height
892 screenHeight: appContainer.height
892 leftMargin: root.leftMargin
893 leftMargin: root.leftMargin
893− minimumY: PanelState.panelHeight
894+ minimumY: panelState.panelHeight
894 }
895 }
895
896
896 Connections {
897 Connections {
@@ -1130,7 +1131,7 @@ FocusScope {
1130 progress: 0
1131 progress: 0
1131 targetHeight: spreadItem.stackHeight
1132 targetHeight: spreadItem.stackHeight
1132 targetX: spreadMaths.targetX
1133 targetX: spreadMaths.targetX
1133− startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1134+ startY: appDelegate.fullscreen ? 0 : panelState.panelHeight
1134 targetY: spreadMaths.targetY
1135 targetY: spreadMaths.targetY
1135 targetAngle: spreadMaths.targetAngle
1136 targetAngle: spreadMaths.targetAngle
1136 targetScale: spreadMaths.targetScale
1137 targetScale: spreadMaths.targetScale
@@ -1249,9 +1250,9 @@ FocusScope {
1249 PropertyChanges {
1250 PropertyChanges {
1250 target: appDelegate
1251 target: appDelegate
1251 x: stageMaths.itemX
1252 x: stageMaths.itemX
1252− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1253+ y: appDelegate.fullscreen ? 0 : panelState.panelHeight
1253 requestedWidth: appContainer.width
1254 requestedWidth: appContainer.width
1254− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1255+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - panelState.panelHeight
1255 visuallyMaximized: true
1256 visuallyMaximized: true
1256 visible: appDelegate.x < root.width
1257 visible: appDelegate.x < root.width
1257 }
1258 }
@@ -1277,10 +1278,10 @@ FocusScope {
1277 PropertyChanges {
1278 PropertyChanges {
1278 target: appDelegate
1279 target: appDelegate
1279 x: stageMaths.itemX
1280 x: stageMaths.itemX
1280− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1281+ y: appDelegate.fullscreen ? 0 : panelState.panelHeight
1281 z: stageMaths.itemZ
1282 z: stageMaths.itemZ
1282 requestedWidth: stageMaths.itemWidth
1283 requestedWidth: stageMaths.itemWidth
1283− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1284+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - panelState.panelHeight
1284 visuallyMaximized: true
1285 visuallyMaximized: true
1285 visible: appDelegate.x < root.width
1286 visible: appDelegate.x < root.width
1286 }
1287 }
@@ -1345,9 +1346,9 @@ FocusScope {
1345 PropertyChanges {
1346 PropertyChanges {
1346 target: appDelegate
1347 target: appDelegate
1347 windowedX: root.leftMargin
1348 windowedX: root.leftMargin
1348− windowedY: PanelState.panelHeight
1349+ windowedY: panelState.panelHeight
1349 windowedWidth: (appContainer.width - root.leftMargin)/2
1350 windowedWidth: (appContainer.width - root.leftMargin)/2
1350− windowedHeight: appContainer.height - PanelState.panelHeight
1351+ windowedHeight: appContainer.height - panelState.panelHeight
1351 }
1352 }
1352 },
1353 },
1353 State {
1354 State {
@@ -1364,9 +1365,9 @@ FocusScope {
1364 PropertyChanges {
1365 PropertyChanges {
1365 target: appDelegate
1366 target: appDelegate
1366 windowedX: root.leftMargin
1367 windowedX: root.leftMargin
1367− windowedY: PanelState.panelHeight
1368+ windowedY: panelState.panelHeight
1368 windowedWidth: (appContainer.width - root.leftMargin)/2
1369 windowedWidth: (appContainer.width - root.leftMargin)/2
1369− windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1370+ windowedHeight: (appContainer.height - panelState.panelHeight)/2
1370 }
1371 }
1371 },
1372 },
1372 State {
1373 State {
@@ -1383,7 +1384,7 @@ FocusScope {
1383 PropertyChanges {
1384 PropertyChanges {
1384 target: appDelegate
1385 target: appDelegate
1385 windowedX: root.leftMargin
1386 windowedX: root.leftMargin
1386− windowedY: (appContainer.height + PanelState.panelHeight)/2
1387+ windowedY: (appContainer.height + panelState.panelHeight)/2
1387 windowedWidth: (appContainer.width - root.leftMargin)/2
1388 windowedWidth: (appContainer.width - root.leftMargin)/2
1388 windowedHeight: appContainer.height/2
1389 windowedHeight: appContainer.height/2
1389 }
1390 }
@@ -1405,8 +1406,8 @@ FocusScope {
1405 State {
1406 State {
1406 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1407 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1407 extend: "normal"
1408 extend: "normal"
1408− PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: PanelState.panelHeight;
1409+ PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: panelState.panelHeight;
1409− windowedWidth: windowedWidth; windowedHeight: appContainer.height - PanelState.panelHeight }
1410+ windowedWidth: windowedWidth; windowedHeight: appContainer.height - panelState.panelHeight }
1410 },
1411 },
1411 State {
1412 State {
1412 name: "minimized"; when: appDelegate.minimized
1413 name: "minimized"; when: appDelegate.minimized
@@ -1505,7 +1506,7 @@ FocusScope {
1505 ]
1506 ]
1506
1507
1507 Binding {
1508 Binding {
1508− target: PanelState
1509+ target: panelState
1509 property: "decorationsAlwaysVisible"
1510 property: "decorationsAlwaysVisible"
1510 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
1511 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
1511 }
1512 }
@@ -1520,7 +1521,7 @@ FocusScope {
1520 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1521 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1521
1522
1522 target: appDelegate
1523 target: appDelegate
1523− minimumY: PanelState.panelHeight // disallow resizing up past Panel
1524+ minimumY: panelState.panelHeight // disallow resizing up past Panel
1524 minWidth: units.gu(10)
1525 minWidth: units.gu(10)
1525 minHeight: units.gu(10)
1526 minHeight: units.gu(10)
1526 borderThickness: units.gu(2)
1527 borderThickness: units.gu(2)
@@ -1550,6 +1551,7 @@ FocusScope {
1550 highlightSize: windowInfoItem.iconMargin / 2
1551 highlightSize: windowInfoItem.iconMargin / 2
1551 stageWidth: appContainer.width
1552 stageWidth: appContainer.width
1552 stageHeight: appContainer.height
1553 stageHeight: appContainer.height
1554+ panelState: root.panelState
1553
1555
1554 requestedWidth: appDelegate.requestedWidth
1556 requestedWidth: appDelegate.requestedWidth
1555 requestedHeight: appDelegate.requestedHeight
1557 requestedHeight: appDelegate.requestedHeight
@@ -1609,6 +1611,7 @@ FocusScope {
1609 visible: enabled
1611 visible: enabled
1610 stageWidth: appContainer.width
1612 stageWidth: appContainer.width
1611 stageHeight: appContainer.height
1613 stageHeight: appContainer.height
1614+ panelState: root.panelState
1612
1615
1613 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1616 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1614 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
1617 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
@@ -1713,6 +1716,7 @@ FocusScope {
1713 leftMargin: root.leftMargin
1716 leftMargin: root.leftMargin
1714 appContainerWidth: appContainer.width
1717 appContainerWidth: appContainer.width
1715 appContainerHeight: appContainer.height
1718 appContainerHeight: appContainer.height
1719+ panelState: root.panelState
1716 }
1720 }
1717
1721
1718 EdgeBarrier {
1722 EdgeBarrier {
qml/Stage/WindowControlsOverlay.qml+2
@@ -27,6 +27,7 @@ Item {
27
27
28 // to be set from outside
28 // to be set from outside
29 property Item target // appDelegate
29 property Item target // appDelegate
30+ property PanelState panelState
30 property alias stageWidth: moveHandler.stageWidth
31 property alias stageWidth: moveHandler.stageWidth
31 property alias stageHeight: moveHandler.stageHeight
32 property alias stageHeight: moveHandler.stageHeight
32
33
@@ -161,6 +162,7 @@ Item {
161 id: moveHandler
162 id: moveHandler
162 objectName: "moveHandler"
163 objectName: "moveHandler"
163 target: root.target
164 target: root.target
165+ panelState: root.panelState
164
166
165 onFakeMaximizeAnimationRequested: root.fakeMaximizeAnimationRequested(amount)
167 onFakeMaximizeAnimationRequested: root.fakeMaximizeAnimationRequested(amount)
166 onFakeMaximizeLeftAnimationRequested: root.fakeMaximizeLeftAnimationRequested(amount)
168 onFakeMaximizeLeftAnimationRequested: root.fakeMaximizeLeftAnimationRequested(amount)
qml/qmldirnew file+1
@@ -0,0 +1 @@
1+singleton ShellNotifier 0.1 ShellNotifier.qml
src/ApplicationArguments.cpp+11−2
@@ -16,7 +16,16 @@
16
16
17#include "ApplicationArguments.h"
17#include "ApplicationArguments.h"
18
18
19−ApplicationArguments::ApplicationArguments(QObject *parent)
19+ApplicationArguments::ApplicationArguments(QCoreApplication *app)
20− : QObject(parent)
20+ : QObject(app)
21+ , UnityCommandLineParser(*app)
21{
22{
22}
23}
24+
25+void ApplicationArguments::setDeviceName(const QString &deviceName)
26+{
27+ if (deviceName != m_deviceName) {
28+ m_deviceName = deviceName;
29+ Q_EMIT deviceNameChanged(m_deviceName);
30+ }
31+}
src/ApplicationArguments.h+16−15
@@ -23,31 +23,32 @@
23#include <QSize>
23#include <QSize>
24#include <QString>
24#include <QString>
25
25
26+#include "UnityCommandLineParser.h"
27+
26−class ApplicationArguments : public QObject
28+class ApplicationArguments : public QObject,
29+ public UnityCommandLineParser
27{
30{
28 Q_OBJECT
31 Q_OBJECT
29 Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged)
32 Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged)
30 Q_PROPERTY(QString mode READ mode CONSTANT)
33 Q_PROPERTY(QString mode READ mode CONSTANT)
34+
35+ Q_PROPERTY(bool hasGeometry READ hasGeometry CONSTANT)
36+ Q_PROPERTY(QSize windowGeometry READ windowGeometry CONSTANT)
37+ Q_PROPERTY(bool hasTestability READ hasTestability CONSTANT)
38+ Q_PROPERTY(bool hasFrameless READ hasFrameless CONSTANT)
39+#ifdef UNITY8_ENABLE_TOUCH_EMULATION
40+ Q_PROPERTY(bool hasMouseToTouch READ hasMouseToTouch CONSTANT)
41+#endif
42+
31public:
43public:
32− ApplicationArguments(QObject *parent = nullptr);
44+ ApplicationArguments(QCoreApplication *app);
33
45
34− void setDeviceName(const QString &deviceName) {
46+ void setDeviceName(const QString &deviceName);
35− if (deviceName != m_deviceName) {
36− m_deviceName = deviceName;
37− Q_EMIT deviceNameChanged(m_deviceName);
38− }
39− }
40− QString deviceName() const { return m_deviceName; }
41
47
42− void setMode(const QString &mode) { m_mode = mode; }
48+ bool hasGeometry() const { return m_windowGeometry.isValid(); }
43− QString mode() const { return m_mode; }
44
49
45Q_SIGNALS:
50Q_SIGNALS:
46 void deviceNameChanged(const QString&);
51 void deviceNameChanged(const QString&);
47−
48−private:
49− QString m_deviceName;
50− QString m_mode;
51};
52};
52
53
53#endif // APPLICATION_ARGUMENTS_H
54#endif // APPLICATION_ARGUMENTS_H
src/CMakeLists.txt−2
@@ -27,9 +27,7 @@ set(SOURCE_FILES
27 ApplicationArguments.cpp
27 ApplicationArguments.cpp
28 main.cpp
28 main.cpp
29 CachingNetworkManagerFactory.cpp
29 CachingNetworkManagerFactory.cpp
30− SecondaryWindow.cpp
31 ShellApplication.cpp
30 ShellApplication.cpp
32− ShellView.cpp
33 UnityCommandLineParser.cpp
31 UnityCommandLineParser.cpp
34 UnixSignalHandler.cpp
32 UnixSignalHandler.cpp
35 DebuggingController.cpp
33 DebuggingController.cpp
src/DebuggingController.cpp+12−1
@@ -49,7 +49,8 @@ public:
49};
49};
50
50
51DebuggingController::DebuggingController(QObject *parent):
51DebuggingController::DebuggingController(QObject *parent):
52− UnityDBusObject(QStringLiteral("/com/canonical/Unity8/Debugging"), QStringLiteral("com.canonical.Unity8"), true, parent)
52+ UnityDBusObject(QStringLiteral("/com/canonical/Unity8/Debugging"), QStringLiteral("com.canonical.Unity8"), true, parent),
53+ m_logOverlay(false)
53{
54{
54}
55}
55
56
@@ -90,3 +91,13 @@ void DebuggingController::SetLoggingFilterRules(const QString &filterRules)
90{
91{
91 QLoggingCategory::setFilterRules(filterRules);
92 QLoggingCategory::setFilterRules(filterRules);
92}
93}
94+
95+void DebuggingController::SetLogOverlay(bool logOverlay)
96+{
97+ if (logOverlay == m_logOverlay) {
98+ return;
99+ }
100+
101+ m_logOverlay = logOverlay;
102+ Q_EMIT logOverlayChanged(m_logOverlay);
103+}
src/DebuggingController.h+14
@@ -32,10 +32,14 @@ class DebuggingController: public UnityDBusObject
32 Q_OBJECT
32 Q_OBJECT
33 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity8.Debugging")
33 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity8.Debugging")
34
34
35+ Q_PROPERTY(bool logOverlay READ logOverlay NOTIFY logOverlayChanged)
36+
35public:
37public:
36 DebuggingController(QObject *parent = nullptr);
38 DebuggingController(QObject *parent = nullptr);
37 ~DebuggingController() = default;
39 ~DebuggingController() = default;
38
40
41+ bool logOverlay() const { return m_logOverlay; }
42+
39public Q_SLOTS:
43public Q_SLOTS:
40 /**
44 /**
41 * Set the QSG_VISUALIZE mode. This follows the vlues supported by Qt in
45 * Set the QSG_VISUALIZE mode. This follows the vlues supported by Qt in
@@ -53,5 +57,15 @@ public Q_SLOTS:
53 */
57 */
54 Q_SCRIPTABLE void SetLoggingFilterRules(const QString &filterRules);
58 Q_SCRIPTABLE void SetLoggingFilterRules(const QString &filterRules);
55
59
60+ /**
61+ * Enable/Disable the shell console log overlay
62+ */
63+ Q_SCRIPTABLE void SetLogOverlay(bool logOverlay);
64+
65+Q_SIGNALS:
66+ void logOverlayChanged(bool logOverlay);
67+
68+private:
69+ bool m_logOverlay;
56};
70};
57#endif // DEBUGGINGCONTROLLER_H
71#endif // DEBUGGINGCONTROLLER_H
src/SecondaryWindow.cppdeleted−40
@@ -1,40 +0,0 @@
1−/*
2− * Copyright (C) 2015 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 "SecondaryWindow.h"
18−
19−// local
20−#include <paths.h>
21−
22−#include <QQmlContext>
23−
24−SecondaryWindow::SecondaryWindow(QQmlEngine *engine)
25− : QQuickView(engine, nullptr)
26−{
27− QByteArray pxpguEnv = qgetenv("GRID_UNIT_PX");
28− bool ok;
29− int pxpgu = pxpguEnv.toInt(&ok);
30− if (!ok) {
31− pxpgu = 8;
32− }
33− engine->rootContext()->setContextProperty(QStringLiteral("internalGu"), pxpgu);
34− setResizeMode(QQuickView::SizeRootObjectToView);
35− setColor("black");
36− setTitle(QStringLiteral("Unity8 Shell - Secondary Screen"));
37−
38− QUrl source(::qmlDirectory() + "/DisabledScreenNotice.qml");
39− setSource(source);
40−}
src/ShellApplication.cpp+31−108
@@ -20,6 +20,7 @@
20#include <QLibrary>
20#include <QLibrary>
21#include <QProcess>
21#include <QProcess>
22#include <QScreen>
22#include <QScreen>
23+#include <QQmlContext>
23
24
24#include <libintl.h>
25#include <libintl.h>
25
26
@@ -34,30 +35,22 @@
34
35
35ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
36ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
36 : QGuiApplication(argc, argv)
37 : QGuiApplication(argc, argv)
38+ , m_qmlArgs(this)
37{
39{
38 setApplicationName(QStringLiteral("unity8"));
40 setApplicationName(QStringLiteral("unity8"));
39 setOrganizationName(QStringLiteral("Canonical"));
41 setOrganizationName(QStringLiteral("Canonical"));
40
42
41− connect(this, &QGuiApplication::screenAdded, this, &ShellApplication::onScreenAdded);
42−
43 setupQmlEngine(isMirServer);
43 setupQmlEngine(isMirServer);
44
44
45− UnityCommandLineParser parser(*this);
46−
47− if (!parser.deviceName().isEmpty()) {
45+ if (m_qmlArgs.deviceName().isEmpty()) {
48− m_deviceName = parser.deviceName();
49− } else {
50 char buffer[200];
46 char buffer[200];
51 property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/);
47 property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/);
52− m_deviceName = QString(buffer);
48+ m_qmlArgs.setDeviceName(QString(buffer));
53 }
49 }
54− m_qmlArgs.setDeviceName(m_deviceName);
55−
56− m_qmlArgs.setMode(parser.mode());
57
50
58 // The testability driver is only loaded by QApplication but not by QGuiApplication.
51 // The testability driver is only loaded by QApplication but not by QGuiApplication.
59 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
52 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
60− if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) {
53+ if (m_qmlArgs.hasTestability() || getenv("QT_LOAD_TESTABILITY")) {
61 QLibrary testLib(QStringLiteral("qttestability"));
54 QLibrary testLib(QStringLiteral("qttestability"));
62 if (testLib.load()) {
55 if (testLib.load()) {
63 typedef void (*TasInitialize)(void);
56 typedef void (*TasInitialize)(void);
@@ -75,58 +68,41 @@ ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
75 bindtextdomain("unity8", translationDirectory().toUtf8().data());
68 bindtextdomain("unity8", translationDirectory().toUtf8().data());
76 textdomain("unity8");
69 textdomain("unity8");
77
70
78− m_shellView = new ShellView(m_qmlEngine, &m_qmlArgs);
71+ m_qmlEngine->rootContext()->setContextProperty(QStringLiteral("applicationArguments"), &m_qmlArgs);
79−
80− if (parser.windowGeometry().isValid()) {
81− m_shellView->setWidth(parser.windowGeometry().width());
82− m_shellView->setHeight(parser.windowGeometry().height());
83− }
84
72
85− if (parser.hasFrameless()) {
73+ QByteArray pxpguEnv = qgetenv("GRID_UNIT_PX");
86− m_shellView->setFlags(Qt::FramelessWindowHint);
74+ bool ok;
75+ int pxpgu = pxpguEnv.toInt(&ok);
76+ if (!ok) {
77+ pxpgu = 8;
87 }
78 }
88−
79+ m_qmlEngine->rootContext()->setContextProperty("internalGu", pxpgu);
80+ m_qmlEngine->load(::qmlDirectory() + "/ShellApplication.qml");
89
81
90 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
82 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
91 // You will need this if you want to interact with touch-only components using a mouse
83 // You will need this if you want to interact with touch-only components using a mouse
92 // Needed only when manually testing on a desktop.
84 // Needed only when manually testing on a desktop.
93− if (parser.hasMouseToTouch()) {
85+ if (m_qmlArgs.hasMouseToTouch()) {
94 m_mouseTouchAdaptor = MouseTouchAdaptor::instance();
86 m_mouseTouchAdaptor = MouseTouchAdaptor::instance();
95 }
87 }
96 #endif
88 #endif
97
89
98− new DebuggingController(this);
90+ m_qmlEngine->rootContext()->setContextProperty("DebuggingController", new DebuggingController(this));
99−
91+
100− // Some hard-coded policy for now.
101− // NB: We don't support more than two screens at the moment
102− //
103− // TODO: Support an arbitrary number of screens and different policies
104− // (eg cloned desktop, several desktops, etc)
105− if (isMirServer && screens().count() == 2) {
106− m_shellView->setScreen(screens().at(1));
107− m_qmlArgs.setDeviceName(QStringLiteral("desktop"));
108−
109− m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
110− m_secondaryWindow->setScreen(screens().at(0));
111− // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that!
112− m_secondaryWindow->setWindowState(Qt::WindowFullScreen);
113− m_secondaryWindow->setVisible(true);
114− }
115−
116− if (parser.mode().compare("greeter") == 0) {
92+// if (parser.mode().compare("greeter") == 0) {
117− QSize primaryScreenSize = this->primaryScreen()->size();
93+// QSize primaryScreenSize = this->primaryScreen()->size();
118− m_shellView->setHeight(primaryScreenSize.height());
94+// m_shellView->setHeight(primaryScreenSize.height());
119− m_shellView->setWidth(primaryScreenSize.width());
95+// m_shellView->setWidth(primaryScreenSize.width());
120− m_shellView->show();
96+// m_shellView->show();
121− m_shellView->requestActivate();
97+// m_shellView->requestActivate();
122− if (!QProcess::startDetached("initctl emit --no-wait unity8-greeter-started")) {
98+// if (!QProcess::startDetached("initctl emit --no-wait unity8-greeter-started")) {
123− qDebug() << "Unable to send unity8-greeter-started event to Upstart";
99+// qDebug() << "Unable to send unity8-greeter-started event to Upstart";
124− }
100+// }
125− } else if (isMirServer || parser.hasFullscreen()) {
101+// } else if (isMirServer || parser.hasFullscreen()) {
126− m_shellView->showFullScreen();
102+// m_shellView->showFullScreen();
127− } else {
103+// } else {
128− m_shellView->show();
104+// m_shellView->show();
129− }
105+// }
130}
106}
131
107
132ShellApplication::~ShellApplication()
108ShellApplication::~ShellApplication()
@@ -136,14 +112,6 @@ ShellApplication::~ShellApplication()
136
112
137void ShellApplication::destroyResources()
113void ShellApplication::destroyResources()
138{
114{
139− // Deletion order is important. Don't use QScopedPointers and the like
140− // Otherwise the process will hang on shutdown (bug somewhere I guess).
141− delete m_shellView;
142− m_shellView = nullptr;
143−
144− delete m_secondaryWindow;
145− m_secondaryWindow = nullptr;
146−
147 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
115 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
148 delete m_mouseTouchAdaptor;
116 delete m_mouseTouchAdaptor;
149 m_mouseTouchAdaptor = nullptr;
117 m_mouseTouchAdaptor = nullptr;
@@ -155,7 +123,7 @@ void ShellApplication::destroyResources()
155
123
156void ShellApplication::setupQmlEngine(bool isMirServer)
124void ShellApplication::setupQmlEngine(bool isMirServer)
157{
125{
158− m_qmlEngine = new QQmlEngine(this);
126+ m_qmlEngine = new QQmlApplicationEngine(this);
159
127
160 m_qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
128 m_qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
161
129
@@ -169,48 +137,3 @@ void ShellApplication::setupQmlEngine(bool isMirServer)
169
137
170 QObject::connect(m_qmlEngine, &QQmlEngine::quit, this, &QGuiApplication::quit);
138 QObject::connect(m_qmlEngine, &QQmlEngine::quit, this, &QGuiApplication::quit);
171}
139}
172−
173−void ShellApplication::onScreenAdded(QScreen * /*screen*/)
174−{
175− // TODO: Support an arbitrary number of screens and different policies
176− // (eg cloned desktop, several desktops, etc)
177− if (screens().count() == 2) {
178− m_shellView->setScreen(screens().at(1));
179− m_qmlArgs.setDeviceName(QStringLiteral("desktop"));
180− // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
181− // its backing QPlatformWindow recreated). So lets refocus it.
182− m_shellView->requestActivate();
183− // QWindow::destroy() is called when it changes between screens. We have to manually make it visible again
184− // <dandrader> This bug is supposedly fixed in Qt 5.5.1, although I can still reproduce it there. :-/
185− m_shellView->setVisible(true);
186−
187− m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
188− m_secondaryWindow->setScreen(screens().at(0));
189−
190− // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that!
191− m_secondaryWindow->setWindowState(Qt::WindowFullScreen);
192− m_secondaryWindow->setVisible(true);
193− }
194−}
195−
196−void ShellApplication::onScreenAboutToBeRemoved(QScreen *screen)
197−{
198− // TODO: Support an arbitrary number of screens and different policies
199− // (eg cloned desktop, several desktops, etc)
200− if (screen == m_shellView->screen()) {
201− const QList<QScreen *> allScreens = screens();
202− Q_ASSERT(allScreens.count() > 1);
203− Q_ASSERT(allScreens.at(0) != screen);
204− Q_ASSERT(m_secondaryWindow);
205− delete m_secondaryWindow;
206− m_secondaryWindow = nullptr;
207− m_shellView->setScreen(allScreens.first());
208− m_qmlArgs.setDeviceName(m_deviceName);
209− // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
210− // its backing QPlatformWindow recreated). So lets refocus it.
211− m_shellView->requestActivate();
212− // QWindow::destroy() is called when it changes between screens. We have to manually make it visible again
213− // <dandrader> This bug is supposedly fixed in Qt 5.5.1, although I can still reproduce it there. :-/
214− m_shellView->setVisible(true);
215− }
216−}
src/ShellApplication.h+2−14
@@ -18,7 +18,7 @@
18#define SHELLAPPLICATION_H
18#define SHELLAPPLICATION_H
19
19
20#include <QGuiApplication>
20#include <QGuiApplication>
21−#include <QQmlEngine>
21+#include <QQmlApplicationEngine>
22#include <QQuickView>
22#include <QQuickView>
23#include <QScopedPointer>
23#include <QScopedPointer>
24
24
@@ -28,9 +28,6 @@
28#include "MouseTouchAdaptor.h"
28#include "MouseTouchAdaptor.h"
29#endif
29#endif
30
30
31−#include "SecondaryWindow.h"
32−#include "ShellView.h"
33−
34class ShellApplication : public QGuiApplication
31class ShellApplication : public QGuiApplication
35{
32{
36 Q_OBJECT
33 Q_OBJECT
@@ -39,25 +36,16 @@ public:
39 virtual ~ShellApplication();
36 virtual ~ShellApplication();
40
37
41 void destroyResources();
38 void destroyResources();
42−public Q_SLOTS:
43− // called by qtmir
44− void onScreenAboutToBeRemoved(QScreen *screen);
45−
46−private Q_SLOTS:
47− void onScreenAdded(QScreen*);
48
39
49private:
40private:
50 void setupQmlEngine(bool isMirServer);
41 void setupQmlEngine(bool isMirServer);
51− QString m_deviceName;
52 ApplicationArguments m_qmlArgs;
42 ApplicationArguments m_qmlArgs;
53− ShellView *m_shellView{nullptr};
54− SecondaryWindow *m_secondaryWindow{nullptr};
55
43
56 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
44 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
57 MouseTouchAdaptor *m_mouseTouchAdaptor{nullptr};
45 MouseTouchAdaptor *m_mouseTouchAdaptor{nullptr};
58 #endif
46 #endif
59
47
60− QQmlEngine *m_qmlEngine{nullptr};
48+ QQmlApplicationEngine *m_qmlEngine{nullptr};
61};
49};
62
50
63#endif // SHELLAPPLICATION_H
51#endif // SHELLAPPLICATION_H
src/ShellView.cppdeleted−63
@@ -1,63 +0,0 @@
1−/*
2− * Copyright (C) 2015 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 "ShellView.h"
18−
19−// Qt
20−#include <QQmlContext>
21−#include <QQuickItem>
22−
23−// local
24−#include <paths.h>
25−
26−ShellView::ShellView(QQmlEngine *engine, QObject *qmlArgs)
27− : QQuickView(engine, nullptr)
28−{
29− setResizeMode(QQuickView::SizeRootObjectToView);
30− setColor("black");
31− setTitle(QStringLiteral("Unity8"));
32−
33− rootContext()->setContextProperty(QStringLiteral("applicationArguments"), qmlArgs);
34−
35− QUrl source(::qmlDirectory() + "/OrientedShell.qml");
36− setSource(source);
37−
38− connect(this, &QWindow::widthChanged, this, &ShellView::onWidthChanged);
39− connect(this, &QWindow::heightChanged, this, &ShellView::onHeightChanged);
40−}
41−
42−void ShellView::onWidthChanged(int w)
43−{
44− // For good measure in case SizeRootObjectToView doesn't fulfill its promise.
45− //
46− // There's at least one situation that's know to leave the root object with an outdated size.
47− // (really looks like Qt bug)
48− // Happens when starting unity8 with an external monitor already connected.
49− // The QResizeEvent we get still has the size of the first screen and since the resize move is triggered
50− // from the resize event handler, the root item doesn't get resized.
51− // TODO: Confirm the Qt bug and submit a patch upstream
52− if (rootObject()) {
53− rootObject()->setWidth(w);
54− }
55−}
56−
57−void ShellView::onHeightChanged(int h)
58−{
59− // See comment in ShellView::onWidthChanged()
60− if (rootObject()) {
61− rootObject()->setHeight(h);
62− }
63−}
src/UnityCommandLineParser.h+1−1
@@ -36,8 +36,8 @@ public:
36 bool hasFullscreen() const { return m_hasFullscreen; }
36 bool hasFullscreen() const { return m_hasFullscreen; }
37 QString deviceName() const { return m_deviceName; }
37 QString deviceName() const { return m_deviceName; }
38 QString mode() const { return m_mode; }
38 QString mode() const { return m_mode; }
39−private:
40
39
40+protected:
41 int parsePixelsValue(const QString &str);
41 int parsePixelsValue(const QString &str);
42 static float getenvFloat(const char* name, float defaultValue);
42 static float getenvFloat(const char* name, float defaultValue);
43 void resolveMode(QCommandLineParser &parser, QCommandLineOption &modeOption);
43 void resolveMode(QCommandLineParser &parser, QCommandLineOption &modeOption);
tests/mocks/Cursor/Cursor.qml+49−2
@@ -15,8 +15,11 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18+import UInput 0.1
19+
20+Canvas {
21+ id: root
18
22
19−Item {
20 property int topBoundaryOffset // effectively panel height
23 property int topBoundaryOffset // effectively panel height
21 property Item confiningItem
24 property Item confiningItem
22
25
@@ -30,5 +33,49 @@ Item {
30 signal pushStopped()
33 signal pushStopped()
31 signal mouseMoved()
34 signal mouseMoved()
32
35
36+ width: units.gu(2)
37+ height: units.gu(2)
38+ antialiasing: true
39+
40+ onPaint: {
41+ var ctx = getContext("2d");
42+ ctx.save();
43+ ctx.clearRect(0,0,width, height);
44+ ctx.strokeStyle = "#000000";
45+ ctx.lineWidth = 1
46+ ctx.fillStyle = "#ffffff";
47+ ctx.globalAlpha = 1.0;
48+ ctx.lineJoin = "round";
49+ ctx.beginPath();
50+
51+ // put rectangle in the middle
52+ // draw the rectangle
53+ ctx.moveTo(width/2,height);
54+ ctx.lineTo(width, height/2);
55+ ctx.lineTo(0,0);
56+
57+ ctx.closePath();
58+ ctx.fill();
59+ ctx.stroke();
60+ ctx.restore();
61+ }
62+
63+ Connections {
64+ target: UInput
33− onMouseMoved: opacity = 1;
65+ onMouseMoved: {
66+ var newX = root.x;
67+ newX += dx;
68+ if (newX < 0) newX = 0;
69+ else if (newX >= parent.width) newX = parent.width-1;
70+
71+ var newY = root.y;
72+ newY += dy;
73+ if (newY < 0) newY = 0;
74+ else if (newY >= parent.height) newY = parent.height-1;
75+
76+ root.x = newX;
77+ root.y = newY;
78+ root.mouseMoved();
79+ }
80+ }
34}
81}
tests/mocks/GSettings.1.0/plugin.cpp+12
@@ -18,6 +18,8 @@
18#include "fake_gsettings.h"
18#include "fake_gsettings.h"
19
19
20#include <QtQml/qqml.h>
20#include <QtQml/qqml.h>
21+#include <QQmlEngine>
22+#include <QQmlContext>
21
23
22static QObject* controllerProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
24static QObject* controllerProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
23{
25{
@@ -31,3 +33,13 @@ void FakeGSettingsQmlPlugin::registerTypes(const char *uri)
31 qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
33 qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
32 "GSettingsSchema can only be used inside of a GSettings component");
34 "GSettingsSchema can only be used inside of a GSettings component");
33}
35}
36+
37+void FakeGSettingsQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
38+{
39+ QQmlExtensionPlugin::initializeEngine(engine, uri);
40+
41+ QString usageType = qgetenv("UNITY_MOCK_DESKTOP");
42+ if (!usageType.isEmpty()) {
43+ GSettingsControllerQml::instance()->setUsageMode("Windowed");
44+ }
45+}
tests/mocks/GSettings.1.0/plugin.h+1
@@ -26,6 +26,7 @@ class FakeGSettingsQmlPlugin : public QQmlExtensionPlugin
26
26
27public:
27public:
28 void registerTypes(const char *uri) override;
28 void registerTypes(const char *uri) override;
29+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
29};
30};
30
31
31#endif // PLUGIN_H
32#endif // PLUGIN_H
tests/mocks/UInput/plugin.cpp+6−1
@@ -19,8 +19,13 @@
19
19
20#include <QtQml/qqml.h>
20#include <QtQml/qqml.h>
21
21
22+QObject* uinputSingleton(QQmlEngine*, QJSEngine*)
23+{
24+ return new MockUInput;
25+}
26+
22void MockUInputPlugin::registerTypes(const char *uri)
27void MockUInputPlugin::registerTypes(const char *uri)
23{
28{
24 Q_ASSERT(uri == QLatin1String("UInput"));
29 Q_ASSERT(uri == QLatin1String("UInput"));
25− qmlRegisterType<MockUInput>(uri, 0, 1, "UInput");
30+ qmlRegisterSingletonType<MockUInput>(uri, 0, 1, "UInput", uinputSingleton);
26}
31}
tests/mocks/Unity/Application/SurfaceManager.cpp+1−1
@@ -21,7 +21,7 @@
21
21
22#include <paths.h>
22#include <paths.h>
23
23
24−#define SURFACEMANAGER_DEBUG 0
24+#define SURFACEMANAGER_DEBUG 1
25
25
26#if SURFACEMANAGER_DEBUG
26#if SURFACEMANAGER_DEBUG
27#define DEBUG_MSG(params) qDebug().nospace() << "SurfaceManager[" << (void*)this << "]::" << __func__ << params
27#define DEBUG_MSG(params) qDebug().nospace() << "SurfaceManager[" << (void*)this << "]::" << __func__ << params
tests/mocks/Unity/InputInfo/InputWindow.qmlnew file+68
@@ -0,0 +1,68 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+import Unity.InputInfo 0.1
4+
5+Rectangle {
6+ id: rect
7+ color: "white"
8+ width: parent.width
9+ height: parent.height
10+
11+ Action {
12+ id: mouseAction
13+ text: checked ? "Remove Mouse" : "Add Mouse"
14+ onTriggered: {
15+ if (checked) {
16+ console.log("ADD")
17+ MockInputDeviceBackend.addMockDevice("/mouse0", InputInfo.Mouse);
18+ } else {
19+ console.log("REMOVE")
20+ MockInputDeviceBackend.removeDevice("/mouse0");
21+ }
22+ }
23+ iconName: "input-mouse-symbolic"
24+ checkable: true
25+ checked: false
26+ }
27+
28+ Action {
29+ id: kbAction
30+ text: checked ? "Remove Keyboard" : "Add Keyboard"
31+ onTriggered: {
32+ if (checked) {
33+ MockInputDeviceBackend.addMockDevice("/kbd0", InputInfo.Keyboard);
34+ } else {
35+ MockInputDeviceBackend.removeDevice("/kbd0");
36+ }
37+ }
38+ iconName: "input-keyboard-symbolic"
39+ checkable: true
40+ checked: false
41+ }
42+
43+ Column {
44+ anchors {
45+ fill: parent
46+ margins: units.gu(1)
47+ }
48+ spacing: units.gu(1)
49+
50+ Button {
51+ anchors {
52+ left: parent.left
53+ right: parent.right
54+ }
55+ action: mouseAction
56+ color: mouseAction.checked ? UbuntuColors.red : UbuntuColors.green
57+ }
58+
59+ Button {
60+ anchors {
61+ left: parent.left
62+ right: parent.right
63+ }
64+ action: kbAction
65+ color: kbAction.checked ? UbuntuColors.red : UbuntuColors.green
66+ }
67+ }
68+}
tests/mocks/Unity/InputInfo/mockcontroller.cpp+24−2
@@ -18,10 +18,32 @@
18
18
19#include "qinputdeviceinfo_mock_p.h"
19#include "qinputdeviceinfo_mock_p.h"
20
20
21+#include <QQuickView>
22+#include <QQmlComponent>
23+#include <QQuickItem>
24+#include <paths.h>
25+
21−MockController::MockController(QObject *parent):
26+MockController::MockController(QQmlEngine *engine)
22− QObject(parent)
23{
27{
28+ QQmlComponent component(engine);
29+ component.setData("import QtQuick 2.4; import Unity.InputInfo 0.1; InputWindow { }", ::qmlDirectory());
30+ QObject *myObject = component.create();
31+ QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
32+ if (item) {
33+ auto window = new QQuickView();
34+ window->setTitle("Input");
35+ item->setParentItem(window->contentItem());
36+ window->setResizeMode(QQuickView::SizeRootObjectToView);
37+ window->setWidth(200);
38+ window->setHeight(100);
39+ window->show();
40+ }
41+}
24
42
43+MockController *MockController::instance(QQmlEngine *engine)
44+{
45+ static MockController* controller = new MockController(engine);
46+ return controller;
25}
47}
26
48
27QInputDevice *MockController::addMockDevice(const QString &devicePath, QInputDevice::InputType type)
49QInputDevice *MockController::addMockDevice(const QString &devicePath, QInputDevice::InputType type)
tests/mocks/Unity/InputInfo/mockcontroller.h+5−1
@@ -20,13 +20,17 @@
20#include <QObject>
20#include <QObject>
21#include "qinputinfo.h"
21#include "qinputinfo.h"
22
22
23+class QQmlEngine;
24+
23class MockController: public QObject
25class MockController: public QObject
24{
26{
25 Q_OBJECT
27 Q_OBJECT
26public:
28public:
27− MockController(QObject *parent = 0);
29+ MockController(QQmlEngine *engine);
28 ~MockController() = default;
30 ~MockController() = default;
29
31
32+ static MockController *instance(QQmlEngine *engine);
33+
30 Q_INVOKABLE QInputDevice* addMockDevice(const QString &devicePath, QInputDevice::InputType type);
34 Q_INVOKABLE QInputDevice* addMockDevice(const QString &devicePath, QInputDevice::InputType type);
31 Q_INVOKABLE void removeDevice(const QString &devicePath);
35 Q_INVOKABLE void removeDevice(const QString &devicePath);
32};
36};
tests/mocks/Unity/InputInfo/plugin.cpp+1−2
@@ -26,9 +26,8 @@
26
26
27static QObject *backendProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
27static QObject *backendProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
28{
28{
29− Q_UNUSED(engine)
30 Q_UNUSED(scriptEngine)
29 Q_UNUSED(scriptEngine)
31− return new MockController(engine);
30+ return MockController::instance(engine);
32}
31}
33
32
34void InputInfoPlugin::registerTypes(const char *uri)
33void InputInfoPlugin::registerTypes(const char *uri)
tests/mocks/Unity/InputInfo/qmldir+2
@@ -1,2 +1,4 @@
1module Unity.InputInfo
1module Unity.InputInfo
2plugin MockInputInfo
2plugin MockInputInfo
3+
4+InputWindow 0.1 InputWindow.qml
tests/mocks/Unity/Screens/CMakeLists.txt+2−1
@@ -5,10 +5,11 @@ include_directories(
5set(MockScreens_SOURCES
5set(MockScreens_SOURCES
6 plugin.cpp
6 plugin.cpp
7 screens.cpp
7 screens.cpp
8+ screenwindow.cpp
8)
9)
9
10
10add_library(MockScreensPlugin MODULE ${MockScreens_SOURCES})
11add_library(MockScreensPlugin MODULE ${MockScreens_SOURCES})
11
12
12−qt5_use_modules(MockScreensPlugin Gui Qml)
13+qt5_use_modules(MockScreensPlugin Gui Qml Quick)
13
14
14add_unity8_mock(Unity.Screens 0.1 Unity/Screens PREFIX mocks TARGETS MockScreensPlugin)
15add_unity8_mock(Unity.Screens 0.1 Unity/Screens PREFIX mocks TARGETS MockScreensPlugin)
tests/mocks/Unity/Screens/plugin.cpp+12−1
@@ -16,14 +16,25 @@
16
16
17#include "plugin.h"
17#include "plugin.h"
18#include "screens.h"
18#include "screens.h"
19+#include "screenwindow.h"
19
20
20#include <QScreen>
21#include <QScreen>
21
22
23+namespace {
24+QObject* screensSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
25+ Q_UNUSED(engine);
26+ Q_UNUSED(scriptEngine);
27+ return new Screens();
28+}
29+}
30+
22void UnityScreensPlugin::registerTypes(const char* uri)
31void UnityScreensPlugin::registerTypes(const char* uri)
23{
32{
24 Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens"));
33 Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens"));
25
34
26 qRegisterMetaType<QScreen*>("QScreen*");
35 qRegisterMetaType<QScreen*>("QScreen*");
27
36
37+ qmlRegisterSingletonType<Screens>(uri, 0, 1, "Screens", screensSingleton);
28− qmlRegisterType<Screens>(uri, 0, 1, "Screens");
38+ qmlRegisterType<ScreenWindow>(uri, 0, 1, "ScreenWindow");
39+ qmlRegisterRevision<QWindow,1>(uri, 0, 1);
29}
40}
tests/mocks/Unity/Screens/screens.cpp+39−2
@@ -26,8 +26,20 @@ Q_DECLARE_METATYPE(QScreen*)
26Screens::Screens(QObject *parent) :
26Screens::Screens(QObject *parent) :
27 QAbstractListModel(parent)
27 QAbstractListModel(parent)
28{
28{
29− // start with one screen attached
29+ bool ok = false;
30+ int screenCount = qEnvironmentVariableIntValue("UNITY_MOCK_SCREEN_COUNT", &ok);
31+ if (!ok) screenCount = 1;
32+ QPoint lastPoint(0,0);
33+ for (int i = 0; i < screenCount; ++i) {
34+ auto screen = new Screen();
35+ screen->enabled = i == 0;
36+ screen->name = QString("Monitor %1").arg(i);
37+ screen->sizes = { QSize(640,480), QSize(1024,748), QSize(1280,1024), QSize(1440,900), QSize(1920,1080) };
38+ screen->geometry = QRect(lastPoint.x(), lastPoint.y(), 1024, 786 );
30− m_screenList.append(new Screen());
39+ m_screenList.append(screen);
40+
41+ lastPoint.rx() += screen->geometry.width();
42+ }
31}
43}
32
44
33Screens::~Screens() noexcept
45Screens::~Screens() noexcept
@@ -41,6 +53,12 @@ QHash<int, QByteArray> Screens::roleNames() const
41 QHash<int, QByteArray> roles;
53 QHash<int, QByteArray> roles;
42 roles[ScreenRole] = "screen";
54 roles[ScreenRole] = "screen";
43 roles[OutputTypeRole] = "outputType";
55 roles[OutputTypeRole] = "outputType";
56+ roles[EnabledRole] = "enabled";
57+ roles[NameRole] = "name";
58+ roles[ScaleRole] = "scale";
59+ roles[FormFactorRole] = "formFactor";
60+ roles[GeometryRole] = "geometry";
61+ roles[SizesRole] = "sizes";
44 return roles;
62 return roles;
45}
63}
46
64
@@ -55,6 +73,25 @@ QVariant Screens::data(const QModelIndex &index, int role) const
55 return QVariant::fromValue(m_screenList.at(index.row())->qScreen);
73 return QVariant::fromValue(m_screenList.at(index.row())->qScreen);
56 case OutputTypeRole:
74 case OutputTypeRole:
57 return m_screenList.at(index.row())->outputTypes;
75 return m_screenList.at(index.row())->outputTypes;
76+ case EnabledRole:
77+ return m_screenList.at(index.row())->enabled;
78+ case NameRole:
79+ return m_screenList.at(index.row())->name;
80+ case ScaleRole:
81+ return m_screenList.at(index.row())->scale;
82+ case FormFactorRole:
83+ return m_screenList.at(index.row())->formFactor;
84+ case GeometryRole:
85+ return m_screenList.at(index.row())->geometry;
86+ case SizesRole:
87+ {
88+ QVariantList sizes;
89+ auto availableSizes = m_screenList.at(index.row())->sizes;
90+ Q_FOREACH(auto size, availableSizes) {
91+ sizes.append(QVariant(size));
92+ }
93+ return sizes;
94+ }
58 }
95 }
59
96
60 return QVariant();
97 return QVariant();
tests/mocks/Unity/Screens/screens.h+22−1
@@ -31,7 +31,13 @@ class Screens : public QAbstractListModel
31public:
31public:
32 enum ItemRoles {
32 enum ItemRoles {
33 ScreenRole = Qt::UserRole + 1,
33 ScreenRole = Qt::UserRole + 1,
34− OutputTypeRole
34+ OutputTypeRole,
35+ EnabledRole,
36+ NameRole,
37+ ScaleRole,
38+ FormFactorRole,
39+ GeometryRole,
40+ SizesRole
35 };
41 };
36
42
37 enum OutputTypes {
43 enum OutputTypes {
@@ -53,6 +59,15 @@ public:
53 };
59 };
54 Q_ENUM(OutputTypes)
60 Q_ENUM(OutputTypes)
55
61
62+ enum FormFactor {
63+ FormFactorUnknown,
64+ FormFactorPhone,
65+ FormFactorTablet,
66+ FormFactorMonitor,
67+ FormFactorTV,
68+ FormFactorProjector,
69+ };
70+
56 explicit Screens(QObject *parent = 0);
71 explicit Screens(QObject *parent = 0);
57 virtual ~Screens() noexcept;
72 virtual ~Screens() noexcept;
58
73
@@ -77,6 +92,12 @@ class Screen
77public:
92public:
78 Screens::OutputTypes outputTypes = Screens::Unknown;
93 Screens::OutputTypes outputTypes = Screens::Unknown;
79 QScreen *qScreen = nullptr;
94 QScreen *qScreen = nullptr;
95+ bool enabled = false;
96+ QString name = QString();
97+ float scale = 1.0;
98+ Screens::FormFactor formFactor = Screens::FormFactorMonitor;
99+ QRect geometry;
100+ QList<QSize> sizes;
80};
101};
81
102
82#endif // SCREENS_H
103#endif // SCREENS_H
tests/mocks/Unity/Screens/screenwindow.cppnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2016 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 "screenwindow.h"
18+
19+ScreenWindow::ScreenWindow(QWindow *parent)
20+ : QQuickWindow(parent)
21+{
22+}
23+
24+QScreen *ScreenWindow::screen() const
25+{
26+ return QQuickWindow::screen();
27+}
28+
29+void ScreenWindow::setScreen(QScreen *screen)
30+{
31+ QQuickWindow::setScreen(screen);
32+}
tests/mocks/Unity/Screens/screenwindow.hnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2016 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 SCREENWINDOW_H
18+#define SCREENWINDOW_H
19+
20+#include <QQuickWindow>
21+
22+class ScreenWindow : public QQuickWindow
23+{
24+ Q_OBJECT
25+ Q_PROPERTY(QScreen *screen READ screen WRITE setScreen NOTIFY screenChanged)
26+public:
27+ ScreenWindow(QWindow *parent = 0);
28+
29+ QScreen *screen() const;
30+ void setScreen(QScreen *screen);
31+
32+Q_SIGNALS:
33+ void screenChanged(QScreen *screen);
34+};
35+
36+#endif // SCREENWINDOW_H
tests/qmltests/Components/tst_VirtualTouchPad.qml+2−2
@@ -39,11 +39,11 @@ Rectangle {
39
39
40 SignalSpy {
40 SignalSpy {
41 id: mouseEventSpy1
41 id: mouseEventSpy1
42− target: touchScreenPad.uinput
42+ target: UInput
43 }
43 }
44 SignalSpy {
44 SignalSpy {
45 id: mouseEventSpy2
45 id: mouseEventSpy2
46− target: touchScreenPad.uinput
46+ target: UInput
47 }
47 }
48
48
49 UnityTestCase {
49 UnityTestCase {
tests/qmltests/Panel/tst_Panel.qml+14−12
@@ -42,6 +42,8 @@ PanelTest {
42 value: keyboardAttached.checked
42 value: keyboardAttached.checked
43 }
43 }
44
44
45+ readonly property alias panelState: panel.panelState
46+
45 SurfaceManager { id: sMgr }
47 SurfaceManager { id: sMgr }
46 ApplicationMenuDataLoader {
48 ApplicationMenuDataLoader {
47 id: appMenuData
49 id: appMenuData
@@ -148,7 +150,7 @@ PanelTest {
148 Layout.fillWidth: true
150 Layout.fillWidth: true
149 CheckBox {
151 CheckBox {
150 id: windowControlsCB
152 id: windowControlsCB
151− onClicked: PanelState.decorationsVisible = checked
153+ onClicked: panelState.decorationsVisible = checked
152 }
154 }
153 Label {
155 Label {
154 text: "Show window decorations"
156 text: "Show window decorations"
@@ -159,7 +161,7 @@ PanelTest {
159 RowLayout {
161 RowLayout {
160 Layout.fillWidth: true
162 Layout.fillWidth: true
161 CheckBox {
163 CheckBox {
162− onClicked: PanelState.title = checked ? "Fake window title" : ""
164+ onClicked: panelState.title = checked ? "Fake window title" : ""
163 }
165 }
164 Label {
166 Label {
165 text: "Show fake window title"
167 text: "Show fake window title"
@@ -245,7 +247,7 @@ PanelTest {
245
247
246 SignalSpy {
248 SignalSpy {
247 id: windowControlButtonsSpy
249 id: windowControlButtonsSpy
248− target: PanelState
250+ target: panelState
249 signalName: "closeClicked"
251 signalName: "closeClicked"
250 }
252 }
251
253
@@ -255,8 +257,8 @@ PanelTest {
255 panel.fullscreenMode = false;
257 panel.fullscreenMode = false;
256 callManager.foregroundCall = null;
258 callManager.foregroundCall = null;
257
259
258− PanelState.title = "";
260+ panelState.title = "";
259− PanelState.decorationsVisible = false;
261+ panelState.decorationsVisible = false;
260
262
261 // Wait for the indicators to get into position.
263 // Wait for the indicators to get into position.
262 // (switches between normal and fullscreen modes are animated)
264 // (switches between normal and fullscreen modes are animated)
@@ -445,7 +447,7 @@ PanelTest {
445 }
447 }
446
448
447 function test_hint(data) {
449 function test_hint(data) {
448− PanelState.title = "Fake Title"
450+ panelState.title = "Fake Title"
449 panel.fullscreenMode = data.fullscreen;
451 panel.fullscreenMode = data.fullscreen;
450 callManager.foregroundCall = data.call;
452 callManager.foregroundCall = data.call;
451
453
@@ -487,7 +489,7 @@ PanelTest {
487 // menus, first by running the hint animation, then after dragging down will
489 // menus, first by running the hint animation, then after dragging down will
488 // expose more of the panel. Releasing the touch will complete the show.
490 // expose more of the panel. Releasing the touch will complete the show.
489 function test_drag_applicationMenu_down_shows_menu(data) {
491 function test_drag_applicationMenu_down_shows_menu(data) {
490− PanelState.title = "Fake Title";
492+ panelState.title = "Fake Title";
491 panel.fullscreenMode = data.fullscreen;
493 panel.fullscreenMode = data.fullscreen;
492 callManager.foregroundCall = data.call;
494 callManager.foregroundCall = data.call;
493
495
@@ -578,7 +580,7 @@ PanelTest {
578 }
580 }
579
581
580 function test_darkenedAreaEatsAllApplicationMenuEvents() {
582 function test_darkenedAreaEatsAllApplicationMenuEvents() {
581− PanelState.title = "Fake Title"
583+ panelState.title = "Fake Title"
582
584
583 // The center of the area not covered by the indicators menu
585 // The center of the area not covered by the indicators menu
584 // Ie, the visible darkened area behind the menu
586 // Ie, the visible darkened area behind the menu
@@ -699,7 +701,7 @@ PanelTest {
699 var windowControlArea = findChild(panel, "windowControlArea");
701 var windowControlArea = findChild(panel, "windowControlArea");
700 verify(windowControlArea, "Window control area should have been created in windowed mode")
702 verify(windowControlArea, "Window control area should have been created in windowed mode")
701
703
702− PanelState.decorationsVisible = true;
704+ panelState.decorationsVisible = true;
703 // click in very topleft corner and verify the close button got clicked too
705 // click in very topleft corner and verify the close button got clicked too
704 mouseMove(panel, 0, 0);
706 mouseMove(panel, 0, 0);
705 mouseClick(panel, 0, 0, undefined /*button*/, undefined /*modifiers*/, 100 /*short delay*/);
707 mouseClick(panel, 0, 0, undefined /*button*/, undefined /*modifiers*/, 100 /*short delay*/);
@@ -760,7 +762,7 @@ PanelTest {
760 }
762 }
761
763
762 function test_stagedApplicationMenuBarShowOnMouseHover() {
764 function test_stagedApplicationMenuBarShowOnMouseHover() {
763− PanelState.title = "Fake Title";
765+ panelState.title = "Fake Title";
764 panel.mode = "staged";
766 panel.mode = "staged";
765 mouseEmulation.checked = false;
767 mouseEmulation.checked = false;
766
768
@@ -778,7 +780,7 @@ PanelTest {
778 }
780 }
779
781
780 function test_windowedApplicationMenuShowOnMouseHoverWhenDecorationsShown() {
782 function test_windowedApplicationMenuShowOnMouseHoverWhenDecorationsShown() {
781− PanelState.title = "Fake Title";
783+ panelState.title = "Fake Title";
782 panel.mode = "windowed";
784 panel.mode = "windowed";
783 mouseEmulation.checked = false;
785 mouseEmulation.checked = false;
784
786
@@ -794,7 +796,7 @@ PanelTest {
794 tryCompare(appTitle, "visible", true, undefined, "App title should still be visible on mouse hover when panel decorations are not visible");
796 tryCompare(appTitle, "visible", true, undefined, "App title should still be visible on mouse hover when panel decorations are not visible");
795 tryCompare(appMenuBar, "visible", false, undefined, "App menu bar should be visible on mouse hover when panel decorations are not visible");
797 tryCompare(appMenuBar, "visible", false, undefined, "App menu bar should be visible on mouse hover when panel decorations are not visible");
796
798
797− PanelState.decorationsVisible = true;
799+ panelState.decorationsVisible = true;
798
800
799 tryCompare(appTitle, "visible", false, undefined, "App title should still be visible on mouse hover when panel decorations are visible");
801 tryCompare(appTitle, "visible", false, undefined, "App title should still be visible on mouse hover when panel decorations are visible");
800 tryCompare(appMenuBar, "visible", true, undefined, "App menu bar should be visible on mouse hover when panel decorations not visible");
802 tryCompare(appMenuBar, "visible", true, undefined, "App menu bar should be visible on mouse hover when panel decorations not visible");
tests/qmltests/Stage/tst_DecoratedWindow.qml+5−1
@@ -52,6 +52,10 @@ Rectangle {
52 surfaceManager: sMgr
52 surfaceManager: sMgr
53 }
53 }
54
54
55+ PanelState {
56+ id: panelState
57+ }
58+
55 Item {
59 Item {
56 id: fakeShell
60 id: fakeShell
57
61
@@ -99,7 +103,7 @@ Rectangle {
99 surface: fakeApplication && fakeApplication.surfaceList.count > 0 ? fakeApplication.surfaceList.get(0) : null
103 surface: fakeApplication && fakeApplication.surfaceList.count > 0 ? fakeApplication.surfaceList.get(0) : null
100
104
101 Binding {
105 Binding {
102− target: PanelState
106+ target: panelState
103 property: "focusedPersistentSurfaceId"
107 property: "focusedPersistentSurfaceId"
104 value: decoratedWindow.surface ? decoratedWindow.surface.persistentId : "x"
108 value: decoratedWindow.surface ? decoratedWindow.surface.persistentId : "x"
105 }
109 }
tests/qmltests/Stage/tst_DesktopStage.qml+8−3
@@ -43,6 +43,10 @@ Item {
43 value: false
43 value: false
44 }
44 }
45
45
46+ PanelState {
47+ id: panelState
48+ }
49+
46 Component.onCompleted: {
50 Component.onCompleted: {
47 QuickUtils.keyboardAttached = true;
51 QuickUtils.keyboardAttached = true;
48 theme.name = "Ubuntu.Components.Themes.SuruDark";
52 theme.name = "Ubuntu.Components.Themes.SuruDark";
@@ -100,6 +104,7 @@ Item {
100 topLevelSurfaceList: topSurfaceList
104 topLevelSurfaceList: topSurfaceList
101 interactive: true
105 interactive: true
102 mode: "windowed"
106 mode: "windowed"
107+ panelState: panelState
103 }
108 }
104 }
109 }
105 }
110 }
@@ -618,19 +623,19 @@ Item {
618 maximizeDelegate(facebookAppDelegate);
623 maximizeDelegate(facebookAppDelegate);
619
624
620 // verify the drop shadow is still not visible
625 // verify the drop shadow is still not visible
621− verify(PanelState.dropShadow == false);
626+ verify(panelState.dropShadow == false);
622
627
623 // start a foreground app, not maximized
628 // start a foreground app, not maximized
624 var dialerAppDelegate = startApplication("dialer-app");
629 var dialerAppDelegate = startApplication("dialer-app");
625
630
626 // verify the drop shadow becomes visible
631 // verify the drop shadow becomes visible
627− verify(PanelState.dropShadow == true);
632+ verify(panelState.dropShadow == true);
628
633
629 // close the maximized app
634 // close the maximized app
630 ApplicationManager.stopApplication("facebook-webapp");
635 ApplicationManager.stopApplication("facebook-webapp");
631
636
632 // verify the drop shadow is gone
637 // verify the drop shadow is gone
633− tryCompare(PanelState, "dropShadow", false);
638+ tryCompare(panelState, "dropShadow", false);
634 }
639 }
635
640
636 function test_threeFingerTapShowsWindowControls_data() {
641 function test_threeFingerTapShowsWindowControls_data() {
tests/qmltests/Stage/tst_WindowResizeArea.qml+1−8
@@ -19,7 +19,6 @@ import QtQuick.Layouts 1.1
19import QtTest 1.0
19import QtTest 1.0
20import Unity.Test 0.1
20import Unity.Test 0.1
21import ".."
21import ".."
22−import "../../../qml/Components/PanelState"
23import "../../../qml/Stage"
22import "../../../qml/Stage"
24import Ubuntu.Components 1.3
23import Ubuntu.Components 1.3
25import Ubuntu.Components.ListItems 1.3 as ListItem
24import Ubuntu.Components.ListItems 1.3 as ListItem
@@ -31,12 +30,6 @@ Item {
31 height: units.gu(60)
30 height: units.gu(60)
32 width: units.gu(85)
31 width: units.gu(85)
33
32
34− Binding {
35− target: PanelState
36− property: "panelHeight"
37− value: units.gu(3)
38− }
39−
40 Component {
33 Component {
41 id: fakeWindowComponent
34 id: fakeWindowComponent
42
35
@@ -352,7 +345,7 @@ Item {
352
345
353 // Make sure it's again where we left it in normal state before destroying
346 // Make sure it's again where we left it in normal state before destroying
354 compare(fakeWindow.requestedX >= 0, true)
347 compare(fakeWindow.requestedX >= 0, true)
355− compare(fakeWindow.requestedY >= PanelState.panelHeight, true)
348+ compare(fakeWindow.requestedY >= 0, true)
356 compare(fakeWindow.requestedX + fakeWindow.width <= root.width, true)
349 compare(fakeWindow.requestedX + fakeWindow.width <= root.width, true)
357 compare(fakeWindow.requestedY + fakeWindow.height <= root.height, true)
350 compare(fakeWindow.requestedY + fakeWindow.height <= root.height, true)
358
351
tests/qmltests/tst_OrientedShell.qml+24−5
@@ -29,7 +29,6 @@ import Utils 0.1
29
29
30import "../../qml"
30import "../../qml"
31import "../../qml/Components"
31import "../../qml/Components"
32−import "../../qml/Components/PanelState"
33import "Stage"
32import "Stage"
34
33
35Rectangle {
34Rectangle {
@@ -75,6 +74,12 @@ Rectangle {
75 deviceFilter: InputInfo.Keyboard
74 deviceFilter: InputInfo.Keyboard
76 }
75 }
77
76
77+ QtObject {
78+ id: _screenWindow
79+ property bool primary: true
80+ }
81+ property alias screenWindow: _screenWindow
82+
78 property int physicalOrientation0
83 property int physicalOrientation0
79 property int physicalOrientation90
84 property int physicalOrientation90
80 property int physicalOrientation180
85 property int physicalOrientation180
@@ -167,6 +172,11 @@ Rectangle {
167 Component.onDestruction: {
172 Component.onDestruction: {
168 orientedShellLoader.itemDestroyed = true;
173 orientedShellLoader.itemDestroyed = true;
169 }
174 }
175+
176+ SurfaceManager {
177+ id: surfaceMan
178+ }
179+ surfaceManager: surfaceMan
170 }
180 }
171 }
181 }
172 }
182 }
@@ -439,6 +449,15 @@ Rectangle {
439 property Item orientedShell: orientedShellLoader.status === Loader.Ready ? orientedShellLoader.item : null
449 property Item orientedShell: orientedShellLoader.status === Loader.Ready ? orientedShellLoader.item : null
440 property Item shell
450 property Item shell
441 property QtObject topLevelSurfaceList
451 property QtObject topLevelSurfaceList
452+ property var panelState: undefined
453+
454+ onOrientedShellChanged: {
455+ if (orientedShell) {
456+ panelState = findInvisibleChild(orientedShell, "panelState");
457+ } else {
458+ panelState = undefined;
459+ }
460+ }
442
461
443 SignalSpy { id: signalSpy }
462 SignalSpy { id: signalSpy }
444 SignalSpy { id: signalSpy2 }
463 SignalSpy { id: signalSpy2 }
@@ -1507,13 +1526,13 @@ Rectangle {
1507 print("exptectedAngle", expectedAngle, point.x, point.y)
1526 print("exptectedAngle", expectedAngle, point.x, point.y)
1508 switch (expectedAngle) {
1527 switch (expectedAngle) {
1509 case 0:
1528 case 0:
1510− return point.x === 0 && point.y === PanelState.panelHeight;
1529+ return point.x === 0 && point.y === panelState.panelHeight;
1511 case 90:
1530 case 90:
1512− return point.x === orientedShell.width - PanelState.panelHeight && point.y === 0;
1531+ return point.x === orientedShell.width - panelState.panelHeight && point.y === 0;
1513 case 180:
1532 case 180:
1514− return point.x === orientedShell.width && point.y === orientedShell.height - PanelState.panelHeight;
1533+ return point.x === orientedShell.width && point.y === orientedShell.height - panelState.panelHeight;
1515 default: // 270
1534 default: // 270
1516− return point.x === PanelState.panelHeight && point.y === orientedShell.height;
1535+ return point.x === panelState.panelHeight && point.y === orientedShell.height;
1517 }
1536 }
1518 }
1537 }
1519
1538
tests/qmltests/tst_Shell.qml+25−11
@@ -62,13 +62,22 @@ Rectangle {
62 if (shell) {
62 if (shell) {
63 topLevelSurfaceList = testCase.findInvisibleChild(shell, "topLevelSurfaceList");
63 topLevelSurfaceList = testCase.findInvisibleChild(shell, "topLevelSurfaceList");
64 appMenuData.surfaceManager = testCase.findInvisibleChild(shell, "surfaceManager");
64 appMenuData.surfaceManager = testCase.findInvisibleChild(shell, "surfaceManager");
65+ panelState = testCase.findInvisibleChild(shell, "panelState");
65 } else {
66 } else {
66 topLevelSurfaceList = null;
67 topLevelSurfaceList = null;
67 appMenuData.surfaceManager = null;
68 appMenuData.surfaceManager = null;
69+ panelState = undefined;
68 }
70 }
69 }
71 }
70
72
71 property var topLevelSurfaceList: null
73 property var topLevelSurfaceList: null
74+ property var panelState: undefined
75+
76+ QtObject {
77+ id: _screenWindow
78+ property bool primary: false
79+ }
80+ property alias screenWindow: _screenWindow
72
81
73 Item {
82 Item {
74 id: shellContainer
83 id: shellContainer
@@ -143,6 +152,11 @@ Rectangle {
143 Component.onDestruction: {
152 Component.onDestruction: {
144 shellLoader.itemDestroyed = true;
153 shellLoader.itemDestroyed = true;
145 }
154 }
155+
156+ SurfaceManager {
157+ id: surfaceMan
158+ }
159+ surfaceManager: surfaceMan
146 }
160 }
147 }
161 }
148 }
162 }
@@ -679,7 +693,7 @@ Rectangle {
679 }
693 }
680
694
681 function ensureInputMethodSurface() {
695 function ensureInputMethodSurface() {
682− var surfaceManager = findInvisibleChild(shell, "surfaceManager");
696+ var surfaceManager = shell.surfaceManager;
683 verify(surfaceManager);
697 verify(surfaceManager);
684 surfaceManager.createInputMethodSurface();
698 surfaceManager.createInputMethodSurface();
685
699
@@ -1886,21 +1900,21 @@ Rectangle {
1886 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
1900 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
1887
1901
1888 tryCompare(appDelegate, "state", "normal");
1902 tryCompare(appDelegate, "state", "normal");
1889− tryCompare(PanelState, "decorationsVisible", false)
1903+ tryCompare(panelState, "decorationsVisible", false)
1890
1904
1891 mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
1905 mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
1892 tryCompare(appDelegate, "state", "maximized");
1906 tryCompare(appDelegate, "state", "maximized");
1893− tryCompare(PanelState, "decorationsVisible", true)
1907+ tryCompare(panelState, "decorationsVisible", true)
1894
1908
1895 ApplicationManager.stopApplication(application.appId);
1909 ApplicationManager.stopApplication(application.appId);
1896− tryCompare(PanelState, "decorationsVisible", false)
1910+ tryCompare(panelState, "decorationsVisible", false)
1897
1911
1898 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
1912 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
1899 // They won't be gone until those surface items are destroyed.
1913 // They won't be gone until those surface items are destroyed.
1900 tryCompareFunction(function() { return application.surfaceList.count }, 0);
1914 tryCompareFunction(function() { return application.surfaceList.count }, 0);
1901
1915
1902 ApplicationManager.startApplication(application.appId);
1916 ApplicationManager.startApplication(application.appId);
1903− tryCompare(PanelState, "decorationsVisible", true)
1917+ tryCompare(panelState, "decorationsVisible", true)
1904 }
1918 }
1905
1919
1906 function test_newAppHasValidGeometry() {
1920 function test_newAppHasValidGeometry() {
@@ -1957,7 +1971,7 @@ Rectangle {
1957 mousePress(appDelegate, appDelegate.width / 2, units.gu(1))
1971 mousePress(appDelegate, appDelegate.width / 2, units.gu(1))
1958 mouseMove(appDelegate, appDelegate.width / 2, -units.gu(100))
1972 mouseMove(appDelegate, appDelegate.width / 2, -units.gu(100))
1959
1973
1960− compare(appDelegate.y >= PanelState.panelHeight, true);
1974+ compare(appDelegate.y >= panelState.panelHeight, true);
1961 }
1975 }
1962
1976
1963 function test_cantResizeWindowUnderPanel() {
1977 function test_cantResizeWindowUnderPanel() {
@@ -1985,7 +1999,7 @@ Rectangle {
1985 mouseMove(decoration, decoration.width/2, -units.gu(100));
1999 mouseMove(decoration, decoration.width/2, -units.gu(100));
1986
2000
1987 // verify we don't go past the panel
2001 // verify we don't go past the panel
1988− compare(appDelegate.y >= PanelState.panelHeight, true);
2002+ compare(appDelegate.y >= panelState.panelHeight, true);
1989 }
2003 }
1990
2004
1991 function test_restoreWindowStateFixesIfUnderPanel() {
2005 function test_restoreWindowStateFixesIfUnderPanel() {
@@ -2009,7 +2023,7 @@ Rectangle {
2009 tryCompareFunction(function () { return topLevelSurfaceList.applicationAt(0).appId; }, application.appId);
2023 tryCompareFunction(function () { return topLevelSurfaceList.applicationAt(0).appId; }, application.appId);
2010
2024
2011 appDelegate = appRepeater.itemAt(0);
2025 appDelegate = appRepeater.itemAt(0);
2012− compare(appDelegate.y >= PanelState.panelHeight, true);
2026+ compare(appDelegate.y >= panelState.panelHeight, true);
2013 }
2027 }
2014
2028
2015 function test_lifecyclePolicyForNonTouchApp_data() {
2029 function test_lifecyclePolicyForNonTouchApp_data() {
@@ -2610,7 +2624,7 @@ Rectangle {
2610 function test_oskDisplacesWindow_data() {
2624 function test_oskDisplacesWindow_data() {
2611 return [
2625 return [
2612 {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
2626 {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
2613− {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
2627+ {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: panelState.panelHeight, oskEnabled: true},
2614 {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
2628 {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
2615 ]
2629 ]
2616 }
2630 }
@@ -2633,8 +2647,8 @@ Rectangle {
2633 dashAppDelegate.windowedY = data.windowY;
2647 dashAppDelegate.windowedY = data.windowY;
2634 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2648 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2635 var initialY = dashAppDelegate.y;
2649 var initialY = dashAppDelegate.y;
2636− print("intial", initialY, "panel", PanelState.panelHeight);
2650+ print("intial", initialY, "panel", panelState.panelHeight);
2637− verify(initialY > PanelState.panelHeight);
2651+ verify(initialY > panelState.panelHeight);
2638
2652
2639 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
2653 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
2640 tryCompare(dashAppDelegate, "y", data.targetDisplacement);
2654 tryCompare(dashAppDelegate, "y", data.targetDisplacement);
tests/uqmlscene/main.cpp+2
@@ -479,6 +479,8 @@ int main(int argc, char ** argv)
479 // TODO: as soon as the engine construction completes, the debug service is
479 // TODO: as soon as the engine construction completes, the debug service is
480 // listening for connections. But actually we aren't ready to debug anything.
480 // listening for connections. But actually we aren't ready to debug anything.
481 QQmlEngine engine;
481 QQmlEngine engine;
482+ engine.rootContext()->setContextProperty("DebuggingController", new DebuggingController(&app));
483+
482 QQmlComponent *component = new QQmlComponent(&engine);
484 QQmlComponent *component = new QQmlComponent(&engine);
483 for (int i = 0; i < imports.size(); ++i)
485 for (int i = 0; i < imports.size(); ++i)
484 engine.addImportPath(imports.at(i));
486 engine.addImportPath(imports.at(i));