Merge remote-tracking branch 'origin/5.6' into 5.7

Conflicts:
	src/corelib/io/qprocess_win.cpp
	src/widgets/itemviews/qheaderview.cpp

Change-Id: I0a59ade9cd6e91f770fdf298a7d72a41e79fd761
This commit is contained in:
Liang Qi 2016-04-27 09:18:05 +02:00
commit 23a36fd2bf
29 changed files with 337 additions and 93 deletions

View File

@ -53,6 +53,15 @@
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
for (int i = 1; i < argc; ++i) {
if (!qstrcmp(argv[i], "-g"))
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
else if (!qstrcmp(argv[i], "-s"))
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
else if (!qstrcmp(argv[i], "-d"))
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
}
QApplication app(argc, argv); QApplication app(argc, argv);
Widget w; Widget w;

View File

@ -60,10 +60,12 @@
#include <QPushButton> #include <QPushButton>
#include <QTextEdit> #include <QTextEdit>
#include <QSplitter> #include <QSplitter>
#include <QGuiApplication>
#include <QSurfaceFormat> #include <QSurfaceFormat>
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <QDebug> #include <QDebug>
#include <QTextStream>
struct Version { struct Version {
const char *str; const char *str;
@ -235,6 +237,24 @@ Widget::Widget(QWidget *parent)
m_renderWindowContainer = new QWidget; m_renderWindowContainer = new QWidget;
addRenderWindow(); addRenderWindow();
QString description;
QTextStream str(&description);
str << "Qt " << QT_VERSION_STR << ' ' << QGuiApplication::platformName();
const char *openGlVariables[] =
{"QT_ANGLE_PLATFORM", "QT_OPENGL", "QT_OPENGL_BUGLIST", "QT_OPENGL_DLL"};
const size_t variableCount = sizeof(openGlVariables) / sizeof(openGlVariables[0]);
for (size_t v = 0; v < variableCount; ++v) {
if (qEnvironmentVariableIsSet(openGlVariables[v]))
str << ' ' << openGlVariables[v] << '=' << qgetenv(openGlVariables[v]);
}
if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES))
str << " Qt::AA_UseOpenGLES";
if (QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL))
str << " Qt::AA_UseSoftwareOpenGL";
if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL))
str << " Qt::AA_UseSoftwareOpenGL";
layout->addWidget(new QLabel(description));
setLayout(layout); setLayout(layout);
} }

View File

@ -991,12 +991,15 @@ struct QMessagePattern {
QString backtraceSeparator; QString backtraceSeparator;
int backtraceDepth; int backtraceDepth;
}; };
QList<BacktraceParams> backtraceArgs; // backtrace argumens in sequence of %{backtrace QVector<BacktraceParams> backtraceArgs; // backtrace argumens in sequence of %{backtrace
#endif #endif
bool fromEnvironment; bool fromEnvironment;
static QBasicMutex mutex; static QBasicMutex mutex;
}; };
#ifdef QLOGGING_HAVE_BACKTRACE
Q_DECLARE_TYPEINFO(QMessagePattern::BacktraceParams, Q_MOVABLE_TYPE);
#endif
QBasicMutex QMessagePattern::mutex; QBasicMutex QMessagePattern::mutex;

View File

@ -151,12 +151,14 @@ static bool fcntlWorksAfterFlock(const QString &fn)
if (fcntlOK.isDestroyed()) if (fcntlOK.isDestroyed())
return QLockFilePrivate::checkFcntlWorksAfterFlock(fn); return QLockFilePrivate::checkFcntlWorksAfterFlock(fn);
bool *worksPtr = fcntlOK->object(fn); bool *worksPtr = fcntlOK->object(fn);
if (!worksPtr) { if (worksPtr)
worksPtr = new bool(QLockFilePrivate::checkFcntlWorksAfterFlock(fn));
fcntlOK->insert(fn, worksPtr);
}
return *worksPtr; return *worksPtr;
const bool val = QLockFilePrivate::checkFcntlWorksAfterFlock(fn);
worksPtr = new bool(val);
fcntlOK->insert(fn, worksPtr);
return val;
} }
static bool setNativeLocks(const QString &fileName, int fd) static bool setNativeLocks(const QString &fileName, int fd)

View File

@ -365,9 +365,6 @@ void QLoggingRegistry::setApiRules(const QString &content)
*/ */
void QLoggingRegistry::updateRules() void QLoggingRegistry::updateRules()
{ {
if (categoryFilter != defaultCategoryFilter)
return;
rules = qtConfigRules + configRules + apiRules + envRules; rules = qtConfigRules + configRules + apiRules + envRules;
for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it) for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it)

View File

