diff options
Diffstat (limited to 'examples/wayland/qwindow-compositor/windowcompositor.cpp')
-rw-r--r-- | examples/wayland/qwindow-compositor/windowcompositor.cpp | 300 |
1 files changed, 300 insertions, 0 deletions
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); +} |