on 84a5759 help sign in
plugins/Cursor/CMakeLists.txt+1
since splitsnapshots
unifiedsplit
@@ -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+146
@@ -0,0 +1,146 @@
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 <QScreen>
23+#include <qpa/qplatformnativeinterface.h>
24+#include <qpa/qplatformscreen.h>
25+
26+InputDispatcherFilter *InputDispatcherFilter::instance()
27+{
28+ static InputDispatcherFilter filter;
29+ return &filter;
30+}
31+
32+InputDispatcherFilter::InputDispatcherFilter(QObject *parent)
33+ : QObject(parent)
34+{
35+ QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface();
36+ m_inputDispatcher = static_cast<QObject*>(ni->nativeResourceForIntegration("InputDispatcher"));
37+ if (m_inputDispatcher) {
38+ m_inputDispatcher->installEventFilter(this);
39+ }
40+}
41+
42+void InputDispatcherFilter::registerPointer(MousePointer *pointer)
43+{
44+ // allow first registered pointer to be visible.
45+ pointer->setVisible(m_pointers.count() == 0);
46+
47+ m_pointers.insert(pointer);
48+ connect(pointer, &MousePointer::mouseMoved, this, [this, pointer]() {
49+ Q_FOREACH(auto p, m_pointers) {
50+ p->setVisible(p == pointer);
51+ }
52+ });
53+}
54+
55+void InputDispatcherFilter::unregisterPointer(MousePointer *pointer)
56+{
57+ m_pointers.remove(pointer);
58+ disconnect(pointer, &MousePointer::mouseMoved, this, 0);
59+}
60+
61+void InputDispatcherFilter::setPosition(const QPointF &pos)
62+{
63+ mousePosition = pos;
64+}
65+
66+bool InputDispatcherFilter::eventFilter(QObject *o, QEvent *e)
67+{
68+ if (o != m_inputDispatcher) return false;
69+
70+ switch (e->type()) {
71+ case QEvent::MouseMove:
72+ case QEvent::MouseButtonPress:
73+ case QEvent::MouseButtonRelease:
74+ {
75+ // FIXME - removed all input filtering for now - this was for extended display
76+ return false;
77+
78+// QMouseEvent* me = static_cast<QMouseEvent*>(e);
79+
80+// // Local position gives relative change of mouse pointer.
81+// QPointF localPos = me->localPos();
82+// QPointF globalPos = me->screenPos();
83+
84+// // Adjust the position
85+// QPointF oldPos(mousePosition.isNull() ? globalPos : mousePosition);
86+// QPointF newPos = adjustedPositionForMovement(oldPos, localPos);
87+
88+// QScreen* currentScreen = screenAt(newPos);
89+// if (currentScreen) {
90+// QRect screenRect = currentScreen->geometry();
91+// qreal unadjustedX = (oldPos + localPos).x();
92+// if (unadjustedX < screenRect.left()) {
93+// Q_EMIT pushedLeftBoundary(currentScreen, qAbs(unadjustedX - screenRect.left()), me->buttons());
94+// } else if (unadjustedX > screenRect.right()) {
95+// Q_EMIT pushedRightBoundary(currentScreen, qAbs(unadjustedX - screenRect.right()), me->buttons());
96+// }
97+// }
98+
99+// // Send the event
100+// QMouseEvent eCopy(me->type(), me->localPos(), newPos, me->button(), me->buttons(), me->modifiers());
101+// eCopy.setTimestamp(me->timestamp());
102+// o->event(&eCopy);
103+// return true;
104+ }
105+ default:
106+ break;
107+ }
108+ return false;
109+}
110+
111+QPointF InputDispatcherFilter::adjustedPositionForMovement(const QPointF &pt, const QPointF &movement) const
112+{
113+ QPointF adjusted = pt + movement;
114+
115+ auto screen = screenAt(adjusted); // first check if our move was to a valid screen.
116+ if (screen) {
117+ return adjusted;
118+ } else if ((screen = screenAt(pt))) { // then check if our old position was valid
119+ QRectF screenBounds = screen->geometry();
120+ // bound the new position to the old screen geometry
121+ adjusted.rx() = qMax(screenBounds.left(), qMin(adjusted.x(), screenBounds.right()-1));
122+ adjusted.ry() = qMax(screenBounds.top(), qMin(adjusted.y(), screenBounds.bottom()-1));
123+ } else {
124+ auto screens = QGuiApplication::screens();
125+
126+ // center of first screen with a pointer.
127+ Q_FOREACH(QScreen* screen, screens) {
128+ Q_FOREACH(MousePointer* pointer, m_pointers) {
129+ if (pointer->screen() == screen) {
130+ return screen->geometry().center();
131+ }
132+ }
133+ }
134+ }
135+ return adjusted;
136+}
137+
138+QScreen *InputDispatcherFilter::screenAt(const QPointF &pt) const
139+{
140+ Q_FOREACH(MousePointer* pointer, m_pointers) {
141+ QScreen* screen = pointer->screen();
142+ if (screen && screen->geometry().contains(pt.toPoint()))
143+ return screen;
144+ }
145+ return nullptr;
146+}
plugins/Cursor/InputDispatcherFilter.hnew file+57
@@ -0,0 +1,57 @@
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+
35+ void unregisterPointer(MousePointer* pointer);
36+
37+ void setPosition(const QPointF &pos);
38+
39+Q_SIGNALS:
40+ void pushedLeftBoundary(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
41+ void pushedRightBoundary(QScreen* screen, qreal amount, Qt::MouseButtons buttons);
42+
43+protected:
44+ InputDispatcherFilter(QObject* parent = nullptr);
45+
46+ bool eventFilter(QObject *o, QEvent *e) override;
47+
48+ QPointF adjustedPositionForMovement(const QPointF& pt, const QPointF& movement) const;
49+ QScreen* screenAt(const QPointF& pt) const;
50+
51+private:
52+ QObject* m_inputDispatcher;
53+ QSet<MousePointer*> m_pointers;
54+ QPointF mousePosition;
55+};
56+
57+#endif // INPUTDISPATCHERFILTER_H
plugins/Cursor/MousePointer.cpp+40−73
@@ -16,84 +16,57 @@
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+ InputDispatcherFilter::instance()->registerPointer(this);
35
32
36−void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
33+ auto mouseMovedFunc = [this]() {
37− Qt::KeyboardModifiers modifiers)
38−{
39− if (!parentItem()) {
40− return;
34+ if (!isEnabled() || !window()) return;
41− }
35+ QPointF globalPosition = mapToItem(nullptr, QPointF(0, 0));
42−
36+ InputDispatcherFilter::instance()->setPosition(globalPosition);
43− if (!movement.isNull()) {
44 Q_EMIT mouseMoved();
37 Q_EMIT mouseMoved();
45− }
38+ };
46−
39+ connect(this, &QQuickItem::xChanged, this, mouseMovedFunc);
47− m_accumulatedMovement += movement;
40+ connect(this, &QQuickItem::yChanged, this, mouseMovedFunc);
48− // don't apply the fractional part
41+
49− QPointF appliedMovement(int(m_accumulatedMovement.x()), int(m_accumulatedMovement.y()));
42+ connect(this, &QQuickItem::enabledChanged, this, [this]() {
50− m_accumulatedMovement -= appliedMovement;
43+ if (!isEnabled()) setVisible(false);
51−
44+ });
52− qreal newX = x() + appliedMovement.x();
45+
53− qreal newY = y() + appliedMovement.y();
46+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedLeftBoundary,
54− const qreal sceneWidth = parentItem()->width();
47+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
55− const qreal sceneHeight = parentItem()->height();
48+ if (window() && window()->screen() == screen) {
56−
49+ Q_EMIT pushedLeftBoundary(amount, buttons);
57− if (newX <= 0 && newY < m_topBoundaryOffset) { // top left corner
58− const auto distance = qSqrt(qPow(newX, 2) + qPow(newY-m_topBoundaryOffset, 2));
59− Q_EMIT pushedTopLeftCorner(qAbs(distance), buttons);
60− m_pushing = true;
61− } else if (newX >= sceneWidth-1 && newY < m_topBoundaryOffset) { // top right corner
62− const auto distance = qSqrt(qPow(newX-sceneWidth, 2) + qPow(newY-m_topBoundaryOffset, 2));
63− Q_EMIT pushedTopRightCorner(qAbs(distance), buttons);
64− m_pushing = true;
65− } else if (newX < 0 && newY >= sceneHeight-1) { // bottom left corner
66− const auto distance = qSqrt(qPow(newX, 2) + qPow(newY-sceneHeight, 2));
67− Q_EMIT pushedBottomLeftCorner(qAbs(distance), buttons);
68− m_pushing = true;
69− } else if (newX >= sceneWidth-1 && newY >= sceneHeight-1) { // bottom right corner
70− const auto distance = qSqrt(qPow(newX-sceneWidth, 2) + qPow(newY-sceneHeight, 2));
71− Q_EMIT pushedBottomRightCorner(qAbs(distance), buttons);
72− m_pushing = true;
73− } else if (newX < 0) { // left edge
74− Q_EMIT pushedLeftBoundary(qAbs(newX), buttons);
75− m_pushing = true;
76− } else if (newX >= sceneWidth) { // right edge
77− Q_EMIT pushedRightBoundary(newX - (sceneWidth - 1), buttons);
78− m_pushing = true;
79− } else if (newY < m_topBoundaryOffset) { // top edge
80− Q_EMIT pushedTopBoundary(qAbs(newY - m_topBoundaryOffset), buttons);
81− m_pushing = true;
82− } else if (Q_LIKELY(newX > 0 && newX < sceneWidth-1 && newY > 0 && newY < sceneHeight-1)) { // normal pos, not pushing
83− if (m_pushing) {
84− Q_EMIT pushStopped();
85− m_pushing = false;
86 }
50 }
87− }
51+ });
88
52
89− applyItemConfinement(newX, newY);
53+ connect(InputDispatcherFilter::instance(), &InputDispatcherFilter::pushedRightBoundary,
54+ this, [this](QScreen* screen, qreal amount, Qt::MouseButtons buttons) {
55+ if (window() && window()->screen() == screen) {
56+ Q_EMIT pushedRightBoundary(amount, buttons);
57+ }
58+ });
59+}
90
60
91− setX(qBound(0.0, newX, sceneWidth - 1));
61+MousePointer::~MousePointer()
92− setY(qBound(0.0, newY, sceneHeight - 1));
62+{
63+ registerScreen(nullptr);
64+ InputDispatcherFilter::instance()->unregisterPointer(this);
65+}
93
66
94− QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0));
67+void MousePointer::handleMouseEvent(ulong /*timestamp*/, QPointF /*movement*/, Qt::MouseButtons /*buttons*/,
95− QWindowSystemInterface::handleMouseEvent(window(), timestamp, scenePosition /*local*/, scenePosition /*global*/,
96− buttons, modifiers);
68+ Qt::KeyboardModifiers /*modifiers*/)
69+{
97}
70}
98
71
99void MousePointer::applyItemConfinement(qreal &newX, qreal &newY)
72void MousePointer::applyItemConfinement(qreal &newX, qreal &newY)
@@ -121,15 +94,8 @@ void MousePointer::applyItemConfinement(qreal &newX, qreal &newY)
121 }
94 }
122}
95}
123
96
124−void MousePointer::handleWheelEvent(ulong timestamp, QPoint angleDelta, Qt::KeyboardModifiers modifiers)
97+void MousePointer::handleWheelEvent(ulong /*timestamp*/, QPoint /*angleDelta*/, Qt::KeyboardModifiers /*modifiers*/)
125{
98{
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}
99}
134
100
135int MousePointer::topBoundaryOffset() const
101int MousePointer::topBoundaryOffset() const
@@ -182,7 +148,7 @@ void MousePointer::registerScreen(QScreen *screen)
182 if (m_registeredScreen) {
148 if (m_registeredScreen) {
183 auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
149 auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
184 if (previousCursor) {
150 if (previousCursor) {
185− previousCursor->setMousePointer(nullptr);
151+ previousCursor->unregisterMousePointer(this);
186 } else {
152 } else {
187 qCritical("QPlatformCursor is not a MirPlatformCursor! Cursor module only works in a Mir server.");
153 qCritical("QPlatformCursor is not a MirPlatformCursor! Cursor module only works in a Mir server.");
188 }
154 }
@@ -193,7 +159,7 @@ void MousePointer::registerScreen(QScreen *screen)
193 if (m_registeredScreen) {
159 if (m_registeredScreen) {
194 auto cursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
160 auto cursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
195 if (cursor) {
161 if (cursor) {
196− cursor->setMousePointer(this);
162+ cursor->registerMousePointer(this);
197 } else {
163 } else {
198 qCritical("QPlaformCursor is not a MirPlatformCursor! Cursor module only works in Mir.");
164 qCritical("QPlaformCursor is not a MirPlatformCursor! Cursor module only works in Mir.");
199 }
165 }
@@ -233,3 +199,4 @@ void MousePointer::setConfiningItem(QQuickItem *item)
233 Q_EMIT confiningItemChanged();
199 Q_EMIT confiningItemChanged();
234 }
200 }
235}
201}
202+
plugins/Cursor/MousePointer.h+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; }
@@ -46,6 +47,8 @@ public:
46 int topBoundaryOffset() const;
47 int topBoundaryOffset() const;
47 void setTopBoundaryOffset(int topBoundaryOffset);
48 void setTopBoundaryOffset(int topBoundaryOffset);
48
49
50+ QScreen* screen() const { return m_registeredScreen; }
51+
49public Q_SLOTS:
52public Q_SLOTS:
50 void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
53 void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
51 Qt::KeyboardModifiers modifiers) override;
54 Qt::KeyboardModifiers modifiers) override;
@@ -90,3 +93,4 @@ private:
90};
93};
91
94
92#endif // MOUSEPOINTER_H
95#endif // MOUSEPOINTER_H
96+
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}
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
@@ -151,10 +153,6 @@ Item {
151 return false;
153 return false;
152 }
154 }
153
155
154− Screens {
155− id: screens
156− }
157−
158 property int orientation
156 property int orientation
159 onPhysicalOrientationChanged: {
157 onPhysicalOrientationChanged: {
160 if (!orientationLocked) {
158 if (!orientationLocked) {
@@ -252,7 +250,7 @@ Item {
252
250
253 Shell {
251 Shell {
254 id: shell
252 id: shell
255− objectName: "shell"
253+ objectName: "shell-"+screenWindow.objectName
256 width: root.width
254 width: root.width
257 height: root.height
255 height: root.height
258 orientation: root.angleToOrientation(orientationAngle)
256 orientation: root.angleToOrientation(orientationAngle)
@@ -265,7 +263,7 @@ Item {
265 // have multiple keyboards around. For now we only enable one keyboard at a time
263 // have multiple keyboards around. For now we only enable one keyboard at a time
266 // thus hiding it here if there is a physical one around or if we have a second
264 // thus hiding it here if there is a physical one around or if we have a second
267 // screen (the virtual touchpad & osk on the phone) attached.
265 // screen (the virtual touchpad & osk on the phone) attached.
268− oskEnabled: (keyboardsModel.count === 0 && screens.count === 1) ||
266+ oskEnabled: (keyboardsModel.count === 0 && Screens.count === 1) ||
269 forceOSKEnabled
267 forceOSKEnabled
270
268
271 usageScenario: {
269 usageScenario: {
qml/Panel/Panel.qml+11−10
@@ -29,6 +29,7 @@ Item {
29 property bool fullscreenMode: false
29 property bool fullscreenMode: false
30 property real indicatorAreaShowProgress: 1.0
30 property real indicatorAreaShowProgress: 1.0
31 property bool locked: false
31 property bool locked: false
32+ property PanelState panelState
32
33
33 MouseArea {
34 MouseArea {
34 anchors.fill: parent
35 anchors.fill: parent
@@ -40,7 +41,7 @@ Item {
40 }
41 }
41
42
42 Binding {
43 Binding {
43− target: PanelState
44+ target: panelState
44 property: "panelHeight"
45 property: "panelHeight"
45 value: indicators.minimizedPanelHeight
46 value: indicators.minimizedPanelHeight
46 }
47 }
@@ -74,7 +75,7 @@ Item {
74 fill: indicatorAreaBackground
75 fill: indicatorAreaBackground
75 bottomMargin: -units.gu(1)
76 bottomMargin: -units.gu(1)
76 }
77 }
77− visible: PanelState.dropShadow && !callHint.visible
78+ visible: panelState.dropShadow && !callHint.visible
78 source: "graphics/rectangular_dropshadow.sci"
79 source: "graphics/rectangular_dropshadow.sci"
79 }
80 }
80
81
@@ -120,14 +121,14 @@ Item {
120 }
121 }
121 height: indicators.minimizedPanelHeight
122 height: indicators.minimizedPanelHeight
122
123
123− visible: ((PanelState.buttonsVisible && parent.containsMouse) || PanelState.buttonsAlwaysVisible)
124+ visible: ((panelState.buttonsVisible && parent.containsMouse) || panelState.buttonsAlwaysVisible)
124 && !root.locked && !callHint.visible
125 && !root.locked && !callHint.visible
125− active: PanelState.buttonsVisible || PanelState.buttonsAlwaysVisible
126+ active: panelState.buttonsVisible || panelState.buttonsAlwaysVisible
126 windowIsMaximized: true
127 windowIsMaximized: true
127− onCloseClicked: PanelState.closeClicked()
128+ onCloseClicked: panelState.closeClicked()
128− onMinimizeClicked: PanelState.minimizeClicked()
129+ onMinimizeClicked: panelState.minimizeClicked()
129− onMaximizeClicked: PanelState.restoreClicked()
130+ onMaximizeClicked: panelState.restoreClicked()
130− closeButtonShown: PanelState.closeButtonShown
131+ closeButtonShown: panelState.closeButtonShown
131 }
132 }
132 }
133 }
133
134
@@ -181,8 +182,8 @@ Item {
181 visible: opacity != 0
182 visible: opacity != 0
182 verticalAlignment: Text.AlignVCenter
183 verticalAlignment: Text.AlignVCenter
183 fontSize: "medium"
184 fontSize: "medium"
184− font.weight: PanelState.buttonsVisible ? Font.Light : Font.Medium
185+ font.weight: panelState.buttonsVisible ? Font.Light : Font.Medium
185− text: PanelState.title
186+ text: panelState.title
186 elide: Text.ElideRight
187 elide: Text.ElideRight
187 maximumLineCount: 1
188 maximumLineCount: 1
188 Behavior on opacity { UbuntuNumberAnimation {} }
189 Behavior on opacity { UbuntuNumberAnimation {} }
qml/Shell.qml+25−21
@@ -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,6 +38,7 @@ 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
@@ -52,6 +53,7 @@ StyledItem {
52 theme.name: "Ubuntu.Components.Themes.SuruDark"
53 theme.name: "Ubuntu.Components.Themes.SuruDark"
53
54
54 // to be set from outside
55 // to be set from outside
56+ property alias surfaceManager: topLevelSurfaceList.surfaceManager
55 property int orientationAngle: 0
57 property int orientationAngle: 0
56 property int orientation
58 property int orientation
57 property Orientations orientations
59 property Orientations orientations
@@ -249,7 +251,6 @@ StyledItem {
249 var mappedCoords = mapFromItem(null, pos.x, pos.y);
251 var mappedCoords = mapFromItem(null, pos.x, pos.y);
250 cursor.x = mappedCoords.x;
252 cursor.x = mappedCoords.x;
251 cursor.y = mappedCoords.y;
253 cursor.y = mappedCoords.y;
252− cursor.mouseNeverMoved = false;
253 }
254 }
254 }
255 }
255
256
@@ -258,21 +259,21 @@ StyledItem {
258 schema.id: "com.canonical.Unity8"
259 schema.id: "com.canonical.Unity8"
259 }
260 }
260
261
262+ PanelState {
263+ id: panelState
264+ objectName: "panelState"
265+ }
266+
261 Item {
267 Item {
262 id: stages
268 id: stages
263 objectName: "stages"
269 objectName: "stages"
264 width: parent.width
270 width: parent.width
265 height: parent.height
271 height: parent.height
266
272
267− SurfaceManager {
268− id: surfaceMan
269− objectName: "surfaceManager"
270− }
271 TopLevelWindowModel {
273 TopLevelWindowModel {
272 id: topLevelSurfaceList
274 id: topLevelSurfaceList
273 objectName: "topLevelSurfaceList"
275 objectName: "topLevelSurfaceList"
274 applicationManager: ApplicationManager // it's a singleton
276 applicationManager: ApplicationManager // it's a singleton
275− surfaceManager: surfaceMan
276 }
277 }
277
278
278 Stage {
279 Stage {
@@ -313,6 +314,7 @@ StyledItem {
313 altTabPressed: physicalKeysMapper.altTabPressed
314 altTabPressed: physicalKeysMapper.altTabPressed
314 oskEnabled: shell.oskEnabled
315 oskEnabled: shell.oskEnabled
315 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
316 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
317+ panelState: panelState
316 }
318 }
317 }
319 }
318
320
@@ -333,8 +335,13 @@ StyledItem {
333 objectName: "greeterLoader"
335 objectName: "greeterLoader"
334 anchors.fill: parent
336 anchors.fill: parent
335 anchors.topMargin: panel.panelHeight
337 anchors.topMargin: panel.panelHeight
336− sourceComponent: shell.mode != "shell" ? integratedGreeter :
338+ sourceComponent: {
339+ if (shell.mode != "shell") {
340+ if (screenWindow.primary) return integratedGreeter;
341+ return secondaryGreeter;
342+ }
337− Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
343+ return Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
344+ }
338 onLoaded: {
345 onLoaded: {
339 item.objectName = "greeter"
346 item.objectName = "greeter"
340 }
347 }
@@ -374,6 +381,13 @@ StyledItem {
374 }
381 }
375 }
382 }
376
383
384+ Component {
385+ id: secondaryGreeter
386+ SecondaryGreeter {
387+ hides: [launcher, panel.indicators]
388+ }
389+ }
390+
377 Timer {
391 Timer {
378 // See powerConnection for why this is useful
392 // See powerConnection for why this is useful
379 id: showGreeterDelayed
393 id: showGreeterDelayed
@@ -479,6 +493,7 @@ StyledItem {
479 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
493 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
480 || greeter.hasLockedApp
494 || greeter.hasLockedApp
481 locked: greeter && greeter.active
495 locked: greeter && greeter.active
496+ panelState: panelState
482 }
497 }
483
498
484 Launcher {
499 Launcher {
@@ -689,23 +704,13 @@ StyledItem {
689
704
690 Cursor {
705 Cursor {
691 id: cursor
706 id: cursor
692− objectName: "cursor"
693 visible: shell.hasMouse
707 visible: shell.hasMouse
694 z: itemGrabber.z + 1
708 z: itemGrabber.z + 1
709+ opacity: 0
695 topBoundaryOffset: panel.panelHeight
710 topBoundaryOffset: panel.panelHeight
696
711
697 confiningItem: stage.itemConfiningMouseCursor
712 confiningItem: stage.itemConfiningMouseCursor
698
713
699− property bool mouseNeverMoved: true
700− Binding {
701− target: cursor; property: "x"; value: shell.width / 2
702− when: cursor.mouseNeverMoved && cursor.visible
703− }
704− Binding {
705− target: cursor; property: "y"; value: shell.height / 2
706− when: cursor.mouseNeverMoved && cursor.visible
707− }
708−
709 height: units.gu(3)
714 height: units.gu(3)
710
715
711 readonly property var previewRectangle: stage.previewRectangle.target &&
716 readonly property var previewRectangle: stage.previewRectangle.target &&
@@ -760,7 +765,6 @@ StyledItem {
760 }
765 }
761
766
762 onMouseMoved: {
767 onMouseMoved: {
763− mouseNeverMoved = false;
764 cursor.opacity = 1;
768 cursor.opacity = 1;
765 }
769 }
766
770
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
@@ -18,6 +18,7 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Unity.Application 0.1
19import Unity.Application 0.1
20import "Spread/MathUtils.js" as MathUtils
20import "Spread/MathUtils.js" as MathUtils
21+import "../Components/PanelState"
21
22
22FocusScope {
23FocusScope {
23 id: root
24 id: root
@@ -70,6 +71,8 @@ FocusScope {
70
71
71 readonly property Item clientAreaItem: applicationWindow
72 readonly property Item clientAreaItem: applicationWindow
72
73
74+ property PanelState panelState
75+
73 signal closeClicked()
76 signal closeClicked()
74 signal maximizeClicked()
77 signal maximizeClicked()
75 signal maximizeHorizontallyClicked()
78 signal maximizeHorizontallyClicked()
@@ -179,6 +182,7 @@ FocusScope {
179 objectName: "moveHandler"
182 objectName: "moveHandler"
180 target: root.parent
183 target: root.parent
181 buttonsWidth: decoration.buttonsWidth
184 buttonsWidth: decoration.buttonsWidth
185+ panelState: root.panelState
182 }
186 }
183
187
184 ApplicationWindow {
188 ApplicationWindow {
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/Spread/ScreensAndWorkspaces.qmlnew file+27
@@ -0,0 +1,27 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+import Unity.Screens 0.1
4+import Unity.Application 0.1
5+import ".."
6+
7+Item {
8+ id: root
9+
10+
11+ Rectangle { anchors.fill: parent; color: "blue"; opacity: .3 }
12+
13+ Row {
14+ anchors.bottom: parent.bottom
15+ anchors.bottomMargin: units.gu(1)
16+ anchors.horizontalCenter: parent.horizontalCenter
17+ spacing: units.gu(1)
18+
19+ Repeater {
20+ model: Screens
21+
22+ delegate: WorkspacePreview {
23+ height: root.height - units.gu(6)
24+ }
25+ }
26+ }
27+}
qml/Stage/Spread/Spread.qml+5−5
@@ -28,10 +28,10 @@ Item {
28 property var spreadFlickable
28 property var spreadFlickable
29
29
30 // some config options
30 // some config options
31− property real contentMargin: 0.16 * root.height
31+ property real contentMargin: 0.1 * root.height
32− property real contentTopMargin: contentMargin
32+ property real contentTopMargin: contentMargin + root.y + windowTitle.height
33− property real contentBottomMargin: 0.35 * contentMargin
33+ property real contentBottomMargin: contentMargin
34− property real windowTitleTopMargin: 3/4 * (contentTopMargin - windowTitle.height)
34+ property real windowTitleTopMargin: contentMargin - windowTitle.height
35 property int stackItemCount: 3
35 property int stackItemCount: 3
36 property real leftRotationAngle: 22
36 property real leftRotationAngle: 22
37 property real rightRotationAngle: 32
37 property real rightRotationAngle: 32
@@ -51,7 +51,7 @@ Item {
51
51
52 readonly property real spreadWidth: rightStackXPos - leftStackXPos
52 readonly property real spreadWidth: rightStackXPos - leftStackXPos
53 readonly property real spreadHeight: root.height
53 readonly property real spreadHeight: root.height
54− readonly property real spreadItemHeight: spreadHeight - contentTopMargin - contentBottomMargin
54+ readonly property real spreadItemHeight: spreadHeight - contentMargin * 2
55 readonly property real spreadItemWidth: stackHeight
55 readonly property real spreadItemWidth: stackHeight
56
56
57 readonly property real dynamicLeftRotationAngle: leftRotationAngle * rotationAngleFactor
57 readonly property real dynamicLeftRotationAngle: leftRotationAngle * rotationAngleFactor
qml/Stage/Stage.qml+36−26
@@ -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: "buttonsVisible"
360 property: "buttonsVisible"
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,21 +377,21 @@ FocusScope {
376 }
377 }
377
378
378 Binding {
379 Binding {
379− target: PanelState
380+ target: panelState
380 property: "dropShadow"
381 property: "dropShadow"
381 value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
382 value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
382 }
383 }
383
384
384 Binding {
385 Binding {
385− target: PanelState
386+ target: panelState
386 property: "closeButtonShown"
387 property: "closeButtonShown"
387 value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
388 value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !priv.focusedAppDelegate.isDash
388 }
389 }
389
390
390 Component.onDestruction: {
391 Component.onDestruction: {
391− PanelState.title = "";
392+ panelState.title = "";
392− PanelState.buttonsVisible = false;
393+ panelState.buttonsVisible = false;
393− PanelState.dropShadow = false;
394+ panelState.dropShadow = false;
394 }
395 }
395
396
396 Instantiator {
397 Instantiator {
@@ -468,7 +469,7 @@ FocusScope {
468 },
469 },
469 State {
470 State {
470 name: "staged"; when: root.mode === "staged"
471 name: "staged"; when: root.mode === "staged"
471− PropertyChanges { target: wallpaper; visible: false }
472+ PropertyChanges { target: wallpaper; visible: priv.focusedAppDelegate && priv.focusedAppDelegate.x === 0 }
472 },
473 },
473 State {
474 State {
474 name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
475 name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
@@ -545,10 +546,16 @@ FocusScope {
545 visible: false
546 visible: false
546 }
547 }
547
548
549+ ScreensAndWorkspaces {
550+ id: screensAndWorkspaces
551+ anchors { left: parent.left; top: parent.top; right: parent.right }
552+ height: parent.height / 3
553+ }
554+
548 Spread {
555 Spread {
549 id: spreadItem
556 id: spreadItem
550 objectName: "spreadItem"
557 objectName: "spreadItem"
551− anchors.fill: appContainer
558+ anchors { left: parent.left; bottom: parent.bottom; right: parent.right; top: screensAndWorkspaces.bottom }
552 leftMargin: root.leftMargin
559 leftMargin: root.leftMargin
553 model: root.topLevelSurfaceList
560 model: root.topLevelSurfaceList
554 spreadFlickable: floatingFlickable
561 spreadFlickable: floatingFlickable
@@ -739,7 +746,7 @@ FocusScope {
739 target: appDelegate
746 target: appDelegate
740 property: "y"
747 property: "y"
741 value: appDelegate.requestedY -
748 value: appDelegate.requestedY -
742− Math.min(appDelegate.requestedY - PanelState.panelHeight,
749+ Math.min(appDelegate.requestedY - panelState.panelHeight,
743 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
750 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
744 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
751 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
745 && root.inputMethodRect.height > 0
752 && root.inputMethodRect.height > 0
@@ -876,7 +883,7 @@ FocusScope {
876 screenWidth: appContainer.width
883 screenWidth: appContainer.width
877 screenHeight: appContainer.height
884 screenHeight: appContainer.height
878 leftMargin: root.leftMargin
885 leftMargin: root.leftMargin
879− minimumY: PanelState.panelHeight
886+ minimumY: panelState.panelHeight
880 }
887 }
881
888
882 Connections {
889 Connections {
@@ -1116,7 +1123,7 @@ FocusScope {
1116 progress: 0
1123 progress: 0
1117 targetHeight: spreadItem.stackHeight
1124 targetHeight: spreadItem.stackHeight
1118 targetX: spreadMaths.targetX
1125 targetX: spreadMaths.targetX
1119− startY: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1126+ startY: appDelegate.fullscreen ? 0 : panelState.panelHeight
1120 targetY: spreadMaths.targetY
1127 targetY: spreadMaths.targetY
1121 targetAngle: spreadMaths.targetAngle
1128 targetAngle: spreadMaths.targetAngle
1122 targetScale: spreadMaths.targetScale
1129 targetScale: spreadMaths.targetScale
@@ -1235,9 +1242,9 @@ FocusScope {
1235 PropertyChanges {
1242 PropertyChanges {
1236 target: appDelegate
1243 target: appDelegate
1237 x: stageMaths.itemX
1244 x: stageMaths.itemX
1238− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1245+ y: appDelegate.fullscreen ? 0 : panelState.panelHeight
1239 requestedWidth: appContainer.width
1246 requestedWidth: appContainer.width
1240− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1247+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - panelState.panelHeight
1241 visuallyMaximized: true
1248 visuallyMaximized: true
1242 visible: appDelegate.x < root.width
1249 visible: appDelegate.x < root.width
1243 }
1250 }
@@ -1263,10 +1270,10 @@ FocusScope {
1263 PropertyChanges {
1270 PropertyChanges {
1264 target: appDelegate
1271 target: appDelegate
1265 x: stageMaths.itemX
1272 x: stageMaths.itemX
1266− y: appDelegate.fullscreen ? 0 : PanelState.panelHeight
1273+ y: appDelegate.fullscreen ? 0 : panelState.panelHeight
1267 z: stageMaths.itemZ
1274 z: stageMaths.itemZ
1268 requestedWidth: stageMaths.itemWidth
1275 requestedWidth: stageMaths.itemWidth
1269− requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - PanelState.panelHeight
1276+ requestedHeight: appDelegate.fullscreen ? appContainer.height : appContainer.height - panelState.panelHeight
1270 visuallyMaximized: true
1277 visuallyMaximized: true
1271 visible: appDelegate.x < root.width
1278 visible: appDelegate.x < root.width
1272 }
1279 }
@@ -1331,9 +1338,9 @@ FocusScope {
1331 PropertyChanges {
1338 PropertyChanges {
1332 target: appDelegate
1339 target: appDelegate
1333 windowedX: root.leftMargin
1340 windowedX: root.leftMargin
1334− windowedY: PanelState.panelHeight
1341+ windowedY: panelState.panelHeight
1335 windowedWidth: (appContainer.width - root.leftMargin)/2
1342 windowedWidth: (appContainer.width - root.leftMargin)/2
1336− windowedHeight: appContainer.height - PanelState.panelHeight
1343+ windowedHeight: appContainer.height - panelState.panelHeight
1337 }
1344 }
1338 },
1345 },
1339 State {
1346 State {
@@ -1350,9 +1357,9 @@ FocusScope {
1350 PropertyChanges {
1357 PropertyChanges {
1351 target: appDelegate
1358 target: appDelegate
1352 windowedX: root.leftMargin
1359 windowedX: root.leftMargin
1353− windowedY: PanelState.panelHeight
1360+ windowedY: panelState.panelHeight
1354 windowedWidth: (appContainer.width - root.leftMargin)/2
1361 windowedWidth: (appContainer.width - root.leftMargin)/2
1355− windowedHeight: (appContainer.height - PanelState.panelHeight)/2
1362+ windowedHeight: (appContainer.height - panelState.panelHeight)/2
1356 }
1363 }
1357 },
1364 },
1358 State {
1365 State {
@@ -1369,7 +1376,7 @@ FocusScope {
1369 PropertyChanges {
1376 PropertyChanges {
1370 target: appDelegate
1377 target: appDelegate
1371 windowedX: root.leftMargin
1378 windowedX: root.leftMargin
1372− windowedY: (appContainer.height + PanelState.panelHeight)/2
1379+ windowedY: (appContainer.height + panelState.panelHeight)/2
1373 windowedWidth: (appContainer.width - root.leftMargin)/2
1380 windowedWidth: (appContainer.width - root.leftMargin)/2
1374 windowedHeight: appContainer.height/2
1381 windowedHeight: appContainer.height/2
1375 }
1382 }
@@ -1391,8 +1398,8 @@ FocusScope {
1391 State {
1398 State {
1392 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1399 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1393 extend: "normal"
1400 extend: "normal"
1394− PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: PanelState.panelHeight;
1401+ PropertyChanges { target: appDelegate; windowedX: windowedX; windowedY: panelState.panelHeight;
1395− windowedWidth: windowedWidth; windowedHeight: appContainer.height - PanelState.panelHeight }
1402+ windowedWidth: windowedWidth; windowedHeight: appContainer.height - panelState.panelHeight }
1396 },
1403 },
1397 State {
1404 State {
1398 name: "minimized"; when: appDelegate.minimized
1405 name: "minimized"; when: appDelegate.minimized
@@ -1491,7 +1498,7 @@ FocusScope {
1491 ]
1498 ]
1492
1499
1493 Binding {
1500 Binding {
1494− target: PanelState
1501+ target: panelState
1495 property: "buttonsAlwaysVisible"
1502 property: "buttonsAlwaysVisible"
1496 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
1503 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
1497 }
1504 }
@@ -1506,7 +1513,7 @@ FocusScope {
1506 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1513 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1507
1514
1508 target: appDelegate
1515 target: appDelegate
1509− minimumY: PanelState.panelHeight // disallow resizing up past Panel
1516+ minimumY: panelState.panelHeight // disallow resizing up past Panel
1510 minWidth: units.gu(10)
1517 minWidth: units.gu(10)
1511 minHeight: units.gu(10)
1518 minHeight: units.gu(10)
1512 borderThickness: units.gu(2)
1519 borderThickness: units.gu(2)
@@ -1536,6 +1543,7 @@ FocusScope {
1536 highlightSize: windowInfoItem.iconMargin / 2
1543 highlightSize: windowInfoItem.iconMargin / 2
1537 stageWidth: appContainer.width
1544 stageWidth: appContainer.width
1538 stageHeight: appContainer.height
1545 stageHeight: appContainer.height
1546+ panelState: root.panelState
1539
1547
1540 requestedWidth: appDelegate.requestedWidth
1548 requestedWidth: appDelegate.requestedWidth
1541 requestedHeight: appDelegate.requestedHeight
1549 requestedHeight: appDelegate.requestedHeight
@@ -1595,6 +1603,7 @@ FocusScope {
1595 visible: enabled
1603 visible: enabled
1596 stageWidth: appContainer.width
1604 stageWidth: appContainer.width
1597 stageHeight: appContainer.height
1605 stageHeight: appContainer.height
1606+ panelState: root.panelState
1598
1607
1599 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1608 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
1600 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
1609 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
@@ -1699,6 +1708,7 @@ FocusScope {
1699 leftMargin: root.leftMargin
1708 leftMargin: root.leftMargin
1700 appContainerWidth: appContainer.width
1709 appContainerWidth: appContainer.width
1701 appContainerHeight: appContainer.height
1710 appContainerHeight: appContainer.height
1711+ panelState: root.panelState
1702 }
1712 }
1703
1713
1704 EdgeBarrier {
1714 EdgeBarrier {
qml/Stage/SurfaceContainer.qml+2
@@ -66,6 +66,8 @@ FocusScope {
66 fillMode: MirSurfaceItem.PadOrCrop
66 fillMode: MirSurfaceItem.PadOrCrop
67 consumesInput: true
67 consumesInput: true
68
68
69+ onSurfaceChanged: print("surface changed", surface, implicitWidth, implicitHeight)
70+
69 surfaceWidth: root.requestedWidth
71 surfaceWidth: root.requestedWidth
70 surfaceHeight: root.requestedHeight
72 surfaceHeight: root.requestedHeight
71
73
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/Stage/WorkspacePreview.qmlnew file+50
@@ -0,0 +1,50 @@
1+import QtQuick 2.4
2+import Ubuntu.Components 1.3
3+import Unity.Application 0.1
4+
5+UbuntuShape {
6+ id: previewSpace
7+
8+ // Set the height. this preview will then automatically adjust the width, keeping aspect ratio of the screen
9+ width: model.geometry.width * previewScale
10+ color: "white"
11+
12+ property int screenWidth: model.geometry.width
13+ property int screenHeight: model.geometry.height
14+ property real previewScale: previewSpace.height / previewSpace.screenHeight
15+
16+ Label {
17+ text: model.name + "," + model.geometry.width
18+ color: "black"
19+ }
20+
21+ Rectangle {
22+ anchors.fill: parent
23+ anchors.topMargin: units.gu(4)
24+
25+ Repeater {
26+ id: topLevelSurfaceRepeater
27+ model: topLevelSurfaceList
28+ delegate: Rectangle {
29+ width: surfaceItem.width
30+ height: surfaceItem.height
31+ x: model.window.position.x * previewSpace.previewScale
32+ y: model.window.position.y * previewSpace.previewScale
33+ color: "blue"
34+ z: topLevelSurfaceRepeater.count - index
35+
36+
37+ MirSurfaceItem {
38+ id: surfaceItem
39+
40+ width: implicitWidth * previewScale
41+ height: implicitHeight * previewScale
42+ surfaceWidth: -1
43+ surfaceHeight: -1
44+ onImplicitHeightChanged: print("item", surfaceItem, "height changed", implicitHeight)
45+ surface: model.window.surface
46+ }
47+ }
48+ }
49+ }
50+}
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
@@ -20,9 +20,7 @@ set(SOURCE_FILES
20 ApplicationArguments.cpp
20 ApplicationArguments.cpp
21 main.cpp
21 main.cpp
22 CachingNetworkManagerFactory.cpp
22 CachingNetworkManagerFactory.cpp
23− SecondaryWindow.cpp
24 ShellApplication.cpp
23 ShellApplication.cpp
25− ShellView.cpp
26 UnityCommandLineParser.cpp
24 UnityCommandLineParser.cpp
27 UnixSignalHandler.cpp
25 UnixSignalHandler.cpp
28 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
26 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
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+29−107
@@ -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
@@ -33,31 +34,23 @@
33
34
34ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
35ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
35 : QGuiApplication(argc, argv)
36 : QGuiApplication(argc, argv)
37+ , m_qmlArgs(this)
36{
38{
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,57 +68,39 @@ 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
72
80− if (parser.windowGeometry().isValid()) {
73+ QByteArray pxpguEnv = qgetenv("GRID_UNIT_PX");
81− m_shellView->setWidth(parser.windowGeometry().width());
74+ bool ok;
82− m_shellView->setHeight(parser.windowGeometry().height());
75+ int pxpgu = pxpguEnv.toInt(&ok);
76+ if (!ok) {
77+ pxpgu = 8;
83 }
78 }
84−
79+ m_qmlEngine->rootContext()->setContextProperty("internalGu", pxpgu);
85− if (parser.hasFrameless()) {
80+ m_qmlEngine->load(::qmlDirectory() + "/ShellApplication.qml");
86− m_shellView->setFlags(Qt::FramelessWindowHint);
87− }
88−
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−
99− // Some hard-coded policy for now.
100− // NB: We don't support more than two screens at the moment
101− //
102− // TODO: Support an arbitrary number of screens and different policies
103− // (eg cloned desktop, several desktops, etc)
104− if (isMirServer && screens().count() == 2) {
105− m_shellView->setScreen(screens().at(1));
106− m_qmlArgs.setDeviceName(QStringLiteral("desktop"));
107−
108− m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
109− m_secondaryWindow->setScreen(screens().at(0));
110− // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that!
111− m_secondaryWindow->setWindowState(Qt::WindowFullScreen);
112− m_secondaryWindow->setVisible(true);
113− }
114−
115− if (parser.mode().compare("greeter") == 0) {
90+// if (parser.mode().compare("greeter") == 0) {
116− QSize primaryScreenSize = this->primaryScreen()->size();
91+// QSize primaryScreenSize = this->primaryScreen()->size();
117− m_shellView->setHeight(primaryScreenSize.height());
92+// m_shellView->setHeight(primaryScreenSize.height());
118− m_shellView->setWidth(primaryScreenSize.width());
93+// m_shellView->setWidth(primaryScreenSize.width());
119− m_shellView->show();
94+// m_shellView->show();
120− m_shellView->requestActivate();
95+// m_shellView->requestActivate();
121− if (!QProcess::startDetached("initctl emit --no-wait unity8-greeter-started")) {
96+// if (!QProcess::startDetached("/sbin/initctl emit --no-wait unity8-greeter-started")) {
122− qDebug() << "Unable to send unity8-greeter-started event to Upstart";
97+// qDebug() << "Unable to send unity8-greeter-started event to Upstart";
123− }
98+// }
124− } else if (isMirServer || parser.hasFullscreen()) {
99+// } else if (isMirServer || parser.hasFullscreen()) {
125− m_shellView->showFullScreen();
100+// m_shellView->showFullScreen();
126− } else {
101+// } else {
127− m_shellView->show();
102+// m_shellView->show();
128− }
103+// }
129}
104}
130
105
131ShellApplication::~ShellApplication()
106ShellApplication::~ShellApplication()
@@ -135,14 +110,6 @@ ShellApplication::~ShellApplication()
135
110
136void ShellApplication::destroyResources()
111void ShellApplication::destroyResources()
137{
112{
138− // Deletion order is important. Don't use QScopedPointers and the like
139− // Otherwise the process will hang on shutdown (bug somewhere I guess).
140− delete m_shellView;
141− m_shellView = nullptr;
142−
143− delete m_secondaryWindow;
144− m_secondaryWindow = nullptr;
145−
146 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
113 #ifdef UNITY8_ENABLE_TOUCH_EMULATION
147 delete m_mouseTouchAdaptor;
114 delete m_mouseTouchAdaptor;
148 m_mouseTouchAdaptor = nullptr;
115 m_mouseTouchAdaptor = nullptr;
@@ -154,7 +121,7 @@ void ShellApplication::destroyResources()
154
121
155void ShellApplication::setupQmlEngine(bool isMirServer)
122void ShellApplication::setupQmlEngine(bool isMirServer)
156{
123{
157− m_qmlEngine = new QQmlEngine(this);
124+ m_qmlEngine = new QQmlApplicationEngine(this);
158
125
159 m_qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
126 m_qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
160
127
@@ -168,48 +135,3 @@ void ShellApplication::setupQmlEngine(bool isMirServer)
168
135
169 QObject::connect(m_qmlEngine, &QQmlEngine::quit, this, &QGuiApplication::quit);
136 QObject::connect(m_qmlEngine, &QQmlEngine::quit, this, &QGuiApplication::quit);
170}
137}
171−
172−void ShellApplication::onScreenAdded(QScreen * /*screen*/)
173−{
174− // TODO: Support an arbitrary number of screens and different policies
175− // (eg cloned desktop, several desktops, etc)
176− if (screens().count() == 2) {
177− m_shellView->setScreen(screens().at(1));
178− m_qmlArgs.setDeviceName(QStringLiteral("desktop"));
179− // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
180− // its backing QPlatformWindow recreated). So lets refocus it.
181− m_shellView->requestActivate();
182− // QWindow::destroy() is called when it changes between screens. We have to manually make it visible again
183− // <dandrader> This bug is supposedly fixed in Qt 5.5.1, although I can still reproduce it there. :-/
184− m_shellView->setVisible(true);
185−
186− m_secondaryWindow = new SecondaryWindow(m_qmlEngine);
187− m_secondaryWindow->setScreen(screens().at(0));
188−
189− // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that!
190− m_secondaryWindow->setWindowState(Qt::WindowFullScreen);
191− m_secondaryWindow->setVisible(true);
192− }
193−}
194−
195−void ShellApplication::onScreenAboutToBeRemoved(QScreen *screen)
196−{
197− // TODO: Support an arbitrary number of screens and different policies
198− // (eg cloned desktop, several desktops, etc)
199− if (screen == m_shellView->screen()) {
200− const QList<QScreen *> allScreens = screens();
201− Q_ASSERT(allScreens.count() > 1);
202− Q_ASSERT(allScreens.at(0) != screen);
203− Q_ASSERT(m_secondaryWindow);
204− delete m_secondaryWindow;
205− m_secondaryWindow = nullptr;
206− m_shellView->setScreen(allScreens.first());
207− m_qmlArgs.setDeviceName(m_deviceName);
208− // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having
209− // its backing QPlatformWindow recreated). So lets refocus it.
210− m_shellView->requestActivate();
211− // QWindow::destroy() is called when it changes between screens. We have to manually make it visible again
212− // <dandrader> This bug is supposedly fixed in Qt 5.5.1, although I can still reproduce it there. :-/
213− m_shellView->setVisible(true);
214− }
215−}
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/ShellView.hdeleted−34
@@ -1,34 +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−#ifndef UNITY_SHELL_VIEW_H
18−#define UNITY_SHELL_VIEW_H
19−
20−#include <QQuickView>
21−
22−class ShellView : public QQuickView
23−{
24− Q_OBJECT
25−
26−public:
27− ShellView(QQmlEngine *engine, QObject *qmlArgs);
28−
29−private Q_SLOTS:
30− void onWidthChanged(int);
31− void onHeightChanged(int);
32−};
33−
34−#endif // UNITY_SHELL_VIEW_H
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+50−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,50 @@ 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}
82+
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/MirSurfaceItem.cpp+5
@@ -293,6 +293,10 @@ void MirSurfaceItem::setSurface(MirSurfaceInterface* surface)
293 connect(m_qmlSurface, &MirSurface::screenshotUrlChanged, this, &MirSurfaceItem::updateScreenshot);
293 connect(m_qmlSurface, &MirSurface::screenshotUrlChanged, this, &MirSurfaceItem::updateScreenshot);
294 connect(m_qmlSurface, &MirSurface::liveChanged, this, &MirSurfaceItem::liveChanged);
294 connect(m_qmlSurface, &MirSurface::liveChanged, this, &MirSurfaceItem::liveChanged);
295 connect(m_qmlSurface, &MirSurface::stateChanged, this, &MirSurfaceItem::surfaceStateChanged);
295 connect(m_qmlSurface, &MirSurface::stateChanged, this, &MirSurfaceItem::surfaceStateChanged);
296+ connect(m_qmlSurface, &MirSurface::sizeChanged, this, [this] () {
297+ m_qmlItem->setSize(m_qmlSurface->size());
298+ setImplicitSize(m_qmlSurface->width(), m_qmlSurface->height());
299+ });
296
300
297 QUrl qmlComponentFilePath;
301 QUrl qmlComponentFilePath;
298 if (!m_qmlSurface->qmlFilePath().isEmpty()) {
302 if (!m_qmlSurface->qmlFilePath().isEmpty()) {
@@ -387,6 +391,7 @@ void MirSurfaceItem::updateSurfaceSize()
387 m_qmlItem->setWidth(m_surfaceWidth);
391 m_qmlItem->setWidth(m_surfaceWidth);
388 m_qmlItem->setHeight(m_surfaceHeight);
392 m_qmlItem->setHeight(m_surfaceHeight);
389 }
393 }
394+ qDebug() << this << "setting implicitsize" << m_surfaceWidth << m_surfaceHeight;
390 setImplicitSize(m_surfaceWidth, m_surfaceHeight);
395 setImplicitSize(m_surfaceWidth, m_surfaceHeight);
391 }
396 }
392}
397}
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+40−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()
45Screens::~Screens()
@@ -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
@@ -52,9 +70,29 @@ QVariant Screens::data(const QModelIndex &index, int role) const
52
70
53 switch(role) {
71 switch(role) {
54 case ScreenRole:
72 case ScreenRole:
73+ qDebug() << "returning" << m_screenList.at(index.row())->qScreen;
55 return QVariant::fromValue(m_screenList.at(index.row())->qScreen);
74 return QVariant::fromValue(m_screenList.at(index.row())->qScreen);
56 case OutputTypeRole:
75 case OutputTypeRole:
57 return m_screenList.at(index.row())->outputTypes;
76 return m_screenList.at(index.row())->outputTypes;
77+ case EnabledRole:
78+ return m_screenList.at(index.row())->enabled;
79+ case NameRole:
80+ return m_screenList.at(index.row())->name;
81+ case ScaleRole:
82+ return m_screenList.at(index.row())->scale;
83+ case FormFactorRole:
84+ return m_screenList.at(index.row())->formFactor;
85+ case GeometryRole:
86+ return m_screenList.at(index.row())->geometry;
87+ case SizesRole:
88+ {
89+ QVariantList sizes;
90+ auto availableSizes = m_screenList.at(index.row())->sizes;
91+ Q_FOREACH(auto size, availableSizes) {
92+ sizes.append(QVariant(size));
93+ }
94+ return sizes;
95+ }
58 }
96 }
59
97
60 return QVariant();
98 return QVariant();
tests/mocks/Unity/Screens/screens.h+23−1
@@ -26,13 +26,20 @@ class Screens : public QAbstractListModel
26{
26{
27 Q_OBJECT
27 Q_OBJECT
28 Q_ENUMS(OutputTypes)
28 Q_ENUMS(OutputTypes)
29+ Q_ENUMS(FormFactor)
29
30
30 Q_PROPERTY(int count READ count NOTIFY countChanged)
31 Q_PROPERTY(int count READ count NOTIFY countChanged)
31
32
32public:
33public:
33 enum ItemRoles {
34 enum ItemRoles {
34 ScreenRole = Qt::UserRole + 1,
35 ScreenRole = Qt::UserRole + 1,
35− OutputTypeRole
36+ OutputTypeRole,
37+ EnabledRole,
38+ NameRole,
39+ ScaleRole,
40+ FormFactorRole,
41+ GeometryRole,
42+ SizesRole
36 };
43 };
37
44
38 enum OutputTypes {
45 enum OutputTypes {
@@ -53,6 +60,15 @@ public:
53 EDP
60 EDP
54 };
61 };
55
62
63+ enum FormFactor {
64+ FormFactorUnknown,
65+ FormFactorPhone,
66+ FormFactorTablet,
67+ FormFactorMonitor,
68+ FormFactorTV,
69+ FormFactorProjector,
70+ };
71+
56 explicit Screens(QObject *parent = 0);
72 explicit Screens(QObject *parent = 0);
57 virtual ~Screens() noexcept;
73 virtual ~Screens() noexcept;
58
74
@@ -77,6 +93,12 @@ class Screen
77public:
93public:
78 Screens::OutputTypes outputTypes = Screens::Unknown;
94 Screens::OutputTypes outputTypes = Screens::Unknown;
79 QScreen *qScreen = nullptr;
95 QScreen *qScreen = nullptr;
96+ bool enabled = false;
97+ QString name = QString();
98+ float scale = 1.0;
99+ Screens::FormFactor formFactor = Screens::FormFactorMonitor;
100+ QRect geometry;
101+ QList<QSize> sizes;
80};
102};
81
103
82#endif // SCREENS_H
104#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+9−8
@@ -23,7 +23,6 @@ import Unity.Application 0.1
23import Unity.Indicators 0.1 as Indicators
23import Unity.Indicators 0.1 as Indicators
24import Ubuntu.Telephony 0.1 as Telephony
24import Ubuntu.Telephony 0.1 as Telephony
25import "../../../qml/Panel"
25import "../../../qml/Panel"
26−import "../../../qml/Components/PanelState"
27
26
28IndicatorTest {
27IndicatorTest {
29 id: root
28 id: root
@@ -33,6 +32,8 @@ IndicatorTest {
33
32
34 Component.onCompleted: theme.name = "Ubuntu.Components.Themes.SuruDark"
33 Component.onCompleted: theme.name = "Ubuntu.Components.Themes.SuruDark"
35
34
35+ readonly property alias panelState: panel.panelState
36+
36 SurfaceManager {}
37 SurfaceManager {}
37
38
38 Binding {
39 Binding {
@@ -109,7 +110,7 @@ IndicatorTest {
109 Layout.fillWidth: true
110 Layout.fillWidth: true
110 CheckBox {
111 CheckBox {
111 id: windowControlsCB
112 id: windowControlsCB
112− onClicked: PanelState.buttonsVisible = checked
113+ onClicked: panelState.buttonsVisible = checked
113 }
114 }
114 Label {
115 Label {
115 text: "Show window controls"
116 text: "Show window controls"
@@ -121,9 +122,9 @@ IndicatorTest {
121 CheckBox {
122 CheckBox {
122 onClicked: {
123 onClicked: {
123 if (checked)
124 if (checked)
124− PanelState.title = "Fake window title"
125+ panelState.title = "Fake window title"
125 else
126 else
126− PanelState.title = ""
127+ panelState.title = ""
127 }
128 }
128 }
129 }
129 Label {
130 Label {
@@ -186,7 +187,7 @@ IndicatorTest {
186
187
187 SignalSpy {
188 SignalSpy {
188 id: windowControlButtonsSpy
189 id: windowControlButtonsSpy
189− target: PanelState
190+ target: panelState
190 signalName: "closeClicked"
191 signalName: "closeClicked"
191 }
192 }
192
193
@@ -510,13 +511,13 @@ IndicatorTest {
510
511
511 // https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1611959
512 // https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1611959
512 function test_windowControlButtonsFittsLaw() {
513 function test_windowControlButtonsFittsLaw() {
513− var buttonsVisible = PanelState.buttonsVisible;
514+ var buttonsVisible = panelState.buttonsVisible;
514− PanelState.buttonsVisible = true;
515+ panelState.buttonsVisible = true;
515 // click in very topleft corner and verify the close button got clicked too
516 // click in very topleft corner and verify the close button got clicked too
516 mouseMove(panel, 0, 0);
517 mouseMove(panel, 0, 0);
517 mouseClick(panel, 0, 0, undefined /*button*/, undefined /*modifiers*/, 100 /*short delay*/);
518 mouseClick(panel, 0, 0, undefined /*button*/, undefined /*modifiers*/, 100 /*short delay*/);
518 compare(windowControlButtonsSpy.count, 1);
519 compare(windowControlButtonsSpy.count, 1);
519− PanelState.buttonsVisible = buttonsVisible;
520+ panelState.buttonsVisible = buttonsVisible;
520 }
521 }
521 }
522 }
522}
523}
tests/qmltests/Stage/tst_DesktopStage.qml+8−3
@@ -41,6 +41,10 @@ Item {
41 value: false
41 value: false
42 }
42 }
43
43
44+ PanelState {
45+ id: panelState
46+ }
47+
44 Component.onCompleted: {
48 Component.onCompleted: {
45 theme.name = "Ubuntu.Components.Themes.SuruDark";
49 theme.name = "Ubuntu.Components.Themes.SuruDark";
46 resetGeometry();
50 resetGeometry();
@@ -92,6 +96,7 @@ Item {
92 topLevelSurfaceList: topSurfaceList
96 topLevelSurfaceList: topSurfaceList
93 interactive: true
97 interactive: true
94 mode: "windowed"
98 mode: "windowed"
99+ panelState: panelState
95 }
100 }
96 }
101 }
97
102
@@ -624,19 +629,19 @@ Item {
624 maximizeDelegate(facebookAppDelegate);
629 maximizeDelegate(facebookAppDelegate);
625
630
626 // verify the drop shadow is still not visible
631 // verify the drop shadow is still not visible
627− verify(PanelState.dropShadow == false);
632+ verify(panelState.dropShadow == false);
628
633
629 // start a foreground app, not maximized
634 // start a foreground app, not maximized
630 var dialerAppDelegate = startApplication("dialer-app");
635 var dialerAppDelegate = startApplication("dialer-app");
631
636
632 // verify the drop shadow becomes visible
637 // verify the drop shadow becomes visible
633− verify(PanelState.dropShadow == true);
638+ verify(panelState.dropShadow == true);
634
639
635 // close the maximized app
640 // close the maximized app
636 ApplicationManager.stopApplication("facebook-webapp");
641 ApplicationManager.stopApplication("facebook-webapp");
637
642
638 // verify the drop shadow is gone
643 // verify the drop shadow is gone
639− tryCompare(PanelState, "dropShadow", false);
644+ tryCompare(panelState, "dropShadow", false);
640 }
645 }
641
646
642 function test_threeFingerTapShowsWindowControls_data() {
647 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
@@ -55,12 +55,21 @@ Rectangle {
55 onShellChanged: {
55 onShellChanged: {
56 if (shell) {
56 if (shell) {
57 topLevelSurfaceList = testCase.findInvisibleChild(shell, "topLevelSurfaceList");
57 topLevelSurfaceList = testCase.findInvisibleChild(shell, "topLevelSurfaceList");
58+ panelState = testCase.findInvisibleChild(shell, "panelState");
58 } else {
59 } else {
59 topLevelSurfaceList = null;
60 topLevelSurfaceList = null;
61+ panelState = undefined;
60 }
62 }
61 }
63 }
62
64
63 property var topLevelSurfaceList: null
65 property var topLevelSurfaceList: null
66+ property var panelState: undefined
67+
68+ QtObject {
69+ id: _screenWindow
70+ property bool primary: false
71+ }
72+ property alias screenWindow: _screenWindow
64
73
65 Item {
74 Item {
66 id: shellContainer
75 id: shellContainer
@@ -135,6 +144,11 @@ Rectangle {
135 Component.onDestruction: {
144 Component.onDestruction: {
136 shellLoader.itemDestroyed = true;
145 shellLoader.itemDestroyed = true;
137 }
146 }
147+
148+ SurfaceManager {
149+ id: surfaceMan
150+ }
151+ surfaceManager: surfaceMan
138 }
152 }
139 }
153 }
140 }
154 }
@@ -671,7 +685,7 @@ Rectangle {
671 }
685 }
672
686
673 function ensureInputMethodSurface() {
687 function ensureInputMethodSurface() {
674− var surfaceManager = findInvisibleChild(shell, "surfaceManager");
688+ var surfaceManager = shell.surfaceManager;
675 verify(surfaceManager);
689 verify(surfaceManager);
676 surfaceManager.createInputMethodSurface();
690 surfaceManager.createInputMethodSurface();
677
691
@@ -1878,21 +1892,21 @@ Rectangle {
1878 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
1892 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
1879
1893
1880 tryCompare(appDelegate, "state", "normal");
1894 tryCompare(appDelegate, "state", "normal");
1881− tryCompare(PanelState, "buttonsVisible", false)
1895+ tryCompare(panelState, "buttonsVisible", false)
1882
1896
1883 mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
1897 mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
1884 tryCompare(appDelegate, "state", "maximized");
1898 tryCompare(appDelegate, "state", "maximized");
1885− tryCompare(PanelState, "buttonsVisible", true)
1899+ tryCompare(panelState, "buttonsVisible", true)
1886
1900
1887 ApplicationManager.stopApplication(application.appId);
1901 ApplicationManager.stopApplication(application.appId);
1888− tryCompare(PanelState, "buttonsVisible", false)
1902+ tryCompare(panelState, "buttonsVisible", false)
1889
1903
1890 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
1904 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
1891 // They won't be gone until those surface items are destroyed.
1905 // They won't be gone until those surface items are destroyed.
1892 tryCompareFunction(function() { return application.surfaceList.count }, 0);
1906 tryCompareFunction(function() { return application.surfaceList.count }, 0);
1893
1907
1894 ApplicationManager.startApplication(application.appId);
1908 ApplicationManager.startApplication(application.appId);
1895− tryCompare(PanelState, "buttonsVisible", true)
1909+ tryCompare(panelState, "buttonsVisible", true)
1896 }
1910 }
1897
1911
1898 function test_newAppHasValidGeometry() {
1912 function test_newAppHasValidGeometry() {
@@ -1948,7 +1962,7 @@ Rectangle {
1948 mousePress(appDelegate, appDelegate.width / 2, units.gu(1))
1962 mousePress(appDelegate, appDelegate.width / 2, units.gu(1))
1949 mouseMove(appDelegate, appDelegate.width / 2, -units.gu(100))
1963 mouseMove(appDelegate, appDelegate.width / 2, -units.gu(100))
1950
1964
1951− compare(appDelegate.y >= PanelState.panelHeight, true);
1965+ compare(appDelegate.y >= panelState.panelHeight, true);
1952 }
1966 }
1953
1967
1954 function test_cantResizeWindowUnderPanel() {
1968 function test_cantResizeWindowUnderPanel() {
@@ -1976,7 +1990,7 @@ Rectangle {
1976 mouseMove(decoration, decoration.width/2, -units.gu(100));
1990 mouseMove(decoration, decoration.width/2, -units.gu(100));
1977
1991
1978 // verify we don't go past the panel
1992 // verify we don't go past the panel
1979− compare(appDelegate.y >= PanelState.panelHeight, true);
1993+ compare(appDelegate.y >= panelState.panelHeight, true);
1980 }
1994 }
1981
1995
1982 function test_restoreWindowStateFixesIfUnderPanel() {
1996 function test_restoreWindowStateFixesIfUnderPanel() {
@@ -2000,7 +2014,7 @@ Rectangle {
2000 tryCompareFunction(function () { return topLevelSurfaceList.applicationAt(0).appId; }, application.appId);
2014 tryCompareFunction(function () { return topLevelSurfaceList.applicationAt(0).appId; }, application.appId);
2001
2015
2002 appDelegate = appRepeater.itemAt(0);
2016 appDelegate = appRepeater.itemAt(0);
2003− compare(appDelegate.y >= PanelState.panelHeight, true);
2017+ compare(appDelegate.y >= panelState.panelHeight, true);
2004 }
2018 }
2005
2019
2006 function test_lifecyclePolicyForNonTouchApp_data() {
2020 function test_lifecyclePolicyForNonTouchApp_data() {
@@ -2601,7 +2615,7 @@ Rectangle {
2601 function test_oskDisplacesWindow_data() {
2615 function test_oskDisplacesWindow_data() {
2602 return [
2616 return [
2603 {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
2617 {tag: "no need to displace", windowHeight: units.gu(10), windowY: units.gu(5), targetDisplacement: units.gu(5), oskEnabled: true},
2604− {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: PanelState.panelHeight, oskEnabled: true},
2618+ {tag: "displace to top", windowHeight: units.gu(50), windowY: units.gu(10), targetDisplacement: panelState.panelHeight, oskEnabled: true},
2605 {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
2619 {tag: "osk not on this screen", windowHeight: units.gu(40), windowY: units.gu(10), targetDisplacement: units.gu(10), oskEnabled: false},
2606 ]
2620 ]
2607 }
2621 }
@@ -2624,8 +2638,8 @@ Rectangle {
2624 dashAppDelegate.windowedY = data.windowY;
2638 dashAppDelegate.windowedY = data.windowY;
2625 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2639 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, 0, 0, 0));
2626 var initialY = dashAppDelegate.y;
2640 var initialY = dashAppDelegate.y;
2627− print("intial", initialY, "panel", PanelState.panelHeight);
2641+ print("intial", initialY, "panel", panelState.panelHeight);
2628− verify(initialY > PanelState.panelHeight);
2642+ verify(initialY > panelState.panelHeight);
2629
2643
2630 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
2644 topLevelSurfaceList.inputMethodSurface.setInputBounds(Qt.rect(0, root.height / 2, root.width, root.height / 2));
2631 tryCompare(dashAppDelegate, "y", data.targetDisplacement);
2645 tryCompare(dashAppDelegate, "y", data.targetDisplacement);