Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwindowsbackingstore.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
7
8#include <QtGui/qwindow.h>
9#include <QtGui/qpainter.h>
10#include <QtGui/private/qwindowsnativeimage_p.h>
11#include <private/qhighdpiscaling_p.h>
12#include <private/qimage_p.h>
13
14#include <QtCore/qdebug.h>
15
17
18/*!
19 \class QWindowsBackingStore
20 \brief Backing store for windows.
21 \internal
22*/
23
25 QPlatformBackingStore(window),
26 m_alphaNeedsFill(false)
27{
28 qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window;
29}
30
32{
33 qCDebug(lcQpaBackingStore) << __FUNCTION__ << this;
34}
35
37{
38 Q_ASSERT(!m_image.isNull());
39 return &m_image->image();
40}
41
42void QWindowsBackingStore::flush(QWindow *window, const QRegion &region,
43 const QPoint &offset)
44{
45 Q_ASSERT(window);
46
47 const QRect br = region.boundingRect();
48 if (QWindowsContext::verbose > 1)
49 qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br;
50 QWindowsWindow *rw = QWindowsWindow::windowsWindowOf(window);
51 Q_ASSERT(rw);
52
53 const bool hasAlpha = rw->format().hasAlpha();
54 const Qt::WindowFlags flags = window->flags();
55 // Note: This condition must be in sync with setWindowOpacity. FIXME: Improve this :)
56 if (rw->isLayered() && hasAlpha && QWindowsWindow::hasNoNativeFrame(rw->handle(), flags)) {
57 // Windows with alpha: Use blend function to update.
58 QRect r = QHighDpi::toNativePixels(window->frameGeometry(), window);
59 QMargins frameMargins = rw->frameMargins();
60 QRect dirtyRect = br.translated(offset + QPoint(frameMargins.left(), frameMargins.top()));
61
62 SIZE size = {r.width(), r.height()};
63 POINT ptDst = {r.x(), r.y()};
64 POINT ptSrc = {0, 0};
65 BLENDFUNCTION blend = {AC_SRC_OVER, 0, BYTE(qRound(255.0 * rw->opacity())), AC_SRC_ALPHA};
66 RECT dirty = {dirtyRect.x(), dirtyRect.y(),
67 dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()};
68 UPDATELAYEREDWINDOWINFO info = {sizeof(info), nullptr, &ptDst, &size,
69 m_image->hdc(), &ptSrc, 0, &blend, ULW_ALPHA, &dirty};
70 const BOOL result = UpdateLayeredWindowIndirect(rw->handle(), &info);
71 if (!result)
72 qErrnoWarning("UpdateLayeredWindowIndirect failed for ptDst=(%d, %d),"
73 " size=(%dx%d), dirty=(%dx%d %d, %d)", r.x(), r.y(),
74 r.width(), r.height(), dirtyRect.width(), dirtyRect.height(),
75 dirtyRect.x(), dirtyRect.y());
76 } else {
77 const HDC dc = rw->getDC();
78 if (!dc) {
79 qErrnoWarning("%s: GetDC failed", __FUNCTION__);
80 return;
81 }
82
83 if (!BitBlt(dc, br.x(), br.y(), br.width(), br.height(),
84 m_image->hdc(), br.x() + offset.x(), br.y() + offset.y(), SRCCOPY)) {
85 const DWORD lastError = GetLastError(); // QTBUG-35926, QTBUG-29716: may fail after lock screen.
86 if (lastError != ERROR_SUCCESS && lastError != ERROR_INVALID_HANDLE)
87 qErrnoWarning(int(lastError), "%s: BitBlt failed", __FUNCTION__);
88 }
89 rw->releaseDC();
90 }
91
92 // Write image for debug purposes.
93 if (QWindowsContext::verbose > 2 && lcQpaBackingStore().isDebugEnabled()) {
94 static int n = 0;
95 const QString fileName = QString::fromLatin1("win%1_%2.png").
96 arg(rw->winId()).arg(n++);
97 m_image->image().save(fileName);
98 qCDebug(lcQpaBackingStore) << "Wrote " << m_image->image().size() << fileName;
99 }
100}
101
102void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
103{
104 if (m_image.isNull() || m_image->image().size() != size) {
105#ifndef QT_NO_DEBUG_OUTPUT
106 if (QWindowsContext::verbose && lcQpaBackingStore().isDebugEnabled()) {
107 qCDebug(lcQpaBackingStore)
108 << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << region
109 << " from: " << (m_image.isNull() ? QSize() : m_image->image().size());
110 }
111#endif
112 QImage::Format format = window()->format().hasAlpha() ?
113 QImage::Format_ARGB32_Premultiplied : QWindowsNativeImage::systemFormat();
114
115 // The backingstore composition (enabling render-to-texture widgets)
116 // punches holes in the backingstores using the alpha channel. Hence
117 // the need for a true alpha format.
118 if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha)
119 m_alphaNeedsFill = true;
120 else // upgrade but here we know app painting does not rely on alpha hence no need to fill
121 format = qt_maybeDataCompatibleAlphaVersion(format);
122
123 QWindowsNativeImage *oldwni = m_image.data();
124 auto *newwni = new QWindowsNativeImage(size.width(), size.height(), format);
125
126 if (oldwni && !region.isEmpty()) {
127 const QImage &oldimg(oldwni->image());
128 QImage &newimg(newwni->image());
129 QRegion staticRegion(region);
130 staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height());
131 staticRegion &= QRect(0, 0, newimg.width(), newimg.height());
132 QPainter painter(&newimg);
133 painter.setCompositionMode(QPainter::CompositionMode_Source);
134 for (const QRect &rect : staticRegion)
135 painter.drawImage(rect, oldimg, rect);
136 }
137
138 m_image.reset(newwni);
139 }
140}
141
142Q_GUI_EXPORT void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
143
144bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy)
145{
146 if (m_image.isNull() || m_image->image().isNull())
147 return false;
148
149 const QPoint offset(dx, dy);
150 const QRect rect = area.boundingRect();
151 qt_scrollRectInImage(m_image->image(), rect, offset);
152
153 return true;
154}
155
156void QWindowsBackingStore::beginPaint(const QRegion &region)
157{
158 if (QWindowsContext::verbose > 1)
159 qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region;
160
161 if (m_alphaNeedsFill) {
162 QPainter p(&m_image->image());
163 p.setCompositionMode(QPainter::CompositionMode_Source);
164 const QColor blank = Qt::transparent;
165 for (const QRect &r : region)
166 p.fillRect(r, blank);
167 }
168}
169
171{
172 if (!m_image.isNull())
173 return m_image->hdc();
174 return nullptr;
175}
176
178{
179 if (m_image.isNull()) {
180 qCWarning(lcQpaBackingStore) <<__FUNCTION__ << "Image is null.";
181 return QImage();
182 }
183 return m_image.data()->image();
184}
185
186QT_END_NAMESPACE
\inmodule QtCore\reentrant
Definition qpoint.h:29
\inmodule QtGui
Definition qwindow.h:63
Backing store for windows.
void beginPaint(const QRegion &) override
This function is called before painting onto the surface begins, with the region in which the paintin...
QPaintDevice * paintDevice() override
Implement this function to return the appropriate paint device.
bool scroll(const QRegion &area, int dx, int dy) override
Scrolls the given area dx pixels to the right and dy downward; both dx and dy may be negative.
void resize(const QSize &size, const QRegion &r) override
QImage toImage() const override
Implemented in subclasses to return the content of the backingstore as a QImage.
Singleton container for all relevant information.
Q_GUI_EXPORT void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)