@ -49,6 +49,7 @@
#include <qfileinfo.h> #include <qfileinfo.h>
#include <qregexp.h> #include <qregexp.h>
#include <qwineventnotifier.h> #include <qwineventnotifier.h>
#include <private/qsystemlibrary_p.h>
#include <private/qthread_p.h> #include <private/qthread_p.h>
#include <qdebug.h> #include <qdebug.h>
@ -817,8 +818,45 @@ qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
return stdinChannel.writer->write(data, maxlen); return stdinChannel.writer->write(data, maxlen);
} }
// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails
// with ERROR_ELEVATION_REQUIRED.
static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments,
const QString &workingDir, qint64 *pid)
{
typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *);
static const ShellExecuteExType shellExecuteEx = // XP ServicePack 1 onwards.
reinterpret_cast<ShellExecuteExType>(QSystemLibrary::resolve(QLatin1String("shell32"),
"ShellExecuteExW"));
if (!shellExecuteEx)
return false;
const QString args = qt_create_commandline(QString(), arguments); // needs arguments only
SHELLEXECUTEINFOW shellExecuteExInfo;
memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW));
shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
shellExecuteExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI;
shellExecuteExInfo.lpVerb = L"runas";
const QString program = QDir::toNativeSeparators(programIn);
shellExecuteExInfo.lpFile = reinterpret_cast<LPCWSTR>(program.utf16());
if (!args.isEmpty())
shellExecuteExInfo.lpParameters = reinterpret_cast<LPCWSTR>(args.utf16());
if (!workingDir.isEmpty())
shellExecuteExInfo.lpDirectory = reinterpret_cast<LPCWSTR>(workingDir.utf16());
shellExecuteExInfo.nShow = SW_SHOWNORMAL;
if (!shellExecuteEx(&shellExecuteExInfo))
return false;
if (pid)
*pid = qint64(GetProcessId(shellExecuteExInfo.hProcess));
CloseHandle(shellExecuteExInfo.hProcess);
return true;
}
bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid) bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid)
{ {
static const DWORD errorElevationRequired = 740;
QString args = qt_create_commandline(program, arguments); QString args = qt_create_commandline(program, arguments);
bool success = false; bool success = false;
PROCESS_INFORMATION pinfo; PROCESS_INFORMATION pinfo;
@ -838,6 +876,8 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
CloseHandle(pinfo.hProcess); CloseHandle(pinfo.hProcess);
if (pid) if (pid)
*pid = pinfo.dwProcessId; *pid = pinfo.dwProcessId;
} else if (GetLastError() == errorElevationRequired) {
success = startDetachedUacPrompt(program, arguments, workingDir, pid);
} }
return success; return success;

View File

@ -520,7 +520,7 @@ QMimeType QMimeDatabase::mimeTypeForUrl(const QUrl &url) const
return mimeTypeForFile(url.toLocalFile()); return mimeTypeForFile(url.toLocalFile());
const QString scheme = url.scheme(); const QString scheme = url.scheme();
if (scheme.startsWith(QLatin1String("http"))) if (scheme.startsWith(QLatin1String("http")) || scheme == QLatin1String("mailto"))
return mimeTypeForName(d->defaultMimeType()); return mimeTypeForName(d->defaultMimeType());
return mimeTypeForFile(url.path()); return mimeTypeForFile(url.path());

View File

