summaryrefslogtreecommitdiffstats
path: root/src/opengl/qopenglcompositor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/qopenglcompositor.cpp')
-rw-r--r--src/opengl/qopenglcompositor.cpp172
1 files changed, 112 insertions, 60 deletions
diff --git a/src/opengl/qopenglcompositor.cpp b/src/opengl/qopenglcompositor.cpp
index abfaca3f9c..3c5b1df905 100644
--- a/src/opengl/qopenglcompositor.cpp
+++ b/src/opengl/qopenglcompositor.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or 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.GPL2 and 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtOpenGL/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
+#include <rhi/qrhi.h>
#include <qpa/qplatformbackingstore.h>
#include "qopenglcompositor_p.h"
@@ -93,14 +58,17 @@ QOpenGLCompositor::~QOpenGLCompositor()
compositor = 0;
}
-void QOpenGLCompositor::setTarget(QOpenGLContext *context, QWindow *targetWindow,
- const QRect &nativeTargetGeometry)
+void QOpenGLCompositor::setTargetWindow(QWindow *targetWindow, const QRect &nativeTargetGeometry)
{
- m_context = context;
m_targetWindow = targetWindow;
m_nativeTargetGeometry = nativeTargetGeometry;
}
+void QOpenGLCompositor::setTargetContext(QOpenGLContext *context)
+{
+ m_context = context;
+}
+
void QOpenGLCompositor::setRotation(int degrees)
{
m_rotation = degrees;
@@ -117,10 +85,23 @@ void QOpenGLCompositor::update()
QImage QOpenGLCompositor::grab()
{
Q_ASSERT(m_context && m_targetWindow);
+ QOpenGLFramebufferObject fbo(m_nativeTargetGeometry.size());
+ grabToFrameBufferObject(&fbo);
+ return fbo.toImage();
+}
+
+bool QOpenGLCompositor::grabToFrameBufferObject(QOpenGLFramebufferObject *fbo, GrabOrientation orientation)
+{
+ Q_ASSERT(fbo);
+ if (fbo->size() != m_nativeTargetGeometry.size()
+ || fbo->format().textureTarget() != GL_TEXTURE_2D)
+ return false;
+
m_context->makeCurrent(m_targetWindow);
- QScopedPointer<QOpenGLFramebufferObject> fbo(new QOpenGLFramebufferObject(m_nativeTargetGeometry.size()));
- renderAll(fbo.data());
- return fbo->toImage();
+ renderAll(fbo,
+ orientation == Flipped ? QOpenGLTextureBlitter::OriginTopLeft
+ : QOpenGLTextureBlitter::OriginBottomLeft);
+ return true;
}
void QOpenGLCompositor::handleRenderAllRequest()
@@ -130,7 +111,7 @@ void QOpenGLCompositor::handleRenderAllRequest()
renderAll(0);
}
-void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo)
+void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo, QOpenGLTextureBlitter::Origin origin)
{
if (fbo)
fbo->bind();
@@ -147,7 +128,7 @@ void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo)
m_windows.at(i)->beginCompositing();
for (int i = 0; i < m_windows.size(); ++i)
- render(m_windows.at(i));
+ render(m_windows.at(i), origin);
m_blitter.release();
if (!fbo)
@@ -188,9 +169,10 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
topLeftRect.width(), topLeftRect.height());
}
-static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &sourceWindowRect,
- const QRect &targetWindowRect,
- QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix)
+static void clippedBlit(const QPlatformTextureList *textures, int idx,
+ const QRect &sourceWindowRect, const QRect &targetWindowRect,
+ QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix,
+ QOpenGLTextureBlitter::Origin sourceOrigin)
{
const QRect clipRect = textures->clipRect(idx);
if (clipRect.isEmpty())
@@ -205,12 +187,13 @@ static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRe
target = *rotationMatrix * target;
const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect, rectInWindow.size(),
- QOpenGLTextureBlitter::OriginBottomLeft);
+ sourceOrigin);
- blitter->blit(textures->textureId(idx), target, source);
+ const uint textureId = textures->texture(idx)->nativeTexture().object;
+ blitter->blit(textureId, target, source);
}
-void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
+void QOpenGLCompositor::render(QOpenGLCompositorWindow *window, QOpenGLTextureBlitter::Origin origin)
{
const QPlatformTextureList *textures = window->textures();
if (!textures)
@@ -220,8 +203,11 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
float currentOpacity = 1.0f;
BlendStateBinder blend;
const QRect sourceWindowRect = window->sourceWindow()->geometry();
+ auto clippedBlitSourceOrigin = origin == QOpenGLTextureBlitter::OriginTopLeft
+ ? QOpenGLTextureBlitter::OriginBottomLeft
+ : QOpenGLTextureBlitter::OriginTopLeft;
for (int i = 0; i < textures->count(); ++i) {
- uint textureId = textures->textureId(i);
+ const uint textureId = textures->texture(i)->nativeTexture().object;
const float opacity = window->sourceWindow()->opacity();
if (opacity != currentOpacity) {
currentOpacity = opacity;
@@ -234,7 +220,7 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
if (m_rotation)
target = m_rotationMatrix * target;
- m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
+ m_blitter.blit(textureId, target, origin);
} else if (textures->count() == 1) {
// A regular QWidget window
const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0;
@@ -242,18 +228,20 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
if (m_rotation)
target = m_rotationMatrix * target;
- m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
+ m_blitter.blit(textureId, target, origin);
} else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
// Texture from an FBO belonging to a QOpenGLWidget or QQuickWidget
blend.set(false);
- clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr);
+ clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
+ m_rotation ? &m_rotationMatrix : nullptr, clippedBlitSourceOrigin);
}
}
for (int i = 0; i < textures->count(); ++i) {
if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
blend.set(true);
- clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr);
+ clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
+ m_rotation ? &m_rotationMatrix : nullptr, clippedBlitSourceOrigin);
}
}
@@ -277,7 +265,9 @@ void QOpenGLCompositor::addWindow(QOpenGLCompositorWindow *window)
{
if (!m_windows.contains(window)) {
m_windows.append(window);
- emit topWindowChanged(window);
+ ensureCorrectZOrder();
+ if (window == m_windows.constLast())
+ emit topWindowChanged(window);
}
}
@@ -290,9 +280,17 @@ void QOpenGLCompositor::removeWindow(QOpenGLCompositorWindow *window)
void QOpenGLCompositor::moveToTop(QOpenGLCompositorWindow *window)
{
+ if (!m_windows.isEmpty() && window == m_windows.constLast()) {
+ // Already on top
+ return;
+ }
+
m_windows.removeOne(window);
m_windows.append(window);
- emit topWindowChanged(window);
+ ensureCorrectZOrder();
+
+ if (window == m_windows.constLast())
+ emit topWindowChanged(window);
}
void QOpenGLCompositor::changeWindowIndex(QOpenGLCompositorWindow *window, int newIdx)
@@ -300,9 +298,63 @@ void QOpenGLCompositor::changeWindowIndex(QOpenGLCompositorWindow *window, int n
int idx = m_windows.indexOf(window);
if (idx != -1 && idx != newIdx) {
m_windows.move(idx, newIdx);
- if (newIdx == m_windows.size() - 1)
+ ensureCorrectZOrder();
+ if (window == m_windows.constLast())
emit topWindowChanged(m_windows.last());
}
}
+void QOpenGLCompositor::ensureCorrectZOrder()
+{
+ const auto originalOrder = m_windows;
+
+ std::sort(m_windows.begin(), m_windows.end(),
+ [this, &originalOrder](QOpenGLCompositorWindow *cw1, QOpenGLCompositorWindow *cw2) {
+ QWindow *w1 = cw1->sourceWindow();
+ QWindow *w2 = cw2->sourceWindow();
+
+ // Case #1: The main window needs to have less z-order. It can never be in
+ // front of our tool windows, popups etc, because it's fullscreen!
+ if (w1 == m_targetWindow || w2 == m_targetWindow)
+ return w1 == m_targetWindow;
+
+ // Case #2:
+ if (w2->isAncestorOf(w1)) {
+ // w1 is transient child of w2. W1 goes in front then.
+ return false;
+ }
+
+ if (w1->isAncestorOf(w2)) {
+ // Or the other way around
+ return true;
+ }
+
+ // Case #3: Modality gets higher Z
+ if (w1->modality() != Qt::NonModal && w2->modality() == Qt::NonModal)
+ return false;
+
+ if (w2->modality() != Qt::NonModal && w1->modality() == Qt::NonModal)
+ return true;
+
+ const bool isTool1 = (w1->flags() & Qt::Tool) == Qt::Tool;
+ const bool isTool2 = (w2->flags() & Qt::Tool) == Qt::Tool;
+ const bool isPurePopup1 = !isTool1 && (w1->flags() & Qt::Popup) == Qt::Popup;
+ const bool isPurePopup2 = !isTool2 && (w2->flags() & Qt::Popup) == Qt::Popup;
+
+ // Case #4: By pure-popup we mean menus and tooltips. Qt::Tool implies Qt::Popup
+ // and we don't want to catch QDockWidget and other tool windows just yet
+ if (isPurePopup1 != isPurePopup2)
+ return !isPurePopup1;
+
+ // Case #5: One of the window is a Tool, that goes to front, as done in other QPAs
+ if (isTool1 != isTool2)
+ return !isTool1;
+
+ // Case #6: Just preserve original sorting:
+ return originalOrder.indexOf(cw1) < originalOrder.indexOf(cw2);
+ });
+}
+
QT_END_NAMESPACE
+
+#include "moc_qopenglcompositor_p.cpp"