diff options
Diffstat (limited to 'examples/wayland/qwindow-compositor')
12 files changed, 736 insertions, 938 deletions
diff --git a/examples/wayland/qwindow-compositor/compositorwindow.cpp b/examples/wayland/qwindow-compositor/compositorwindow.cpp index 7d855016f..a902a7d0d 100644 --- a/examples/wayland/qwindow-compositor/compositorwindow.cpp +++ b/examples/wayland/qwindow-compositor/compositorwindow.cpp @@ -39,23 +39,215 @@ ****************************************************************************/ #include "compositorwindow.h" -#include <QTouchEvent> -CompositorWindow::CompositorWindow(const QSurfaceFormat &format, const QRect &geometry) - : m_format(format) +#include <QMouseEvent> +#include <QOpenGLWindow> +#include <QOpenGLTexture> +#include <QOpenGLFunctions> +#include <QMatrix4x4> + +#include "windowcompositor.h" +#include <QtWaylandCompositor/qwaylandinput.h> + +CompositorWindow::CompositorWindow() + : m_backgroundTexture(0) + , m_compositor(0) + , m_grabState(NoGrab) + , m_dragIconView(0) +{ +} + +void CompositorWindow::setCompositor(WindowCompositor *comp) { + m_compositor = comp; + connect(m_compositor, &WindowCompositor::startMove, this, &CompositorWindow::startMove); + connect(m_compositor, &WindowCompositor::startResize, this, &CompositorWindow::startResize); + connect(m_compositor, &WindowCompositor::dragStarted, this, &CompositorWindow::startDrag); + connect(m_compositor, &WindowCompositor::frameOffset, this, &CompositorWindow::setFrameOffset); +} + +void CompositorWindow::initializeGL() +{ + QImage backgroundImage = QImage(QLatin1String(":/background.jpg")); + m_backgroundTexture = new QOpenGLTexture(backgroundImage, QOpenGLTexture::DontGenerateMipMaps); + m_backgroundTexture->setMinificationFilter(QOpenGLTexture::Nearest); + m_backgroundImageSize = backgroundImage.size(); + m_textureBlitter.create(); +} + +void CompositorWindow::drawBackground() +{ + for (int y = 0; y < height(); y += m_backgroundImageSize.height()) { + for (int x = 0; x < width(); x += m_backgroundImageSize.width()) { + QMatrix4x4 targetTransform = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(x,y), m_backgroundImageSize), QRect(QPoint(0,0), size())); + m_textureBlitter.blit(m_backgroundTexture->textureId(), + targetTransform, + QOpenGLTextureBlitter::OriginTopLeft); + } + } +} + +void CompositorWindow::paintGL() +{ + m_compositor->startRender(); + QOpenGLFunctions *functions = context()->functions(); + functions->glClearColor(1.f, .6f, .0f, 0.5f); + functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + m_textureBlitter.bind(); + drawBackground(); + + functions->glEnable(GL_BLEND); + functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Q_FOREACH (WindowCompositorView *view, m_compositor->views()) { + if (view->isCursor()) + continue; + GLuint textureId = view->getTexture(); + QWaylandSurface *surface = view->surface(); + if (surface && surface->isMapped()) { + QSize s = surface->size(); + if (!s.isEmpty()) { + QRectF surfaceGeometry(view->position(), s); + QOpenGLTextureBlitter::Origin surfaceOrigin = + view->currentBuffer().origin() == QWaylandSurface::OriginTopLeft + ? QOpenGLTextureBlitter::OriginTopLeft + : QOpenGLTextureBlitter::OriginBottomLeft; + QMatrix4x4 targetTransform = QOpenGLTextureBlitter::targetTransform(surfaceGeometry, QRect(QPoint(), size())); + m_textureBlitter.blit(textureId, targetTransform, surfaceOrigin); + } + } + } + functions->glDisable(GL_BLEND); + + m_textureBlitter.release(); + m_compositor->endRender(); +} + +WindowCompositorView *CompositorWindow::viewAt(const QPointF &point) +{ + WindowCompositorView *ret = 0; + Q_FOREACH (WindowCompositorView *view, m_compositor->views()) { + if (view == m_dragIconView) + continue; + QPointF topLeft = view->position(); + QWaylandSurface *surface = view->surface(); + QRectF geo(topLeft, surface->size()); + if (geo.contains(point)) + ret = view; + } + return ret; +} + +void CompositorWindow::startMove() +{ + m_grabState = MoveGrab; +} + +void CompositorWindow::startResize(int edge) +{ + m_initialSize = m_mouseView->surface()->size(); + m_grabState = ResizeGrab; + m_resizeEdge = edge; +} + +void CompositorWindow::startDrag(WindowCompositorView *dragIcon) +{ + m_grabState = DragGrab; + m_dragIconView = dragIcon; + m_compositor->raise(dragIcon); +} + +void CompositorWindow::setFrameOffset(const QPoint &offset) +{ + if (m_mouseView) + m_mouseView->setPosition(m_mouseView->position() + offset); +} + +void CompositorWindow::mousePressEvent(QMouseEvent *e) +{ + if (mouseGrab()) + return; + if (m_mouseView.isNull()) { + m_mouseView = viewAt(e->localPos()); + if (!m_mouseView) { + m_compositor->closePopups(); + return; + } + if (e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::MetaModifier) + m_grabState = MoveGrab; //start move + else + m_compositor->raise(m_mouseView); + m_initialMousePos = e->localPos(); + m_mouseOffset = e->localPos() - m_mouseView->position(); + + QMouseEvent moveEvent(QEvent::MouseMove, e->localPos(), e->globalPos(), Qt::NoButton, Qt::NoButton, e->modifiers()); + sendMouseEvent(&moveEvent, m_mouseView); + } + sendMouseEvent(e, m_mouseView); +} + +void CompositorWindow::mouseReleaseEvent(QMouseEvent *e) +{ + if (!mouseGrab()) + sendMouseEvent(e, m_mouseView); + if (e->buttons() == Qt::NoButton) { + if (m_grabState == DragGrab) { + WindowCompositorView *view = viewAt(e->localPos()); + m_compositor->handleDrag(view, e); + } + m_mouseView = 0; + m_grabState = NoGrab; + } +} + +void CompositorWindow::mouseMoveEvent(QMouseEvent *e) +{ + switch (m_grabState) { + case NoGrab: { + WindowCompositorView *view = m_mouseView ? m_mouseView.data() : viewAt(e->localPos()); + sendMouseEvent(e, view); + if (!view) + setCursor(Qt::ArrowCursor); + } + break; + case MoveGrab: { + m_mouseView->setPosition(e->localPos() - m_mouseOffset); + update(); + } + break; + case ResizeGrab: { + QPoint delta = (e->localPos() - m_initialMousePos).toPoint(); + m_compositor->handleResize(m_mouseView, m_initialSize, delta, m_resizeEdge); + } + break; + case DragGrab: { + WindowCompositorView *view = viewAt(e->localPos()); + m_compositor->handleDrag(view, e); + if (m_dragIconView) { + m_dragIconView->setPosition(e->localPos()); + update(); + } + } + break; + } +} + +void CompositorWindow::sendMouseEvent(QMouseEvent *e, WindowCompositorView *target) +{ + if (!target) + return; + + QPointF mappedPos = e->localPos() - target->position(); + QMouseEvent viewEvent(e->type(), mappedPos, e->localPos(), e->button(), e->buttons(), e->modifiers()); + m_compositor->handleMouseEvent(target, &viewEvent); +} + +void CompositorWindow::keyPressEvent(QKeyEvent *e) { - setSurfaceType(QWindow::OpenGLSurface); - setGeometry(geometry); - setFormat(format); - create(); - m_context = new QOpenGLContext; - m_context->setFormat(format); - m_context->create(); + m_compositor->defaultInputDevice()->sendKeyPressEvent(e->nativeScanCode()); } -void CompositorWindow::touchEvent(QTouchEvent *event) +void CompositorWindow::keyReleaseEvent(QKeyEvent *e) { - // Do not want any automatically synthesized mouse events - // so make sure the touch is always accepted. - event->accept(); + m_compositor->defaultInputDevice()->sendKeyReleaseEvent(e->nativeScanCode()); } diff --git a/examples/wayland/qwindow-compositor/compositorwindow.h b/examples/wayland/qwindow-compositor/compositorwindow.h index 24c50c535..720db5bc7 100644 --- a/examples/wayland/qwindow-compositor/compositorwindow.h +++ b/examples/wayland/qwindow-compositor/compositorwindow.h @@ -41,24 +41,61 @@ #ifndef COMPOSITORWINDOW_H #define COMPOSITORWINDOW_H -#include <QWindow> -#include <QOpenGLContext> -#include <QSurfaceFormat> +#include <QOpenGLWindow> +#include <QPointer> +#include <QtGui/private/qopengltextureblitter_p.h> -class CompositorWindow : public QWindow +QT_BEGIN_NAMESPACE + +class WindowCompositor; +class WindowCompositorView; +class QOpenGLTexture; + +class CompositorWindow : public QOpenGLWindow { public: - CompositorWindow(const QSurfaceFormat &format, const QRect &geometry); - QOpenGLContext* context() { return m_context; } - bool makeCurrent() { return m_context->makeCurrent(this); } - void swapBuffers() { m_context->swapBuffers(this); } + CompositorWindow(); + + void setCompositor(WindowCompositor *comp); protected: - void touchEvent(QTouchEvent *event); + void initializeGL() Q_DECL_OVERRIDE; + void paintGL() Q_DECL_OVERRIDE; + + void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + + void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE; + void keyReleaseEvent(QKeyEvent *e) Q_DECL_OVERRIDE; + +private slots: + void startMove(); + void startResize(int edge); + void startDrag(WindowCompositorView *dragIcon); + void setFrameOffset(const QPoint &offset); private: - QOpenGLContext *m_context; - QSurfaceFormat m_format; + enum GrabState { NoGrab, MoveGrab, ResizeGrab, DragGrab }; + + WindowCompositorView *viewAt(const QPointF &point); + bool mouseGrab() const { return m_grabState != NoGrab ;} + void drawBackground(); + void sendMouseEvent(QMouseEvent *e, WindowCompositorView *target); + + QOpenGLTextureBlitter m_textureBlitter; + QSize m_backgroundImageSize; + QOpenGLTexture *m_backgroundTexture; + WindowCompositor *m_compositor; + QPointer<WindowCompositorView> m_mouseView; + GrabState m_grabState; + QSize m_initialSize; + int m_resizeEdge; + QPointF m_mouseOffset; + QPointF m_initialMousePos; + WindowCompositorView *m_dragIconView; }; +QT_END_NAMESPACE + #endif // COMPOSITORWINDOW_H diff --git a/examples/wayland/qwindow-compositor/doc/src/qwindow-compositor.qdoc b/examples/wayland/qwindow-compositor/doc/src/qwindow-compositor.qdoc new file mode 100644 index 000000000..d268aca43 --- /dev/null +++ b/examples/wayland/qwindow-compositor/doc/src/qwindow-compositor.qdoc @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \title Qt Wayland Compositor Examples - QWindow Compositor + \example qwindow-compositor + \brief QWindow Compositor is an example that demonstrates how to write a Wayland compositor in C++. + \ingroup qtwaylandcompositor-examples + + QWindow Compositor is a desktop-style Wayland compositor example that demonstrates the power + of the Qt Wayland Compositor C++ APIs. +*/ diff --git a/examples/wayland/qwindow-compositor/main.cpp b/examples/wayland/qwindow-compositor/main.cpp index b4be143b5..c4fa43256 100644 --- a/examples/wayland/qwindow-compositor/main.cpp +++ b/examples/wayland/qwindow-compositor/main.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the Qt Compositor. +** This file is part of the examples of the Qt Wayland module ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: @@ -38,36 +38,19 @@ ** ****************************************************************************/ -#include "compositorwindow.h" -#include "qwindowcompositor.h" - #include <QGuiApplication> -#include <QStringList> -#include <QScreen> -#include <QSurfaceFormat> +#include "compositorwindow.h" +#include "windowcompositor.h" int main(int argc, char *argv[]) { - // Enable the following to have touch events generated from mouse events. - // Very handy for testing touch event delivery without a real touch device. - // QGuiApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true); - QGuiApplication app(argc, argv); - QScreen *screen = QGuiApplication::primaryScreen(); - QRect screenGeometry = screen->availableGeometry(); - - QSurfaceFormat format; - format.setDepthBufferSize(16); - format.setStencilBufferSize(8); - - QRect geom = screenGeometry; - if (QCoreApplication::arguments().contains(QLatin1String("-nofullscreen"))) - geom = QRect(screenGeometry.width() / 4, screenGeometry.height() / 4, - screenGeometry.width() / 2, screenGeometry.height() / 2); - - CompositorWindow window(format, geom); - QWindowCompositor compositor(&window); + CompositorWindow window; + WindowCompositor compositor(&window); + window.setCompositor(&compositor); + compositor.create(); + window.resize(800,600); window.show(); return app.exec(); diff --git a/examples/wayland/qwindow-compositor/qwindow-compositor.pro b/examples/wayland/qwindow-compositor/qwindow-compositor.pro index 4bab000b5..994276d99 100644 --- a/examples/wayland/qwindow-compositor/qwindow-compositor.pro +++ b/examples/wayland/qwindow-compositor/qwindow-compositor.pro @@ -1,25 +1,18 @@ -QT += gui gui-private core-private compositor +QT += gui gui-private core-private waylandcompositor waylandcompositor-private LIBS += -L ../../lib -#include (../../src/qt-compositor/qt-compositor.pri) HEADERS += \ compositorwindow.h \ - qwindowcompositor.h \ - textureblitter.h + windowcompositor.h SOURCES += main.cpp \ compositorwindow.cpp \ - qwindowcompositor.cpp \ - textureblitter.cpp + windowcompositor.cpp -# to make QtCompositor/... style includes working without installing +# to make QtWaylandCompositor/... style includes working without installing INCLUDEPATH += $$PWD/../../include -# if you want to compile QtCompositor as part of the application -# instead of linking to it, remove the QT += compositor and uncomment -# the following line -#include(../../src/compositor/compositor.pri) RESOURCES += qwindow-compositor.qrc diff --git a/examples/wayland/qwindow-compositor/qwindow-compositor.qrc b/examples/wayland/qwindow-compositor/qwindow-compositor.qrc index 20dd10a53..688dd900e 100644 --- a/examples/wayland/qwindow-compositor/qwindow-compositor.qrc +++ b/examples/wayland/qwindow-compositor/qwindow-compositor.qrc @@ -1,5 +1,5 @@ <RCC> <qresource prefix="/"> - <file alias="background.jpg">../qml-compositor/background.jpg</file> + <file alias="background.jpg">../pure-qml/images/background.jpg</file> </qresource> </RCC> diff --git a/examples/wayland/qwindow-compositor/qwindowcompositor.cpp b/examples/wayland/qwindow-compositor/qwindowcompositor.cpp deleted file mode 100644 index 58df7ead5..000000000 --- a/examples/wayland/qwindow-compositor/qwindowcompositor.cpp +++ /dev/null @@ -1,485 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Compositor. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qwindowcompositor.h" - -#include <QMouseEvent> -#include <QKeyEvent> -#include <QTouchEvent> -#include <QOpenGLFunctions> -#include <QOpenGLTexture> -#include <QGuiApplication> -#include <QCursor> -#include <QPixmap> -#include <QLinkedList> -#include <QScreen> -#include <QPainter> - -#include <QtCompositor/qwaylandinput.h> -#include <QtCompositor/qwaylandbufferref.h> -#include <QtCompositor/qwaylandsurfaceview.h> -#include <QtCompositor/qwaylandoutput.h> - -QT_BEGIN_NAMESPACE - -class BufferAttacher : public QWaylandBufferAttacher -{ -public: - BufferAttacher() - : QWaylandBufferAttacher() - , shmTex(0) - { - } - - ~BufferAttacher() - { - delete shmTex; - } - - void attach(const QWaylandBufferRef &ref) Q_DECL_OVERRIDE - { - if (bufferRef) { - if (bufferRef.isShm()) { - delete shmTex; - shmTex = 0; - } else { - bufferRef.destroyTexture(); - } - } - - bufferRef = ref; - - if (bufferRef) { - if (bufferRef.isShm()) { - shmTex = new QOpenGLTexture(bufferRef.image(), QOpenGLTexture::DontGenerateMipMaps); - shmTex->setWrapMode(QOpenGLTexture::ClampToEdge); - texture = shmTex->textureId(); - textureTarget = GL_TEXTURE_2D; - } else { - texture = bufferRef.createTexture(); - textureTarget = bufferRef.textureTarget(); - } - } - } - - void unmap() - { - delete shmTex; - shmTex = 0; - bufferRef = QWaylandBufferRef(); - } - - QImage image() const - { - if (!bufferRef || !bufferRef.isShm()) - return QImage(); - return bufferRef.image(); - } - - void updateTexture() - { - if (bufferRef) - bufferRef.updateTexture(); - } - - QOpenGLTexture *shmTex; - QWaylandBufferRef bufferRef; - GLuint texture; - GLenum textureTarget; -}; - -QWindowCompositor::QWindowCompositor(CompositorWindow *window) - : QWaylandCompositor(0, DefaultExtensions) - , m_window(window) - , m_backgroundTexture(0) - , m_textureBlitter(0) - , m_renderScheduler(this) - , m_draggingWindow(0) - , m_dragKeyIsPressed(false) - , m_cursorSurface(0) - , m_cursorHotspotX(0) - , m_cursorHotspotY(0) - , m_modifiers(Qt::NoModifier) -{ - m_window->makeCurrent(); - - m_textureBlitter = new TextureBlitter(); - m_backgroundImage = makeBackgroundImage(QLatin1String(":/background.jpg")); - m_renderScheduler.setSingleShot(true); - connect(&m_renderScheduler,SIGNAL(timeout()),this,SLOT(render())); - - QOpenGLFunctions *functions = m_window->context()->functions(); - functions->glGenFramebuffers(1, &m_surface_fbo); - - window->installEventFilter(this); - - setRetainedSelectionEnabled(true); - - createOutput(window, "", ""); - addDefaultShell(); -} - -QWindowCompositor::~QWindowCompositor() -{ - delete m_textureBlitter; -} - - -QImage QWindowCompositor::makeBackgroundImage(const QString &fileName) -{ - Q_ASSERT(m_window); - - int width = m_window->width(); - int height = m_window->height(); - QImage baseImage(fileName); - QImage patternedBackground(width, height, baseImage.format()); - QPainter painter(&patternedBackground); - - QSize imageSize = baseImage.size(); - for (int y = 0; y < height; y += imageSize.height()) { - for (int x = 0; x < width; x += imageSize.width()) { - painter.drawImage(x, y, baseImage); - } - } - - return patternedBackground; -} - -void QWindowCompositor::ensureKeyboardFocusSurface(QWaylandSurface *oldSurface) -{ - QWaylandSurface *kbdFocus = defaultInputDevice()->keyboardFocus(); - if (kbdFocus == oldSurface || !kbdFocus) - defaultInputDevice()->setKeyboardFocus(m_surfaces.isEmpty() ? 0 : m_surfaces.last()); -} - -void QWindowCompositor::surfaceDestroyed() -{ - QWaylandSurface *surface = static_cast<QWaylandSurface *>(sender()); - m_surfaces.removeOne(surface); - ensureKeyboardFocusSurface(surface); - m_renderScheduler.start(0); -} - -void QWindowCompositor::surfaceMapped() -{ - QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); - QPoint pos; - if (!m_surfaces.contains(surface)) { - if (surface->windowType() != QWaylandSurface::Popup) { - uint px = 0; - uint py = 0; - if (!QCoreApplication::arguments().contains(QLatin1String("-stickytopleft"))) { - px = 1 + (qrand() % (m_window->width() - surface->size().width() - 2)); - py = 1 + (qrand() % (m_window->height() - surface->size().height() - 2)); - } - pos = QPoint(px, py); - QWaylandSurfaceView *view = surface->views().first(); - view->setPos(pos); - } - } else { - m_surfaces.removeOne(surface); - } - - if (surface->windowType() == QWaylandSurface::Popup) { - QWaylandSurfaceView *view = surface->views().first(); - view->setPos(surface->transientParent()->views().first()->pos() + surface->transientOffset()); - } - - m_surfaces.append(surface); - defaultInputDevice()->setKeyboardFocus(surface); - - m_renderScheduler.start(0); -} - -void QWindowCompositor::surfaceUnmapped() -{ - QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); - if (m_surfaces.removeOne(surface)) - m_surfaces.insert(0, surface); - - ensureKeyboardFocusSurface(surface); - m_renderScheduler.start(0); -} - -void QWindowCompositor::surfaceCommitted() -{ - QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); - surfaceCommitted(surface); -} - -void QWindowCompositor::surfacePosChanged() -{ - m_renderScheduler.start(0); -} - -void QWindowCompositor::surfaceCommitted(QWaylandSurface *surface) -{ - Q_UNUSED(surface) - m_renderScheduler.start(0); -} - -void QWindowCompositor::surfaceCreated(QWaylandSurface *surface) -{ - connect(surface, SIGNAL(surfaceDestroyed()), this, SLOT(surfaceDestroyed())); - connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped())); - connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped())); - connect(surface, SIGNAL(redraw()), this, SLOT(surfaceCommitted())); - connect(surface, SIGNAL(extendedSurfaceReady()), this, SLOT(sendExpose())); - m_renderScheduler.start(0); - - surface->setBufferAttacher(new BufferAttacher); -} - -void QWindowCompositor::sendExpose() -{ - QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); - surface->sendOnScreenVisibilityChange(true); -} - -void QWindowCompositor::updateCursor(bool hasBuffer) -{ - Q_UNUSED(hasBuffer) - if (!m_cursorSurface) - return; - - QImage image = static_cast<BufferAttacher *>(m_cursorSurface->bufferAttacher())->image(); - - QCursor cursor(QPixmap::fromImage(image), m_cursorHotspotX, m_cursorHotspotY); - static bool cursorIsSet = false; - if (cursorIsSet) { - QGuiApplication::changeOverrideCursor(cursor); - } else { - QGuiApplication::setOverrideCursor(cursor); - cursorIsSet = true; - } -} - -QPointF QWindowCompositor::toView(QWaylandSurfaceView *view, const QPointF &pos) const -{ - return pos - view->pos(); -} - -void QWindowCompositor::setCursorSurface(QWaylandSurface *surface, int hotspotX, int hotspotY) -{ - if ((m_cursorSurface != surface) && surface) - connect(surface, SIGNAL(configure(bool)), this, SLOT(updateCursor(bool))); - - m_cursorSurface = surface; - m_cursorHotspotX = hotspotX; - m_cursorHotspotY = hotspotY; - if (m_cursorSurface && !m_cursorSurface->bufferAttacher()) - m_cursorSurface->setBufferAttacher(new BufferAttacher); -} - -QWaylandSurfaceView *QWindowCompositor::viewAt(const QPointF &point, QPointF *local) -{ - for (int i = m_surfaces.size() - 1; i >= 0; --i) { - QWaylandSurface *surface = m_surfaces.at(i); - foreach (QWaylandSurfaceView *view, surface->views()) { - QRectF geo(view->pos(), surface->size()); - if (geo.contains(point)) { - if (local) - *local = toView(view, point); - return view; - } - } - } - return 0; -} - -void QWindowCompositor::render() -{ - m_window->makeCurrent(); - frameStarted(); - - cleanupGraphicsResources(); - - if (!m_backgroundTexture) - m_backgroundTexture = new QOpenGLTexture(m_backgroundImage, QOpenGLTexture::DontGenerateMipMaps); - - m_textureBlitter->bind(GL_TEXTURE_2D); - // Draw the background image texture - m_textureBlitter->drawTexture(m_backgroundTexture->textureId(), - QRect(QPoint(0, 0), m_backgroundImage.size()), - m_window->size(), - 0, false, true); - - foreach (QWaylandSurface *surface, m_surfaces) { - if (!surface->visible()) - continue; - BufferAttacher *ba = static_cast<BufferAttacher *>(surface->bufferAttacher()); - ba->updateTexture(); - const GLuint texture = ba->texture; - const GLenum target = ba->textureTarget; - m_textureBlitter->bind(target); - foreach (QWaylandSurfaceView *view, surface->views()) { - QRect geo(view->pos().toPoint(),surface->size()); - m_textureBlitter->drawTexture(texture,geo,m_window->size(),0,false,surface->isYInverted()); - } - } - - m_textureBlitter->release(); - sendFrameCallbacks(surfaces()); - - // N.B. Never call glFinish() here as the busylooping with vsync 'feature' of the nvidia binary driver is not desirable. - m_window->swapBuffers(); -} - -bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event) -{ - if (obj != m_window) - return false; - - QWaylandInputDevice *input = defaultInputDevice(); - - switch (event->type()) { - case QEvent::Expose: - m_renderScheduler.start(0); - if (m_window->isExposed()) { - // Alt-tabbing away normally results in the alt remaining in - // pressed state in the clients xkb state. Prevent this by sending - // a release. This is not an issue in a "real" compositor but - // is very annoying when running in a regular window on xcb. - Qt::KeyboardModifiers mods = QGuiApplication::queryKeyboardModifiers(); - if (m_modifiers != mods && input->keyboardFocus()) { - Qt::KeyboardModifiers stuckMods = m_modifiers ^ mods; - if (stuckMods & Qt::AltModifier) - input->sendKeyReleaseEvent(64); // native scancode for left alt - m_modifiers = mods; - } - } - break; - case QEvent::MouseButtonPress: { - QPointF local; - QMouseEvent *me = static_cast<QMouseEvent *>(event); - QWaylandSurfaceView *target = viewAt(me->localPos(), &local); - if (m_dragKeyIsPressed && target) { - m_draggingWindow = target; - m_drag_diff = local; - } else { - if (target && input->keyboardFocus() != target->surface()) { - input->setKeyboardFocus(target->surface()); - m_surfaces.removeOne(target->surface()); - m_surfaces.append(target->surface()); - m_renderScheduler.start(0); - } - input->sendMousePressEvent(me->button(), local, me->localPos()); - } - return true; - } - case QEvent::MouseButtonRelease: { - QWaylandSurfaceView *target = input->mouseFocus(); - if (m_draggingWindow) { - m_draggingWindow = 0; - m_drag_diff = QPointF(); - } else { - QMouseEvent *me = static_cast<QMouseEvent *>(event); - QPointF localPos; - if (target) - localPos = toView(target, me->localPos()); - input->sendMouseReleaseEvent(me->button(), localPos, me->localPos()); - } - return true; - } - case QEvent::MouseMove: { - QMouseEvent *me = static_cast<QMouseEvent *>(event); - if (m_draggingWindow) { - m_draggingWindow->setPos(me->localPos() - m_drag_diff); - m_renderScheduler.start(0); - } else { - QPointF local; - QWaylandSurfaceView *target = viewAt(me->localPos(), &local); - input->sendMouseMoveEvent(target, local, me->localPos()); - } - break; - } - case QEvent::Wheel: { - QWheelEvent *we = static_cast<QWheelEvent *>(event); - input->sendMouseWheelEvent(we->orientation(), we->delta()); - break; - } - case QEvent::KeyPress: { - QKeyEvent *ke = static_cast<QKeyEvent *>(event); - if (ke->key() == Qt::Key_Meta || ke->key() == Qt::Key_Super_L) { - m_dragKeyIsPressed = true; - } - m_modifiers = ke->modifiers(); - QWaylandSurface *targetSurface = input->keyboardFocus(); - if (targetSurface) - input->sendKeyPressEvent(ke->nativeScanCode()); - break; - } - case QEvent::KeyRelease: { - QKeyEvent *ke = static_cast<QKeyEvent *>(event); - if (ke->key() == Qt::Key_Meta || ke->key() == Qt::Key_Super_L) { - m_dragKeyIsPressed = false; - } - m_modifiers = ke->modifiers(); - QWaylandSurface *targetSurface = input->keyboardFocus(); - if (targetSurface) - input->sendKeyReleaseEvent(ke->nativeScanCode()); - break; - } - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - { - QWaylandSurfaceView *target = 0; - QTouchEvent *te = static_cast<QTouchEvent *>(event); - QList<QTouchEvent::TouchPoint> points = te->touchPoints(); - QPoint pointPos; - if (!points.isEmpty()) { - pointPos = points.at(0).pos().toPoint(); - target = viewAt(pointPos); - } - if (target && target != input->mouseFocus()) - input->setMouseFocus(target, pointPos, pointPos); - if (input->mouseFocus()) - input->sendFullTouchEvent(te); - break; - } - default: - break; - } - return false; -} - -QT_END_NAMESPACE diff --git a/examples/wayland/qwindow-compositor/qwindowcompositor.h b/examples/wayland/qwindow-compositor/qwindowcompositor.h deleted file mode 100644 index cb70369c2..000000000 --- a/examples/wayland/qwindow-compositor/qwindowcompositor.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Compositor. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINDOWCOMPOSITOR_H -#define QWINDOWCOMPOSITOR_H - -#include "qwaylandcompositor.h" -#include "qwaylandsurface.h" -#include "textureblitter.h" -#include "compositorwindow.h" - -#include <QtGui/private/qopengltexturecache_p.h> -#include <QObject> -#include <QTimer> - -QT_BEGIN_NAMESPACE - -class QWaylandSurfaceView; -class QOpenGLTexture; - -class QWindowCompositor : public QObject, public QWaylandCompositor -{ - Q_OBJECT -public: - QWindowCompositor(CompositorWindow *window); - ~QWindowCompositor(); - -private slots: - void surfaceDestroyed(); - void surfaceMapped(); - void surfaceUnmapped(); - void surfaceCommitted(); - void surfacePosChanged(); - - void render(); -protected: - void surfaceCommitted(QWaylandSurface *surface); - void surfaceCreated(QWaylandSurface *surface); - - QWaylandSurfaceView* viewAt(const QPointF &point, QPointF *local = 0); - - bool eventFilter(QObject *obj, QEvent *event); - QPointF toView(QWaylandSurfaceView *view, const QPointF &pos) const; - - void setCursorSurface(QWaylandSurface *surface, int hotspotX, int hotspotY); - - void ensureKeyboardFocusSurface(QWaylandSurface *oldSurface); - QImage makeBackgroundImage(const QString &fileName); - -private slots: - void sendExpose(); - void updateCursor(bool hasBuffer); - -private: - void drawSubSurface(const QPoint &offset, QWaylandSurface *surface); - - CompositorWindow *m_window; - QImage m_backgroundImage; - QOpenGLTexture *m_backgroundTexture; - QList<QWaylandSurface *> m_surfaces; - TextureBlitter *m_textureBlitter; - GLuint m_surface_fbo; - QTimer m_renderScheduler; - - //Dragging windows around - QWaylandSurfaceView *m_draggingWindow; - bool m_dragKeyIsPressed; - QPointF m_drag_diff; - - //Cursor - QWaylandSurface *m_cursorSurface; - int m_cursorHotspotX; - int m_cursorHotspotY; - - Qt::KeyboardModifiers m_modifiers; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWCOMPOSITOR_H diff --git a/examples/wayland/qwindow-compositor/textureblitter.cpp b/examples/wayland/qwindow-compositor/textureblitter.cpp deleted file mode 100644 index df4fa18d8..000000000 --- a/examples/wayland/qwindow-compositor/textureblitter.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Compositor. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "textureblitter.h" - -#include <QtGui/QOpenGLShaderProgram> -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLFunctions> - -#ifndef GL_TEXTURE_EXTERNAL_OES -#define GL_TEXTURE_EXTERNAL_OES 0x8D65 -#endif - -QT_BEGIN_NAMESPACE - -TextureBlitter::TextureBlitter() - : m_shaderProgram(new QOpenGLShaderProgram) - , m_shaderProgramExternal(new QOpenGLShaderProgram) - , m_currentProgram(0) - , m_currentTarget(GL_TEXTURE_2D) -{ - static const char *textureVertexProgram = - "uniform highp mat4 matrix;\n" - "attribute highp vec3 vertexCoordEntry;\n" - "attribute highp vec2 textureCoordEntry;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " textureCoord = textureCoordEntry;\n" - " gl_Position = matrix * vec4(vertexCoordEntry, 1);\n" - "}\n"; - - static const char *textureFragmentProgram = - "uniform sampler2D texture;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, textureCoord);\n" - "}\n"; - - static const char *textureFragmentProgramExternal = - "#extension GL_OES_EGL_image_external : require\n" - "uniform samplerExternalOES texture;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, textureCoord);\n" - "}\n"; - - m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); - m_shaderProgram->link(); - - m_shaderProgramExternal->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - m_shaderProgramExternal->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgramExternal); - m_shaderProgramExternal->link(); -} - -TextureBlitter::~TextureBlitter() -{ - delete m_shaderProgram; - delete m_shaderProgramExternal; -} - -void TextureBlitter::bind(quint32 target) -{ - m_currentTarget = target; - switch (target) { - case GL_TEXTURE_2D: - m_currentProgram = m_shaderProgram; - break; - case GL_TEXTURE_EXTERNAL_OES: - m_currentProgram = m_shaderProgramExternal; - break; - default: - qFatal("INVALID TARGET TYPE %d", target); - break; - } - - m_currentProgram->bind(); - - m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry"); - m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry"); - m_matrixLocation = m_shaderProgram->uniformLocation("matrix"); - - //Enable transparent windows - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -} - -void TextureBlitter::release() -{ - m_currentProgram->release(); -} - -void TextureBlitter::drawTexture(int textureId, const QRectF &targetRect, const QSize &targetSize, int depth, bool targethasInvertedY, bool sourceHasInvertedY) -{ - - glViewport(0,0,targetSize.width(),targetSize.height()); - GLfloat zValue = depth / 1000.0f; - //Set Texture and Vertex coordinates - const GLfloat textureCoordinates[] = { - 0, 0, - 1, 0, - 1, 1, - 0, 1 - }; - - GLfloat x1 = targetRect.left(); - GLfloat x2 = targetRect.right(); - GLfloat y1, y2; - if (targethasInvertedY) { - if (sourceHasInvertedY) { - y1 = targetRect.top(); - y2 = targetRect.bottom(); - } else { - y1 = targetRect.bottom(); - y2 = targetRect.top(); - } - } else { - if (sourceHasInvertedY) { - y1 = targetSize.height() - targetRect.top(); - y2 = targetSize.height() - targetRect.bottom(); - } else { - y1 = targetSize.height() - targetRect.bottom(); - y2 = targetSize.height() - targetRect.top(); - } - } - - const GLfloat vertexCoordinates[] = { - GLfloat(x1), GLfloat(y1), zValue, - GLfloat(x2), GLfloat(y1), zValue, - GLfloat(x2), GLfloat(y2), zValue, - GLfloat(x1), GLfloat(y2), zValue - }; - - //Set matrix to transfrom geometry values into gl coordinate space. - m_transformMatrix.setToIdentity(); - m_transformMatrix.scale( 2.0f / targetSize.width(), 2.0f / targetSize.height() ); - m_transformMatrix.translate(-targetSize.width() / 2.0f, -targetSize.height() / 2.0f); - - //attach the data! - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - currentContext->functions()->glEnableVertexAttribArray(m_vertexCoordEntry); - currentContext->functions()->glEnableVertexAttribArray(m_textureCoordEntry); - - currentContext->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); - currentContext->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); - - m_currentProgram->setUniformValue(m_matrixLocation, m_transformMatrix); - - glBindTexture(m_currentTarget, textureId); - - glTexParameterf(m_currentTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(m_currentTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBindTexture(m_currentTarget, 0); - - currentContext->functions()->glDisableVertexAttribArray(m_vertexCoordEntry); - currentContext->functions()->glDisableVertexAttribArray(m_textureCoordEntry); -} - -QT_END_NAMESPACE diff --git a/examples/wayland/qwindow-compositor/textureblitter.h b/examples/wayland/qwindow-compositor/textureblitter.h deleted file mode 100644 index 85e2bbfb4..000000000 --- a/examples/wayland/qwindow-compositor/textureblitter.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Compositor. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef TEXTUREBLITTER_H -#define TEXTUREBLITTER_H - -#include <QtGui/QMatrix4x4> - -QT_BEGIN_NAMESPACE - -class QOpenGLShaderProgram; -class TextureBlitter -{ -public: - TextureBlitter(); - ~TextureBlitter(); - void bind(quint32 target); - void release(); - void drawTexture(int textureId, const QRectF &sourceGeometry, - const QSize &targetRect, int depth, - bool targethasInvertedY, bool sourceHasInvertedY); - -private: - QOpenGLShaderProgram *m_shaderProgram; - QOpenGLShaderProgram *m_shaderProgramExternal; - QOpenGLShaderProgram *m_currentProgram; - QMatrix4x4 m_transformMatrix; - - int m_matrixLocation; - int m_vertexCoordEntry; - int m_textureCoordEntry; - - quint32 m_currentTarget; -}; - -QT_END_NAMESPACE - -#endif // TEXTUREBLITTER_H diff --git a/examples/wayland/qwindow-compositor/windowcompositor.cpp b/examples/wayland/qwindow-compositor/windowcompositor.cpp new file mode 100644 index 000000000..24a0e0f52 --- /dev/null +++ b/examples/wayland/qwindow-compositor/windowcompositor.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Wayland module +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "windowcompositor.h" + +#include <QMouseEvent> +#include <QKeyEvent> +#include <QTouchEvent> + +#include <QtWaylandCompositor/QWaylandShellSurface> +#include <QtWaylandCompositor/qwaylandinput.h> +#include <QtWaylandCompositor/qwaylanddrag.h> + +#include <QDebug> + +GLuint WindowCompositorView::getTexture() { + if (advance()) { + if (m_texture) + glDeleteTextures(1, &m_texture); + + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + currentBuffer().bindToTexture(); + } + return m_texture; +} + +bool WindowCompositorView::isCursor() const +{ + return surface()->isCursorSurface(); +} + +WindowCompositor::WindowCompositor(QWindow *window) + : QWaylandCompositor() + , m_window(window) + , m_shell(new QWaylandShell(this)) +{ + connect(m_shell, &QWaylandShell::createShellSurface, this, &WindowCompositor::onCreateShellSurface); +} + +WindowCompositor::~WindowCompositor() +{ +} + +void WindowCompositor::create() +{ + new QWaylandOutput(this, m_window); + QWaylandCompositor::create(); + + connect(this, &QWaylandCompositor::surfaceCreated, this, &WindowCompositor::onSurfaceCreated); + connect(defaultInputDevice(), &QWaylandInputDevice::cursorSurfaceRequest, this, &WindowCompositor::adjustCursorSurface); + connect(defaultInputDevice()->drag(), &QWaylandDrag::dragStarted, this, &WindowCompositor::startDrag); +} + +void WindowCompositor::onSurfaceCreated(QWaylandSurface *surface) +{ + connect(surface, &QWaylandSurface::surfaceDestroyed, this, &WindowCompositor::surfaceDestroyed); + connect(surface, &QWaylandSurface::mappedChanged, this, &WindowCompositor::surfaceMappedChanged); + connect(surface, &QWaylandSurface::redraw, this, &WindowCompositor::triggerRender); + connect(surface, &QWaylandSurface::offsetForNextFrame, this, &WindowCompositor::frameOffset); + WindowCompositorView *view = new WindowCompositorView; + view->setSurface(surface); + view->setOutput(outputFor(m_window)); + m_views << view; + connect(view, &QWaylandView::surfaceDestroyed, this, &WindowCompositor::viewSurfaceDestroyed); +} + +void WindowCompositor::surfaceMappedChanged() +{ + QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); + if (surface->isMapped()) { + if (!surface->isCursorSurface()) + defaultInputDevice()->setKeyboardFocus(surface); + } else if (popupActive()) { + for (int i = 0; i < m_popupViews.count(); i++) { + if (m_popupViews.at(i)->surface() == surface) { + m_popupViews.removeAt(i); + break; + } + } + } + triggerRender(); +} + +void WindowCompositor::surfaceDestroyed() +{ + triggerRender(); +} + +void WindowCompositor::viewSurfaceDestroyed() +{ + WindowCompositorView *view = qobject_cast<WindowCompositorView*>(sender()); + m_views.removeAll(view); + delete view; +} + +void WindowCompositor::surfaceCommittedSlot() +{ + triggerRender(); +} + +WindowCompositorView * WindowCompositor::findView(const QWaylandSurface *s) const +{ + Q_FOREACH (WindowCompositorView* view, m_views) { + if (view->surface() == s) + return view; + } + return Q_NULLPTR; +} + +void WindowCompositor::onCreateShellSurface(QWaylandSurface *s, QWaylandClient *client, uint id) +{ + QWaylandSurface *surface = s; + + QWaylandShellSurface *shellSurface = new QWaylandShellSurface(m_shell, surface, client, id); + connect(shellSurface, &QWaylandShellSurface::startMove, this, &WindowCompositor::onStartMove); + connect(shellSurface, &QWaylandShellSurface::startResize, this, &WindowCompositor::onStartResize); + connect(shellSurface, &QWaylandShellSurface::setTransient, this, &WindowCompositor::onSetTransient); + connect(shellSurface, &QWaylandShellSurface::setPopup, this, &WindowCompositor::onSetPopup); + WindowCompositorView *view = findView(s); + Q_ASSERT(view); + view->m_shellSurface = shellSurface; +} + +void WindowCompositor::onStartMove() +{ + closePopups(); + emit startMove(); +} + +void WindowCompositor::onStartResize(QWaylandInputDevice *, QWaylandShellSurface::ResizeEdge edges) +{ + closePopups(); + emit startResize(int(edges)); +} + +void WindowCompositor::onSetTransient(QWaylandSurface *parentSurface, const QPoint &relativeToParent, QWaylandShellSurface::FocusPolicy focusPolicy) +{ + qDebug() << "Transient window support not implemented" << parentSurface << relativeToParent << focusPolicy; +} + +void WindowCompositor::onSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurface *parent, const QPoint &relativeToParent) +{ + Q_UNUSED(inputDevice); + QWaylandShellSurface *surface = qobject_cast<QWaylandShellSurface*>(sender()); + WindowCompositorView *view = findView(surface->surface()); + m_popupViews << view; + if (view) { + raise(view); + WindowCompositorView *parentView = findView(parent); + if (parentView) + view->setPosition(parentView->position() + relativeToParent); + } +} + +void WindowCompositor::triggerRender() +{ + m_window->requestUpdate(); +} + +void WindowCompositor::startRender() +{ + QWaylandOutput *out = defaultOutput(); + if (out) + out->frameStarted(); +} + +void WindowCompositor::endRender() +{ + QWaylandOutput *out = defaultOutput(); + if (out) + out->sendFrameCallbacks(); +} + +void WindowCompositor::updateCursor() +{ + m_cursorView.advance(); + QImage image = m_cursorView.currentBuffer().image(); + if (!image.isNull()) + m_window->setCursor(QCursor(QPixmap::fromImage(image), m_cursorHotspotX, m_cursorHotspotY)); +} + +void WindowCompositor::adjustCursorSurface(QWaylandSurface *surface, int hotspotX, int hotspotY) +{ + if ((m_cursorView.surface() != surface)) { + if (m_cursorView.surface()) + disconnect(m_cursorView.surface(), &QWaylandSurface::redraw, this, &WindowCompositor::updateCursor); + if (surface) + connect(surface, &QWaylandSurface::redraw, this, &WindowCompositor::updateCursor); + } + + m_cursorView.setSurface(surface); + m_cursorHotspotX = hotspotX; + m_cursorHotspotY = hotspotY; +} + +void WindowCompositor::closePopups() +{ + Q_FOREACH (WindowCompositorView *view, m_popupViews) + view->m_shellSurface->sendPopupDone(); + m_popupViews.clear(); +} + +void WindowCompositor::handleMouseEvent(QWaylandView *target, QMouseEvent *me) +{ + if (target && popupActive() && me->type() == QEvent::MouseButtonPress + && target->surface()->client() != m_popupViews.first()->surface()->client()) { + closePopups(); + } + QWaylandInputDevice *input = defaultInputDevice(); + switch (me->type()) { + case QEvent::MouseButtonPress: + input->sendMousePressEvent(me->button()); + break; + case QEvent::MouseButtonRelease: + input->sendMouseReleaseEvent(me->button()); + break; + case QEvent::MouseMove: + input->sendMouseMoveEvent(target, me->localPos(), me->globalPos()); + default: + break; + } +} + +void WindowCompositor::handleResize(WindowCompositorView *target, const QSize &initialSize, const QPoint &delta, int edge) +{ + QWaylandShellSurface *shellSurface = target->m_shellSurface; + if (!shellSurface) + return; + QWaylandShellSurface::ResizeEdge edges = QWaylandShellSurface::ResizeEdge(edge); + QSize newSize = shellSurface->sizeForResize(initialSize, delta, edges); + shellSurface->sendConfigure(newSize, edges); +} + +void WindowCompositor::startDrag() +{ + QWaylandDrag *currentDrag = defaultInputDevice()->drag(); + Q_ASSERT(currentDrag); + WindowCompositorView *iconView = findView(currentDrag->icon()); + + emit dragStarted(iconView); +} + +void WindowCompositor::handleDrag(WindowCompositorView *target, QMouseEvent *me) +{ + QPointF pos = me->localPos(); + QWaylandSurface *surface = 0; + if (target) { + pos -= target->position(); + surface = target->surface(); + } + QWaylandDrag *currentDrag = defaultInputDevice()->drag(); + currentDrag->dragMove(surface, pos); + if (me->buttons() == Qt::NoButton) + currentDrag->drop(); +} + +void WindowCompositor::raise(WindowCompositorView *view) +{ + m_views.removeOne(view); + m_views.append(view); +} diff --git a/examples/wayland/qwindow-compositor/windowcompositor.h b/examples/wayland/qwindow-compositor/windowcompositor.h new file mode 100644 index 000000000..6f878d3a6 --- /dev/null +++ b/examples/wayland/qwindow-compositor/windowcompositor.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Wayland module +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOWCOMPOSITOR_H +#define WINDOWCOMPOSITOR_H + +#include <QtWaylandCompositor/QWaylandCompositor> +#include <QtWaylandCompositor/QWaylandSurface> +#include <QtWaylandCompositor/QWaylandView> +#include <QtWaylandCompositor/QWaylandShellSurface> +#include <QTimer> + +QT_BEGIN_NAMESPACE + +class QWaylandShell; +class QWaylandShellSurface; + +class WindowCompositorView : public QWaylandView +{ + Q_OBJECT +public: + WindowCompositorView() : m_texture(0), m_shellSurface(0) {} + GLuint getTexture(); + QPointF position() const { return m_position; } + void setPosition(const QPointF &pos) { m_position = pos; } + bool isCursor() const; + bool hasShell() const { return m_shellSurface; } +private: + friend class WindowCompositor; + GLuint m_texture; + QPointF m_position; + QWaylandShellSurface *m_shellSurface; +}; + +class WindowCompositor : public QWaylandCompositor +{ + Q_OBJECT +public: + WindowCompositor(QWindow *window); + ~WindowCompositor(); + void create() Q_DECL_OVERRIDE; + + void startRender(); + void endRender(); + + QList<WindowCompositorView*> views() const { return m_views; } + void raise(WindowCompositorView *view); + + void handleMouseEvent(QWaylandView *target, QMouseEvent *me); + void handleResize(WindowCompositorView *target, const QSize &initialSize, const QPoint &delta, int edge); + void handleDrag(WindowCompositorView *target, QMouseEvent *me); + + bool popupActive() const { return !m_popupViews.isEmpty(); } + void closePopups(); +protected: + void adjustCursorSurface(QWaylandSurface *surface, int hotspotX, int hotspotY); + +signals: + void startMove(); + void startResize(int edge); + void dragStarted(WindowCompositorView *dragIcon); + void frameOffset(const QPoint &offset); + +private slots: + void surfaceMappedChanged(); + void surfaceDestroyed(); + void surfaceCommittedSlot(); + void viewSurfaceDestroyed(); + void onStartMove(); + void onStartResize(QWaylandInputDevice *inputDevice, QWaylandShellSurface::ResizeEdge edges); + + void startDrag(); + + void triggerRender(); + + void onSurfaceCreated(QWaylandSurface *surface); + void onCreateShellSurface(QWaylandSurface *s, QWaylandClient *client, uint id); + void onSetTransient(QWaylandSurface *parentSurface, const QPoint &relativeToParent, QWaylandShellSurface::FocusPolicy focusPolicy); + void onSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurface *parent, const QPoint &relativeToParent); + + void updateCursor(); +private: + WindowCompositorView *findView(const QWaylandSurface *s) const; + QWindow *m_window; + QList<WindowCompositorView*> m_views; + QList<WindowCompositorView*> m_popupViews; + QWaylandShell *m_shell; + QWaylandView m_cursorView; + int m_cursorHotspotX; + int m_cursorHotspotY; +}; + + +QT_END_NAMESPACE + +#endif // WINDOWCOMPOSITOR_H |