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.cpp117
1 files changed, 99 insertions, 18 deletions
diff --git a/src/opengl/qopenglcompositor.cpp b/src/opengl/qopenglcompositor.cpp
index ae500181e4..3c5b1df905 100644
--- a/src/opengl/qopenglcompositor.cpp
+++ b/src/opengl/qopenglcompositor.cpp
@@ -4,7 +4,7 @@
#include <QtOpenGL/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
-#include <QtGui/private/qrhi_p.h>
+#include <rhi/qrhi.h>
#include <qpa/qplatformbackingstore.h>
#include "qopenglcompositor_p.h"
@@ -85,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()
@@ -98,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();
@@ -115,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)
@@ -156,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())
@@ -173,13 +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);
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)
@@ -189,6 +203,9 @@ 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) {
const uint textureId = textures->texture(i)->nativeTexture().object;
const float opacity = window->sourceWindow()->opacity();
@@ -203,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;
@@ -211,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);
}
}
@@ -246,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);
}
}
@@ -259,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)
@@ -269,11 +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"