summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/wasm/qwasmcompositor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/wasm/qwasmcompositor.cpp')
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp721
1 files changed, 721 insertions, 0 deletions
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
new file mode 100644
index 0000000000..f3ea013325
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -0,0 +1,721 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmcompositor.h"
+#include "qwasmwindow.h"
+#include "qwasmstylepixmaps_p.h"
+
+#include <QtGui/qopengltexture.h>
+
+#include <QtGui/private/qwindow_p.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QtGui/qopengltextureblitter.h>
+#include <QtGui/qpainter.h>
+#include <private/qpixmapcache_p.h>
+
+#include <private/qguiapplication_p.h>
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qguiapplication.h>
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+
+QWasmCompositedWindow::QWasmCompositedWindow()
+ : window(nullptr)
+ , parentWindow(nullptr)
+ , flushPending(false)
+ , visible(false)
+{
+}
+
+QWasmCompositor::QWasmCompositor()
+ : m_frameBuffer(nullptr)
+ , m_blitter(new QOpenGLTextureBlitter)
+ , m_needComposit(false)
+ , m_inFlush(false)
+ , m_inResize(false)
+ , m_isEnabled(true)
+ , m_targetDevicePixelRatio(1)
+{
+}
+
+QWasmCompositor::~QWasmCompositor()
+{
+ delete m_frameBuffer;
+}
+
+void QWasmCompositor::setEnabled(bool enabled)
+{
+ m_isEnabled = enabled;
+}
+
+void QWasmCompositor::addWindow(QWasmWindow *window, QWasmWindow *parentWindow)
+{
+ QWasmCompositedWindow compositedWindow;
+ compositedWindow.window = window;
+ compositedWindow.parentWindow = parentWindow;
+ m_compositedWindows.insert(window, compositedWindow);
+
+ if (parentWindow == 0)
+ m_windowStack.append(window);
+ else
+ m_compositedWindows[parentWindow].childWindows.append(window);
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::removeWindow(QWasmWindow *window)
+{
+ QWasmWindow *platformWindow = m_compositedWindows[window].parentWindow;
+
+ if (platformWindow) {
+ QWasmWindow *parentWindow = window;
+ m_compositedWindows[parentWindow].childWindows.removeAll(window);
+ }
+
+ m_windowStack.removeAll(window);
+ m_compositedWindows.remove(window);
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::setScreen(QWasmScreen *screen)
+{
+ m_screen = screen;
+}
+
+void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
+{
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ if (compositedWindow.visible == visible)
+ return;
+
+ compositedWindow.visible = visible;
+ compositedWindow.flushPending = true;
+ if (visible)
+ compositedWindow.damage = compositedWindow.window->geometry();
+ else
+ m_globalDamage = compositedWindow.window->geometry(); // repaint previosly covered area.
+
+ requestRedraw();
+}
+
+void QWasmCompositor::raise(QWasmWindow *window)
+{
+ if (m_compositedWindows.size() <= 1)
+ return;
+
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ compositedWindow.damage = compositedWindow.window->geometry();
+ m_windowStack.removeAll(window);
+ m_windowStack.append(window);
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::lower(QWasmWindow *window)
+{
+ if (m_compositedWindows.size() <= 1)
+ return;
+
+ m_windowStack.removeAll(window);
+ m_windowStack.prepend(window);
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ m_globalDamage = compositedWindow.window->geometry(); // repaint previosly covered area.
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::setParent(QWasmWindow *window, QWasmWindow *parent)
+{
+ m_compositedWindows[window].parentWindow = parent;
+
+ requestRedraw();
+}
+
+void QWasmCompositor::flush(QWasmWindow *window, const QRegion &region)
+{
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ compositedWindow.flushPending = true;
+ compositedWindow.damage = region;
+
+ requestRedraw();
+}
+
+int QWasmCompositor::windowCount() const
+{
+ return m_windowStack.count();
+}
+
+
+void QWasmCompositor::redrawWindowContent()
+{
+ // Redraw window content by sending expose events. This redraw
+ // will cause a backing store flush, which will call requestRedraw()
+ // to composit.
+ for (QWasmWindow *platformWindow : m_windowStack) {
+ QWindow *window = platformWindow->window();
+ QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(
+ window, QRect(QPoint(0, 0), window->geometry().size()));
+ }
+}
+
+void QWasmCompositor::requestRedraw()
+{
+ if (m_needComposit)
+ return;
+
+ m_needComposit = true;
+ QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
+}
+
+QWindow *QWasmCompositor::windowAt(QPoint p, int padding) const
+{
+ int index = m_windowStack.count() - 1;
+ // qDebug() << "window at" << "point" << p << "window count" << index;
+
+ while (index >= 0) {
+ const QWasmCompositedWindow &compositedWindow = m_compositedWindows[m_windowStack.at(index)];
+ //qDebug() << "windwAt testing" << compositedWindow.window <<
+
+ QRect geometry = compositedWindow.window->windowFrameGeometry()
+ .adjusted(-padding, -padding, padding, padding);
+
+ if (compositedWindow.visible && geometry.contains(p))
+ return m_windowStack.at(index)->window();
+ --index;
+ }
+
+ return 0;
+}
+
+QWindow *QWasmCompositor::keyWindow() const
+{
+ return m_windowStack.at(m_windowStack.count() - 1)->window();
+}
+
+bool QWasmCompositor::event(QEvent *ev)
+{
+ if (ev->type() == QEvent::UpdateRequest) {
+ if (m_isEnabled)
+ frame();
+ return true;
+ }
+
+ return QObject::event(ev);
+}
+
+void QWasmCompositor::blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry)
+{
+ QMatrix4x4 m;
+ m.translate(-1.0f, -1.0f);
+
+ m.scale(2.0f / (float)screen->geometry().width(),
+ 2.0f / (float)screen->geometry().height());
+
+ m.translate((float)targetGeometry.width() / 2.0f,
+ (float)-targetGeometry.height() / 2.0f);
+
+ m.translate(targetGeometry.x(), screen->geometry().height() - targetGeometry.y());
+
+ m.scale(0.5f * (float)targetGeometry.width(),
+ 0.5f * (float)targetGeometry.height());
+
+ blitter->blit(texture->textureId(), m, QOpenGLTextureBlitter::OriginTopLeft);
+}
+
+void QWasmCompositor::drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+{
+ QWasmBackingStore *backingStore = window->backingStore();
+
+ QOpenGLTexture const *texture = backingStore->getUpdatedTexture();
+
+ blit(blitter, screen, texture, window->geometry());
+}
+
+QPalette QWasmCompositor::makeWindowPalette()
+{
+ QPalette palette;
+ palette.setColor(QPalette::Active, QPalette::Highlight,
+ palette.color(QPalette::Active, QPalette::Highlight));
+ palette.setColor(QPalette::Active, QPalette::Base,
+ palette.color(QPalette::Active, QPalette::Highlight));
+ palette.setColor(QPalette::Inactive, QPalette::Highlight,
+ palette.color(QPalette::Inactive, QPalette::Dark));
+ palette.setColor(QPalette::Inactive, QPalette::Base,
+ palette.color(QPalette::Inactive, QPalette::Dark));
+ palette.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ palette.color(QPalette::Inactive, QPalette::Window));
+
+ return palette;
+}
+
+QRect QWasmCompositor::titlebarRect(QWasmTitleBarOptions tb, QWasmCompositor::SubControls subcontrol)
+{
+ QRect ret;
+ const int controlMargin = 2;
+ const int controlHeight = tb.rect.height() - controlMargin *2;
+ const int delta = controlHeight + controlMargin;
+ int offset = 0;
+
+ bool isMinimized = tb.state & Qt::WindowMinimized;
+ bool isMaximized = tb.state & Qt::WindowMaximized;
+
+ ret = tb.rect;
+ switch (subcontrol) {
+ case SC_TitleBarLabel:
+ if (tb.flags & Qt::WindowSystemMenuHint)
+ ret.adjust(delta, 0, -delta, 0);
+ break;
+ case SC_TitleBarCloseButton:
+ if (tb.flags & Qt::WindowSystemMenuHint) {
+ ret.adjust(0, 0, -delta, 0);
+ offset += delta;
+ }
+ break;
+ case SC_TitleBarMaxButton:
+ if (!isMaximized && tb.flags & Qt::WindowMaximizeButtonHint) {
+ ret.adjust(0, 0, -delta*2, 0);
+ offset += (delta +delta);
+ }
+ break;
+ case SC_TitleBarNormalButton:
+ if (isMinimized && (tb.flags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (isMaximized && (tb.flags & Qt::WindowMaximizeButtonHint))
+ ret.adjust(0, 0, -delta*2, 0);
+ offset += (delta +delta);
+ break;
+ case SC_TitleBarSysMenu:
+ if (tb.flags & Qt::WindowSystemMenuHint) {
+ ret.setRect(tb.rect.left() + controlMargin, tb.rect.top() + controlMargin,
+ controlHeight, controlHeight);
+ }
+ break;
+ default:
+ break;
+ };
+
+ if (subcontrol != SC_TitleBarLabel && subcontrol != SC_TitleBarSysMenu) {
+ ret.setRect(tb.rect.right() - offset, tb.rect.top() + controlMargin,
+ controlHeight, controlHeight);
+ }
+
+ if (qApp->layoutDirection() == Qt::LeftToRight)
+ return ret;
+
+ QRect rect = ret;
+ rect.translate(2 * (tb.rect.right() - ret.right()) +
+ ret.width() - tb.rect.width(), 0);
+
+ return rect;
+}
+
+int dpiScaled(qreal value)
+{
+ return value * (qreal(qt_defaultDpiX()) / 96.0);
+}
+
+QWasmCompositor::QWasmTitleBarOptions QWasmCompositor::makeTitleBarOptions(const QWasmWindow *window)
+{
+ int width = window->windowFrameGeometry().width();
+ int border = window->borderWidth();
+
+ QWasmTitleBarOptions titleBarOptions;
+
+ titleBarOptions.rect = QRect(border, border, width - 2 * border, window->titleHeight());
+ titleBarOptions.flags = window->window()->flags();
+ titleBarOptions.state = window->window()->windowState();
+
+ bool isMaximized = titleBarOptions.state & Qt::WindowMaximized; // this gets reset when maximized
+
+ if (titleBarOptions.flags & (Qt::WindowTitleHint))
+ titleBarOptions.subControls |= SC_TitleBarLabel;
+ if (titleBarOptions.flags & Qt::WindowMaximizeButtonHint) {
+ if (isMaximized)
+ titleBarOptions.subControls |= SC_TitleBarNormalButton;
+ else
+ titleBarOptions.subControls |= SC_TitleBarMaxButton;
+ }
+ if (titleBarOptions.flags & Qt::WindowSystemMenuHint) {
+ titleBarOptions.subControls |= SC_TitleBarCloseButton;
+ titleBarOptions.subControls |= SC_TitleBarSysMenu;
+ }
+
+
+ titleBarOptions.palette = QWasmCompositor::makeWindowPalette();
+
+ if (window->window()->isActive())
+ titleBarOptions.palette.setCurrentColorGroup(QPalette::Active);
+ else
+ titleBarOptions.palette.setCurrentColorGroup(QPalette::Inactive);
+
+ if (window->activeSubControl() != QWasmCompositor::SC_None)
+ titleBarOptions.subControls = window->activeSubControl();
+
+ if (!window->window()->title().isEmpty())
+ titleBarOptions.titleBarOptionsString = window->window()->title();
+
+ return titleBarOptions;
+}
+
+void QWasmCompositor::drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+{
+ int width = window->windowFrameGeometry().width();
+ int height = window->windowFrameGeometry().height();
+ qreal dpr = window->devicePixelRatio();
+
+ QImage image(QSize(width * dpr, height * dpr), QImage::Format_RGB32);
+ image.setDevicePixelRatio(dpr);
+ QPainter painter(&image);
+ painter.fillRect(QRect(0, 0, width, height), painter.background());
+
+ QWasmTitleBarOptions titleBarOptions = makeTitleBarOptions(window);
+
+ drawTitlebarWindow(titleBarOptions, &painter);
+
+ QWasmFrameOptions frameOptions;
+ frameOptions.rect = QRect(0, 0, width, height);
+ frameOptions.lineWidth = dpiScaled(4.);
+
+ drawFrameWindow(frameOptions, &painter);
+
+ painter.end();
+
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setMinificationFilter(QOpenGLTexture::Nearest);
+ texture.setMagnificationFilter(QOpenGLTexture::Nearest);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ texture.setData(image, QOpenGLTexture::DontGenerateMipMaps);
+ texture.create();
+ texture.bind();
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE,
+ image.constScanLine(0));
+
+ blit(blitter, screen, &texture, QRect(window->windowFrameGeometry().topLeft(), QSize(width, height)));
+}
+
+void QWasmCompositor::drawFrameWindow(QWasmFrameOptions options, QPainter *painter)
+{
+ int x = options.rect.x();
+ int y = options.rect.y();
+ int w = options.rect.width();
+ int h = options.rect.height();
+ const QColor &c1 = options.palette.light().color();
+ const QColor &c2 = options.palette.shadow().color();
+ const QColor &c3 = options.palette.midlight().color();
+ const QColor &c4 = options.palette.dark().color();
+ const QBrush *fill = 0;
+
+ const qreal devicePixelRatio = painter->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ painter->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ }
+
+ QPen oldPen = painter->pen();
+ QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
+ painter->setPen(c1);
+ painter->drawPolyline(a, 3);
+ QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
+ painter->setPen(c2);
+ painter->drawPolyline(b, 3);
+ if (w > 4 && h > 4) {
+ QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
+ painter->setPen(c3);
+ painter->drawPolyline(c, 3);
+ QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
+ painter->setPen(c4);
+ painter->drawPolyline(d, 3);
+ if (fill)
+ painter->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
+ }
+ painter->setPen(oldPen);
+}
+
+//from commonstyle.cpp
+static QPixmap cachedPixmapFromXPM(const char * const *xpm)
+{
+ QPixmap result;
+ const QString tag = QString::asprintf("xpm:0x%p", static_cast<const void*>(xpm));
+ if (!QPixmapCache::find(tag, &result)) {
+ result = QPixmap(xpm);
+ QPixmapCache::insert(tag, result);
+ }
+ return result;
+}
+
+void QWasmCompositor::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
+ const QPixmap &pixmap) const
+{
+ qreal scale = pixmap.devicePixelRatio();
+ QSize size = pixmap.size() / scale;
+ int x = rect.x();
+ int y = rect.y();
+ int w = size.width();
+ int h = size.height();
+ if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
+ y += rect.size().height()/2 - h/2;
+ else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
+ y += rect.size().height() - h;
+ if ((alignment & Qt::AlignRight) == Qt::AlignRight)
+ x += rect.size().width() - w;
+ else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
+ x += rect.size().width()/2 - w/2;
+
+ QRect aligned = QRect(x, y, w, h);
+ QRect inter = aligned.intersected(rect);
+
+ painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), inter.width() * scale, inter.height() *scale);
+}
+
+
+void QWasmCompositor::drawTitlebarWindow(QWasmTitleBarOptions tb, QPainter *painter)
+{
+ QRect ir;
+ if (tb.subControls.testFlag(SC_TitleBarLabel)) {
+ QColor left = tb.palette.highlight().color();
+ QColor right = tb.palette.base().color();
+
+ QBrush fillBrush(left);
+ if (left != right) {
+ QPoint p1(tb.rect.x(), tb.rect.top() + tb.rect.height()/2);
+ QPoint p2(tb.rect.right(), tb.rect.top() + tb.rect.height()/2);
+ QLinearGradient lg(p1, p2);
+ lg.setColorAt(0, left);
+ lg.setColorAt(1, right);
+ fillBrush = lg;
+ }
+
+ painter->fillRect(tb.rect, fillBrush);
+ ir = titlebarRect(tb, SC_TitleBarLabel);
+ painter->setPen(tb.palette.highlightedText().color());
+ painter->drawText(ir.x() + 2, ir.y(), ir.width() - 2, ir.height(),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb.titleBarOptionsString);
+ } // SC_TitleBarLabel
+
+ bool down = false;
+ QPixmap pixmap;
+
+ if (tb.subControls.testFlag(SC_TitleBarCloseButton)
+ && tb.flags & Qt::WindowSystemMenuHint) {
+ ir = titlebarRect(tb, SC_TitleBarCloseButton);
+ down = tb.subControls & SC_TitleBarCloseButton && (tb.state & State_Sunken);
+ pixmap = cachedPixmapFromXPM(qt_close_xpm).scaled(QSize(10, 10));
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ } //SC_TitleBarCloseButton
+
+ if (tb.subControls.testFlag(SC_TitleBarMaxButton)
+ && tb.flags & Qt::WindowMaximizeButtonHint
+ && !(tb.state & Qt::WindowMaximized)) {
+ ir = titlebarRect(tb, SC_TitleBarMaxButton);
+ down = tb.subControls & SC_TitleBarMaxButton && (tb.state & State_Sunken);
+ pixmap = cachedPixmapFromXPM(qt_maximize_xpm).scaled(QSize(10, 10));
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ } //SC_TitleBarMaxButton
+
+ bool drawNormalButton = (tb.subControls & SC_TitleBarNormalButton)
+ && (((tb.flags & Qt::WindowMinimizeButtonHint)
+ && (tb.flags & Qt::WindowMinimized))
+ || ((tb.flags & Qt::WindowMaximizeButtonHint)
+ && (tb.flags & Qt::WindowMaximized)));
+
+ if (drawNormalButton) {
+ ir = titlebarRect(tb, SC_TitleBarNormalButton);
+ down = tb.subControls & SC_TitleBarNormalButton && (tb.state & State_Sunken);
+ pixmap = cachedPixmapFromXPM(qt_normalizeup_xpm).scaled( QSize(10, 10));
+
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ } // SC_TitleBarNormalButton
+
+ if (tb.subControls & SC_TitleBarSysMenu && tb.flags & Qt::WindowSystemMenuHint) {
+ ir = titlebarRect(tb, SC_TitleBarSysMenu);
+ pixmap = cachedPixmapFromXPM(qt_menu_xpm).scaled(QSize(10, 10));
+ drawItemPixmap(painter, ir, Qt::AlignCenter, pixmap);
+ }
+}
+
+void QWasmCompositor::drawShadePanel(QWasmTitleBarOptions options, QPainter *painter)
+{
+ int lineWidth = 1;
+ QPalette palette = options.palette;
+ const QBrush *fill = &options.palette.brush(QPalette::Button);
+
+ int x = options.rect.x();
+ int y = options.rect.y();
+ int w = options.rect.width();
+ int h = options.rect.height();
+
+ const qreal devicePixelRatio = painter->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ painter->scale(inverseScale, inverseScale);
+
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ lineWidth = qRound(devicePixelRatio * lineWidth);
+ }
+
+ QColor shade = palette.dark().color();
+ QColor light = palette.light().color();
+
+ if (fill) {
+ if (fill->color() == shade)
+ shade = palette.shadow().color();
+ if (fill->color() == light)
+ light = palette.midlight().color();
+ }
+ QPen oldPen = painter->pen();
+ QVector<QLineF> lines;
+ lines.reserve(2*lineWidth);
+
+ painter->setPen(light);
+ int x1, y1, x2, y2;
+ int i;
+ x1 = x;
+ y1 = y2 = y;
+ x2 = x + w - 2;
+ for (i = 0; i < lineWidth; i++) // top shadow
+ lines << QLineF(x1, y1++, x2--, y2++);
+
+ x2 = x1;
+ y1 = y + h - 2;
+ for (i = 0; i < lineWidth; i++) // left shado
+ lines << QLineF(x1++, y1, x2++, y2--);
+
+ painter->drawLines(lines);
+ lines.clear();
+ painter->setPen(shade);
+ x1 = x;
+ y1 = y2 = y+h-1;
+ x2 = x+w-1;
+ for (i=0; i<lineWidth; i++) { // bottom shadow
+ lines << QLineF(x1++, y1--, x2, y2--);
+ }
+ x1 = x2;
+ y1 = y;
+ y2 = y + h - lineWidth - 1;
+ for (i = 0; i < lineWidth; i++) // right shadow
+ lines << QLineF(x1--, y1++, x2--, y2);
+
+ painter->drawLines(lines);
+ if (fill) // fill with fill color
+ painter->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
+ painter->setPen(oldPen); // restore pen
+
+}
+
+void QWasmCompositor::drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+{
+ if (window->window()->type() != Qt::Popup)
+ drawWindowDecorations(blitter, screen, window);
+ drawWindowContent(blitter, screen, window);
+}
+
+void QWasmCompositor::frame()
+{
+ if (!m_needComposit)
+ return;
+
+ m_needComposit = false;
+
+ if (m_windowStack.empty() || !m_screen)
+ return;
+
+ QWasmWindow *someWindow = nullptr;
+
+ foreach (QWasmWindow *window, m_windowStack) {
+ if (window->window()->surfaceClass() == QSurface::Window
+ && qt_window_private(static_cast<QWindow *>(window->window()))->receivedExpose) {
+ someWindow = window;
+ break;
+ }
+ }
+
+ if (!someWindow)
+ return;
+
+ if (m_context.isNull()) {
+ m_context.reset(new QOpenGLContext());
+ //mContext->setFormat(mScreen->format());
+ m_context->setScreen(m_screen->screen());
+ m_context->create();
+ }
+
+ m_context->makeCurrent(someWindow->window());
+
+ if (!m_blitter->isCreated())
+ m_blitter->create();
+
+ qreal dpr = m_screen->devicePixelRatio();
+ glViewport(0, 0, m_screen->geometry().width() * dpr, m_screen->geometry().height() * dpr);
+
+ m_context->functions()->glClearColor(0.2, 0.2, 0.2, 1.0);
+ m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ m_blitter->bind();
+ m_blitter->setRedBlueSwizzle(true);
+
+ foreach (QWasmWindow *window, m_windowStack) {
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+
+ if (!compositedWindow.visible)
+ continue;
+
+ drawWindow(m_blitter.data(), m_screen, window);
+ }
+
+ m_blitter->release();
+
+ if (someWindow && someWindow->window()->surfaceType() == QSurface::OpenGLSurface)
+ m_context->swapBuffers(someWindow->window());
+}
+
+void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
+{
+ QWindow *modalWindow;
+ bool blocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow);
+
+ if (blocked) {
+ raise(static_cast<QWasmWindow*>(modalWindow->handle()));
+ return;
+ }
+
+ requestRedraw();
+ QWindowSystemInterface::handleWindowActivated(window->window());
+}