@ -10092,6 +10092,9 @@ static inline int qt_find_latin1_string(const QChar *haystack, int size,
QLatin1String needle, QLatin1String needle,
int from, Qt::CaseSensitivity cs) int from, Qt::CaseSensitivity cs)
{ {
if (size < needle.size())
return -1;
const char *latin1 = needle.latin1(); const char *latin1 = needle.latin1();
int len = needle.size(); int len = needle.size();
QVarLengthArray<ushort> s(len); QVarLengthArray<ushort> s(len);

View File

@ -72,7 +72,7 @@ public:
inline QDBusArgumentPrivate(int flags = 0) inline QDBusArgumentPrivate(int flags = 0)
: message(0), ref(1), capabilities(flags) : message(0), ref(1), capabilities(flags)
{ } { }
~QDBusArgumentPrivate(); virtual ~QDBusArgumentPrivate();
static bool checkRead(QDBusArgumentPrivate *d); static bool checkRead(QDBusArgumentPrivate *d);
static bool checkReadAndDetach(QDBusArgumentPrivate *&d); static bool checkReadAndDetach(QDBusArgumentPrivate *&d);

View File

@ -1956,7 +1956,7 @@ void QNetworkReplyHttpImplPrivate::_q_networkSessionConnected()
void QNetworkReplyHttpImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) void QNetworkReplyHttpImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState)
{ {
if (sessionState == QNetworkSession::Disconnected if (sessionState == QNetworkSession::Disconnected
&& (state != Idle || state != Reconnecting)) { && state != Idle && state != Reconnecting) {
error(QNetworkReplyImpl::NetworkSessionFailedError, error(QNetworkReplyImpl::NetworkSessionFailedError,
QCoreApplication::translate("QNetworkReply", "Network session error.")); QCoreApplication::translate("QNetworkReply", "Network session error."));
finished(); finished();

View File

@ -325,7 +325,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected()
void QNetworkReplyImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState) void QNetworkReplyImplPrivate::_q_networkSessionStateChanged(QNetworkSession::State sessionState)
{ {
if (sessionState == QNetworkSession::Disconnected if (sessionState == QNetworkSession::Disconnected
&& (state != Idle || state != Reconnecting)) { && state != Idle && state != Reconnecting) {
error(QNetworkReplyImpl::NetworkSessionFailedError, error(QNetworkReplyImpl::NetworkSessionFailedError,
QCoreApplication::translate("QNetworkReply", "Network session error.")); QCoreApplication::translate("QNetworkReply", "Network session error."));
finished(); finished();

View File

@ -2181,7 +2181,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
} }
do { do {
if (state() != ConnectedState) if (state() != ConnectedState && state() != BoundState)
return false; return false;
bool readyToRead = false; bool readyToRead = false;

View File

@ -72,6 +72,7 @@ typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
QCocoaWindow *_platformWindow; QCocoaWindow *_platformWindow;
BOOL _grabbingMouse; BOOL _grabbingMouse;
BOOL _releaseOnMouseUp; BOOL _releaseOnMouseUp;
QPointer<QObject> _watcher;
} }
@property (nonatomic, readonly) QCocoaNSWindow *window; @property (nonatomic, readonly) QCocoaNSWindow *window;
@ -321,6 +322,11 @@ public: // for QNSView
}; };
QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false) QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
// This object is tracked by a 'watcher'
// object in a window helper, preventing use of dangling
// pointers.
QObject sentinel;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -99,6 +99,7 @@ static bool isMouseEvent(NSEvent *ev)
// make sure that m_nsWindow stays valid until the // make sure that m_nsWindow stays valid until the
// QCocoaWindow is deleted by Qt. // QCocoaWindow is deleted by Qt.
[_window setReleasedWhenClosed:NO]; [_window setReleasedWhenClosed:NO];
_watcher = &_platformWindow->sentinel;
} }
return self; return self;
@ -107,7 +108,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)handleWindowEvent:(NSEvent *)theEvent - (void)handleWindowEvent:(NSEvent *)theEvent
{ {
QCocoaWindow *pw = self.platformWindow; QCocoaWindow *pw = self.platformWindow;
if (pw && pw->m_forwardWindow) { if (_watcher && pw && pw->m_forwardWindow) {
if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) { if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) {
QNSView *forwardView = pw->m_qtView; QNSView *forwardView = pw->m_qtView;
if (theEvent.type == NSLeftMouseUp) { if (theEvent.type == NSLeftMouseUp) {
@ -146,7 +147,7 @@ static bool isMouseEvent(NSEvent *ev)
if (!self.window.delegate) if (!self.window.delegate)
return; // Already detached, pending NSAppKitDefined event return; // Already detached, pending NSAppKitDefined event
if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { if (_watcher && pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
NSPoint loc = [theEvent locationInWindow]; NSPoint loc = [theEvent locationInWindow];
NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]]; NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]];
NSRect contentFrame = [[self.window contentView] frame]; NSRect contentFrame = [[self.window contentView] frame];
@ -162,6 +163,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)detachFromPlatformWindow - (void)detachFromPlatformWindow
{ {
_platformWindow = 0; _platformWindow = 0;
_watcher.clear();
[self.window.delegate release]; [self.window.delegate release];
self.window.delegate = nil; self.window.delegate = nil;
} }

View File

@ -374,13 +374,11 @@ QWindowsWindow *QWindowsIntegration::createPlatformWindowHelper(QWindow *window,
QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate() QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
{ {
#if defined(QT_OPENGL_DYNAMIC) #if defined(QT_OPENGL_DYNAMIC)
const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers();
QWindowsOpenGLTester::Renderer requestedRenderer = QWindowsOpenGLTester::requestedRenderer(); QWindowsOpenGLTester::Renderer requestedRenderer = QWindowsOpenGLTester::requestedRenderer();
switch (requestedRenderer) { switch (requestedRenderer) {
case QWindowsOpenGLTester::DesktopGl: case QWindowsOpenGLTester::DesktopGl:
if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) { if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag) if ((QWindowsOpenGLTester::supportedRenderers() & QWindowsOpenGLTester::DisableRotationFlag)
&& !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) { && !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) {
qCWarning(lcQpaGl, "Unable to disable rotation."); qCWarning(lcQpaGl, "Unable to disable rotation.");
} }
@ -406,6 +404,7 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
break; break;
} }
const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers();
if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) { if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) {
if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) { if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag) if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag)

View File

@ -1135,6 +1135,8 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args
return S_OK; return S_OK;
} }
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
// Activate topWindow // Activate topWindow
if (!d->visibleWindows.isEmpty()) { if (!d->visibleWindows.isEmpty()) {
Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated

View File

@ -567,6 +567,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
, m_buttons(0) , m_buttons(0)
, m_focusWindow(0) , m_focusWindow(0)
, m_mouseGrabber(0) , m_mouseGrabber(0)
, m_mousePressWindow(0)
, m_clientLeader(0) , m_clientLeader(0)
, m_systemTrayTracker(0) , m_systemTrayTracker(0)
, m_glIntegration(Q_NULLPTR) , m_glIntegration(Q_NULLPTR)
@ -1379,6 +1380,11 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w)
void QXcbConnection::setMouseGrabber(QXcbWindow *w) void QXcbConnection::setMouseGrabber(QXcbWindow *w)
{ {
m_mouseGrabber = w; m_mouseGrabber = w;
m_mousePressWindow = Q_NULLPTR;
}
void QXcbConnection::setMousePressWindow(QXcbWindow *w)
{
m_mousePressWindow = w;
} }
void QXcbConnection::grabServer() void QXcbConnection::grabServer()

View File

@ -481,6 +481,8 @@ public:
void setFocusWindow(QXcbWindow *); void setFocusWindow(QXcbWindow *);
QXcbWindow *mouseGrabber() const { return m_mouseGrabber; } QXcbWindow *mouseGrabber() const { return m_mouseGrabber; }
void setMouseGrabber(QXcbWindow *); void setMouseGrabber(QXcbWindow *);
QXcbWindow *mousePressWindow() const { return m_mousePressWindow; }
void setMousePressWindow(QXcbWindow *);
QByteArray startupId() const { return m_startupId; } QByteArray startupId() const { return m_startupId; }
void setStartupId(const QByteArray &nextId) { m_startupId = nextId; } void setStartupId(const QByteArray &nextId) { m_startupId = nextId; }
@ -668,6 +670,7 @@ private:
QXcbWindow *m_focusWindow; QXcbWindow *m_focusWindow;
QXcbWindow *m_mouseGrabber; QXcbWindow *m_mouseGrabber;
QXcbWindow *m_mousePressWindow;
xcb_window_t m_clientLeader; xcb_window_t m_clientLeader;
QByteArray m_startupId; QByteArray m_startupId;

View File

@ -592,8 +592,12 @@ QXcbWindow::~QXcbWindow()
{ {
if (window()->type() != Qt::ForeignWindow) if (window()->type() != Qt::ForeignWindow)
destroy(); destroy();
else if (connection()->mouseGrabber() == this) else {
if (connection()->mouseGrabber() == this)
connection()->setMouseGrabber(Q_NULLPTR); connection()->setMouseGrabber(Q_NULLPTR);
if (connection()->mousePressWindow() == this)
connection()->setMousePressWindow(Q_NULLPTR);
}
} }
void QXcbWindow::destroy() void QXcbWindow::destroy()
@ -851,6 +855,16 @@ void QXcbWindow::hide()
if (connection()->mouseGrabber() == this) if (connection()->mouseGrabber() == this)
connection()->setMouseGrabber(Q_NULLPTR); connection()->setMouseGrabber(Q_NULLPTR);
if (QPlatformWindow *w = connection()->mousePressWindow()) {
// Unset mousePressWindow when it (or one of its parents) is unmapped
while (w) {
if (w == this) {
connection()->setMousePressWindow(Q_NULLPTR);
break;
}
w = w->parent();
}
}
m_mapped = false; m_mapped = false;
@ -2199,6 +2213,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
return; return;
} }
connection()->setMousePressWindow(this);
handleMouseEvent(timestamp, local, global, modifiers, source); handleMouseEvent(timestamp, local, global, modifiers, source);
} }
@ -2213,19 +2229,44 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
return; return;
} }
if (connection()->buttons() == Qt::NoButton)
connection()->setMousePressWindow(Q_NULLPTR);
handleMouseEvent(timestamp, local, global, modifiers, source); handleMouseEvent(timestamp, local, global, modifiers, source);
} }
static bool ignoreLeaveEvent(quint8 mode, quint8 detail) static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
{ {
return (mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM /* Checking for XCB_NOTIFY_MODE_GRAB and XCB_NOTIFY_DETAIL_ANCESTOR prevents unwanted
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL * enter/leave events on AwesomeWM on mouse button press. It also ignores duplicated
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL; * enter/leave events on Alt+Tab switching on some WMs with XInput2 events.
* Without XInput2 events the (Un)grabAncestor cannot be checked when mouse button is
* not pressed, otherwise (e.g. on Alt+Tab) it can igonre important enter/leave events.
*/
if (conn) {
const bool mouseButtonsPressed = (conn->buttons() != Qt::NoButton);
#ifdef XCB_USE_XINPUT22
return mouseButtonsPressed || (conn->isAtLeastXI22() && conn->xi2MouseEvents());
#else
return mouseButtonsPressed;
#endif
}
return true;
} }
static bool ignoreEnterEvent(quint8 mode, quint8 detail) static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
{ {
return ((mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR) // Check for AwesomeWM return ((doCheckUnGrabAncestor(conn)
&& mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|| (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR)
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
}
static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn = Q_NULLPTR)
{
return ((doCheckUnGrabAncestor(conn)
&& mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|| (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB) || (mode != XCB_NOTIFY_MODE_NORMAL && mode != XCB_NOTIFY_MODE_UNGRAB)
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL || detail == XCB_NOTIFY_DETAIL_VIRTUAL
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL); || detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
@ -2259,9 +2300,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
const QPoint global = QPoint(root_x, root_y); const QPoint global = QPoint(root_x, root_y);
if (ignoreEnterEvent(mode, detail) if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
|| (connection()->buttons() != Qt::NoButton
&& QGuiApplicationPrivate::lastCursorPosition != global))
return; return;
const QPoint local(event_x, event_y); const QPoint local(event_x, event_y);
@ -2273,11 +2312,7 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
{ {
connection()->setTime(timestamp); connection()->setTime(timestamp);
const QPoint global(root_x, root_y); if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow())
if (ignoreLeaveEvent(mode, detail)
|| (connection()->buttons() != Qt::NoButton
&& QGuiApplicationPrivate::lastCursorPosition != global))
return; return;
EnterEventChecker checker; EnterEventChecker checker;
@ -2300,6 +2335,11 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i
{ {
QPoint local(event_x, event_y); QPoint local(event_x, event_y);
QPoint global(root_x, root_y); QPoint global(root_x, root_y);
// "mousePressWindow" can be NULL i.e. if a window will be grabbed or umnapped, so set it again here
if (connection()->buttons() != Qt::NoButton && connection()->mousePressWindow() == Q_NULLPTR)
connection()->setMousePressWindow(this);
handleMouseEvent(timestamp, local, global, modifiers, source); handleMouseEvent(timestamp, local, global, modifiers, source);
} }

View File

@ -867,9 +867,11 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in
if (newName == idx.data().toString()) if (newName == idx.data().toString())
return true; return true;
const QString parentPath = filePath(parent(idx));
if (newName.isEmpty() if (newName.isEmpty()
|| QDir::toNativeSeparators(newName).contains(QDir::separator()) || QDir::toNativeSeparators(newName).contains(QDir::separator())
|| !QDir(filePath(parent(idx))).rename(oldName, newName)) { || !QDir(parentPath).rename(oldName, newName)) {
#ifndef QT_NO_MESSAGEBOX #ifndef QT_NO_MESSAGEBOX
QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"), QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"),
QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.") QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.")
@ -896,7 +898,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in
parentNode->visibleChildren.removeAt(visibleLocation); parentNode->visibleChildren.removeAt(visibleLocation);
QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName); QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName);
parentNode->children[newName] = oldValue; parentNode->children[newName] = oldValue;
QFileInfo info(d->rootDir, newName); QFileInfo info(parentPath, newName);
oldValue->fileName = newName; oldValue->fileName = newName;
oldValue->parent = parentNode; oldValue->parent = parentNode;
#ifndef QT_NO_FILESYSTEMWATCHER #ifndef QT_NO_FILESYSTEMWATCHER
@ -908,7 +910,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in
parentNode->visibleChildren.insert(visibleLocation, newName); parentNode->visibleChildren.insert(visibleLocation, newName);
d->delayedSort(); d->delayedSort();
emit fileRenamed(filePath(idx.parent()), oldName, newName); emit fileRenamed(parentPath, oldName, newName);
} }
return true; return true;
} }

