From de1b98e9c16afd1f428652e800cbeb35414b2b4f Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Tue, 28 Jan 2014 16:20:13 +0100 Subject: [PATCH] Fallback to QWidget::grab() if QScreen::grabWindow() fails. QScreen::grabWindow() is not always reliable because it grabs from the framebuffer. (The window might then be covered by other windows, e.g. "Stays on top"-Windows, popups etc). If QScreen::grabWindow() fails we therefore fallback to QWidget::grab(). This will not grab from the frame buffer, but it will ask the widget to render itself (with its current state) to a pixmap and return it. QWidget::grab() should usually return the expected pixmap, and the pixmap it gives is not subject to the state of the window manager. This means that both QScreen::grabWindow() *and* QWidget::grab() must produce an unexpected pixmap in order for the test to fail. Change-Id: I276554155bb1e5b510d2a2d43628d91669464fe2 Reviewed-by: Friedemann Kleint Reviewed-by: Frederik Gladhorn --- .../widgets/kernel/qwidget/tst_qwidget.cpp | 117 +++++++++--------- 1 file changed, 56 insertions(+), 61 deletions(-) diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 38b629cad7..ecbe774f22 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -4816,73 +4816,68 @@ static inline QByteArray msgRgbMismatch(unsigned actual, unsigned expected) QByteArrayLiteral(" != 0x") + QByteArray::number(expected, 16); } -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) -QT_BEGIN_NAMESPACE -extern Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); -QT_END_NAMESPACE - -// grabs the window *without including any overlapping windows* -static QPixmap grabWindow(QWindow *window, int x, int y, int width, int height) -{ - const HWND hwnd = (HWND)window->winId(); - - // Create and setup bitmap - const HDC displayDc = ::GetDC(0); - const HDC bitmapDc = ::CreateCompatibleDC(displayDc); - const HBITMAP bitmap = ::CreateCompatibleBitmap(displayDc, width, height); - const HGDIOBJ oldBitmap = ::SelectObject(bitmapDc, bitmap); - - // copy data - const HDC windowDc = ::GetDC(hwnd); - ::BitBlt(bitmapDc, 0, 0, width, height, windowDc, x, y, SRCCOPY); - - // clean up all but bitmap - ::ReleaseDC(hwnd, windowDc); - ::SelectObject(bitmapDc, oldBitmap); - ::DeleteDC(bitmapDc); - - const QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap); - - ::DeleteObject(bitmap); - ::ReleaseDC(0, displayDc); - - return pixmap; -} -#else -// fallback for other platforms. static QPixmap grabWindow(QWindow *window, int x, int y, int width, int height) { QScreen *screen = window->screen(); return screen ? screen->grabWindow(window->winId(), x, y, width, height) : QPixmap(); } -#endif //defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) -#define VERIFY_COLOR(child, region, color) do { \ - const QRegion r = QRegion(region); \ - QWindow *window = child.window()->windowHandle(); \ - Q_ASSERT(window); \ - const QPoint offset = child.mapTo(child.window(), QPoint(0,0)); \ - for (int i = 0; i < r.rects().size(); ++i) { \ - const QRect rect = r.rects().at(i).translated(offset); \ - for (int t = 0; t < 5; t++) { \ - const QPixmap pixmap = grabWindow(window, \ - rect.left(), rect.top(), \ - rect.width(), rect.height()); \ - QCOMPARE(pixmap.size(), rect.size()); \ - QPixmap expectedPixmap(pixmap); /* ensure equal formats */ \ - expectedPixmap.detach(); \ - expectedPixmap.fill(color); \ - QImage image = pixmap.toImage(); \ - uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; \ - uint firstPixel = image.pixel(0,0) | alphaCorrection; \ - if ( firstPixel != QColor(color).rgb() && t < 4 ) \ - { QTest::qWait(200); continue; } \ - QVERIFY2(firstPixel == QColor(color).rgb(), msgRgbMismatch(firstPixel, QColor(color).rgb())); \ - QCOMPARE(pixmap, expectedPixmap); \ - break; \ - } \ - } \ -} while (0) +#define VERIFY_COLOR(child, region, color) verifyColor(child, region, color, __LINE__) + +bool verifyColor(QWidget &child, const QRegion ®ion, const QColor &color, unsigned int callerLine) +{ + const QRegion r = QRegion(region); + QWindow *window = child.window()->windowHandle(); + Q_ASSERT(window); + const QPoint offset = child.mapTo(child.window(), QPoint(0,0)); + bool grabBackingStore = false; + for (int i = 0; i < r.rects().size(); ++i) { + QRect rect = r.rects().at(i).translated(offset); + for (int t = 0; t < 6; t++) { + const QPixmap pixmap = grabBackingStore + ? child.grab(rect) + : grabWindow(window, rect.left(), rect.top(), rect.width(), rect.height()); + if (!QTest::qCompare(pixmap.size(), rect.size(), "pixmap.size()", "rect.size()", __FILE__, callerLine)) + return false; + QPixmap expectedPixmap(pixmap); /* ensure equal formats */ + expectedPixmap.detach(); + expectedPixmap.fill(color); + QImage image = pixmap.toImage(); + uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; + uint firstPixel = image.pixel(0,0) | alphaCorrection; + if (t < 5) { + /* Normal run. + If it succeeds: return success + If it fails: do not return, but wait a bit and reiterate (retry) + */ + if (firstPixel == QColor(color).rgb() + && image == expectedPixmap.toImage()) { + return true; + } else { + if (t == 4) { + grabBackingStore = true; + rect = r.rects().at(i); + } else { + QTest::qWait(200); + } + } + } else { + // Last run, report failure if it still fails + if (!QTest::qVerify(firstPixel == QColor(color).rgb(), + "firstPixel == QColor(color).rgb()", + qPrintable(msgRgbMismatch(firstPixel, QColor(color).rgb())), + __FILE__, callerLine)) + return false; + if (!QTest::qVerify(image == expectedPixmap.toImage(), + "image == expectedPixmap.toImage()", + "grabbed pixmap differs from expected pixmap", + __FILE__, callerLine)) + return false; + } + } + } + return true; +} void tst_QWidget::popupEnterLeave() {