on 07f86b2 help sign in
unity8/tests/mocks/Unity/Application/MirSurfaceItem.cpp
438 lines 13 kB history raw
1/*
2 * Copyright (C) 2014-2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include "MirSurfaceItem.h"
19#include <paths.h>
21#include <QGuiApplication>
22#include <QQuickView>
23#include <QQmlContext>
24#include <QQmlProperty>
25#include <QQmlEngine>
26#include <QString>
28#include <QDebug>
30using namespace unity::shell::application;
32#define MIRSURFACEITEM_DEBUG 0
34#if MIRSURFACEITEM_DEBUG
35#define DEBUG_MSG(params) qDebug().nospace() << "MirSurfaceItem::" << __func__ << " " << params
36#else
37#define DEBUG_MSG(params) ((void)0)
38#endif
40MirSurfaceItem::MirSurfaceItem(QQuickItem *parent)
41 : MirSurfaceItemInterface(parent)
42 , m_qmlSurface(nullptr)
43 , m_qmlContentComponent(nullptr)
44 , m_qmlItem(nullptr)
45 , m_consumesInput(false)
46 , m_orientationAngle(nullptr)
47 , m_surfaceWidth(0)
48 , m_surfaceHeight(0)
49 , m_touchPressCount(0)
50 , m_touchReleaseCount(0)
51 , m_mousePressCount(0)
52 , m_mouseReleaseCount(0)
54 DEBUG_MSG((void*)(this) << name());
55 setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
56 Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
57 Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
58 Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
59 Qt::ExtraButton12 | Qt::ExtraButton13);
61 connect(this, &QQuickItem::activeFocusChanged, this, &MirSurfaceItem::updateMirSurfaceActiveFocus);
62 connect(this, &QQuickItem::visibleChanged, this, &MirSurfaceItem::updateMirSurfaceExposure);
64 connect(this, &MirSurfaceItem::consumesInputChanged, this, [this]() {
65 updateMirSurfaceActiveFocus(hasActiveFocus());
66 });
68 // We're just clipping contents in the mock. The real QtMir would copy only relevant buffer instead
69 setClip(true);
72MirSurfaceItem::~MirSurfaceItem()
74 DEBUG_MSG((void*)(this) << name());
75 setSurface(nullptr);
76 delete m_orientationAngle;
79void MirSurfaceItem::printComponentErrors()
81 QList<QQmlError> errors = m_qmlContentComponent->errors();
82 for (int i = 0; i < errors.count(); ++i) {
83 qDebug() << errors[i];
84 }
87Mir::Type MirSurfaceItem::type() const
89 if (m_qmlSurface) {
90 return m_qmlSurface->type();
91 } else {
92 return Mir::UnknownType;
93 }
96Mir::State MirSurfaceItem::surfaceState() const
98 if (m_qmlSurface) {
99 return m_qmlSurface->state();
100 } else {
101 return Mir::UnknownState;
102 }
105QString MirSurfaceItem::name() const
107 if (m_qmlSurface) {
108 return m_qmlSurface->name();
109 } else {
110 return QString();
111 }
114bool MirSurfaceItem::live() const
116 if (m_qmlSurface) {
117 return m_qmlSurface->live();
118 } else {
119 return false;
120 }
123Mir::ShellChrome MirSurfaceItem::shellChrome() const
125 if (m_qmlSurface) {
126 return m_qmlSurface->shellChrome();
127 } else {
128 return Mir::NormalChrome;
129 }
132Mir::OrientationAngle MirSurfaceItem::orientationAngle() const
134 if (m_orientationAngle) {
135 Q_ASSERT(!m_qmlSurface);
136 return *m_orientationAngle;
137 } else if (m_qmlSurface) {
138 return m_qmlSurface->orientationAngle();
139 } else {
140 return Mir::Angle0;
141 }
144void MirSurfaceItem::setOrientationAngle(Mir::OrientationAngle angle)
146 DEBUG_MSG(angle);
148 if (m_qmlSurface) {
149 Q_ASSERT(!m_orientationAngle);
150 m_qmlSurface->setOrientationAngle(angle);
151 } else if (!m_orientationAngle) {
152 m_orientationAngle = new Mir::OrientationAngle;
153 *m_orientationAngle = angle;
154 Q_EMIT orientationAngleChanged(angle);
155 } else if (*m_orientationAngle != angle) {
156 *m_orientationAngle = angle;
157 Q_EMIT orientationAngleChanged(angle);
158 }
160 if (m_qmlItem) {
161 QQmlProperty orientationProp(m_qmlItem, "orientationAngle");
162 if (orientationProp.isValid()) {
163 orientationProp.write(QVariant::fromValue(orientationAngle()));
164 }
165 }
168void MirSurfaceItem::updateScreenshot(QUrl screenshotUrl)
170 if (m_qmlItem) {
171 QQmlProperty screenshotSource(m_qmlItem, "screenshotSource");
172 if (screenshotSource.isValid()) {
173 screenshotSource.write(QVariant::fromValue(screenshotUrl));
174 }
175 }
178void MirSurfaceItem::onComponentStatusChanged(QQmlComponent::Status status)
180 if (status == QQmlComponent::Ready) {
181 createQmlContentItem();
182 }
185void MirSurfaceItem::createQmlContentItem()
187 DEBUG_MSG("");
189 m_qmlItem = qobject_cast<QQuickItem*>(m_qmlContentComponent->create());
190 m_qmlItem->setParentItem(this);
192 if (m_fillMode == FillMode::Stretch && width() != 0 && height() != 0) {
193 m_qmlItem->setWidth(width());
194 m_qmlItem->setHeight(height());
195 } else {
196 m_qmlItem->setWidth(m_surfaceWidth);
197 m_qmlItem->setHeight(m_surfaceHeight);
198 }
200 qDebug() << "set size to" << m_surfaceWidth;
201 setImplicitWidth(m_qmlItem->implicitWidth());
202 setImplicitHeight(m_qmlItem->implicitHeight());
204 {
205 QQmlProperty screenshotSource(m_qmlItem, "screenshotSource");
206 if (screenshotSource.isValid()) {
207 screenshotSource.write(QVariant::fromValue(m_qmlSurface->screenshotUrl()));
208 }
209 }
211 {
212 QQmlProperty orientationProp(m_qmlItem, "orientationAngle");
213 if (orientationProp.isValid()) {
214 orientationProp.write(QVariant::fromValue(orientationAngle()));
215 }
216 }
218 {
219 QQmlProperty surfaceProperty(m_qmlItem, "surface");
220 if (surfaceProperty.isValid()) {
221 surfaceProperty.write(QVariant::fromValue(m_qmlSurface));
222 }
223 }
226void MirSurfaceItem::touchEvent(QTouchEvent * event)
228 if (event->type() == QEvent::TouchBegin) {
229 m_touchTrail.clear();
230 }
232 if (event->touchPointStates() & Qt::TouchPointPressed) {
233 ++m_touchPressCount;
234 Q_EMIT touchPressCountChanged(m_touchPressCount);
235 } else if (event->touchPointStates() & Qt::TouchPointReleased) {
236 ++m_touchReleaseCount;
237 Q_EMIT touchReleaseCountChanged(m_touchReleaseCount);
238 }
240 Q_FOREACH(const QTouchEvent::TouchPoint &touchPoint, event->touchPoints()) {
241 QString id(touchPoint.id());
242 QVariantList list = m_touchTrail[id].toList();
243 list.append(QVariant::fromValue(touchPoint.pos()));
244 if (list.count() > 100) list.pop_front();
245 m_touchTrail[id] = list;
246 }
248 if (m_qmlItem) {
249 QQmlProperty touchTrail(m_qmlItem, "touchTrail");
250 touchTrail.write(m_touchTrail);
251 }
254void MirSurfaceItem::mousePressEvent(QMouseEvent * event)
256 m_mousePressCount++;
257 Q_EMIT mousePressCountChanged(m_mousePressCount);
258 event->accept();
261void MirSurfaceItem::mouseMoveEvent(QMouseEvent * event)
263 event->accept();
266void MirSurfaceItem::mouseReleaseEvent(QMouseEvent * event)
268 m_mouseReleaseCount++;
269 Q_EMIT mouseReleaseCountChanged(m_mouseReleaseCount);
270 event->accept();
273void MirSurfaceItem::setSurface(MirSurfaceInterface* surface)
275 DEBUG_MSG("this=" << (void*)(this) << " name=" << name() << " surface=" << surface);
277 if (m_qmlSurface == surface) {
278 return;
279 }
281 if (m_qmlSurface) {
282 delete m_qmlItem;
283 m_qmlItem = nullptr;
285 delete m_qmlContentComponent;
286 m_qmlContentComponent = nullptr;
288 if (hasActiveFocus() && m_consumesInput && m_qmlSurface->live()) {
289 m_qmlSurface->setActiveFocus(false);
290 }
292 disconnect(m_qmlSurface, nullptr, this, nullptr);
293 m_qmlSurface->unregisterView((qintptr)this);
294 }
296 m_qmlSurface = static_cast<MirSurface*>(surface);
298 if (m_qmlSurface) {
299 m_qmlSurface->registerView((qintptr)this);
301 updateSurfaceSize();
302 updateMirSurfaceExposure();
304 if (m_orientationAngle) {
305 m_qmlSurface->setOrientationAngle(*m_orientationAngle);
306 connect(m_qmlSurface, &MirSurfaceInterface::orientationAngleChanged, this, &MirSurfaceItem::orientationAngleChanged);
307 delete m_orientationAngle;
308 m_orientationAngle = nullptr;
309 } else {
310 connect(m_qmlSurface, &MirSurfaceInterface::orientationAngleChanged, this, &MirSurfaceItem::orientationAngleChanged);
311 Q_EMIT orientationAngleChanged(m_qmlSurface->orientationAngle());
312 }
314 connect(m_qmlSurface, &MirSurface::screenshotUrlChanged, this, &MirSurfaceItem::updateScreenshot);
315 connect(m_qmlSurface, &MirSurface::liveChanged, this, &MirSurfaceItem::liveChanged);
316 connect(m_qmlSurface, &MirSurface::stateChanged, this, &MirSurfaceItem::surfaceStateChanged);
317 connect(m_qmlSurface, &MirSurface::sizeChanged, this, [this] () {
318 if (m_fillMode == FillMode::Stretch) {
319 m_qmlItem->setSize(QSize(this->width(), this->height()));
320 } else {
321 m_qmlItem->setSize(m_qmlSurface->size());
322 }
323 setImplicitSize(m_qmlSurface->width(), m_qmlSurface->height());
324 });
325 m_surfaceWidth = surface->size().width();
326 m_surfaceHeight = surface->size().height();
328 QUrl qmlComponentFilePath;
329 if (!m_qmlSurface->qmlFilePath().isEmpty()) {
330 qmlComponentFilePath = m_qmlSurface->qmlFilePath();
331 } else {
332 qmlComponentFilePath = QUrl("qrc:///Unity/Application/MirSurfaceItem.qml");
333 }
335 m_qmlContentComponent = new QQmlComponent(QQmlEngine::contextForObject(parent())->engine(), qmlComponentFilePath);
337 switch (m_qmlContentComponent->status()) {
338 case QQmlComponent::Ready:
339 createQmlContentItem();
340 qDebug() << "content created" << m_surfaceWidth << implicitWidth() << width();
341 break;
342 case QQmlComponent::Loading:
343 connect(m_qmlContentComponent, &QQmlComponent::statusChanged,
344 this, &MirSurfaceItem::onComponentStatusChanged);
345 break;
346 case QQmlComponent::Error:
347 printComponentErrors();
348 qFatal("MirSurfaceItem: failed to create content component.");
349 break;
350 default:
351 qFatal("MirSurfaceItem: Unhandled component status");
352 }
354 if (m_consumesInput) {
355 m_qmlSurface->setActiveFocus(hasActiveFocus());
356 }
357 }
359 Q_EMIT surfaceChanged(m_qmlSurface);
363void MirSurfaceItem::updateMirSurfaceActiveFocus(bool focused)
365 if (m_qmlSurface && m_consumesInput && m_qmlSurface->live()) {
366 m_qmlSurface->setActiveFocus(focused);
367 }
370void MirSurfaceItem::updateMirSurfaceExposure()
372 if (!m_qmlSurface) return;
374 m_qmlSurface->setViewExposure((qintptr)this, isVisible());
377void MirSurfaceItem::setConsumesInput(bool value)
379 if (m_consumesInput != value) {
380 m_consumesInput = value;
381 Q_EMIT consumesInputChanged(value);
382 }
385int MirSurfaceItem::surfaceWidth() const
387 return m_surfaceWidth;
390void MirSurfaceItem::setSurfaceWidth(int value)
392// qDebug() << "setSurfaceWidth called" << value;
393 if (value != -1 && m_surfaceWidth != value) {
394 m_surfaceWidth = value;
395 Q_EMIT surfaceWidthChanged(m_surfaceWidth);
396 updateSurfaceSize();
397 }
400int MirSurfaceItem::surfaceHeight() const
402 return m_surfaceHeight;
405void MirSurfaceItem::setSurfaceHeight(int value)
407 if (value != -1 && m_surfaceHeight != value) {
408 m_surfaceHeight = value;
409 Q_EMIT surfaceHeightChanged(m_surfaceHeight);
410 updateSurfaceSize();
411 }
414void MirSurfaceItem::updateSurfaceSize()
416 if (m_qmlSurface && m_surfaceWidth > 0 && m_surfaceHeight > 0) {
417 m_qmlSurface->resize(m_surfaceWidth, m_surfaceHeight);
418 if (m_qmlItem) {
419 if (m_fillMode == FillMode::Stretch) {
420 m_qmlItem->setWidth(width());
421 m_qmlItem->setHeight(height());
422 } else {
423 m_qmlItem->setWidth(m_surfaceWidth);
424 m_qmlItem->setHeight(m_surfaceHeight);
425 }
426 }
427 qDebug() << this << "setting implicitsize" << m_surfaceWidth << m_surfaceHeight;
428 setImplicitSize(m_surfaceWidth, m_surfaceHeight);
429 }
432void MirSurfaceItem::setFillMode(FillMode value)
434 if (value != m_fillMode) {
435 m_fillMode = value;
436 Q_EMIT fillModeChanged(m_fillMode);
437 }