View File

@ -3013,29 +3013,40 @@ QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) c
{ {
Q_D(const QHeaderView); Q_D(const QHeaderView);
const int max = d->modelSectionCount(); const int max = d->modelSectionCount();
if (d->orientation == Qt::Horizontal) {
int left = max;
int right = 0;
int rangeLeft, rangeRight;
if (d->orientation == Qt::Horizontal) {
int logicalLeft = max;
int logicalRight = 0;
if (d->visualIndices.empty()) {
// If no reordered sections, skip redundant visual-to-logical transformations
for (const auto &r : selection) { for (const auto &r : selection) {
if (r.parent().isValid() || !r.isValid()) if (r.parent().isValid() || !r.isValid())
continue; // we only know about toplevel items and we don't want invalid ranges continue; // we only know about toplevel items and we don't want invalid ranges
// FIXME an item inside the range may be the leftmost or rightmost if (r.left() < logicalLeft)
rangeLeft = visualIndex(r.left()); logicalLeft = r.left();
if (rangeLeft == -1) // in some cases users may change the selections if (r.right() > logicalRight)
continue; // before we have a chance to do the layout logicalRight = r.right();
rangeRight = visualIndex(r.right()); }
if (rangeRight == -1) // in some cases users may change the selections } else {
continue; // before we have a chance to do the layout int left = max;
if (rangeLeft < left) int right = 0;
left = rangeLeft; for (const auto &r : selection) {
if (rangeRight > right) if (r.parent().isValid() || !r.isValid())
right = rangeRight; continue; // we only know about toplevel items and we don't want invalid ranges
for (int k = r.left(); k <= r.right(); ++k) {
int visual = visualIndex(k);
if (visual == -1) // in some cases users may change the selections
continue; // before we have a chance to do the layout
if (visual < left)
left = visual;
if (visual > right)
right = visual;
}
}
logicalLeft = logicalIndex(left);
logicalRight = logicalIndex(right);
} }
int logicalLeft = logicalIndex(left);
int logicalRight = logicalIndex(right);
if (logicalLeft < 0 || logicalLeft >= count() || if (logicalLeft < 0 || logicalLeft >= count() ||
logicalRight < 0 || logicalRight >= count()) logicalRight < 0 || logicalRight >= count())
@ -3047,31 +3058,44 @@ QRegion QHeaderView::visualRegionForSelection(const QItemSelection &selection) c
return QRect(leftPos, 0, rightPos - leftPos, height()); return QRect(leftPos, 0, rightPos - leftPos, height());
} }
// orientation() == Qt::Vertical // orientation() == Qt::Vertical
int logicalTop = max;
int logicalBottom = 0;
if (d->visualIndices.empty()) {
// If no reordered sections, skip redundant visual-to-logical transformations
for (const auto &r : selection) {
if (r.parent().isValid() || !r.isValid())
continue; // we only know about toplevel items and we don't want invalid ranges
if (r.top() < logicalTop)
logicalTop = r.top();
if (r.bottom() > logicalBottom)
logicalBottom = r.bottom();
}
} else {
int top = max; int top = max;
int bottom = 0; int bottom = 0;
int rangeTop, rangeBottom;
for (const auto &r : selection) { for (const auto &r : selection) {
if (r.parent().isValid() || !r.isValid()) if (r.parent().isValid() || !r.isValid())
continue; // we only know about toplevel items continue; // we only know about toplevel items and we don't want invalid ranges
// FIXME an item inside the range may be the leftmost or rightmost for (int k = r.top(); k <= r.bottom(); ++k) {
rangeTop = visualIndex(r.top()); int visual = visualIndex(k);
if (rangeTop == -1) // in some cases users may change the selections if (visual == -1) // in some cases users may change the selections
continue; // before we have a chance to do the layout continue; // before we have a chance to do the layout
rangeBottom = visualIndex(r.bottom()); if (visual < top)
if (rangeBottom == -1) // in some cases users may change the selections top = visual;
continue; // before we have a chance to do the layout if (visual > bottom)
if (rangeTop < top) bottom = visual;
top = rangeTop; }
if (rangeBottom > bottom)
bottom = rangeBottom;
} }
int logicalTop = logicalIndex(top); logicalTop = logicalIndex(top);
int logicalBottom = logicalIndex(bottom); logicalBottom = logicalIndex(bottom);
}
if (logicalTop == -1 || logicalBottom == -1) if (logicalTop < 0 || logicalTop >= count() ||
return QRect(); logicalBottom < 0 || logicalBottom >= count())
return QRegion();
int topPos = sectionViewportPosition(logicalTop); int topPos = sectionViewportPosition(logicalTop);
int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom); int bottomPos = sectionViewportPosition(logicalBottom) + sectionSize(logicalBottom);

