summaryrefslogtreecommitdiffstats
path: root/src/compositor/compositor_api/qwaylandquickitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/compositor/compositor_api/qwaylandquickitem.cpp')
-rw-r--r--src/compositor/compositor_api/qwaylandquickitem.cpp554
1 files changed, 398 insertions, 156 deletions
diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp
index 4a5880bb2..c643598be 100644
--- a/src/compositor/compositor_api/qwaylandquickitem.cpp
+++ b/src/compositor/compositor_api/qwaylandquickitem.cpp
@@ -1,37 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) any later version
-** approved by the KDE Free Qt Foundation. The licenses are as published by
-** the Free Software Foundation and appearing in the file LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwaylandquickitem.h"
#include "qwaylandquickitem_p.h"
#include "qwaylandquicksurface.h"
#include "qwaylandinputmethodcontrol.h"
#include "qwaylandtextinput.h"
+#include "qwaylandtextinputv3.h"
+#include "qwaylandqttextinputmethod.h"
#include "qwaylandquickoutput.h"
#include <QtWaylandCompositor/qwaylandcompositor.h>
#include <QtWaylandCompositor/qwaylandseat.h>
@@ -42,21 +18,30 @@
#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h>
#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
+#if QT_CONFIG(opengl)
+# include <QtOpenGL/QOpenGLTexture>
+# include <QtGui/QOpenGLFunctions>
+#endif
+
#include <QtGui/QKeyEvent>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
-#include <QtGui/QOpenGLFunctions>
-#include <QtGui/QOpenGLTexture>
#include <QtQuick/QSGSimpleTextureNode>
#include <QtQuick/QQuickWindow>
+#include <QtQuick/qsgtexture.h>
+#include <QtCore/QFile>
#include <QtCore/QMutexLocker>
#include <QtCore/QMutex>
#include <wayland-server-core.h>
#include <QThread>
+#if QT_CONFIG(opengl)
+#include <QtGui/private/qshaderdescription_p.h>
+#endif
+
#ifndef GL_TEXTURE_EXTERNAL_OES
#define GL_TEXTURE_EXTERNAL_OES 0x8D65
#endif
@@ -67,126 +52,219 @@ QT_BEGIN_NAMESPACE
static const struct {
const char * const vertexShaderSourceFile;
const char * const fragmentShaderSourceFile;
- GLenum textureTarget;
int planeCount;
bool canProvideTexture;
QSGMaterial::Flags materialFlags;
QSGMaterialType materialType;
} bufferTypes[] = {
// BufferFormatEgl_Null
- { "", "", 0, 0, false, 0, {} },
+ { "", "", 0, false, {}, {} },
- // BufferFormatEgl_RGB
+ // BufferFormatEgl_RGB (GL_TEXTURE_2D)
{
- ":/qt-project.org/wayland/compositor/shaders/surface.vert",
- ":/qt-project.org/wayland/compositor/shaders/surface_rgbx.frag",
- GL_TEXTURE_2D, 1, true,
+ ":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
+ ":/qt-project.org/wayland/compositor/shaders/surface_rgbx.frag.qsb",
+ 1, true,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_RGBA
+ // BufferFormatEgl_RGBA (GL_TEXTURE_2D)
{
- ":/qt-project.org/wayland/compositor/shaders/surface.vert",
- ":/qt-project.org/wayland/compositor/shaders/surface_rgba.frag",
- GL_TEXTURE_2D, 1, true,
+ ":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
+ ":/qt-project.org/wayland/compositor/shaders/surface_rgba.frag.qsb",
+ 1, true,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_EXTERNAL_OES
+ // BufferFormatEgl_EXTERNAL_OES (GL_TEXTURE_EXTERNAL_OES)
{
- ":/qt-project.org/wayland/compositor/shaders/surface.vert",
+ ":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
":/qt-project.org/wayland/compositor/shaders/surface_oes_external.frag",
- GL_TEXTURE_EXTERNAL_OES, 1, false,
+ 1, false,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_Y_U_V
+ // BufferFormatEgl_Y_U_V (GL_TEXTURE_2D)
{
- ":/qt-project.org/wayland/compositor/shaders/surface.vert",
- ":/qt-project.org/wayland/compositor/shaders/surface_y_u_v.frag",
- GL_TEXTURE_2D, 3, false,
+ ":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
+ ":/qt-project.org/wayland/compositor/shaders/surface_y_u_v.frag.qsb",
+ 3, false,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_Y_UV
+ // BufferFormatEgl_Y_UV (GL_TEXTURE_2D)
{
- ":/qt-project.org/wayland/compositor/shaders/surface.vert",
- ":/qt-project.org/wayland/compositor/shaders/surface_y_uv.frag",
- GL_TEXTURE_2D, 2, false,
+ ":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
+ ":/qt-project.org/wayland/compositor/shaders/surface_y_uv.frag.qsb",
+ 2, false,
QSGMaterial::Blending,
{}
},
- // BufferFormatEgl_Y_XUXV
+ // BufferFormatEgl_Y_XUXV (GL_TEXTURE_2D)
{
- ":/qt-project.org/wayland/compositor/shaders/surface.vert",
- ":/qt-project.org/wayland/compositor/shaders/surface_y_xuxv.frag",
- GL_TEXTURE_2D, 2, false,
+ ":/qt-project.org/wayland/compositor/shaders/surface.vert.qsb",
+ ":/qt-project.org/wayland/compositor/shaders/surface_y_xuxv.frag.qsb",
+ 2, false,
QSGMaterial::Blending,
{}
}
};
QWaylandBufferMaterialShader::QWaylandBufferMaterialShader(QWaylandBufferRef::BufferFormatEgl format)
- : m_format(format)
{
- setShaderSourceFile(QOpenGLShader::Vertex, QString::fromLatin1(bufferTypes[format].vertexShaderSourceFile));
- setShaderSourceFile(QOpenGLShader::Fragment, QString::fromLatin1(bufferTypes[format].fragmentShaderSourceFile));
+ Q_UNUSED(format);
+ setShaderFileName(VertexStage, QString::fromLatin1(bufferTypes[format].vertexShaderSourceFile));
+ auto fragmentShaderSourceFile = QString::fromLatin1(bufferTypes[format].fragmentShaderSourceFile);
+
+ if (format == QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES)
+ setupExternalOESShader(fragmentShaderSourceFile);
+ else
+ setShaderFileName(FragmentStage, fragmentShaderSourceFile);
}
-void QWaylandBufferMaterialShader::updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+void QWaylandBufferMaterialShader::setupExternalOESShader(const QString &shaderFilename)
{
- QSGMaterialShader::updateState(state, newEffect, oldEffect);
+#if QT_CONFIG(opengl)
+ QFile shaderFile(shaderFilename);
+ if (!shaderFile.open(QIODevice::ReadOnly)) {
+ qCWarning(qLcWaylandCompositor) << "Cannot find external OES shader file:" << shaderFilename;
+ return;
+ }
+ QByteArray FS = shaderFile.readAll();
+
+ static const char *FS_GLES_PREAMBLE =
+ "#extension GL_OES_EGL_image_external : require\n"
+ "precision highp float;\n";
+ static const char *FS_GL_PREAMBLE =
+ "#version 120\n"
+ "#extension GL_OES_EGL_image_external : require\n";
+ QByteArray fsGLES = FS_GLES_PREAMBLE + FS;
+ QByteArray fsGL = FS_GL_PREAMBLE + FS;
+
+ QShaderDescription desc;
+ QShaderDescriptionPrivate *descData = QShaderDescriptionPrivate::get(&desc);
+
+ QShaderDescription::InOutVariable texCoordInput;
+ texCoordInput.name = "v_texcoord";
+ texCoordInput.type = QShaderDescription::Vec2;
+ texCoordInput.location = 0;
+
+ descData->inVars = { texCoordInput };
+
+ QShaderDescription::InOutVariable fragColorOutput;
+ fragColorOutput.name = "gl_FragColor";
+ fragColorOutput.type = QShaderDescription::Vec4;
+ fragColorOutput.location = 0;
+
+ descData->outVars = { fragColorOutput };
+
+ QShaderDescription::BlockVariable matrixBlockVar;
+ matrixBlockVar.name = "qt_Matrix";
+ matrixBlockVar.type = QShaderDescription::Mat4;
+ matrixBlockVar.offset = 0;
+ matrixBlockVar.size = 64;
+
+ QShaderDescription::BlockVariable opacityBlockVar;
+ opacityBlockVar.name = "qt_Opacity";
+ opacityBlockVar.type = QShaderDescription::Float;
+ opacityBlockVar.offset = 64;
+ opacityBlockVar.size = 4;
+
+ QShaderDescription::UniformBlock ubufStruct;
+ ubufStruct.blockName = "buf";
+ ubufStruct.structName = "ubuf";
+ ubufStruct.size = 64 + 4;
+ ubufStruct.binding = 0;
+ ubufStruct.members = { matrixBlockVar, opacityBlockVar };
+
+ descData->uniformBlocks = { ubufStruct };
+
+ QShaderDescription::InOutVariable samplerTex0;
+ samplerTex0.name = "tex0";
+ samplerTex0.type = QShaderDescription::SamplerExternalOES;
+ samplerTex0.binding = 1;
+
+ descData->combinedImageSamplers = { samplerTex0 };
+
+ QShader shaderPack;
+ shaderPack.setStage(QShader::FragmentStage);
+ shaderPack.setDescription(desc);
+ shaderPack.setShader(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)), QShaderCode(fsGLES));
+ shaderPack.setShader(QShaderKey(QShader::GlslShader, QShaderVersion(120)), QShaderCode(fsGL));
+
+ setShader(FragmentStage, shaderPack);
+#else
+ Q_UNUSED(shaderFilename);
+#endif
+}
- QWaylandBufferMaterial *material = static_cast<QWaylandBufferMaterial *>(newEffect);
- material->bind();
+bool QWaylandBufferMaterialShader::updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *)
+{
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ Q_ASSERT(buf->size() >= 68);
- if (state.isMatrixDirty())
- program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+ if (state.isMatrixDirty()) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data(), m.constData(), 64);
+ changed = true;
+ }
- if (state.isOpacityDirty())
- program()->setUniformValue(m_id_opacity, state.opacity());
-}
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64, &opacity, 4);
+ changed = true;
+ }
-const char * const *QWaylandBufferMaterialShader::attributeNames() const
-{
- static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", nullptr };
- return attr;
+ return changed;
}
-void QWaylandBufferMaterialShader::initialize()
+void QWaylandBufferMaterialShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
{
- QSGMaterialShader::initialize();
-
- m_id_matrix = program()->uniformLocation("qt_Matrix");
- m_id_opacity = program()->uniformLocation("qt_Opacity");
+ Q_UNUSED(state);
- for (int i = 0; i < bufferTypes[m_format].planeCount; i++) {
- m_id_tex << program()->uniformLocation("tex" + QByteArray::number(i));
- program()->setUniformValue(m_id_tex[i], i);
+ QWaylandBufferMaterial *material = static_cast<QWaylandBufferMaterial *>(newMaterial);
+ switch (binding) {
+ case 1:
+ *texture = material->m_scenegraphTextures.at(0);
+ break;
+ case 2:
+ *texture = material->m_scenegraphTextures.at(1);
+ break;
+ case 3:
+ *texture = material->m_scenegraphTextures.at(2);
+ break;
+ default:
+ return;
}
- Q_ASSERT(m_id_tex.size() == bufferTypes[m_format].planeCount);
+ // This is for the shared memory case, and is a no-op for others,
+ // this is where the upload from the QImage happens when not yet done.
+ // ### or is this too late? (if buffer.image() disappears in the meantime then this is the wrong...)
+ if (*texture)
+ (*texture)->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
}
QWaylandBufferMaterial::QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEgl format)
: m_format(format)
{
- QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions();
-
- gl->glBindTexture(bufferTypes[m_format].textureTarget, 0);
setFlag(bufferTypes[m_format].materialFlags);
}
QWaylandBufferMaterial::~QWaylandBufferMaterial()
{
+ qDeleteAll(m_scenegraphTextures);
}
-void QWaylandBufferMaterial::setTextureForPlane(int plane, QOpenGLTexture *texture)
+void QWaylandBufferMaterial::setTextureForPlane(int plane,
+ QOpenGLTexture *texture,
+ QSGTexture *scenegraphTexture)
{
if (plane < 0 || plane >= bufferTypes[m_format].planeCount) {
qWarning("plane index is out of range");
@@ -198,10 +276,15 @@ void QWaylandBufferMaterial::setTextureForPlane(int plane, QOpenGLTexture *textu
ensureTextures(plane - 1);
- if (m_textures.size() <= plane)
+ if (m_textures.size() <= plane) {
m_textures << texture;
- else
+ m_scenegraphTextures << scenegraphTexture;
+ } else {
+ delete m_scenegraphTextures[plane];
+
m_textures[plane] = texture;
+ m_scenegraphTextures[plane] = scenegraphTexture;
+ }
}
void QWaylandBufferMaterial::bind()
@@ -228,8 +311,9 @@ QSGMaterialType *QWaylandBufferMaterial::type() const
return const_cast<QSGMaterialType *>(&bufferTypes[m_format].materialType);
}
-QSGMaterialShader *QWaylandBufferMaterial::createShader() const
+QSGMaterialShader *QWaylandBufferMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
{
+ Q_UNUSED(renderMode);
return new QWaylandBufferMaterialShader(m_format);
}
@@ -248,8 +332,38 @@ void QWaylandBufferMaterial::ensureTextures(int count)
{
for (int plane = m_textures.size(); plane < count; plane++) {
m_textures << nullptr;
+ m_scenegraphTextures << nullptr;
}
}
+
+void QWaylandBufferMaterial::setBufferRef(QWaylandQuickItem *surfaceItem, const QWaylandBufferRef &ref)
+{
+ m_bufferRef = ref;
+ for (int plane = 0; plane < bufferTypes[ref.bufferFormatEgl()].planeCount; plane++) {
+ if (auto texture = ref.toOpenGLTexture(plane)) {
+ QQuickWindow::CreateTextureOptions opt;
+ QWaylandQuickSurface *waylandSurface = qobject_cast<QWaylandQuickSurface *>(surfaceItem->surface());
+ if (waylandSurface != nullptr && waylandSurface->useTextureAlpha() && !waylandSurface->isOpaque())
+ opt |= QQuickWindow::TextureHasAlphaChannel;
+ QSGTexture *scenegraphTexture;
+ if (ref.bufferFormatEgl() == QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES) {
+ scenegraphTexture = QNativeInterface::QSGOpenGLTexture::fromNativeExternalOES(texture->textureId(),
+ surfaceItem->window(),
+ ref.size(),
+ opt);
+ } else {
+ scenegraphTexture = QNativeInterface::QSGOpenGLTexture::fromNative(texture->textureId(),
+ surfaceItem->window(),
+ ref.size(),
+ opt);
+ }
+ scenegraphTexture->setFiltering(surfaceItem->smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
+ setTextureForPlane(plane, texture, scenegraphTexture);
+ }
+ }
+
+ bind();
+}
#endif // QT_CONFIG(opengl)
QMutex *QWaylandQuickItemPrivate::mutex = nullptr;
@@ -263,8 +377,7 @@ public:
~QWaylandSurfaceTextureProvider() override
{
- if (m_sgTex)
- m_sgTex->deleteLater();
+ delete m_sgTex;
}
void setBufferRef(QWaylandQuickItem *surfaceItem, const QWaylandBufferRef &buffer)
@@ -276,21 +389,18 @@ public:
if (m_ref.hasBuffer()) {
if (buffer.isSharedMemory()) {
m_sgTex = surfaceItem->window()->createTextureFromImage(buffer.image());
-#if QT_CONFIG(opengl)
- if (m_sgTex)
- m_sgTex->bind();
-#endif
} else {
#if QT_CONFIG(opengl)
QQuickWindow::CreateTextureOptions opt;
QWaylandQuickSurface *surface = qobject_cast<QWaylandQuickSurface *>(surfaceItem->surface());
- if (surface && surface->useTextureAlpha()) {
+ if (surface && surface->useTextureAlpha() && !surface->isOpaque()) {
opt |= QQuickWindow::TextureHasAlphaChannel;
}
auto texture = buffer.toOpenGLTexture();
+ GLuint textureId = texture->textureId();
auto size = surface->bufferSize();
- m_sgTex = surfaceItem->window()->createTextureFromId(texture->textureId(), size, opt);
+ m_sgTex = QNativeInterface::QSGOpenGLTexture::fromNative(textureId, surfaceItem->window(), size, opt);
#else
qCWarning(qLcWaylandCompositor) << "Without OpenGL support only shared memory textures are supported";
#endif
@@ -315,6 +425,7 @@ private:
/*!
* \qmltype WaylandQuickItem
+ * \instantiates QWaylandQuickItem
* \inqmlmodule QtWayland.Compositor
* \since 5.8
* \brief Provides a Qt Quick item that represents a WaylandView.
@@ -339,9 +450,8 @@ private:
* Constructs a QWaylandQuickItem with the given \a parent.
*/
QWaylandQuickItem::QWaylandQuickItem(QQuickItem *parent)
- : QQuickItem(*new QWaylandQuickItemPrivate(), parent)
+ : QWaylandQuickItem(*new QWaylandQuickItemPrivate(), parent)
{
- d_func()->init();
}
/*!
@@ -351,6 +461,7 @@ QWaylandQuickItem::QWaylandQuickItem(QWaylandQuickItemPrivate &dd, QQuickItem *p
: QQuickItem(dd, parent)
{
d_func()->init();
+ connect(this, &QQuickItem::activeFocusChanged, this, &QWaylandQuickItem::updateFocus);
}
/*!
@@ -360,13 +471,16 @@ QWaylandQuickItem::~QWaylandQuickItem()
{
Q_D(QWaylandQuickItem);
disconnect(this, &QQuickItem::windowChanged, this, &QWaylandQuickItem::updateWindow);
+ disconnect(this, &QQuickItem::activeFocusChanged, this, &QWaylandQuickItem::updateFocus);
QMutexLocker locker(d->mutex);
- if (d->provider)
+ if (d->provider) {
+ disconnect(d->texProviderConnection);
d->provider->deleteLater();
+ }
}
/*!
- * \qmlproperty WaylandCompositor QtWaylandCompositor::WaylandQuickItem::compositor
+ * \qmlproperty WaylandCompositor QtWayland.Compositor::WaylandQuickItem::compositor
*
* This property holds the compositor for the surface rendered by this WaylandQuickItem.
*/
@@ -392,7 +506,7 @@ QWaylandView *QWaylandQuickItem::view() const
}
/*!
- * \qmlproperty WaylandSurface QtWaylandCompositor::WaylandQuickItem::surface
+ * \qmlproperty WaylandSurface QtWayland.Compositor::WaylandQuickItem::surface
*
* This property holds the surface rendered by this WaylandQuickItem.
*/
@@ -412,16 +526,21 @@ QWaylandSurface *QWaylandQuickItem::surface() const
void QWaylandQuickItem::setSurface(QWaylandSurface *surface)
{
Q_D(QWaylandQuickItem);
+ QWaylandSurface *oldSurf = d->view->surface();
QWaylandCompositor *oldComp = d->view->surface() ? d->view->surface()->compositor() : nullptr;
d->view->setSurface(surface);
QWaylandCompositor *newComp = d->view->surface() ? d->view->surface()->compositor() : nullptr;
if (oldComp != newComp)
emit compositorChanged();
+ if (oldSurf != surface)
+ emit surfaceChanged();
+
+ updateFocus();
update();
}
/*!
- * \qmlproperty enum QtWaylandCompositor::WaylandQuickItem::origin
+ * \qmlproperty enum QtWayland.Compositor::WaylandQuickItem::origin
*
* This property holds the origin of the QWaylandQuickItem.
*/
@@ -467,7 +586,7 @@ void QWaylandQuickItem::mousePressEvent(QMouseEvent *event)
return;
}
- if (!inputRegionContains(event->localPos())) {
+ if (!inputRegionContains(event->position())) {
event->ignore();
return;
}
@@ -477,9 +596,9 @@ void QWaylandQuickItem::mousePressEvent(QMouseEvent *event)
if (d->focusOnClick)
takeFocus(seat);
- seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->localPos()), event->windowPos());
+ seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->position()), event->scenePosition());
seat->sendMousePressEvent(event->button());
- d->hoverPos = event->localPos();
+ d->hoverPos = event->position();
}
/*!
@@ -494,21 +613,21 @@ void QWaylandQuickItem::mouseMoveEvent(QMouseEvent *event)
if (d->isDragging) {
QWaylandQuickOutput *currentOutput = qobject_cast<QWaylandQuickOutput *>(view()->output());
//TODO: also check if dragging onto other outputs
- QWaylandQuickItem *targetItem = qobject_cast<QWaylandQuickItem *>(currentOutput->pickClickableItem(mapToScene(event->localPos())));
+ QWaylandQuickItem *targetItem = qobject_cast<QWaylandQuickItem *>(currentOutput->pickClickableItem(mapToScene(event->position())));
QWaylandSurface *targetSurface = targetItem ? targetItem->surface() : nullptr;
if (targetSurface) {
- QPointF position = mapToItem(targetItem, event->localPos());
+ QPointF position = mapToItem(targetItem, event->position());
QPointF surfacePosition = targetItem->mapToSurface(position);
seat->drag()->dragMove(targetSurface, surfacePosition);
}
} else
#endif // QT_CONFIG(draganddrop)
{
- seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->localPos()), event->windowPos());
- d->hoverPos = event->localPos();
+ seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->position()), event->scenePosition());
+ d->hoverPos = event->position();
}
} else {
- emit mouseMove(event->windowPos());
+ emit mouseMove(event->scenePosition());
event->ignore();
}
}
@@ -542,14 +661,14 @@ void QWaylandQuickItem::mouseReleaseEvent(QMouseEvent *event)
void QWaylandQuickItem::hoverEnterEvent(QHoverEvent *event)
{
Q_D(QWaylandQuickItem);
- if (!inputRegionContains(event->posF())) {
+ if (!inputRegionContains(event->position())) {
event->ignore();
return;
}
if (d->shouldSendInputEvents()) {
QWaylandSeat *seat = compositor()->seatFor(event);
- seat->sendMouseMoveEvent(d->view.data(), event->posF(), mapToScene(event->posF()));
- d->hoverPos = event->posF();
+ seat->sendMouseMoveEvent(d->view.data(), event->position(), mapToScene(event->position()));
+ d->hoverPos = event->position();
} else {
event->ignore();
}
@@ -562,16 +681,16 @@ void QWaylandQuickItem::hoverMoveEvent(QHoverEvent *event)
{
Q_D(QWaylandQuickItem);
if (surface()) {
- if (!inputRegionContains(event->posF())) {
+ if (!inputRegionContains(event->position())) {
event->ignore();
return;
}
}
if (d->shouldSendInputEvents()) {
QWaylandSeat *seat = compositor()->seatFor(event);
- if (event->posF() != d->hoverPos) {
- seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->posF()), mapToScene(event->posF()));
- d->hoverPos = event->posF();
+ if (event->position() != d->hoverPos) {
+ seat->sendMouseMoveEvent(d->view.data(), mapToSurface(event->position()), mapToScene(event->position()));
+ d->hoverPos = event->position();
}
} else {
event->ignore();
@@ -640,7 +759,7 @@ void QWaylandQuickItem::keyPressEvent(QKeyEvent *event)
void QWaylandQuickItem::keyReleaseEvent(QKeyEvent *event)
{
Q_D(QWaylandQuickItem);
- if (d->shouldSendInputEvents() && hasFocus()) {
+ if (d->shouldSendInputEvents()) {
QWaylandSeat *seat = compositor()->seatFor(event);
seat->sendFullKeyEvent(event);
} else {
@@ -658,9 +777,9 @@ void QWaylandQuickItem::touchEvent(QTouchEvent *event)
QWaylandSeat *seat = compositor()->seatFor(event);
QPointF pointPos;
- const QList<QTouchEvent::TouchPoint> &points = event->touchPoints();
+ const QList<QTouchEvent::TouchPoint> &points = event->points();
if (!points.isEmpty())
- pointPos = points.at(0).pos();
+ pointPos = points.at(0).position();
if (event->type() == QEvent::TouchBegin && !inputRegionContains(pointPos)) {
event->ignore();
@@ -729,10 +848,16 @@ void QWaylandQuickItem::handleSubsurfaceAdded(QWaylandSurface *childSurface)
childItem->setSurface(childSurface);
childItem->setVisible(true);
childItem->setParentItem(this);
+ childItem->setParent(this);
connect(childSurface, &QWaylandSurface::subsurfacePositionChanged, childItem, &QWaylandQuickItem::handleSubsurfacePosition);
+ connect(childSurface, &QWaylandSurface::destroyed, childItem, &QObject::deleteLater);
} else {
bool success = QMetaObject::invokeMethod(d->subsurfaceHandler, "handleSubsurfaceAdded", Q_ARG(QWaylandSurface *, childSurface));
if (!success)
+ success = QMetaObject::invokeMethod(d->subsurfaceHandler, "handleSubsurfaceAdded",
+ Q_ARG(QVariant, QVariant::fromValue(childSurface)));
+
+ if (!success)
qWarning("QWaylandQuickItem: subsurfaceHandler does not implement handleSubsurfaceAdded()");
}
}
@@ -771,8 +896,15 @@ void QWaylandQuickItem::handlePlaceBelow(QWaylandSurface *referenceSurface)
}
}
+void QWaylandQuickItem::updateFocus()
+{
+ Q_D(const QWaylandQuickItem);
+ if (hasActiveFocus() && compositor())
+ compositor()->defaultSeat()->setKeyboardFocus(d->view->surface());
+}
+
/*!
- \qmlproperty object QtWaylandCompositor::WaylandQuickItem::subsurfaceHandler
+ \qmlproperty object QtWayland.Compositor::WaylandQuickItem::subsurfaceHandler
This property provides a way to override the default subsurface behavior.
@@ -784,8 +916,9 @@ void QWaylandQuickItem::handlePlaceBelow(QWaylandSurface *referenceSurface)
\code
ShellSurfaceItem {
subsurfaceHandler: QtObject {
- function handleSubsurfaceAdded(child) {
- //create custom surface item, and connect the subsurfacePositionChanged signal
+ function handleSubsurfaceAdded(child) {
+ // create custom surface item, and connect the subsurfacePositionChanged signal
+ }
}
}
\endcode
@@ -810,6 +943,11 @@ void QWaylandQuickItem::setSubsurfaceHandler(QObject *handler)
}
/*!
+ * \qmlproperty WaylandOutput QtWayland.Compositor::WaylandQuickItem::output
+ *
+ * This property holds the output on which this item is displayed.
+ */
+/*!
* \property QWaylandQuickItem::output
*
* This property holds the output on which this item is displayed.
@@ -827,7 +965,7 @@ void QWaylandQuickItem::setOutput(QWaylandOutput *output)
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::bufferLocked
+ * \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::bufferLocked
*
* This property holds whether the item's buffer is currently locked. As long as
* the buffer is locked, it will not be released and returned to the client.
@@ -852,6 +990,10 @@ void QWaylandQuickItem::setBufferLocked(bool locked)
{
Q_D(QWaylandQuickItem);
d->view->setBufferLocked(locked);
+
+ // Apply the latest surface size
+ if (!locked)
+ updateSize();
}
/*!
@@ -961,7 +1103,7 @@ void QWaylandQuickItem::takeFocus(QWaylandSeat *device)
{
forceActiveFocus();
- if (!surface())
+ if (!surface() || !surface()->client())
return;
QWaylandSeat *target = device;
@@ -969,9 +1111,27 @@ void QWaylandQuickItem::takeFocus(QWaylandSeat *device)
target = compositor()->defaultSeat();
}
target->setKeyboardFocus(surface());
- QWaylandTextInput *textInput = QWaylandTextInput::findIn(target);
- if (textInput)
- textInput->setFocus(surface());
+
+ qCDebug(qLcWaylandCompositorInputMethods) << Q_FUNC_INFO << " surface:" << surface()
+ << ", client:" << surface()->client()
+ << ", textinputprotocol:" << (int)(surface()->client()->textInputProtocols());
+ if (surface()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV2)) {
+ QWaylandTextInput *textInput = QWaylandTextInput::findIn(target);
+ if (textInput)
+ textInput->setFocus(surface());
+ }
+
+ if (surface()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV3)) {
+ QWaylandTextInputV3 *textInputV3 = QWaylandTextInputV3::findIn(target);
+ if (textInputV3)
+ textInputV3->setFocus(surface());
+ }
+
+ if (surface()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::QtTextInputMethodV1)) {
+ QWaylandQtTextInputMethod *textInputMethod = QWaylandQtTextInputMethod::findIn(target);
+ if (textInputMethod)
+ textInputMethod->setFocus(surface());
+ }
}
/*!
@@ -1004,6 +1164,12 @@ void QWaylandQuickItem::updateSize()
{
Q_D(QWaylandQuickItem);
+ // No resize if buffer is locked
+ if (isBufferLocked()) {
+ qWarning() << "No update on item size as the buffer is currently locked";
+ return;
+ }
+
QSize size(0, 0);
if (surface())
size = surface()->destinationSize() * d->scaleFactor();
@@ -1012,7 +1178,7 @@ void QWaylandQuickItem::updateSize()
}
/*!
- * \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::focusOnClick
+ * \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::focusOnClick
*
* This property specifies whether the WaylandQuickItem should take focus when
* it is clicked or touched.
@@ -1127,7 +1293,7 @@ QVariant QWaylandQuickItem::inputMethodQuery(Qt::InputMethodQuery query, QVarian
#endif
/*!
- \qmlproperty bool QtWaylandCompositor::WaylandQuickItem::paintEnabled
+ \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::paintEnabled
Returns true if the item is hidden, though the texture
is still updated. As opposed to hiding the item by
@@ -1136,12 +1302,14 @@ QVariant QWaylandQuickItem::inputMethodQuery(Qt::InputMethodQuery query, QVarian
*/
/*!
- Returns true if the item is hidden, though the texture
+ \property QWaylandQuickItem::paintEnabled
+
+ Holds \c true if the item is hidden, though the texture
is still updated. As opposed to hiding the item by
- setting \l{Item::visible}{visible} to \c false, setting this property to \c false
+ setting \l{QQuickItem::}{visible} to \c false, setting this property to \c false
will not prevent mouse or keyboard input from reaching item.
*/
-bool QWaylandQuickItem::paintEnabled() const
+bool QWaylandQuickItem::isPaintEnabled() const
{
Q_D(const QWaylandQuickItem);
return d->paintEnabled;
@@ -1150,10 +1318,28 @@ bool QWaylandQuickItem::paintEnabled() const
void QWaylandQuickItem::setPaintEnabled(bool enabled)
{
Q_D(QWaylandQuickItem);
- d->paintEnabled = enabled;
+
+ if (enabled != d->paintEnabled) {
+ d->paintEnabled = enabled;
+ emit paintEnabledChanged();
+ }
+
update();
}
+/*!
+ \qmlproperty bool QtWayland.Compositor::WaylandQuickItem::touchEventsEnabled
+
+ This property holds \c true if touch events are forwarded to the client
+ surface, \c false otherwise.
+*/
+
+/*!
+ \property QWaylandQuickItem::touchEventsEnabled
+
+ This property holds \c true if touch events are forwarded to the client
+ surface, \c false otherwise.
+*/
bool QWaylandQuickItem::touchEventsEnabled() const
{
Q_D(const QWaylandQuickItem);
@@ -1188,15 +1374,15 @@ void QWaylandQuickItem::updateWindow()
if (d->connectedWindow) {
connect(d->connectedWindow, &QQuickWindow::beforeSynchronizing, this, &QWaylandQuickItem::beforeSync, Qt::DirectConnection);
connect(d->connectedWindow, &QQuickWindow::screenChanged, this, &QWaylandQuickItem::updateSize); // new screen may have new dpr
- }
- if (compositor() && d->connectedWindow) {
- QWaylandOutput *output = compositor()->outputFor(d->connectedWindow);
- Q_ASSERT(output);
- d->view->setOutput(output);
- }
+ if (compositor()) {
+ QWaylandOutput *output = compositor()->outputFor(d->connectedWindow);
+ Q_ASSERT(output);
+ d->view->setOutput(output);
+ }
- updateSize(); // because scaleFactor depends on devicePixelRatio, which may be different for the new window
+ updateSize(); // because scaleFactor depends on devicePixelRatio, which may be different for the new window
+ }
}
void QWaylandQuickItem::updateOutput()
@@ -1237,7 +1423,7 @@ void QWaylandQuickItem::updateInputMethod(Qt::InputMethodQueries queries)
#endif
/*!
- * \qmlsignal void QtWaylandCompositor::WaylandQuickItem::surfaceDestroyed()
+ * \qmlsignal void QtWayland.Compositor::WaylandQuickItem::surfaceDestroyed()
*
* This signal is emitted when the client has destroyed the \c wl_surface associated
* with the WaylandQuickItem. The handler for this signal is expected to either destroy the
@@ -1268,7 +1454,7 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
d->lastMatrix = data->transformNode->combinedMatrix();
const bool bufferHasContent = d->view->currentBuffer().hasContent();
- if (d->view->isBufferLocked() && !bufferHasContent && d->paintEnabled)
+ if (d->view->isBufferLocked() && d->paintEnabled)
return oldNode;
if (!bufferHasContent || !d->paintEnabled || !surface()) {
@@ -1286,16 +1472,42 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
|| bufferTypes[ref.bufferFormatEgl()].canProvideTexture
#endif
) {
+#if QT_CONFIG(opengl)
+ if (oldNode && !d->paintByProvider) {
+ // Need to re-create a node
+ delete oldNode;
+ oldNode = nullptr;
+ }
+ d->paintByProvider = true;
+#endif
// This case could covered by the more general path below, but this is more efficient (especially when using ShaderEffect items).
QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);
if (!node) {
node = new QSGSimpleTextureNode();
+ if (smooth())
+ node->setFiltering(QSGTexture::Linear);
d->newTexture = true;
}
- if (!d->provider)
+ if (!d->provider) {
d->provider = new QWaylandSurfaceTextureProvider();
+ if (compositor()) {
+ d->texProviderConnection =
+ QObject::connect(
+ compositor(),
+ &QObject::destroyed,
+ this,
+ [this](QObject*) {
+ auto *itemPriv = QWaylandQuickItemPrivate::get(this);
+ if (itemPriv->provider) {
+ itemPriv->provider->deleteLater();
+ itemPriv->provider = nullptr;
+ }
+ disconnect(itemPriv->texProviderConnection); }
+ );
+ }
+ }
if (d->newTexture) {
d->newTexture = false;
@@ -1316,6 +1528,13 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
#if QT_CONFIG(opengl)
Q_ASSERT(!d->provider);
+ if (oldNode && d->paintByProvider) {
+ // Need to re-create a node
+ delete oldNode;
+ oldNode = nullptr;
+ }
+ d->paintByProvider = false;
+
QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode);
if (!node) {
@@ -1334,13 +1553,20 @@ QSGNode *QWaylandQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->newTexture) {
d->newTexture = false;
- for (int plane = 0; plane < bufferTypes[ref.bufferFormatEgl()].planeCount; plane++)
- if (auto texture = ref.toOpenGLTexture(plane))
- material->setTextureForPlane(plane, texture);
- material->bind();
+ material->setBufferRef(this, ref);
}
- QSGGeometry::updateTexturedRectGeometry(geometry, rect, QRectF(0, 0, 1, 1));
+ const QSize surfaceSize = ref.size() / surface()->bufferScale();
+ const QRectF sourceGeometry = surface()->sourceGeometry();
+ const QRectF normalizedCoordinates =
+ sourceGeometry.isValid()
+ ? QRectF(sourceGeometry.x() / surfaceSize.width(),
+ sourceGeometry.y() / surfaceSize.height(),
+ sourceGeometry.width() / surfaceSize.width(),
+ sourceGeometry.height() / surfaceSize.height())
+ : QRectF(0, 0, 1, 1);
+
+ QSGGeometry::updateTexturedRectGeometry(geometry, rect, normalizedCoordinates);
node->setGeometry(geometry);
node->setFlag(QSGNode::OwnsGeometry, true);
@@ -1383,20 +1609,34 @@ void QWaylandQuickItem::setInputEventsEnabled(bool enabled)
void QWaylandQuickItem::lower()
{
- QQuickItem *parent = parentItem();
+ Q_D(QWaylandQuickItem);
+ d->lower();
+}
+
+void QWaylandQuickItemPrivate::lower()
+{
+ Q_Q(QWaylandQuickItem);
+ QQuickItem *parent = q->parentItem();
Q_ASSERT(parent);
- QQuickItem *bottom = parent->childItems().first();
- if (this != bottom)
- stackBefore(bottom);
+ QQuickItem *bottom = parent->childItems().constFirst();
+ if (q != bottom)
+ q->stackBefore(bottom);
}
void QWaylandQuickItem::raise()
{
- QQuickItem *parent = parentItem();
+ Q_D(QWaylandQuickItem);
+ d->raise();
+}
+
+void QWaylandQuickItemPrivate::raise()
+{
+ Q_Q(QWaylandQuickItem);
+ QQuickItem *parent = q->parentItem();
Q_ASSERT(parent);
- QQuickItem *top = parent->childItems().last();
- if (this != top)
- stackAfter(top);
+ QQuickItem *top = parent->childItems().constLast();
+ if (q != top)
+ q->stackAfter(top);
}
void QWaylandQuickItem::sendMouseMoveEvent(const QPointF &position, QWaylandSeat *seat)
@@ -1526,3 +1766,5 @@ void QWaylandQuickItemPrivate::placeBelowParent()
}
QT_END_NAMESPACE
+
+#include "moc_qwaylandquickitem.cpp"