diff options
43 files changed, 1226 insertions, 238 deletions
diff --git a/examples/qml-compositor/main.cpp b/examples/qml-compositor/main.cpp index 066cfee..fdf27b3 100644 --- a/examples/qml-compositor/main.cpp +++ b/examples/qml-compositor/main.cpp @@ -57,14 +57,13 @@ class QmlCompositor : public QSGView, public WaylandCompositor { Q_OBJECT public: - QmlCompositor() : WaylandCompositor(this) { - setMouseTracking(true); + QmlCompositor() : WaylandCompositor(this, const_cast<QOpenGLContext *>(QOpenGLContext::currentContext())) { + //setMouseTracking(true); setSource(QUrl(QLatin1String("qrc:qml/QmlCompositor/main.qml"))); setResizeMode(QSGView::SizeRootObjectToView); winId(); - if (platformWindow()) { - platformWindow()->glContext(); - } + + connect(this, SIGNAL(frameSwapped()), this, SLOT(frameSwappedSlot())); } signals: @@ -103,17 +102,15 @@ private slots: emit windowDestroyed(QVariant::fromValue(static_cast<QSGItem *>(item))); } + void frameSwappedSlot() { + frameFinished(); + } + protected: void surfaceCreated(WaylandSurface *surface) { connect(surface, SIGNAL(mapped(const QSize &)), this, SLOT(surfaceMapped(const QSize &))); } - void paintEvent(QPaintEvent *event) { - QSGView::paintEvent(event); - frameFinished(); - glFinish(); - } - private: QMap<QObject *, WaylandSurfaceItem *> m_windowMap; }; @@ -133,7 +130,6 @@ int main(int argc, char *argv[]) QObject::connect(&compositor, SIGNAL(windowResized(QVariant)), compositor.rootObject(), SLOT(windowResized(QVariant))); return app.exec(); - } #include "main.moc" diff --git a/examples/qml-compositor/qml-compositor.pro b/examples/qml-compositor/qml-compositor.pro index 7aed420..4390133 100644 --- a/examples/qml-compositor/qml-compositor.pro +++ b/examples/qml-compositor/qml-compositor.pro @@ -17,6 +17,13 @@ LIBS += -L ../../lib QT += declarative QT += opengl +# to be removed once scenegraph gets rid of its widget dependencies +QT += widgets widgets-private + +!isEmpty(QT.core.MAJOR_VERSION):greaterThan(QT.core.MAJOR_VERSION, 4) { + QT += core-private gui-private declarative-private opengl-private +} + include (../../src/qt-compositor/qt-compositor.pri) # Input diff --git a/examples/qwidget-compositor-mdi/main.cpp b/examples/qwidget-compositor-mdi/main.cpp index 7f32c09..752014a 100644 --- a/examples/qwidget-compositor-mdi/main.cpp +++ b/examples/qwidget-compositor-mdi/main.cpp @@ -51,13 +51,12 @@ #include <QPainter> #include <QMouseEvent> -#ifdef QT_COMPOSITOR_WAYLAND_GL -#include <QGLContext> -#include <QGLWidget> -#endif - #include <QDebug> +// This has no GL support, meaning only readback-based GL clients will work. +// Others, e.g. xcomposite-glx, will typically crash the client as there is no +// corresponding integration on the compositor side. + class QSurfaceWidget : public QWidget { Q_OBJECT @@ -70,6 +69,12 @@ public: private slots: void surfaceDamaged(const QRect &rect) { + + // NB! This is dangerous. There may be no paintEvent() called, for + // example if the mdi subwindow is completely covered by another one. + // And in that case there is no frameFinished() -> the client may block + // in its waitForFrameSync() for a long time... + update(rect); } @@ -133,9 +138,9 @@ private slots: void surfaceMapped(const QSize &size) { m_surface->setInputFocus(); - widget()->setMinimumSize(size); - resize(sizeHint()); - show(); + widget()->setMinimumSize(size); + resize(sizeHint()); + show(); } void surfaceDamaged(const QRect &) { diff --git a/examples/qwidget-compositor-mdi/qt-compositor.pro b/examples/qwidget-compositor-mdi/qt-compositor.pro index 59db258..3cd110b 100644 --- a/examples/qwidget-compositor-mdi/qt-compositor.pro +++ b/examples/qwidget-compositor-mdi/qt-compositor.pro @@ -10,6 +10,8 @@ DESTDIR=$$PWD/../../bin/ include (../../src/qt-compositor/qt-compositor.pri) +QT += widgets gui-private widgets-private + # Input SOURCES += main.cpp diff --git a/examples/qwidget-compositor/main.cpp b/examples/qwidget-compositor/main.cpp index 13b4b57..8e71860 100644 --- a/examples/qwidget-compositor/main.cpp +++ b/examples/qwidget-compositor/main.cpp @@ -55,23 +55,23 @@ #include <QDebug> -#include "qtouchscreen.h" - -static int touch_x_min, touch_x_max, touch_y_min, touch_y_max; - -class QWidgetCompositor; - -class TouchObserver : public QTouchScreenObserver -{ -public: - TouchObserver(QWidgetCompositor *compositor) - : m_compositor(compositor) { } - void touch_configure(int x_min, int x_max, int y_min, int y_max); - void touch_point(QEvent::Type state, const QList<QWindowSystemInterface::TouchPoint> &points); - -private: - QWidgetCompositor *m_compositor; -}; +//#include "qtouchscreen.h" +// +//static int touch_x_min, touch_x_max, touch_y_min, touch_y_max; +// +//class QWidgetCompositor; +// +//class TouchObserver : public QTouchScreenObserver +//{ +//public: +// TouchObserver(QWidgetCompositor *compositor) +// : m_compositor(compositor) { } +// void touch_configure(int x_min, int x_max, int y_min, int y_max); +// void touch_point(QEvent::Type state, const QList<QWindowSystemInterface::TouchPoint> &points); +// +//private: +// QWidgetCompositor *m_compositor; +//}; #ifdef QT_COMPOSITOR_WAYLAND_GL class QWidgetCompositor : public QGLWidget, public WaylandCompositor @@ -81,7 +81,11 @@ class QWidgetCompositor : public QWidget, public WaylandCompositor { Q_OBJECT public: - QWidgetCompositor() : WaylandCompositor(this), m_dragSurface(0) { + QWidgetCompositor() + : WaylandCompositor(windowHandle(),const_cast<QGLContext *>(context())->contextHandle()) + , m_moveSurface(0) + , m_dragSourceSurface(0) + { setMouseTracking(true); setRetainedSelectionEnabled(true); m_background = QImage(QLatin1String("background.jpg")); @@ -89,8 +93,8 @@ public: //so that clients can successfully initialize egl winId(); #ifdef QT_COMPOSITOR_WAYLAND_GL - if (platformWindow()) { - platformWindow()->glContext(); + if (windowHandle()) { +// windowHandle()->surfaceHandle(); } #endif } @@ -151,12 +155,7 @@ protected: for (int i = 0; i < m_surfaces.size(); ++i) { if (m_surfaces.at(i)->type() == WaylandSurface::Texture) { #ifdef QT_COMPOSITOR_WAYLAND_GL - QPlatformGLContext *glcontext = platformWindow()->glContext(); - if (glcontext) { - QGLContext *context = QGLContext::fromPlatformGLContext(glcontext); - context->makeCurrent(); - context->drawTexture(m_surfaces.at(i)->geometry(),m_surfaces.at(i)->texture()); - } + drawTexture(m_surfaces.at(i)->geometry(), m_surfaces.at(i)->texture()); break; #endif //QT_COMPOSITOR_WAYLAND_GL } else if (m_surfaces.at(i)->type() == WaylandSurface::Shm) { @@ -165,6 +164,9 @@ protected: } } + if (!m_cursor.isNull()) + p.drawImage(m_cursorPos - m_cursorHotspot, m_cursor); + frameFinished(); #ifdef QT_COMPOSITOR_WAYLAND_GL @@ -190,12 +192,15 @@ protected: } void mousePressEvent(QMouseEvent *e) { + m_cursorPos = e->pos(); + if (!m_cursor.isNull()) + update(); QPoint local; if (WaylandSurface *surface = surfaceAt(e->pos(), &local)) { raise(surface); if (e->modifiers() & Qt::ControlModifier) { - m_dragSurface = surface; - m_dragOffset = local; + m_moveSurface = surface; + m_moveOffset = local; } else { surface->sendMousePressEvent(local, e->button()); } @@ -203,10 +208,27 @@ protected: } void mouseMoveEvent(QMouseEvent *e) { - if (m_dragSurface) { - QRect geometry = m_dragSurface->geometry(); - geometry.moveTo(e->pos() - m_dragOffset); - m_dragSurface->setGeometry(geometry); + m_cursorPos = e->pos(); + if (!m_cursor.isNull()) + update(); + if (isDragging()) { + QPoint global = e->pos(); // "global" here means the window of the compositor + QPoint local; + WaylandSurface *surface = surfaceAt(e->pos(), &local); + if (surface) { + if (!m_dragSourceSurface) + m_dragSourceSurface = surface; + if (m_dragSourceSurface == surface) + m_lastDragSourcePos = local; + raise(surface); + } + sendDragMoveEvent(global, local, surface); + return; + } + if (m_moveSurface) { + QRect geometry = m_moveSurface->geometry(); + geometry.moveTo(e->pos() - m_moveOffset); + m_moveSurface->setGeometry(geometry); update(); return; } @@ -216,8 +238,16 @@ protected: } void mouseReleaseEvent(QMouseEvent *e) { - if (m_dragSurface) { - m_dragSurface = 0; + if (isDragging()) { + sendDragEndEvent(); + if (m_dragSourceSurface) { + // Must send a release event to the source too, no matter where the cursor is now. + m_dragSourceSurface->sendMouseReleaseEvent(m_lastDragSourcePos, e->button()); + m_dragSourceSurface = 0; + } + } + if (m_moveSurface) { + m_moveSurface = 0; return; } QPoint local; @@ -250,64 +280,76 @@ protected: return 0; } + void changeCursor(const QImage &image, int hotspotX, int hotspotY) { + m_cursor = image; + m_cursorHotspot = QPoint(hotspotX, hotspotY); + update(); + } + private: QImage m_background; QPixmap m_backgroundScaled; QList<WaylandSurface *> m_surfaces; - WaylandSurface *m_dragSurface; - QPoint m_dragOffset; + WaylandSurface *m_moveSurface; + QPoint m_moveOffset; + WaylandSurface *m_dragSourceSurface; + QPoint m_lastDragSourcePos; + + QImage m_cursor; + QPoint m_cursorPos; + QPoint m_cursorHotspot; friend class TouchObserver; }; -void TouchObserver::touch_configure(int x_min, int x_max, int y_min, int y_max) -{ - touch_x_min = x_min; - touch_x_max = x_max; - touch_y_min = y_min; - touch_y_max = y_max; -} - -void TouchObserver::touch_point(QEvent::Type state, const QList<QWindowSystemInterface::TouchPoint> &points) -{ - Q_UNUSED(state); - WaylandSurface *focusSurface = m_compositor->inputFocus(); - if (focusSurface) { - if (points.isEmpty()) - return; - for (int i = 0; i < points.count(); ++i) { - const QWindowSystemInterface::TouchPoint &point(points.at(i)); - - // These are hw coordinates. - int x = int(point.area.left()); - int y = int(point.area.top()); - - // Wayland expects surface-relative coordinates. - - // Translate so that (0, 0) is the top-left corner. - x = qBound(touch_x_min, x, touch_x_max) - touch_x_min; - y = qBound(touch_y_min, y, touch_y_max) - touch_y_min; - - // Get a normalized position in range 0..1. - const int hw_w = touch_x_max - touch_x_min; - const int hw_h = touch_y_max - touch_y_min; - const qreal nx = x / qreal(hw_w); - const qreal ny = y / qreal(hw_h); - - // Map to surface. - QRect winRect(focusSurface->geometry()); - x = int(nx * winRect.width()); - y = int(ny * winRect.height()); - - focusSurface->sendTouchPointEvent(point.id, - x, y, - point.state); - } - focusSurface->sendTouchFrameEvent(); - } -} +//void TouchObserver::touch_configure(int x_min, int x_max, int y_min, int y_max) +//{ +// touch_x_min = x_min; +// touch_x_max = x_max; +// touch_y_min = y_min; +// touch_y_max = y_max; +//} + +//void TouchObserver::touch_point(QEvent::Type state, const QList<QWindowSystemInterface::TouchPoint> &points) +//{ +// Q_UNUSED(state); +// WaylandSurface *focusSurface = m_compositor->inputFocus(); +// if (focusSurface) { +// if (points.isEmpty()) +// return; +// for (int i = 0; i < points.count(); ++i) { +// const QWindowSystemInterface::TouchPoint &point(points.at(i)); + +// // These are hw coordinates. +// int x = int(point.area.left()); +// int y = int(point.area.top()); + +// // Wayland expects surface-relative coordinates. + +// // Translate so that (0, 0) is the top-left corner. +// x = qBound(touch_x_min, x, touch_x_max) - touch_x_min; +// y = qBound(touch_y_min, y, touch_y_max) - touch_y_min; + +// // Get a normalized position in range 0..1. +// const int hw_w = touch_x_max - touch_x_min; +// const int hw_h = touch_y_max - touch_y_min; +// const qreal nx = x / qreal(hw_w); +// const qreal ny = y / qreal(hw_h); + +// // Map to surface. +// QRect winRect(focusSurface->geometry()); +// x = int(nx * winRect.width()); +// y = int(ny * winRect.height()); + +// focusSurface->sendTouchPointEvent(point.id, +// x, y, +// point.state); +// } +// focusSurface->sendTouchFrameEvent(); +// } +//} int main(int argc, char *argv[]) { @@ -317,7 +359,7 @@ int main(int argc, char *argv[]) compositor.resize(800, 600); compositor.show(); - QTouchScreenHandlerThread t(QString(), new TouchObserver(&compositor)); +// QTouchScreenHandlerThread t(QString(), new TouchObserver(&compositor)); return app.exec(); } diff --git a/examples/qwidget-compositor/qwidget-compositor.pro b/examples/qwidget-compositor/qwidget-compositor.pro index 353b34c..88dd757 100644 --- a/examples/qwidget-compositor/qwidget-compositor.pro +++ b/examples/qwidget-compositor/qwidget-compositor.pro @@ -23,9 +23,12 @@ isEmpty(QT_SOURCE_TREE) { } else { QTBASE = $$QT_SOURCE_TREE } -TOUCHSCREEN_BASE = $$QTBASE/src/plugins/generic/touchscreen -SOURCES += $$TOUCHSCREEN_BASE/qtouchscreen.cpp -HEADERS += $$TOUCHSCREEN_BASE/qtouchscreen.h -INCLUDEPATH += $$TOUCHSCREEN_BASE -LIBS += -ludev -lmtdev -QT += gui-private +#TOUCHSCREEN_BASE = $$QTBASE/src/plugins/generic/touchscreen +#SOURCES += $$TOUCHSCREEN_BASE/qtouchscreen.cpp +#HEADERS += $$TOUCHSCREEN_BASE/qtouchscreen.h +#INCLUDEPATH += $$TOUCHSCREEN_BASE +#LIBS += -ludev -lmtdev +QT += gui-private widgets widgets-private + +target.path += $$[QT_INSTALL_DATA]/bin +INSTALLS += target diff --git a/examples/qwindow-compositor/main.cpp b/examples/qwindow-compositor/main.cpp new file mode 100644 index 0000000..d9e8b47 --- /dev/null +++ b/examples/qwindow-compositor/main.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** This file is part of QtCompositor** +** +** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** Contact: Nokia Corporation qt-info@nokia.com +** +** 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 Nokia Corporation and its Subsidiary(-ies) 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. +** +****************************************************************************/ +#include "qopenglwindow.h" +#include "qwindowcompositor.h" + +#include <QGuiApplication> +#include <QtGui/QScreen> +#include <QtGui/QSurfaceFormat> + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + QScreen *screen = QGuiApplication::primaryScreen(); + QRect screenGeometry = screen->availableGeometry(); + + QSurfaceFormat format; + format.setDepthBufferSize(16); + + QOpenGLWindow *window = new QOpenGLWindow(format, screenGeometry); + + QWindowCompositor compositor(window); + window->show(); + + return app.exec(); +} diff --git a/examples/qwindow-compositor/qopenglwindow.cpp b/examples/qwindow-compositor/qopenglwindow.cpp new file mode 100644 index 0000000..2a53c4c --- /dev/null +++ b/examples/qwindow-compositor/qopenglwindow.cpp @@ -0,0 +1,13 @@ +#include "qopenglwindow.h" + +QOpenGLWindow::QOpenGLWindow(const QSurfaceFormat &format, const QRect &geometry) + : m_format(format) +{ + setSurfaceType(QWindow::OpenGLSurface); + setGeometry(geometry); + setFormat(format); + create(); + m_context = new QOpenGLContext; + m_context->setFormat(format); + m_context->create(); +} diff --git a/examples/qwindow-compositor/qopenglwindow.h b/examples/qwindow-compositor/qopenglwindow.h new file mode 100644 index 0000000..12ccb45 --- /dev/null +++ b/examples/qwindow-compositor/qopenglwindow.h @@ -0,0 +1,22 @@ +#ifndef QOPENGLWINDOW_H +#define QOPENGLWINDOW_H + +#include <QWindow> +#include <QOpenGLContext> +#include <QSurfaceFormat> + +class QOpenGLWindow : public QWindow +{ +public: + QOpenGLWindow(const QSurfaceFormat &format, const QRect &geometry); +public: + QOpenGLContext* context() { return m_context; } + bool makeCurrent() { return m_context->makeCurrent(this); } + void swapBuffers() { m_context->swapBuffers(this); } + +private: + QOpenGLContext *m_context; + QSurfaceFormat m_format; +}; + +#endif // QOPENGLWINDOW_H diff --git a/examples/qwindow-compositor/qwindow-compositor.pro b/examples/qwindow-compositor/qwindow-compositor.pro new file mode 100644 index 0000000..5b160a8 --- /dev/null +++ b/examples/qwindow-compositor/qwindow-compositor.pro @@ -0,0 +1,48 @@ +TEMPLATE = app +TARGET = qwindow-compositor +DEPENDPATH += . +INCLUDEPATH += . + +# comment out the following to not use pkg-config in the pri files +CONFIG += use_pkgconfig + +DESTDIR=$$PWD/../../bin/ + +include (../../src/qt-compositor/qt-compositor.pri) + +# Input +SOURCES += main.cpp \ + qopenglwindow.cpp \ + surfacerenderer.cpp \ + qwindowcompositor.cpp + +CONFIG += qt warn_on debug create_prl link_prl +OBJECTS_DIR = .obj/release-shared +MOC_DIR = .moc/release-shared + +# Touch support +isEmpty(QT_SOURCE_TREE) { + QTBASE = $$[QT_INSTALL_DATA] +} else { + QTBASE = $$QT_SOURCE_TREE +} +#TOUCHSCREEN_BASE = $$QTBASE/src/plugins/generic/touchscreen +#SOURCES += $$TOUCHSCREEN_BASE/qtouchscreen.cpp +#HEADERS += $$TOUCHSCREEN_BASE/qtouchscreen.h +#INCLUDEPATH += $$TOUCHSCREEN_BASE +#LIBS += -ludev -lmtdev +QT += gui opengl + +target.path += $$[QT_INSTALL_BINS] +INSTALLS += target + +HEADERS += \ + qopenglwindow.h \ + surfacerenderer.h \ + qwindowcompositor.h + + + + + + diff --git a/examples/qwindow-compositor/qwindowcompositor.cpp b/examples/qwindow-compositor/qwindowcompositor.cpp new file mode 100644 index 0000000..1b0c002 --- /dev/null +++ b/examples/qwindow-compositor/qwindowcompositor.cpp @@ -0,0 +1,91 @@ +#include "qwindowcompositor.h" + +QWindowCompositor::QWindowCompositor(QOpenGLWindow *window) + : WaylandCompositor(window, window->context()) + , m_window(window) +{ + m_backgroundImage = QImage(QLatin1String("background.jpg")); + m_renderer = new SurfaceRenderer(m_window->context(), m_window); + m_backgroundTexture = m_renderer->textureFromImage(m_backgroundImage); + + render(); +} + +void QWindowCompositor::surfaceDestroyed(QObject *object) +{ + WaylandSurface *surface = static_cast<WaylandSurface *>(object); + m_surfaces.removeAll(surface); + render(); +} + +void QWindowCompositor::surfaceMapped(const QSize &size) +{ + WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender()); + QPoint pos; + if (!m_surfaces.contains(surface)) { + uint px = 1 + (qrand() % (m_window->width() - size.width() - 2)); + uint py = 1 + (qrand() % (m_window->height() - size.height() - 2)); + pos = QPoint(px, py); + surface->setGeometry(QRect(pos, size)); + m_surfaces.append(surface); + } else { + surface->setGeometry(QRect(window()->geometry().topLeft(),size)); + } + setInputFocus(surface); + render(); +} + +void QWindowCompositor::surfaceDamaged(const QRect &rect) +{ + WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender()); + surfaceDamaged(surface, rect); +} + +void QWindowCompositor::surfaceDamaged(WaylandSurface *surface, const QRect &rect) +{ + Q_UNUSED(surface) + Q_UNUSED(rect) + render(); +} + +void QWindowCompositor::surfaceCreated(WaylandSurface *surface) +{ + connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); + connect(surface, SIGNAL(mapped(const QSize &)), this, SLOT(surfaceMapped(const QSize &))); + connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &))); + render(); +} + +WaylandSurface * QWindowCompositor::surfaceAt(const QPoint &point, QPoint *local) +{ + for (int i = m_surfaces.size() - 1; i >= 0; --i) { + if (m_surfaces.at(i)->geometry().contains(point)) { + if (local) + *local = point - m_surfaces.at(i)->geometry().topLeft(); + return m_surfaces.at(i); + } + } + return 0; +} + +void QWindowCompositor::render() +{ + m_window->makeCurrent(); + + //Draw the background Image texture + m_renderer->drawTexture(m_backgroundTexture, m_window->geometry(), 0); + + //Iterate all surfaces in m_surfaces + //If type == WaylandSurface::Texture draw textureId at geometry + foreach (WaylandSurface *surface, m_surfaces) { + if (surface->type() == WaylandSurface::Texture) + m_renderer->drawTexture(surface->texture(), surface->geometry(), 1); //depth argument should be dynamic (focused should be top). + else if (surface->type() == WaylandSurface::Shm) + m_renderer->drawImage(surface->image(), surface->geometry()); + } + frameFinished(); + glFinish(); + m_window->swapBuffers(); + m_window->context()->doneCurrent(); +} + diff --git a/examples/qwindow-compositor/qwindowcompositor.h b/examples/qwindow-compositor/qwindowcompositor.h new file mode 100644 index 0000000..efb448e --- /dev/null +++ b/examples/qwindow-compositor/qwindowcompositor.h @@ -0,0 +1,37 @@ +#ifndef QWINDOWCOMPOSITOR_H +#define QWINDOWCOMPOSITOR_H + +#include "waylandcompositor.h" +#include "waylandsurface.h" +#include "surfacerenderer.h" +#include "qopenglwindow.h" + +#include <QObject> + +class QWindowCompositor : public QObject, public WaylandCompositor +{ + Q_OBJECT +public: + QWindowCompositor(QOpenGLWindow *window); +private slots: + void surfaceDestroyed(QObject *object); + void surfaceMapped(const QSize &size); + void surfaceDamaged(const QRect &rect); + +protected: + void surfaceDamaged(WaylandSurface *surface, const QRect &rect); + void surfaceCreated(WaylandSurface *surface); + + WaylandSurface* surfaceAt(const QPoint &point, QPoint *local = 0); + + void render(); + +private: + QOpenGLWindow *m_window; + QImage m_backgroundImage; + GLuint m_backgroundTexture; + QList<WaylandSurface *> m_surfaces; + SurfaceRenderer *m_renderer; +}; + +#endif // QWINDOWCOMPOSITOR_H diff --git a/examples/qwindow-compositor/surfacerenderer.cpp b/examples/qwindow-compositor/surfacerenderer.cpp new file mode 100644 index 0000000..10ed41e --- /dev/null +++ b/examples/qwindow-compositor/surfacerenderer.cpp @@ -0,0 +1,109 @@ +#include "surfacerenderer.h" + +#include <QOpenGLFunctions> + +SurfaceRenderer::SurfaceRenderer(QOpenGLContext *context, QWindow *surface) + : m_context(context) + , m_surface(surface) +{ + 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"; + + const char *textureFragmentProgram = + "uniform sampler2D texture;\n" + "varying highp vec2 textureCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(texture, textureCoord);\n" + "}\n"; + + m_context->makeCurrent(m_surface); + + //Enable transparent windows + glEnable(GL_BLEND); + glBlendFunc (GL_ONE,GL_ONE_MINUS_SRC_ALPHA); + + //May need to manually set context here + m_shaderProgram = new QGLShaderProgram(); + + m_shaderProgram->addShaderFromSourceCode(QGLShader::Vertex, textureVertexProgram); + m_shaderProgram->addShaderFromSourceCode(QGLShader::Fragment, textureFragmentProgram); + m_shaderProgram->link(); + m_shaderProgram->bind(); + + m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry"); + m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry"); + m_matrixLocation = m_shaderProgram->uniformLocation("matrix"); + +} + +void SurfaceRenderer::drawImage(const QImage &image, const QRect &geometry) +{ + drawTexture(textureFromImage(image), geometry); +} + +void SurfaceRenderer::drawTexture(int textureId, const QRect &geometry, int depth) +{ + GLfloat zValue = depth / 1000.0f; + //Set Texture and Vertex coordinates + GLfloat textureCoordinates[] = { 0, 0, + 1, 0, + 1, 1, + 0, 1 + }; + + GLfloat vertexCoordinates[] = { geometry.left(), geometry.top(), zValue, + geometry.right(), geometry.top(), zValue, + geometry.right(), geometry.bottom(), zValue, + geometry.left(), geometry.bottom(), zValue + }; + + //Set matrix to transfrom geometry values into gl coordinate space. + m_transformMatrix.setToIdentity(); + m_transformMatrix.scale( 2.0f / m_surface->geometry().width(), 2.0f / m_surface->geometry().height()); + m_transformMatrix.translate(-m_surface->geometry().width() / 2.0f, -m_surface->geometry().height() / 2.0f); + + m_shaderProgram->bind(); + + //attach the data! + m_context->functions()->glEnableVertexAttribArray(m_vertexCoordEntry); + m_context->functions()->glEnableVertexAttribArray(m_textureCoordEntry); + + m_context->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); + m_context->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); + m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix); + + glBindTexture(GL_TEXTURE_2D, textureId); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindTexture(GL_TEXTURE_2D, 0); + + m_context->functions()->glDisableVertexAttribArray(m_vertexCoordEntry); + m_context->functions()->glDisableVertexAttribArray(m_textureCoordEntry); + m_shaderProgram->release(); +} + +GLuint SurfaceRenderer::textureFromImage(const QImage &image) +{ + //TODO: Replace this line + QImage convertedImage = QGLWidget::convertToGLFormat(image); + + GLuint textureId; + //Copy QImage data to Texture + glBindTexture(GL_TEXTURE_2D, textureId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, convertedImage.width(), convertedImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, convertedImage.constBits()); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + return textureId; +} diff --git a/examples/qwindow-compositor/surfacerenderer.h b/examples/qwindow-compositor/surfacerenderer.h new file mode 100644 index 0000000..df60b9d --- /dev/null +++ b/examples/qwindow-compositor/surfacerenderer.h @@ -0,0 +1,29 @@ +#ifndef SURFACERENDERER_H +#define SURFACERENDERER_H + +#include <QOpenGLContext> +#include <QGLShaderProgram> +#include <QWindow> + +class SurfaceRenderer +{ +public: + SurfaceRenderer(QOpenGLContext *context, QWindow *surface); + + void drawImage(const QImage &image, const QRect &geometry); + void drawTexture(int textureId, const QRect &geometry, int depth = 0); + GLuint textureFromImage(const QImage &image); + +private: + + QOpenGLContext *m_context; + QWindow *m_surface; + QGLShaderProgram *m_shaderProgram; + QMatrix4x4 m_transformMatrix; + + int m_matrixLocation; + int m_vertexCoordEntry; + int m_textureCoordEntry; +}; + +#endif // SURFACERENDERER_H diff --git a/src/qt-compositor/compositor_api/waylandcompositor.cpp b/src/qt-compositor/compositor_api/waylandcompositor.cpp index ee3e949..a682237 100644 --- a/src/qt-compositor/compositor_api/waylandcompositor.cpp +++ b/src/qt-compositor/compositor_api/waylandcompositor.cpp @@ -44,14 +44,16 @@ #include "wayland_wrapper/wlsurface.h" #include "wayland_wrapper/wlselection.h" #include <QtCore/QCoreApplication> +#include <QDebug> #ifdef QT_COMPOSITOR_DECLARATIVE #include "waylandsurfaceitem.h" #endif -WaylandCompositor::WaylandCompositor(QWidget *topLevelWidget, const char *socketName) +WaylandCompositor::WaylandCompositor(QWindow *window, QOpenGLContext *context, const char *socketName) : m_compositor(0) - , m_toplevel_widget(topLevelWidget) + , m_glContext(context) + , m_toplevel_widget(window) , m_socket_name(socketName) { QStringList arguments = QCoreApplication::instance()->arguments(); @@ -108,7 +110,12 @@ WaylandSurface *WaylandCompositor::directRenderSurface() const return surf ? surf->handle() : 0; } -QWidget * WaylandCompositor::topLevelWidget() const +QOpenGLContext * WaylandCompositor::glContext() const +{ + return m_glContext; +} + +QWindow * WaylandCompositor::window() const { return m_toplevel_widget; } @@ -151,3 +158,27 @@ void WaylandCompositor::setOutputGeometry(const QRect &geometry) { m_compositor->setOutputGeometry(geometry); } + +bool WaylandCompositor::isDragging() const +{ + return m_compositor->isDragging(); +} + +void WaylandCompositor::sendDragMoveEvent(const QPoint &global, const QPoint &local, + WaylandSurface *surface) +{ + m_compositor->sendDragMoveEvent(global, local, surface ? surface->handle() : 0); +} + +void WaylandCompositor::sendDragEndEvent() +{ + m_compositor->sendDragEndEvent(); +} + +void WaylandCompositor::changeCursor(const QImage &image, int hotspotX, int hotspotY) +{ + Q_UNUSED(image); + Q_UNUSED(hotspotX); + Q_UNUSED(hotspotY); + qDebug() << "changeCursor" << image.size() << hotspotX << hotspotY; +} diff --git a/src/qt-compositor/compositor_api/waylandcompositor.h b/src/qt-compositor/compositor_api/waylandcompositor.h index 1075265..11660b8 100644 --- a/src/qt-compositor/compositor_api/waylandcompositor.h +++ b/src/qt-compositor/compositor_api/waylandcompositor.h @@ -44,11 +44,9 @@ #include <QObject> #include <QImage> #include <QRect> +#include <QOpenGLContext> -#ifdef QT_COMPOSITOR_WAYLAND_GL -#include <QtOpenGL/QGLContext> -#endif - +class QGLContext; class QWidget; class QMimeData; class WaylandSurface; @@ -61,7 +59,7 @@ namespace Wayland class WaylandCompositor { public: - WaylandCompositor(QWidget *topLevelWidget = 0, const char *socketName = 0); + WaylandCompositor(QWindow *window = 0, QOpenGLContext *context = 0, const char *socketName = 0); virtual ~WaylandCompositor(); void frameFinished(WaylandSurface *surface = 0); @@ -73,7 +71,8 @@ public: void setDirectRenderSurface(WaylandSurface *surface); WaylandSurface *directRenderSurface() const; - QWidget *topLevelWidget()const; + QOpenGLContext *glContext() const; + QWindow *window()const; virtual void surfaceCreated(WaylandSurface *surface) = 0; @@ -87,11 +86,18 @@ public: void setScreenOrientation(qint32 orientationInDegrees); void setOutputGeometry(const QRect &outputGeometry); + bool isDragging() const; + void sendDragMoveEvent(const QPoint &global, const QPoint &local, WaylandSurface *surface); + void sendDragEndEvent(); + + virtual void changeCursor(const QImage &image, int hotspotX, int hotspotY); + private: static void retainedSelectionChanged(QMimeData *mimeData, void *param); Wayland::Compositor *m_compositor; - QWidget *m_toplevel_widget; + QOpenGLContext *m_glContext; + QWindow *m_toplevel_widget; QByteArray m_socket_name; }; diff --git a/src/qt-compositor/compositor_api/waylandsurfaceitem.cpp b/src/qt-compositor/compositor_api/waylandsurfaceitem.cpp index e503a03..31889d7 100644 --- a/src/qt-compositor/compositor_api/waylandsurfaceitem.cpp +++ b/src/qt-compositor/compositor_api/waylandsurfaceitem.cpp @@ -49,29 +49,32 @@ #include <QtDeclarative/QSGSimpleRectNode> #include <QtDeclarative/QSGCanvas> -void WaylandSurfaceItem::surfaceDamaged(const QRect &) +class WaylandSurfaceTextureProvider : public QSGTextureProvider { - QSGTexture *oldTexture = m_texture; - - if (m_surface->type() == WaylandSurface::Texture) { - QSGEngine::TextureOption opt = useTextureAlpha() ? QSGEngine::TextureHasAlphaChannel : QSGEngine::TextureOption(0); +public: + WaylandSurfaceTextureProvider() : t(0) { } - m_texture = canvas()->sceneGraphEngine()->createTextureFromId(m_surface->texture(), - m_surface->geometry().size(), - opt); - } else { - m_texture = canvas()->sceneGraphEngine()->createTextureFromImage(m_surface->image()); + QSGTexture *texture() const { + if (t) + t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest); + return t; } - delete oldTexture; + QSGTexture *t; + bool smooth; +}; - emit textureChanged(); +void WaylandSurfaceItem::surfaceDamaged(const QRect &) +{ + m_damaged = true; + update(); } WaylandSurfaceItem::WaylandSurfaceItem(QSGItem *parent) : QSGItem(parent) , m_surface(0) , m_texture(0) + , m_provider(0) , m_paintEnabled(true) , m_touchEventsEnabled(false) { @@ -81,6 +84,7 @@ WaylandSurfaceItem::WaylandSurfaceItem(WaylandSurface *surface, QSGItem *parent) : QSGItem(parent) , m_surface(0) , m_texture(0) + , m_provider(0) , m_paintEnabled(true) , m_touchEventsEnabled(false) { @@ -102,14 +106,15 @@ void WaylandSurfaceItem::init(WaylandSurface *surface) setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); connect(surface, SIGNAL(mapped(const QSize &)), this, SLOT(surfaceMapped(const QSize &))); connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); - connect(this, SIGNAL(textureChanged()), this, SLOT(update())); connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &))); + m_damaged = false; + } WaylandSurfaceItem::~WaylandSurfaceItem() { - delete m_texture; + m_texture->deleteLater(); } void WaylandSurfaceItem::setSurface(WaylandSurface *surface) @@ -122,26 +127,26 @@ bool WaylandSurfaceItem::isYInverted() const return m_surface->isYInverted(); } -QSGTexture *WaylandSurfaceItem::texture() const +QSGTextureProvider *WaylandSurfaceItem::textureProvider() const { - if (m_texture) - m_texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); - return m_texture; + if (!m_provider) + m_provider = new WaylandSurfaceTextureProvider(); + return m_provider; } -void WaylandSurfaceItem::mousePressEvent(QGraphicsSceneMouseEvent *event) +void WaylandSurfaceItem::mousePressEvent(QMouseEvent *event) { if (m_surface) m_surface->sendMousePressEvent(toSurface(event->pos()), event->button()); } -void WaylandSurfaceItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +void WaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event) { if (m_surface) m_surface->sendMouseMoveEvent(toSurface(event->pos())); } -void WaylandSurfaceItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +void WaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event) { if (m_surface) m_surface->sendMouseReleaseEvent(toSurface(event->pos()), event->button()); @@ -216,6 +221,25 @@ QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa { QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode); + if (m_damaged) { + QSGTexture *oldTexture = m_texture; + if (m_surface->type() == WaylandSurface::Texture) { + QSGEngine::TextureOption opt = useTextureAlpha() ? QSGEngine::TextureHasAlphaChannel : QSGEngine::TextureOption(0); + m_texture = canvas()->sceneGraphEngine()->createTextureFromId(m_surface->texture(), + m_surface->geometry().size(), + opt); + } else { + m_texture = canvas()->sceneGraphEngine()->createTextureFromImage(m_surface->image()); + } + delete oldTexture; + m_damaged = false; + } + + if (m_provider) { + m_provider->t = m_texture; + m_provider->smooth = smooth(); + } + if (!m_texture || !m_paintEnabled) { delete oldNode; return 0; @@ -255,7 +279,7 @@ void WaylandSurfaceItem::setClientRenderingEnabled(bool enabled) m_surface->sendOnScreenVisibilityChange(enabled); } - emit clientRenderingEnabledChanged(); + emit clientRenderingEnabledChanged(); } } diff --git a/src/qt-compositor/compositor_api/waylandsurfaceitem.h b/src/qt-compositor/compositor_api/waylandsurfaceitem.h index bc296b5..95b1429 100644 --- a/src/qt-compositor/compositor_api/waylandsurfaceitem.h +++ b/src/qt-compositor/compositor_api/waylandsurfaceitem.h @@ -47,12 +47,13 @@ #include <private/qsgtextureprovider_p.h> class WaylandSurface; +class WaylandSurfaceTextureProvider; + Q_DECLARE_METATYPE(WaylandSurface*) -class WaylandSurfaceItem : public QSGItem, public QSGTextureProvider +class WaylandSurfaceItem : public QSGItem { Q_OBJECT - Q_INTERFACES(QSGTextureProvider) Q_PROPERTY(WaylandSurface* surface READ surface WRITE setSurface) Q_PROPERTY(bool paintEnabled READ paintEnabled WRITE setPaintEnabled) Q_PROPERTY(bool useTextureAlpha READ useTextureAlpha WRITE setUseTextureAlpha NOTIFY useTextureAlphaChanged) @@ -69,8 +70,8 @@ public: Q_INVOKABLE bool isYInverted() const; - QSGTexture *texture() const; - const char *textureChangedSignal() const { return SIGNAL(textureChanged()); } + bool isTextureProvider() const { return true; } + QSGTextureProvider *textureProvider() const; bool paintEnabled() const; bool useTextureAlpha() const { return m_useTextureAlpha; } @@ -82,9 +83,9 @@ public: void setTouchEventsEnabled(bool enabled); protected: - void mousePressEvent(QGraphicsSceneMouseEvent *event); - void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); @@ -101,7 +102,6 @@ private slots: void surfaceDamaged(const QRect &); signals: - void textureChanged(); void useTextureAlphaChanged(); void clientRenderingEnabledChanged(); void touchEventsEnabledChanged(); @@ -115,10 +115,12 @@ private: WaylandSurface *m_surface; QSGTexture *m_texture; + mutable WaylandSurfaceTextureProvider *m_provider; bool m_paintEnabled; bool m_useTextureAlpha; bool m_clientRenderingEnabled; bool m_touchEventsEnabled; + bool m_damaged; }; #endif diff --git a/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbbuffer.h b/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbbuffer.h index d2649ce..61d431d 100644 --- a/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbbuffer.h +++ b/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbbuffer.h @@ -7,7 +7,7 @@ #include <wayland-server.h> #include <QtCore/QSize> -#include <QtGui/QApplication> +#include <QtWidgets/QApplication> #include <QtCore/QTextStream> #include <QtGui/QPlatformNativeInterface> diff --git a/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbhwintegration.cpp b/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbhwintegration.cpp index 6e6bb53..0b021d3 100644 --- a/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbhwintegration.cpp +++ b/src/qt-compositor/hardware_integration/dri2_xcb/dri2xcbhwintegration.cpp @@ -22,15 +22,15 @@ GraphicsHardwareIntegration * GraphicsHardwareIntegration::createGraphicsHardwar class DrmObject : public Wayland::Object<struct wl_object> { public: - DrmObject(Wayland::Compositor *compositor, QWidget *topLevelWidget) + DrmObject(Wayland::Compositor *compositor, QWidget *window) :m_compositor(compositor) { QPlatformNativeInterface *nativeInterface = QApplicationPrivate::platformIntegration()->nativeInterface(); - char *deviceName = static_cast<char *>(nativeInterface->nativeResourceForWidget("GraphicsDevice",topLevelWidget)); + char *deviceName = static_cast<char *>(nativeInterface->nativeResourceForWidget("GraphicsDevice",window)); m_device_name = QByteArray(deviceName); - m_connection = static_cast<xcb_connection_t *>(nativeInterface->nativeResourceForWidget("Connection",topLevelWidget)); - m_egl_display = static_cast<EGLDisplay>(nativeInterface->nativeResourceForWidget("EglDisplay",topLevelWidget)); + m_connection = static_cast<xcb_connection_t *>(nativeInterface->nativeResourceForWidget("Connection",window)); + m_egl_display = static_cast<EGLDisplay>(nativeInterface->nativeResourceForWidget("EglDisplay",window)); } QByteArray deviceName() { @@ -108,10 +108,10 @@ Dri2XcbHWIntegration::Dri2XcbHWIntegration(WaylandCompositor *compositor) void Dri2XcbHWIntegration::initializeHardware(Wayland::Display *waylandDisplay) { //we need a winId now. - m_compositor->topLevelWidget()->winId(); + m_compositor->window()->winId(); - m_drm_object = new DrmObject(m_compositor->handle(),m_compositor->topLevelWidget()); + m_drm_object = new DrmObject(m_compositor->handle(),m_compositor->window()); waylandDisplay->addGlobalObject(m_drm_object->base(),&wl_drm_interface,&drm_interface,post_drm_device); } diff --git a/src/qt-compositor/hardware_integration/hardware_integration.pri b/src/qt-compositor/hardware_integration/hardware_integration.pri index f5a1568..c67d99c 100644 --- a/src/qt-compositor/hardware_integration/hardware_integration.pri +++ b/src/qt-compositor/hardware_integration/hardware_integration.pri @@ -1,6 +1,6 @@ isEmpty(QT_WAYLAND_GL_CONFIG):QT_WAYLAND_GL_CONFIG = $$(QT_WAYLAND_GL_CONFIG) -contains(QT_CONFIG, opengl):!isEqual(QT_WAYLAND_GL_CONFIG,nogl) { +!mac:contains(QT_CONFIG, opengl):!isEqual(QT_WAYLAND_GL_CONFIG,nogl) { HEADERS += \ $$PWD/graphicshardwareintegration.h @@ -35,7 +35,7 @@ contains(QT_CONFIG, opengl):!isEqual(QT_WAYLAND_GL_CONFIG,nogl) { } mesa_egl { - include (mesa_egl/mesa_egl.pri) + include (wayland_egl/wayland_egl.pri) } dri2_xcb { include (dri2_xcb/dri2_xcb.pri) diff --git a/src/qt-compositor/hardware_integration/mesa_egl/mesa_egl.pri b/src/qt-compositor/hardware_integration/wayland_egl/wayland_egl.pri index 1ac2dad..2589239 100644 --- a/src/qt-compositor/hardware_integration/mesa_egl/mesa_egl.pri +++ b/src/qt-compositor/hardware_integration/wayland_egl/wayland_egl.pri @@ -3,7 +3,7 @@ LIBS += -lEGL DEFINES += QT_COMPOSITOR_MESA_EGL SOURCES += \ - $$PWD/mesaeglintegration.cpp + $$PWD/waylandeglintegration.cpp HEADERS += \ - $$PWD/mesaeglintegration.h + $$PWD/waylandeglintegration.h diff --git a/src/qt-compositor/hardware_integration/mesa_egl/mesaeglintegration.cpp b/src/qt-compositor/hardware_integration/wayland_egl/waylandeglintegration.cpp index c47754c..e20c262 100644 --- a/src/qt-compositor/hardware_integration/mesa_egl/mesaeglintegration.cpp +++ b/src/qt-compositor/hardware_integration/wayland_egl/waylandeglintegration.cpp @@ -38,10 +38,11 @@ ** ****************************************************************************/ -#include "mesaeglintegration.h" +#include "waylandeglintegration.h" -#include <QtGui/QApplication> #include <QtGui/QPlatformNativeInterface> +#include <QtGui/QGuiApplication> +#include <QtGui/QOpenGLContext> #define EGL_EGLEXT_PROTOTYPES #include <EGL/egl.h> @@ -53,13 +54,13 @@ GraphicsHardwareIntegration * GraphicsHardwareIntegration::createGraphicsHardwareIntegration(WaylandCompositor *compositor) { - return new MesaEglIntegration(compositor); + return new WaylandEglIntegration(compositor); } -class MesaEglIntegrationPrivate +class WaylandEglIntegrationPrivate { public: - MesaEglIntegrationPrivate() + WaylandEglIntegrationPrivate() : egl_display(EGL_NO_DISPLAY) , egl_context(EGL_NO_CONTEXT) { } @@ -68,22 +69,22 @@ public: bool valid; }; -MesaEglIntegration::MesaEglIntegration(WaylandCompositor *compositor) +WaylandEglIntegration::WaylandEglIntegration(WaylandCompositor *compositor) : GraphicsHardwareIntegration(compositor) - , d_ptr(new MesaEglIntegrationPrivate) + , d_ptr(new WaylandEglIntegrationPrivate) { d_ptr->valid = false; } -void MesaEglIntegration::initializeHardware(Wayland::Display *waylandDisplay) +void WaylandEglIntegration::initializeHardware(Wayland::Display *waylandDisplay) { - Q_D(MesaEglIntegration); + Q_D(WaylandEglIntegration); //We need a window id now :) - m_compositor->topLevelWidget()->winId(); + m_compositor->window()->winId(); - QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface(); + QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); if (nativeInterface) { - d->egl_display = nativeInterface->nativeResourceForWidget("EglDisplay",m_compositor->topLevelWidget()); + d->egl_display = nativeInterface->nativeResourceForWindow("EglDisplay", m_compositor->window()); if (d->egl_display) { const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS); if (extensionString && strstr(extensionString, "EGL_WL_bind_wayland_display") @@ -94,17 +95,17 @@ void MesaEglIntegration::initializeHardware(Wayland::Display *waylandDisplay) } if (!d->valid) - fprintf(stderr, "Failed to initialize egl display\n"); + qWarning("Failed to initialize egl display\n"); - d->egl_context = nativeInterface->nativeResourceForWidget("EglContext",m_compositor->topLevelWidget()); + d->egl_context = nativeInterface->nativeResourceForContext("EglContext", m_compositor->glContext()); } } -GLuint MesaEglIntegration::createTextureFromBuffer(wl_buffer *buffer) +GLuint WaylandEglIntegration::createTextureFromBuffer(wl_buffer *buffer) { - Q_D(MesaEglIntegration); + Q_D(WaylandEglIntegration); if (!d->valid) { - fprintf(stderr, "createTextureFromBuffer() failed\n"); + qWarning("createTextureFromBuffer() failed\n"); return 0; } diff --git a/src/qt-compositor/hardware_integration/mesa_egl/mesaeglintegration.h b/src/qt-compositor/hardware_integration/wayland_egl/waylandeglintegration.h index a70fc85..f727051 100644 --- a/src/qt-compositor/hardware_integration/mesa_egl/mesaeglintegration.h +++ b/src/qt-compositor/hardware_integration/wayland_egl/waylandeglintegration.h @@ -38,27 +38,27 @@ ** ****************************************************************************/ -#ifndef MESAEGLINTEGRATION_H -#define MESAEGLINTEGRATION_H +#ifndef WAYLANDEGLINTEGRATION_H +#define WAYLANDEGLINTEGRATION_H #include "hardware_integration/graphicshardwareintegration.h" #include <QtCore/QScopedPointer> -class MesaEglIntegrationPrivate; +class WaylandEglIntegrationPrivate; -class MesaEglIntegration : public GraphicsHardwareIntegration +class WaylandEglIntegration : public GraphicsHardwareIntegration { - Q_DECLARE_PRIVATE(MesaEglIntegration) + Q_DECLARE_PRIVATE(WaylandEglIntegration) public: - MesaEglIntegration(WaylandCompositor *compositor); + WaylandEglIntegration(WaylandCompositor *compositor); void initializeHardware(Wayland::Display *waylandDisplay); GLuint createTextureFromBuffer(wl_buffer *buffer); private: - Q_DISABLE_COPY(MesaEglIntegration) - QScopedPointer<MesaEglIntegrationPrivate> d_ptr; + Q_DISABLE_COPY(WaylandEglIntegration) + QScopedPointer<WaylandEglIntegrationPrivate> d_ptr; }; -#endif // MESAEGLINTEGRATION_H +#endif // WAYLANDEGLINTEGRATION_H diff --git a/src/qt-compositor/hardware_integration/xcomposite_egl/xcompositeeglintegration.cpp b/src/qt-compositor/hardware_integration/xcomposite_egl/xcompositeeglintegration.cpp index 511072d..3f47fd9 100644 --- a/src/qt-compositor/hardware_integration/xcomposite_egl/xcompositeeglintegration.cpp +++ b/src/qt-compositor/hardware_integration/xcomposite_egl/xcompositeeglintegration.cpp @@ -4,7 +4,7 @@ #include "wayland_wrapper/wlcompositor.h" #include "wayland-xcomposite-server-protocol.h" -#include <QtGui/QApplication> +#include <QtWidgets/QApplication> #include <QtGui/QPlatformNativeInterface> #include <QtGui/QPlatformGLContext> @@ -42,10 +42,10 @@ XCompositeEglIntegration::XCompositeEglIntegration(WaylandCompositor *compositor { QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface(); if (nativeInterface) { - mDisplay = static_cast<Display *>(nativeInterface->nativeResourceForWidget("Display",m_compositor->topLevelWidget())); + mDisplay = static_cast<Display *>(nativeInterface->nativeResourceForWidget("Display",m_compositor->window())); if (!mDisplay) qFatal("could not retireve Display from platform integration"); - mEglDisplay = static_cast<EGLDisplay>(nativeInterface->nativeResourceForWidget("EGLDisplay",m_compositor->topLevelWidget())); + mEglDisplay = static_cast<EGLDisplay>(nativeInterface->nativeResourceForWidget("EGLDisplay",m_compositor->window())); if (!mEglDisplay) qFatal("could not retrieve EGLDisplay from plaform integration"); } else { @@ -56,11 +56,8 @@ XCompositeEglIntegration::XCompositeEglIntegration(WaylandCompositor *compositor void XCompositeEglIntegration::initializeHardware(Wayland::Display *waylandDisplay) { - XCompositeHandler *handler = new XCompositeHandler(m_compositor->handle(),mDisplay,m_compositor->topLevelWidget()); + XCompositeHandler *handler = new XCompositeHandler(m_compositor->handle(),mDisplay,m_compositor->window()); waylandDisplay->addGlobalObject(handler->base(), &wl_xcomposite_interface, &XCompositeHandler::xcomposite_interface,XCompositeHandler::send_root_information); - - QPlatformGLContext *glContext = m_compositor->topLevelWidget()->platformWindow()->glContext(); - } GLuint XCompositeEglIntegration::createTextureFromBuffer(wl_buffer *buffer) diff --git a/src/qt-compositor/hardware_integration/xcomposite_glx/xcompositeglxintegration.cpp b/src/qt-compositor/hardware_integration/xcomposite_glx/xcompositeglxintegration.cpp index 9ce38a9..f109414 100644 --- a/src/qt-compositor/hardware_integration/xcomposite_glx/xcompositeglxintegration.cpp +++ b/src/qt-compositor/hardware_integration/xcomposite_glx/xcompositeglxintegration.cpp @@ -4,9 +4,8 @@ #include "wayland_wrapper/wlcompositor.h" #include "wayland-xcomposite-server-protocol.h" -#include <QtGui/QApplication> #include <QtGui/QPlatformNativeInterface> -#include <QtGui/QPlatformGLContext> +#include <QtGui/QOpenGLContext> #include "xcompositebuffer.h" #include "xcompositehandler.h" @@ -43,9 +42,9 @@ XCompositeGLXIntegration::XCompositeGLXIntegration(WaylandCompositor *compositor : GraphicsHardwareIntegration(compositor) , mDisplay(0) { - QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface(); + QPlatformNativeInterface *nativeInterface = QGuiApplicationPrivate::platformIntegration()->nativeInterface(); if (nativeInterface) { - mDisplay = static_cast<Display *>(nativeInterface->nativeResourceForWidget("Display",m_compositor->topLevelWidget())); + mDisplay = static_cast<Display *>(nativeInterface->nativeResourceForWindow("Display",m_compositor->window())); if (!mDisplay) qFatal("could not retireve Display from platform integration"); } else { @@ -56,10 +55,11 @@ XCompositeGLXIntegration::XCompositeGLXIntegration(WaylandCompositor *compositor void XCompositeGLXIntegration::initializeHardware(Wayland::Display *waylandDisplay) { - XCompositeHandler *handler = new XCompositeHandler(m_compositor->handle(),mDisplay,m_compositor->topLevelWidget()); + XCompositeHandler *handler = new XCompositeHandler(m_compositor->handle(),mDisplay,m_compositor->window()); waylandDisplay->addGlobalObject(handler->base(), &wl_xcomposite_interface, &XCompositeHandler::xcomposite_interface,XCompositeHandler::send_root_information); - QPlatformGLContext *glContext = m_compositor->topLevelWidget()->platformWindow()->glContext(); + QOpenGLContext *glContext = new QOpenGLContext(); + glContext->create(); m_glxBindTexImageEXT = reinterpret_cast<PFNGLXBINDTEXIMAGEEXTPROC>(glContext->getProcAddress("glXBindTexImageEXT")); if (!m_glxBindTexImageEXT) { @@ -69,6 +69,8 @@ void XCompositeGLXIntegration::initializeHardware(Wayland::Display *waylandDispl if (!m_glxReleaseTexImageEXT) { qDebug() << "Did not find glxReleaseTexImageExt"; } + + delete glContext; } GLuint XCompositeGLXIntegration::createTextureFromBuffer(wl_buffer *buffer) diff --git a/src/qt-compositor/hardware_integration/xcomposite_share/xcomposite_share.pri b/src/qt-compositor/hardware_integration/xcomposite_share/xcomposite_share.pri index 31faa90..e4001a5 100644 --- a/src/qt-compositor/hardware_integration/xcomposite_share/xcomposite_share.pri +++ b/src/qt-compositor/hardware_integration/xcomposite_share/xcomposite_share.pri @@ -10,3 +10,5 @@ SOURCES += \ $$PWD/wayland-xcomposite-protocol.c \ $$PWD/xcompositebuffer.cpp \ $$PWD/xcompositehandler.cpp + +QT += gui-private diff --git a/src/qt-compositor/hardware_integration/xcomposite_share/xcompositebuffer.h b/src/qt-compositor/hardware_integration/xcomposite_share/xcompositebuffer.h index 42b20ee..5c34e4b 100644 --- a/src/qt-compositor/hardware_integration/xcomposite_share/xcompositebuffer.h +++ b/src/qt-compositor/hardware_integration/xcomposite_share/xcompositebuffer.h @@ -10,7 +10,7 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtWidgets/QWidget> #include <X11/X.h> diff --git a/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.cpp b/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.cpp index bb10bba..4a64eb8 100644 --- a/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.cpp +++ b/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.cpp @@ -5,14 +5,13 @@ #include "xcompositebuffer.h" #include <X11/extensions/Xcomposite.h> -XCompositeHandler::XCompositeHandler(Wayland::Compositor *compositor, Display *display, QWidget *topLevelWidget) +XCompositeHandler::XCompositeHandler(Wayland::Compositor *compositor, Display *display, QWindow *window) : mCompositor(compositor) - , mTopLevelWidget(topLevelWidget) + , mwindow(window) , mDisplay(display) { - mFakeRootWidget = new QWidget(mCompositor->topLevelWidget()); - mFakeRootWidget->setGeometry(-1,-1,1,1); - mFakeRootWidget->setAttribute(Qt::WA_NativeWindow); + mFakeRootWidget = new QWindow(mCompositor->window()); + mFakeRootWidget->setGeometry(QRect(-1,-1,1,1)); int composite_event_base, composite_error_base; if (XCompositeQueryExtension(mDisplay, &composite_event_base, &composite_error_base)) { diff --git a/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.h b/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.h index dc85473..7126e14 100644 --- a/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.h +++ b/src/qt-compositor/hardware_integration/xcomposite_share/xcompositehandler.h @@ -8,7 +8,7 @@ class XCompositeHandler : public Wayland::Object<struct wl_object> { public: - XCompositeHandler(Wayland::Compositor *compositor, Display *display, QWidget *topLevelWidget); + XCompositeHandler(Wayland::Compositor *compositor, Display *display, QWindow *window); void createBuffer(struct wl_client *client, uint32_t id, Window window, const QSize &size, struct wl_visual *visual); static void send_root_information(struct wl_client *client, struct wl_object *global, uint32_t version); @@ -16,8 +16,8 @@ public: private: Wayland::Compositor *mCompositor; - QWidget *mTopLevelWidget; - QWidget *mFakeRootWidget; + QWindow *mwindow; + QWindow *mFakeRootWidget; Display *mDisplay; static void create_buffer(struct wl_client *client, diff --git a/src/qt-compositor/hardware_integration/xcomposite_share/xlibinclude.h b/src/qt-compositor/hardware_integration/xcomposite_share/xlibinclude.h index 9253776..dfb0c29 100644 --- a/src/qt-compositor/hardware_integration/xcomposite_share/xlibinclude.h +++ b/src/qt-compositor/hardware_integration/xcomposite_share/xlibinclude.h @@ -7,6 +7,7 @@ #include <QtCore/QMetaType> #include <QtCore/QVariant> #include <QtGui/QCursor> +#include <QtGui/private/qguiapplication_p.h> #include <X11/Xlib.h> #include "X11/extensions/Xcomposite.h" diff --git a/src/qt-compositor/qt-compositor.pri b/src/qt-compositor/qt-compositor.pri index ee143e3..a791985 100644 --- a/src/qt-compositor/qt-compositor.pri +++ b/src/qt-compositor/qt-compositor.pri @@ -1,10 +1,9 @@ INCLUDEPATH += $$PWD DEFINES += QT_WAYLAND_WINDOWMANAGER_SUPPORT -use_pkgconfig { +!mac:use_pkgconfig { QMAKE_CXXFLAGS += $$system(pkg-config --cflags wayland-server) - #for some reason this is not included in the cflags line - INCLUDEPATH += $$system(pkg-config --variable=includedir wayland-server) + LIBS += $$system(pkg-config --libs wayland-server) #set the rpath diff --git a/src/qt-compositor/qt-compositor.pro b/src/qt-compositor/qt-compositor.pro index 1e11e89..d24766d 100644 --- a/src/qt-compositor/qt-compositor.pro +++ b/src/qt-compositor/qt-compositor.pro @@ -11,3 +11,6 @@ headers.path = $$headers_path/qt-compositor headers.files = $$HEADERS INSTALLS = target headers + +QT += gui-private +QT += widgets-private diff --git a/src/qt-compositor/wayland_wrapper/wayland_wrapper.pri b/src/qt-compositor/wayland_wrapper/wayland_wrapper.pri index 348267e..16a0e7e 100644 --- a/src/qt-compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/qt-compositor/wayland_wrapper/wayland_wrapper.pri @@ -4,7 +4,8 @@ HEADERS += \ $$PWD/wloutput.h \ $$PWD/wlshmbuffer.h \ $$PWD/wlsurface.h \ - $$PWD/wlselection.h + $$PWD/wlselection.h \ + $$PWD/wldrag.h SOURCES += \ $$PWD/wlcompositor.cpp \ @@ -12,4 +13,5 @@ SOURCES += \ $$PWD/wloutput.cpp \ $$PWD/wlshmbuffer.cpp \ $$PWD/wlsurface.cpp \ - $$PWD/wlselection.cpp + $$PWD/wlselection.cpp \ + $$PWD/wldrag.cpp diff --git a/src/qt-compositor/wayland_wrapper/wlcompositor.cpp b/src/qt-compositor/wayland_wrapper/wlcompositor.cpp index 032e14d..453a9ac 100644 --- a/src/qt-compositor/wayland_wrapper/wlcompositor.cpp +++ b/src/qt-compositor/wayland_wrapper/wlcompositor.cpp @@ -45,11 +45,9 @@ #include "wlshmbuffer.h" #include "wlsurface.h" #include "wlselection.h" +#include "wldrag.h" #include "waylandcompositor.h" -#include <QApplication> -#include <QDesktopWidget> - #include <QSocketNotifier> #include <QDebug> @@ -72,6 +70,18 @@ namespace Wayland { +static Compositor *compositor; + +static ShmBuffer *currentCursor; + +static void shmBufferDestroyed(ShmBuffer *buf) +{ + if (currentCursor == buf) { + compositor->qtCompositor()->changeCursor(QImage(), 0, 0); + currentCursor = 0; + } +} + void input_device_attach(struct wl_client *client, struct wl_input_device *device_base, uint32_t time, @@ -80,11 +90,16 @@ void input_device_attach(struct wl_client *client, Q_UNUSED(client); Q_UNUSED(device_base); Q_UNUSED(time); - Q_UNUSED(buffer); Q_UNUSED(x); Q_UNUSED(y); - qDebug() << "Client %p input device attach" << client; + qDebug() << "Client input device attach" << client << buffer << x << y; + + ShmBuffer *shmBuffer = static_cast<ShmBuffer *>(buffer->user_data); + if (shmBuffer) { + compositor->qtCompositor()->changeCursor(shmBuffer->image(), x, y); + currentCursor = shmBuffer; + } } const static struct wl_input_device_interface input_device_interface = { @@ -142,10 +157,9 @@ void shell_drag(struct wl_client *client, struct wl_shell *shell, uint32_t id) { - Q_UNUSED(client); Q_UNUSED(shell); - Q_UNUSED(id); qDebug() << "shellDrag"; + Drag::instance()->create(client, id); } void shell_selection(struct wl_client *client, @@ -189,8 +203,6 @@ const static struct wl_shell_interface shell_interface = { set_fullscreen }; -static Compositor *compositor; - Compositor *Compositor::instance() { return compositor; @@ -208,11 +220,14 @@ Compositor::Compositor(WaylandCompositor *qt_compositor) #if defined (QT_COMPOSITOR_WAYLAND_GL) , m_graphics_hw_integration(0) #endif + , m_dragActive(false) { compositor = this; + m_shm.addDestroyCallback(shmBufferDestroyed); #if defined (QT_COMPOSITOR_WAYLAND_GL) - if (qt_compositor->topLevelWidget()->platformWindowFormat().windowApi() != QPlatformWindowFormat::Raster) + QWindow *window = qt_compositor->window(); + if (window && window->surfaceType() != QWindow::RasterSurface) m_graphics_hw_integration = GraphicsHardwareIntegration::createGraphicsHardwareIntegration(qt_compositor); #endif m_windowManagerWaylandProtocol = new WindowManagerServerIntegration(this); @@ -396,9 +411,9 @@ Surface *Compositor::pointerFocus() const return m_pointerFocusSurface; } -QWidget * Compositor::topLevelWidget() const +QWindow *Compositor::window() const { - return m_qt_compositor->topLevelWidget(); + return m_qt_compositor->window(); } GraphicsHardwareIntegration * Compositor::graphicsHWIntegration() const @@ -480,3 +495,18 @@ QList<Wayland::Surface *> Wayland::Compositor::surfacesForClient(wl_client *clie return ret; } +bool Wayland::Compositor::isDragging() const +{ + return m_dragActive; +} + +void Wayland::Compositor::sendDragMoveEvent(const QPoint &global, const QPoint &local, + Surface *surface) +{ + Drag::instance()->dragMove(global, local, surface); +} + +void Wayland::Compositor::sendDragEndEvent() +{ + Drag::instance()->dragEnd(); +} diff --git a/src/qt-compositor/wayland_wrapper/wlcompositor.h b/src/qt-compositor/wayland_wrapper/wlcompositor.h index 647bdf6..6f357ab 100644 --- a/src/qt-compositor/wayland_wrapper/wlcompositor.h +++ b/src/qt-compositor/wayland_wrapper/wlcompositor.h @@ -51,7 +51,6 @@ class WaylandCompositor; class GraphicsHardwareIntegration; -class QWidget; class WindowManagerServerIntegration; namespace Wayland { @@ -88,7 +87,7 @@ public: static uint currentTimeMsecs(); - QWidget *topLevelWidget() const; + QWindow *window() const; GraphicsHardwareIntegration *graphicsHWIntegration() const; void initializeHardwareIntegration(); @@ -110,6 +109,10 @@ public: void setScreenOrientation(qint32 orientationInDegrees); void setOutputGeometry(const QRect &geometry); + bool isDragging() const; + void sendDragMoveEvent(const QPoint &global, const QPoint &local, Surface *surface); + void sendDragEndEvent(); + signals: void clientAdded(wl_client *client); @@ -149,6 +152,9 @@ private: GraphicsHardwareIntegration *m_graphics_hw_integration; #endif WindowManagerServerIntegration *m_windowManagerWaylandProtocol; + + bool m_dragActive; + friend class Drag; }; } diff --git a/src/qt-compositor/wayland_wrapper/wldrag.cpp b/src/qt-compositor/wayland_wrapper/wldrag.cpp new file mode 100644 index 0000000..734d617 --- /dev/null +++ b/src/qt-compositor/wayland_wrapper/wldrag.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** This file is part of QtCompositor** +** +** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** Contact: Nokia Corporation qt-info@nokia.com +** +** 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 Nokia Corporation and its Subsidiary(-ies) 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. +** +****************************************************************************/ + +#include "wldrag.h" +#include "wlcompositor.h" +#include "wlsurface.h" +#include <wayland-util.h> +#include <string.h> +#include <unistd.h> +#include <QDebug> + +namespace Wayland { + +void Drag::dragOfferAccept(struct wl_client *client, + struct wl_drag_offer *offer, uint32_t time, const char *type) +{ + qDebug() << "dragOfferAccept" << client << offer << type; + Q_UNUSED(time); + Drag *self = Drag::instance(); + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + drag->target = client; + QString wantedType = QString::fromLatin1(type); + if (!self->m_offerList.contains(wantedType)) { + qWarning("dragOfferAccept: Client accepted type '%s' that has not been offered", + qPrintable(type)); + type = 0; + } + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_TARGET, type); +} + +void Drag::dragOfferReceive(struct wl_client *client, + struct wl_drag_offer *offer, int fd) +{ + qDebug() << "dragOfferReceive" << client << offer << fd; + Q_UNUSED(client); + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_FINISH, fd); + close(fd); +} + +void Drag::dragOfferReject(struct wl_client *client, struct wl_drag_offer *offer) +{ + qDebug() << "dragOfferReject" << client << offer; + Q_UNUSED(client); + struct wl_drag *drag = container_of(offer, struct wl_drag, drag_offer); + if (drag->target == client) + drag->target = 0; + wl_client_post_event(drag->source->client, &drag->resource.object, + WL_DRAG_REJECT); +} + +const struct wl_drag_offer_interface Drag::dragOfferInterface = { + Drag::dragOfferAccept, + Drag::dragOfferReceive, + Drag::dragOfferReject +}; + +void Drag::dragOffer(struct wl_client *client, struct wl_drag *drag, const char *type) +{ + qDebug() << "dragOffer" << client << drag << type; + Q_UNUSED(client); + Q_UNUSED(drag); + instance()->m_offerList.append(QString::fromLatin1(type)); +} + +void Drag::dragActivate(struct wl_client *client, + struct wl_drag *drag, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time) +{ + qDebug() << "dragActivate" << client << drag << surface; + Q_UNUSED(client); + Q_UNUSED(device); + Q_UNUSED(time); + Drag *self = Drag::instance(); + drag->source = surface; + drag->drag_offer.object.interface = &wl_drag_offer_interface; + drag->drag_offer.object.implementation = (void (**)()) &dragOfferInterface; + wl_display *dpy = Compositor::instance()->wl_display(); + wl_display_add_object(dpy, &drag->drag_offer.object); + wl_display_add_global(dpy, &drag->drag_offer.object, 0); + Surface *focus = Compositor::instance()->pointerFocus(); + QPoint pos; + if (focus) + pos = focus->lastMousePos(); + // ### Sending local as global, which is wrong, but oh well. + self->setPointerFocus(surface, pos, pos); +} + +void Drag::setPointerFocus(wl_surface *surface, const QPoint &global, const QPoint &local) +{ + if (!m_drag) + return; + + if (m_drag->drag_focus == surface) + return; + + uint timestamp = Compositor::currentTimeMsecs(); + if (m_drag->drag_focus + && (!surface || m_drag->drag_focus->client != surface->client)) { + qDebug() << "WL_DRAG_OFFER_POINTER_FOCUS with null"; + wl_client_post_event(m_drag->drag_focus->client, + &m_drag->drag_offer.object, + WL_DRAG_OFFER_POINTER_FOCUS, + timestamp, 0, 0, 0, 0, 0); + } + if (surface + && (!m_drag->drag_focus || m_drag->drag_focus->client != surface->client)) { + wl_client_post_global(surface->client, + &m_drag->drag_offer.object); + foreach (const QString &format, m_offerList) { + QByteArray mimeTypeBa = format.toLatin1(); + qDebug() << "WL_DRAG_OFFER_OFFER" << mimeTypeBa; + wl_client_post_event(surface->client, &m_drag->drag_offer.object, + WL_DRAG_OFFER_OFFER, mimeTypeBa.constData()); + } + } + + if (surface) { + qDebug() << "WL_DRAG_OFFER_POINTER_FOCUS" << surface << global << local; + wl_client_post_event(surface->client, + &m_drag->drag_offer.object, + WL_DRAG_OFFER_POINTER_FOCUS, + timestamp, surface, + global.x(), global.y(), local.x(), local.y()); + Compositor::instance()->m_dragActive = true; + } + + m_drag->drag_focus = surface; + m_drag->target = 0; +} + +void Drag::dragDestroy(struct wl_client *client, struct wl_drag *drag) +{ + qDebug() << "dragDestroy"; + wl_resource_destroy(&drag->resource, client, Compositor::currentTimeMsecs()); +} + +const struct wl_drag_interface Drag::dragInterface = { + Drag::dragOffer, + Drag::dragActivate, + Drag::dragDestroy +}; + +void Drag::destroyDrag(struct wl_resource *resource, struct wl_client *client) +{ + Q_UNUSED(client); + struct wl_drag *drag = container_of(resource, struct wl_drag, resource); + wl_display *dpy = Compositor::instance()->wl_display(); + wl_display_remove_global(dpy, &drag->drag_offer.object); + delete drag; +} + +void Drag::create(struct wl_client *client, uint32_t id) +{ + Q_UNUSED(client); + m_offerList.clear(); + wl_drag *drag = new wl_drag; + memset(drag, 0, sizeof *drag); + drag->resource.object.id = id; + drag->resource.object.interface = &wl_drag_interface; + drag->resource.object.implementation = (void (**)()) &dragInterface; + drag->resource.destroy = destroyDrag; + wl_client_add_resource(client, &drag->resource); + m_drag = drag; +} + +void Drag::done(bool sending) +{ + qDebug() << "drag done"; + Compositor::instance()->m_dragActive = false; + if (!sending) { + setPointerFocus(0, QPoint(), QPoint()); + // ### hack: Send a pointerFocus with null surface to the source too, this is + // mandatory even if the previous pointerFocus went to the same client, otherwise + // Qt will not know the drag is over without a drop. + wl_client_post_event(m_drag->source->client, + &m_drag->drag_offer.object, + WL_DRAG_OFFER_POINTER_FOCUS, + Compositor::instance()->currentTimeMsecs(), + 0, 0, 0, 0, 0); + } + m_drag = 0; +} + +void Drag::dragMove(const QPoint &global, const QPoint &local, Surface *surface) +{ + if (!m_drag) + return; +// qDebug() << "dragMove" << global << local << surface; + if (surface) { + setPointerFocus(surface->base(), global, local); + uint timestamp = Compositor::currentTimeMsecs(); + wl_client_post_event(surface->base()->client, + &m_drag->drag_offer.object, + WL_DRAG_OFFER_MOTION, + timestamp, + global.x(), global.y(), local.x(), local.y()); + } else { + setPointerFocus(0, global, local); + } +} + +void Drag::dragEnd() +{ + qDebug() << "dragEnd"; + if (!m_drag) + return; + if (m_drag->target) { + qDebug() << "WL_DRAG_OFFER_DROP" << m_drag->target; + wl_client_post_event(m_drag->target, + &m_drag->drag_offer.object, + WL_DRAG_OFFER_DROP); + done(true); + } else { + done(false); + } +} + +Q_GLOBAL_STATIC(Drag, globalInstance) + +Drag *Drag::instance() +{ + return globalInstance(); +} + +Drag::Drag() + : m_drag(0) +{ +} + +} diff --git a/src/qt-compositor/wayland_wrapper/wldrag.h b/src/qt-compositor/wayland_wrapper/wldrag.h new file mode 100644 index 0000000..e9a2b9a --- /dev/null +++ b/src/qt-compositor/wayland_wrapper/wldrag.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** This file is part of QtCompositor** +** +** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** Contact: Nokia Corporation qt-info@nokia.com +** +** 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 Nokia Corporation and its Subsidiary(-ies) 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. +** +****************************************************************************/ + +#ifndef WLDRAG_H +#define WLDRAG_H + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QMimeData> +#include <wayland-server.h> + +QT_BEGIN_NAMESPACE +class QSocketNotifier; +QT_END_NAMESPACE + +namespace Wayland { + +class Surface; + +class Drag : public QObject +{ + Q_OBJECT + +public: + static Drag *instance(); + Drag(); + void create(struct wl_client *client, uint32_t id); + void dragMove(const QPoint &global, const QPoint &local, Surface *surface); + void dragEnd(); + +private: + static void destroyDrag(struct wl_resource *resource, struct wl_client *client); + + static void dragOffer(struct wl_client *client, struct wl_drag *drag, const char *type); + static void dragActivate(struct wl_client *client, + struct wl_drag *drag, + struct wl_surface *surface, + struct wl_input_device *device, uint32_t time); + static void dragDestroy(struct wl_client *client, struct wl_drag *drag); + static const struct wl_drag_interface dragInterface; + + static void dragOfferAccept(struct wl_client *client, + struct wl_drag_offer *offer, uint32_t time, const char *type); + static void dragOfferReceive(struct wl_client *client, + struct wl_drag_offer *offer, int fd); + static void dragOfferReject(struct wl_client *client, struct wl_drag_offer *offer); + static const struct wl_drag_offer_interface dragOfferInterface; + + void setPointerFocus(wl_surface *surface, const QPoint &global, const QPoint &local); + void done(bool sending); + + QStringList m_offerList; + wl_drag *m_drag; +}; + +} + +#endif // WLDRAG_H diff --git a/src/qt-compositor/wayland_wrapper/wloutput.cpp b/src/qt-compositor/wayland_wrapper/wloutput.cpp index 39bf7c9..ba3e45a 100644 --- a/src/qt-compositor/wayland_wrapper/wloutput.cpp +++ b/src/qt-compositor/wayland_wrapper/wloutput.cpp @@ -39,9 +39,9 @@ ****************************************************************************/ #include "wloutput.h" - -#include <QtGui/QApplication> -#include <QtGui/QDesktopWidget> +#include <QGuiApplication> +#include <QtGui/QScreen> +#include <QRect> namespace Wayland { @@ -58,11 +58,11 @@ void output_post_geometry(struct wl_client *client, struct wl_object *global, ui Output::Output() - : m_geometry(QPoint(0,0), QApplication::desktop()->screenGeometry().size()) - , m_displayId(-1) + : m_displayId(-1) , m_numQueued(0) { - + QScreen *screen = QGuiApplication::primaryScreen(); + m_geometry = QRect(QPoint(0, 0), screen->availableGeometry().size()); } void Output::setGeometry(const QRect &geometry) diff --git a/src/qt-compositor/wayland_wrapper/wlshmbuffer.cpp b/src/qt-compositor/wayland_wrapper/wlshmbuffer.cpp index e3fb4bd..2ecb2b0 100644 --- a/src/qt-compositor/wayland_wrapper/wlshmbuffer.cpp +++ b/src/qt-compositor/wayland_wrapper/wlshmbuffer.cpp @@ -93,9 +93,12 @@ void ShmBuffer::damage() } +static ShmHandler *handlerInstance; + ShmHandler::ShmHandler(Display *display) : m_display(display) { + handlerInstance = this; m_shm = wl_shm_init(m_display->handle(),&shm_callbacks); } @@ -133,7 +136,16 @@ void ShmHandler::buffer_damaged_callback(struct wl_buffer *buffer, void ShmHandler::buffer_destroyed_callback(struct wl_buffer *buffer) { - delete static_cast<ShmBuffer *>(buffer->user_data); + ShmBuffer *shmbuf = static_cast<ShmBuffer *>(buffer->user_data); + for (int i = 0; i < handlerInstance->m_extraCallbacks.count(); ++i) + handlerInstance->m_extraCallbacks.at(i)(shmbuf); + delete shmbuf; +} + +void ShmHandler::addDestroyCallback(DestroyCallback callback) +{ + if (!m_extraCallbacks.contains(callback)) + m_extraCallbacks.append(callback); } } diff --git a/src/qt-compositor/wayland_wrapper/wlshmbuffer.h b/src/qt-compositor/wayland_wrapper/wlshmbuffer.h index ee3184d..e8092ce 100644 --- a/src/qt-compositor/wayland_wrapper/wlshmbuffer.h +++ b/src/qt-compositor/wayland_wrapper/wlshmbuffer.h @@ -76,6 +76,9 @@ public: ShmHandler(Display *display); ~ShmHandler(); + typedef void (*DestroyCallback)(ShmBuffer *); + void addDestroyCallback(DestroyCallback callback); + private: Display *m_display; struct wl_shm *m_shm; @@ -86,8 +89,9 @@ private: int32_t x, int32_t y, int32_t width, int32_t height); static void buffer_destroyed_callback(struct wl_buffer *buffer); - + QList<DestroyCallback> m_extraCallbacks; }; + } #endif //WL_SHMBUFFER_H diff --git a/src/qt-compositor/wayland_wrapper/wlsurface.cpp b/src/qt-compositor/wayland_wrapper/wlsurface.cpp index f13466d..f8862ee 100644 --- a/src/qt-compositor/wayland_wrapper/wlsurface.cpp +++ b/src/qt-compositor/wayland_wrapper/wlsurface.cpp @@ -49,11 +49,13 @@ #include <wayland-server.h> +#ifdef Q_OS_LINUX #include <linux/input.h> +#endif #ifdef QT_COMPOSITOR_WAYLAND_GL #include "hardware_integration/graphicshardwareintegration.h" -#include <QtGui/QPlatformGLContext> +#include <QtGui/QPlatformOpenGLContext> #endif #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT @@ -71,6 +73,7 @@ public: , textureCreatedForBuffer(false) , directRenderBuffer(0) , processId(0) + , previousBuffer(0) , surfaceBuffer(0) , surfaceType(WaylandSurface::Invalid) @@ -96,6 +99,10 @@ public: void attach(struct wl_buffer *buffer) { bool emitMap = !surfaceBuffer; + if (surfaceBuffer && ! textureCreatedForBuffer) { + qWarning() << "### WaylandSurface::attach() releasing undisplayed buffer ###"; + wl_client_post_event(client,&surfaceBuffer->resource.object,WL_BUFFER_RELEASE); + } surfaceBuffer = buffer; surfaceType = WaylandSurface::Invalid; textureCreatedForBuffer = false; @@ -114,11 +121,14 @@ public: GLuint texture_id; #endif bool textureCreatedForBuffer; - wl_buffer *directRenderBuffer; + struct wl_buffer *directRenderBuffer; qint64 processId; QByteArray authenticationToken; QVariantMap windowProperties; + QPoint lastMousePos; + + struct wl_buffer *previousBuffer; private: struct wl_buffer *surfaceBuffer; WaylandSurface::Type surfaceType; @@ -202,8 +212,13 @@ void Surface::damage(const QRect &rect) glDeleteTextures(1,&d->texture_id); d->textureCreatedForBuffer = false; } - if (d->compositor->graphicsHWIntegration()->postBuffer(d->directRenderBuffer)) + if (d->compositor->graphicsHWIntegration()->postBuffer(d->buffer())) { + if (d->previousBuffer) { + wl_client_post_event(d->client,&d->previousBuffer->resource.object,WL_BUFFER_RELEASE); + } + d->previousBuffer = d->buffer(); return; + } } #endif @@ -229,8 +244,12 @@ GLuint Surface::textureId() const if (d->compositor->graphicsHWIntegration() && d->type() == WaylandSurface::Texture && !d->textureCreatedForBuffer) { glDeleteTextures(1,&d->texture_id); + if (d->previousBuffer) { + wl_client_post_event(d->client,&d->previousBuffer->resource.object,WL_BUFFER_RELEASE); + } Surface *that = const_cast<Surface *>(this); GraphicsHardwareIntegration *hwIntegration = d->compositor->graphicsHWIntegration(); + that->d_func()->previousBuffer = d->buffer(); that->d_func()->texture_id = hwIntegration->createTextureFromBuffer(d->buffer()); that->d_func()->textureCreatedForBuffer = true; } @@ -297,6 +316,11 @@ void Surface::setWindowProperty(const QString &name, const QVariant &value, bool uint32_t toWaylandButton(Qt::MouseButton button) { +#ifndef BTN_LEFT +uint32_t BTN_LEFT = 0x110; +uint32_t BTN_RIGHT = 0x111; +uint32_t BTN_MIDDLE = 0x112; +#endif switch (button) { case Qt::LeftButton: return BTN_LEFT; @@ -305,6 +329,13 @@ uint32_t toWaylandButton(Qt::MouseButton button) default: return BTN_MIDDLE; } + +} + +QPoint Surface::lastMousePos() const +{ + Q_D(const Surface); + return d->lastMousePos; } void Surface::sendMousePressEvent(int x, int y, Qt::MouseButton button) @@ -333,6 +364,7 @@ void Surface::sendMouseMoveEvent(int x, int y) { Q_D(Surface); if (d->client) { + d->lastMousePos = QPoint(x, y); uint32_t time = d->compositor->currentTimeMsecs(); d->compositor->setPointerFocus(this, QPoint(x, y)); wl_client_post_event(d->client, &d->compositor->defaultInputDevice()->object, diff --git a/src/qt-compositor/wayland_wrapper/wlsurface.h b/src/qt-compositor/wayland_wrapper/wlsurface.h index c921496..31e10c7 100644 --- a/src/qt-compositor/wayland_wrapper/wlsurface.h +++ b/src/qt-compositor/wayland_wrapper/wlsurface.h @@ -104,6 +104,7 @@ public: qint64 processId() const; void setProcessId(qint64 processId); QByteArray authenticationToken() const; + void setAuthenticationToken(const QByteArray &authenticationToken); QVariantMap windowProperties() const; QVariant windowProperty(const QString &propertyName) const; @@ -111,6 +112,8 @@ public: void setSurfaceCreationFinished(bool isCreated); + QPoint lastMousePos() const; + protected: QScopedPointer<SurfacePrivate> d_ptr; private: |