View File

@ -5263,7 +5263,9 @@ QPixmap QWidget::grab(const QRect &rectangle)
if (!r.intersects(rect())) if (!r.intersects(rect()))
return QPixmap(); return QPixmap();
QPixmap res(r.size()); const qreal dpr = devicePixelRatioF();
QPixmap res((QSizeF(r.size()) * dpr).toSize());
res.setDevicePixelRatio(dpr);
if (!d->isOpaque) if (!d->isOpaque)
res.fill(Qt::transparent); res.fill(Qt::transparent);
d->render(&res, QPoint(), QRegion(r), renderFlags); d->render(&res, QPoint(), QRegion(r), renderFlags);

View File

@ -3422,12 +3422,28 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom
QSize textSize = option->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); QSize textSize = option->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2);
int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget);
const int width = textSize.width()
+ (option->subControls & QStyle::SC_GroupBoxCheckBox ? indicatorWidth + 5 : 0);
rect = QRect(); rect = QRect();
if (option->rect.width() > width) {
switch (groupBox->textAlignment & Qt::AlignHorizontal_Mask) {
case Qt::AlignHCenter:
rect.moveLeft((option->rect.width() - width) / 2);
break;
case Qt::AlignRight:
rect.moveLeft(option->rect.width() - width);
break;
}
}
if (subControl == SC_GroupBoxCheckBox) { if (subControl == SC_GroupBoxCheckBox) {
rect.setWidth(indicatorWidth); rect.setWidth(indicatorWidth);
rect.setHeight(indicatorHeight); rect.setHeight(indicatorHeight);
rect.moveTop(textSize.height() > indicatorHeight ? (textSize.height() - indicatorHeight) / 2 : 0); rect.moveTop(textSize.height() > indicatorHeight ? (textSize.height() - indicatorHeight) / 2 : 0);
rect.moveLeft(1); rect.translate(1, 0);
} else if (subControl == SC_GroupBoxLabel) { } else if (subControl == SC_GroupBoxLabel) {
rect.setSize(textSize); rect.setSize(textSize);
rect.moveTop(1); rect.moveTop(1);

View File

@ -1149,7 +1149,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget)) if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
alignment |= Qt::TextHideMnemonic; alignment |= Qt::TextHideMnemonic;
if (widget) { // Not needed for QtQuick Controls if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls
//The rect adjustment is a workaround for the menu not really filling its background. //The rect adjustment is a workaround for the menu not really filling its background.
XPThemeData theme(widget, painter, XPThemeData theme(widget, painter,
QWindowsXPStylePrivate::MenuTheme, QWindowsXPStylePrivate::MenuTheme,

View File

@ -513,6 +513,8 @@ void tst_QMimeDatabase::mimeTypeForUrl()
QVERIFY(db.mimeTypeForUrl(QUrl::fromEncoded("http://foo/bar.png")).isDefault()); // HTTP can't know before downloading QVERIFY(db.mimeTypeForUrl(QUrl::fromEncoded("http://foo/bar.png")).isDefault()); // HTTP can't know before downloading
QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar.png")).name(), QString::fromLatin1("image/png")); QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar.png")).name(), QString::fromLatin1("image/png"));
QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar")).name(), QString::fromLatin1("application/octet-stream")); // unknown extension QCOMPARE(db.mimeTypeForUrl(QUrl::fromEncoded("ftp://foo/bar")).name(), QString::fromLatin1("application/octet-stream")); // unknown extension
QCOMPARE(db.mimeTypeForUrl(QUrl("mailto:something@example.com")).name(), QString::fromLatin1("application/octet-stream")); // unknown
QCOMPARE(db.mimeTypeForUrl(QUrl("mailto:something@polish.pl")).name(), QString::fromLatin1("application/octet-stream")); // unknown, NOT perl ;)
} }
void tst_QMimeDatabase::mimeTypeForData_data() void tst_QMimeDatabase::mimeTypeForData_data()

View File

@ -29,9 +29,16 @@
#include <QtCore> #include <QtCore>
#include <QtNetwork> #include <QtNetwork>
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC)
# include <crtdbg.h>
#endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// Windows: Suppress crash notification dialog.
#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) && defined(Q_CC_MSVC)
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
#endif
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
QTcpServer server; QTcpServer server;

View File

@ -693,6 +693,7 @@ void tst_QFileSystemModel::nameFilters()
} }
void tst_QFileSystemModel::setData_data() void tst_QFileSystemModel::setData_data()
{ {
QTest::addColumn<QString>("subdirName");
QTest::addColumn<QStringList>("files"); QTest::addColumn<QStringList>("files");
QTest::addColumn<QString>("oldFileName"); QTest::addColumn<QString>("oldFileName");
QTest::addColumn<QString>("newFileName"); QTest::addColumn<QString>("newFileName");
@ -702,7 +703,15 @@ void tst_QFileSystemModel::setData_data()
<< QDir::temp().absolutePath() + '/' + "a" << QDir::temp().absolutePath() + '/' + "a"
<< false; << false;
*/ */
QTest::newRow("in current dir") << (QStringList() << "a" << "b" << "c") QTest::newRow("in current dir")
<< QString()
<< (QStringList() << "a" << "b" << "c")
<< "a"
<< "d"
<< true;
QTest::newRow("in subdir")
<< "s"
<< (QStringList() << "a" << "b" << "c")
<< "a" << "a"
<< "d" << "d"
<< true; << true;
@ -711,15 +720,25 @@ void tst_QFileSystemModel::setData_data()
void tst_QFileSystemModel::setData() void tst_QFileSystemModel::setData()
{ {
QSignalSpy spy(model, SIGNAL(fileRenamed(QString,QString,QString))); QSignalSpy spy(model, SIGNAL(fileRenamed(QString,QString,QString)));
QString tmp = flatDirTestPath; QFETCH(QString, subdirName);
QFETCH(QStringList, files); QFETCH(QStringList, files);
QFETCH(QString, oldFileName); QFETCH(QString, oldFileName);
QFETCH(QString, newFileName); QFETCH(QString, newFileName);
QFETCH(bool, success); QFETCH(bool, success);
QString tmp = flatDirTestPath;
if (!subdirName.isEmpty()) {
QDir dir(tmp);
QVERIFY(dir.mkdir(subdirName));
tmp.append('/' + subdirName);
}
QVERIFY(createFiles(tmp, files)); QVERIFY(createFiles(tmp, files));
QModelIndex root = model->setRootPath(tmp); QModelIndex tmpIdx = model->setRootPath(flatDirTestPath);
QTRY_COMPARE(model->rowCount(root), files.count()); if (!subdirName.isEmpty()) {
tmpIdx = model->index(tmp);
model->fetchMore(tmpIdx);
}
QTRY_COMPARE(model->rowCount(tmpIdx), files.count());
QModelIndex idx = model->index(tmp + '/' + oldFileName); QModelIndex idx = model->index(tmp + '/' + oldFileName);
QCOMPARE(idx.isValid(), true); QCOMPARE(idx.isValid(), true);
@ -727,16 +746,21 @@ void tst_QFileSystemModel::setData()
model->setReadOnly(false); model->setReadOnly(false);
QCOMPARE(model->setData(idx, newFileName), success); QCOMPARE(model->setData(idx, newFileName), success);
model->setReadOnly(true);
if (success) { if (success) {
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QList<QVariant> arguments = spy.takeFirst(); QList<QVariant> arguments = spy.takeFirst();
QCOMPARE(model->data(idx, QFileSystemModel::FileNameRole).toString(), newFileName); QCOMPARE(model->data(idx, QFileSystemModel::FileNameRole).toString(), newFileName);
QCOMPARE(model->fileInfo(idx).filePath(), tmp + '/' + newFileName);
QCOMPARE(model->index(arguments.at(0).toString()), model->index(tmp)); QCOMPARE(model->index(arguments.at(0).toString()), model->index(tmp));
QCOMPARE(arguments.at(1).toString(), oldFileName); QCOMPARE(arguments.at(1).toString(), oldFileName);
QCOMPARE(arguments.at(2).toString(), newFileName); QCOMPARE(arguments.at(2).toString(), newFileName);
QCOMPARE(QFile::rename(tmp + '/' + newFileName, tmp + '/' + oldFileName), true); QCOMPARE(QFile::rename(tmp + '/' + newFileName, tmp + '/' + oldFileName), true);
} }
QTRY_COMPARE(model->rowCount(root), files.count()); QTRY_COMPARE(model->rowCount(tmpIdx), files.count());
// cleanup
if (!subdirName.isEmpty())
QVERIFY(QDir(tmp).removeRecursively());
} }
void tst_QFileSystemModel::sortPersistentIndex() void tst_QFileSystemModel::sortPersistentIndex()

View File

@ -73,6 +73,7 @@ public:
void testEvent(); void testEvent();
void testhorizontalOffset(); void testhorizontalOffset();
void testverticalOffset(); void testverticalOffset();
void testVisualRegionForSelection();
friend class tst_QHeaderView; friend class tst_QHeaderView;
}; };
@ -204,6 +205,7 @@ private slots:
void QTBUG8650_crashOnInsertSections(); void QTBUG8650_crashOnInsertSections();
void QTBUG12268_hiddenMovedSectionSorting(); void QTBUG12268_hiddenMovedSectionSorting();
void QTBUG14242_hideSectionAutoSize(); void QTBUG14242_hideSectionAutoSize();
void QTBUG50171_visualRegionForSwappedItems();
void ensureNoIndexAtLength(); void ensureNoIndexAtLength();
void offsetConsistent(); void offsetConsistent();
@ -2281,6 +2283,24 @@ void tst_QHeaderView::QTBUG14242_hideSectionAutoSize()
QCOMPARE(calced_length, afterlength); QCOMPARE(calced_length, afterlength);
} }
void tst_QHeaderView::QTBUG50171_visualRegionForSwappedItems()
{
protected_QHeaderView headerView(Qt::Horizontal);
QtTestModel model;
model.rows = 2;
model.cols = 3;
headerView.setModel(&model);
headerView.swapSections(1, 2);
headerView.hideSection(0);
headerView.testVisualRegionForSelection();
}
void protected_QHeaderView::testVisualRegionForSelection()
{
QRegion r = visualRegionForSelection(QItemSelection(model()->index(1, 0), model()->index(1, 2)));
QCOMPARE(r.boundingRect().contains(QRect(1, 1, length() - 2, 1)), true);
}
void tst_QHeaderView::ensureNoIndexAtLength() void tst_QHeaderView::ensureNoIndexAtLength()
{ {
QTableView qtv; QTableView qtv;

View File

@ -3030,8 +3030,23 @@ protected:
QSize sizeHint() const { return QSize(500, 500); } QSize sizeHint() const { return QSize(500, 500); }
}; };
// Scale to remove devicePixelRatio should scaling be active.
static QPixmap grabFromWidget(QWidget *w, const QRect &rect)
{
QPixmap pixmap = w->grab(rect);
const qreal devicePixelRatio = pixmap.devicePixelRatioF();
if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
pixmap = pixmap.scaled((QSizeF(pixmap.size()) / devicePixelRatio).toSize(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
pixmap.setDevicePixelRatio(1);
}
return pixmap;
}
void tst_QWidget::testContentsPropagation() void tst_QWidget::testContentsPropagation()
{ {
if (!qFuzzyCompare(qApp->devicePixelRatio(), qreal(1)))
QSKIP("This test does not work with scaling.");
ContentsPropagationWidget widget; ContentsPropagationWidget widget;
widget.setFixedSize(500, 500); widget.setFixedSize(500, 500);
widget.setContentsPropagation(false); widget.setContentsPropagation(false);
@ -9203,7 +9218,7 @@ void tst_QWidget::rectOutsideCoordinatesLimit_task144779()
QPixmap correct(main.size()); QPixmap correct(main.size());
correct.fill(Qt::green); correct.fill(Qt::green);
const QPixmap mainPixmap = main.grab(QRect(QPoint(0, 0), QSize(-1, -1))); const QPixmap mainPixmap = grabFromWidget(&main, QRect(QPoint(0, 0), QSize(-1, -1)));
QTRY_COMPARE(mainPixmap.toImage().convertToFormat(QImage::Format_RGB32), QTRY_COMPARE(mainPixmap.toImage().convertToFormat(QImage::Format_RGB32),
correct.toImage().convertToFormat(QImage::Format_RGB32)); correct.toImage().convertToFormat(QImage::Format_RGB32));
@ -9667,10 +9682,10 @@ void tst_QWidget::grab()
p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0); p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0);
p.end(); p.end();
QPixmap actual = widget.grab(QRect(64, 64, 64, 64)); QPixmap actual = grabFromWidget(&widget, QRect(64, 64, 64, 64));
QVERIFY(lenientCompare(actual, expected)); QVERIFY(lenientCompare(actual, expected));
actual = widget.grab(QRect(64, 64, -1, -1)); actual = grabFromWidget(&widget, QRect(64, 64, -1, -1));
QVERIFY(lenientCompare(actual, expected)); QVERIFY(lenientCompare(actual, expected));
// Make sure a widget that is not yet shown is grabbed correctly. // Make sure a widget that is not yet shown is grabbed correctly.