Add diaglib under manual tests.

Add a set of helper functions and classes providing functionality
for dumping widget/window hierarchies and logging events. They
can be used by including a .pri file for diagnosing bugs and
comparing Qt 5 to Qt 4.

Change-Id: I0206f8e57b02540cd80a3e9446c894023d442ddc
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
This commit is contained in:
Friedemann Kleint 2014-11-07 15:57:25 +01:00
parent 63ae74f365
commit 034ff4deaf
13 changed files with 1104 additions and 0 deletions

View File

@ -0,0 +1,34 @@
This is a collection of functions and classes helpful for diagnosing bugs
in Qt 4 and Qt 5. It can be included in the application's .pro file by
adding:
include([path to Qt sources]/tests/manual/diaglib/diaglib.pri)
For Qt 4, the environment variable QTDIR may be used:
include($$(QTDIR)/tests/manual/diaglib/diaglib.pri)
The .pri file adds the define QT_DIAG_LIB, so, diagnostic
code can be enlosed within #ifdef to work without it as well.
All functions and classes are in the QtDiag namespace.
class EventFilter (eventfilter.h):
An event filter that logs Qt events to qDebug() depending on
configured categories (for example mouse, keyboard, etc).
function glInfo() (glinfo.h):
Returns a string describing the Open GL configuration (obtained
by querying GL_VENDOR and GL_RENDERER). Available only
when the QT qmake variable contains opengl.
functions dumpNativeWindows(), dumpNativeQtTopLevels():
These functions du,p out the hierarchy of native Windows. Currently
implemented for Windows only.
function dumpAllWidgets() (qwidgetdump.h):
Dumps the hierarchy of QWidgets including information about flags,
visibility, geometry, etc.
function dumpAllWindows() (qwindowdump.h):
Dumps the hierarchy of QWindows including information about flags,
visibility, geometry, etc.

View File

@ -0,0 +1,43 @@
INCLUDEPATH += $$PWD
SOURCES += \
$$PWD/eventfilter.cpp \
$$PWD/qwindowdump.cpp \
HEADERS += \
$$PWD/eventfilter.h \
$$PWD/qwindowdump.h \
$$PWD/nativewindowdump.h
win32 {
SOURCES += $$PWD/nativewindowdump_win.cpp
LIBS *= -luser32
} else {
SOURCES += $$PWD/nativewindowdump.cpp
}
greaterThan(QT_MAJOR_VERSION, 4) {
QT += gui-private core-private
contains(QT, widgets) {
HEADERS += \
$$PWD/$$PWD/qwidgetdump.h
SOURCES += \
$$PWD/qwidgetdump.cpp
}
} else {
HEADERS += \
$$PWD/$$PWD/qwidgetdump.h
SOURCES += \
$$PWD/qwidgetdump.cpp
}
contains(QT, opengl) {
HEADERS += \
$$PWD/glinfo.h
SOURCES += \
$$PWD/glinfo.cpp
}
DEFINES += QT_DIAG_LIB

View File

@ -0,0 +1,113 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "eventfilter.h"
#include <QtGui/QMouseEvent>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
namespace QtDiag {
EventFilter::EventFilter(EventCategories eventCategories, QObject *p)
: QObject(p)
{
init(eventCategories);
}
EventFilter::EventFilter(QObject *p)
: QObject(p)
{
init(EventCategories(0xFFFFFFF));
}
void EventFilter::init(EventCategories eventCategories)
{
if (eventCategories & MouseEvents) {
m_eventTypes << QEvent::MouseButtonPress << QEvent::MouseButtonRelease
<< QEvent::MouseButtonDblClick << QEvent::NonClientAreaMouseButtonPress
<< QEvent::NonClientAreaMouseButtonRelease
<< QEvent::NonClientAreaMouseButtonDblClick
<< QEvent::Enter << QEvent::Leave;
}
if (eventCategories & MouseMoveEvents)
m_eventTypes << QEvent::MouseMove << QEvent::NonClientAreaMouseMove;
if (eventCategories & TouchEvents) {
m_eventTypes << QEvent::TouchBegin << QEvent::TouchUpdate << QEvent::TouchEnd;
#if QT_VERSION >= 0x050000
m_eventTypes << QEvent::TouchCancel;
#endif
}
if (eventCategories & TabletEvents) {
m_eventTypes << QEvent::TabletEnterProximity << QEvent::TabletLeaveProximity
<< QEvent::TabletMove << QEvent::TabletPress << QEvent::TabletRelease;
}
if (eventCategories & DragAndDropEvents) {
m_eventTypes << QEvent::DragEnter << QEvent::DragMove << QEvent::DragLeave
<< QEvent::Drop << QEvent::DragResponse;
}
if (eventCategories & KeyEvents) {
m_eventTypes << QEvent::KeyPress << QEvent::KeyRelease << QEvent::ShortcutOverride
<< QEvent::Shortcut;
}
if (eventCategories & GeometryEvents)
m_eventTypes << QEvent::Move << QEvent::Resize;
if (eventCategories & PaintEvents) {
m_eventTypes << QEvent::UpdateRequest << QEvent::Paint
<< QEvent::Show << QEvent::Hide;
#if QT_VERSION >= 0x050000
m_eventTypes << QEvent::Expose;
#endif
}
if (eventCategories & TimerEvents)
m_eventTypes << QEvent::Timer << QEvent::ZeroTimerEvent;
if (eventCategories & ObjectEvents) {
m_eventTypes << QEvent::ChildAdded << QEvent::ChildPolished
<< QEvent::ChildRemoved << QEvent::Create << QEvent::Destroy;
}
}
bool EventFilter::eventFilter(QObject *o, QEvent *e)
{
static int n = 0;
if (m_eventTypes.contains(e->type())) {
QDebug debug = qDebug().nospace();
const QString on = o->objectName();
debug << '#' << n++ << ' ' << o->metaObject()->className();
if (!on.isEmpty())
debug << '/' << on;
debug << ' ' << e;
}
return false;
}
} // namespace QtDiag

View File

@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _EVENTFILTER_
#define _EVENTFILTER_
#include <QtCore/QObject>
#include <QtCore/QEvent>
#include <QtCore/QList>
namespace QtDiag {
// Event filter that can for example be installed on QApplication
// to log relevant events.
class EventFilter : public QObject {
public:
enum EventCategory {
MouseEvents = 0x00001,
MouseMoveEvents = 0x00002,
TouchEvents = 0x00004,
TabletEvents = 0x00008,
DragAndDropEvents = 0x00010,
KeyEvents = 0x00020,
GeometryEvents = 0x00040,
PaintEvents = 0x00080,
TimerEvents = 0x00100,
ObjectEvents = 0x00200
};
Q_DECLARE_FLAGS(EventCategories, EventCategory)
explicit EventFilter(EventCategories eventCategories, QObject *p = 0);
explicit EventFilter(QObject *p = 0);
bool eventFilter(QObject *, QEvent *);
private:
void init(EventCategories eventCategories);
QList<QEvent::Type> m_eventTypes;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(EventFilter::EventCategories)
} // namespace QtDiag
#endif

View File

@ -0,0 +1,112 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "glinfo.h"
#include <QtOpenGL/QGLFunctions>
#include <QtOpenGL/QGLWidget>
#if QT_VERSION > 0x050000
# if QT_VERSION >= 0x050400
# include <QtWidgets/QOpenGLWidget>
# include <QtGui/QOpenGLWindow>
# else // 5.4
# include <QtGui/QWindow>
# endif // 5.0..5.4
# include <QtGui/QOpenGLContext>
# include <QtGui/QOpenGLFunctions>
# include <QtGui/QWindow>
#endif
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <QtCore/QTimer>
namespace QtDiag {
#if QT_VERSION > 0x050000
static QString getGlString(const QOpenGLContext *ctx, GLenum name)
{
if (const GLubyte *p = ctx->functions()->glGetString(name))
return QString::fromLatin1(reinterpret_cast<const char *>(p));
return QString();
}
static QString glInfo(const QOpenGLContext *ctx)
{
return getGlString(ctx, GL_VENDOR)
+ QLatin1Char('\n')
+ getGlString(ctx, GL_RENDERER);
}
static QString glInfo(const QGLContext *ctx)
{
return glInfo(ctx->contextHandle());
}
QString glInfo(const QObject *o)
{
# if QT_VERSION >= 0x050400
if (o->isWindowType()) {
if (const QOpenGLWindow *oglw = qobject_cast<const QOpenGLWindow *>(o))
return glInfo(oglw->context());
return QString();
}
# endif // 5.4
if (o->isWidgetType()) {
if (const QGLWidget *g = qobject_cast<const QGLWidget *>(o))
return glInfo(g->context());
# if QT_VERSION >= 0x050400
if (const QOpenGLWidget *g = qobject_cast<const QOpenGLWidget *>(o))
return glInfo(g->context());
# endif // 5.4
}
return QString();
}
#else // Qt4:
static QString getGlString(GLenum name)
{
if (const GLubyte *p = glGetString(name))
return QString::fromLatin1(reinterpret_cast<const char *>(p));
return QString();
}
QString glInfo(const QWidget *)
{
return getGlString(GL_VENDOR) + QLatin1Char('\n') + getGlString(GL_RENDERER);
}
#endif
} // namespace QtDiag

View File

@ -0,0 +1,48 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _GLINFO_
#define _GLINFO_
#include <QtCore/QtGlobal>
QT_FORWARD_DECLARE_CLASS(QObject)
QT_FORWARD_DECLARE_CLASS(QString)
namespace QtDiag {
QString glInfo(const QObject *o);
} // namespace QtDiag
#endif

View File

@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "nativewindowdump.h"
namespace QtDiag {
void dumpNativeWindows(WId)
{
}
void dumpNativeQtTopLevels()
{
}
} // namespace QtDiag

View File

@ -0,0 +1,46 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _NATIVEWINDOWDUMP_
#define _NATIVEWINDOWDUMP_
#include <QtGui/qwindowdefs.h>
namespace QtDiag {
void dumpNativeWindows(WId root = 0);
void dumpNativeQtTopLevels();
} // namespace QtDiag
#endif

View File

@ -0,0 +1,207 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "nativewindowdump.h"
#include "qwindowdump.h"
#include <QtCore/QTextStream>
#include <QtCore/QSharedPointer>
#include <QtCore/QDebug>
#include <QtCore/QVector>
#include <QtCore/qt_windows.h>
namespace QtDiag {
struct DumpContext {
DumpContext() : indentation(0) {}
int indentation;
QSharedPointer<QTextStream> stream;
};
#define debugWinStyle(str, style, styleConstant) \
if (style & styleConstant) \
str << ' ' << #styleConstant;
static void formatNativeWindow(HWND hwnd, QTextStream &str)
{
str << hex << showbase << quintptr(hwnd) << noshowbase << dec;
RECT rect;
if (GetWindowRect(hwnd, &rect)) {
str << ' ' << (rect.right - rect.left) << 'x' << (rect.bottom - rect.top)
<< '+' << rect.left << '+' << rect.top;
}
if (IsWindowVisible(hwnd))
str << " [visible]";
str << hex << showbase;
if (const LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE)) {
str << " style=" << style;
debugWinStyle(str, style, WS_OVERLAPPED)
debugWinStyle(str, style, WS_POPUP)
debugWinStyle(str, style, WS_MINIMIZE)
debugWinStyle(str, style, WS_CHILD)
debugWinStyle(str, style, WS_VISIBLE)
debugWinStyle(str, style, WS_DISABLED)
debugWinStyle(str, style, WS_CLIPSIBLINGS)
debugWinStyle(str, style, WS_CLIPCHILDREN)
debugWinStyle(str, style, WS_MAXIMIZE)
debugWinStyle(str, style, WS_CAPTION)
debugWinStyle(str, style, WS_BORDER)
debugWinStyle(str, style, WS_DLGFRAME)
debugWinStyle(str, style, WS_VSCROLL)
debugWinStyle(str, style, WS_HSCROLL)
debugWinStyle(str, style, WS_SYSMENU)
debugWinStyle(str, style, WS_THICKFRAME)
debugWinStyle(str, style, WS_GROUP)
debugWinStyle(str, style, WS_TABSTOP)
debugWinStyle(str, style, WS_MINIMIZEBOX)
debugWinStyle(str, style, WS_MAXIMIZEBOX)
}
if (const LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE)) {
str << " exStyle=" << exStyle;
debugWinStyle(str, exStyle, WS_EX_DLGMODALFRAME)
debugWinStyle(str, exStyle, WS_EX_NOPARENTNOTIFY)
debugWinStyle(str, exStyle, WS_EX_TOPMOST)
debugWinStyle(str, exStyle, WS_EX_ACCEPTFILES)
debugWinStyle(str, exStyle, WS_EX_TRANSPARENT)
debugWinStyle(str, exStyle, WS_EX_MDICHILD)
debugWinStyle(str, exStyle, WS_EX_TOOLWINDOW)
debugWinStyle(str, exStyle, WS_EX_WINDOWEDGE)
debugWinStyle(str, exStyle, WS_EX_CLIENTEDGE)
debugWinStyle(str, exStyle, WS_EX_CONTEXTHELP)
debugWinStyle(str, exStyle, WS_EX_RIGHT)
debugWinStyle(str, exStyle, WS_EX_LEFT)
debugWinStyle(str, exStyle, WS_EX_RTLREADING)
debugWinStyle(str, exStyle, WS_EX_LTRREADING)
debugWinStyle(str, exStyle, WS_EX_LEFTSCROLLBAR)
debugWinStyle(str, exStyle, WS_EX_RIGHTSCROLLBAR)
debugWinStyle(str, exStyle, WS_EX_CONTROLPARENT)
debugWinStyle(str, exStyle, WS_EX_STATICEDGE)
debugWinStyle(str, exStyle, WS_EX_APPWINDOW)
debugWinStyle(str, exStyle, WS_EX_LAYERED)
debugWinStyle(str, exStyle, WS_EX_NOINHERITLAYOUT)
debugWinStyle(str, exStyle, WS_EX_NOREDIRECTIONBITMAP)
debugWinStyle(str, exStyle, WS_EX_LAYOUTRTL)
debugWinStyle(str, exStyle, WS_EX_COMPOSITED)
debugWinStyle(str, exStyle, WS_EX_NOACTIVATE)
}
str << noshowbase << dec;
wchar_t buf[512];
if (GetWindowText(hwnd, buf, sizeof(buf)/sizeof(buf[0])))
str << " title=\"" << QString::fromWCharArray(buf) << '"';
if (GetClassName(hwnd, buf, sizeof(buf)/sizeof(buf[0])))
str << " class=\"" << QString::fromWCharArray(buf) << '"';
str << '\n';
}
static void dumpNativeWindowRecursion(HWND hwnd, DumpContext *dc);
BOOL CALLBACK dumpWindowEnumChildProc(HWND hwnd, LPARAM lParam)
{
dumpNativeWindowRecursion(hwnd, reinterpret_cast<DumpContext *>(lParam));
return TRUE;
}
static void dumpNativeWindowRecursion(HWND hwnd, DumpContext *dc)
{
indentStream(*dc->stream, dc->indentation);
formatNativeWindow(hwnd, *dc->stream);
DumpContext nextLevel = *dc;
nextLevel.indentation += 2;
EnumChildWindows(hwnd, dumpWindowEnumChildProc, reinterpret_cast<LPARAM>(&nextLevel));
}
/* recurse by Z order, same result */
static void dumpNativeWindowRecursionByZ(HWND hwnd, DumpContext *dc)
{
indentStream(*dc->stream, dc->indentation);
formatNativeWindow(hwnd, *dc->stream);
if (const HWND topChild = GetTopWindow(hwnd)) {
DumpContext nextLevel = *dc;
nextLevel.indentation += 2;
for (HWND child = topChild; child ; child = GetNextWindow(child, GW_HWNDNEXT))
dumpNativeWindowRecursionByZ(child, &nextLevel);
}
}
typedef QVector<WId> WIdVector;
static void dumpNativeWindows(const WIdVector& wins)
{
DumpContext dc;
QString s;
dc.stream = QSharedPointer<QTextStream>(new QTextStream(&s));
foreach (WId win, wins)
dumpNativeWindowRecursion(reinterpret_cast<HWND>(win), &dc);
#if QT_VERSION > 0x050000
qDebug().noquote() << s;
#else
qDebug("%s", qPrintable(s));
#endif
}
void dumpNativeWindows(WId rootIn)
{
const WId root = rootIn ? rootIn : reinterpret_cast<WId>(GetDesktopWindow());
dumpNativeWindows(WIdVector(1, root));
}
BOOL CALLBACK findQtTopLevelEnumChildProc(HWND hwnd, LPARAM lParam)
{
WIdVector *v = reinterpret_cast<WIdVector *>(lParam);
wchar_t buf[512];
if (GetClassName(hwnd, buf, sizeof(buf)/sizeof(buf[0]))) {
if (wcsstr(buf, L"Qt"))
v->append(reinterpret_cast<WId>(hwnd));
}
return TRUE;
}
static WIdVector findQtTopLevels()
{
WIdVector result;
EnumChildWindows(GetDesktopWindow(),
findQtTopLevelEnumChildProc,
reinterpret_cast<LPARAM>(&result));
return result;
}
void dumpNativeQtTopLevels()
{
dumpNativeWindows(findQtTopLevels());
}
} // namespace QtDiag

View File

@ -0,0 +1,94 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwidgetdump.h"
#include <QWidget>
#if QT_VERSION > 0x050000
# include <QtGui/QScreen>
# include <QtGui/QWindow>
#endif
#include <QApplication>
#include <QtCore/QMetaObject>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
namespace QtDiag {
static void dumpWidgetRecursion(QTextStream &str, const QWidget *w,
FormatWindowOptions options, int depth = 0)
{
indentStream(str, 2 * depth);
formatObject(str, w);
str << ' ' << (w->isVisible() ? "[visible] " : "[hidden] ");
if (const WId nativeWinId = w->internalWinId())
str << "[native: " << hex << showbase << nativeWinId << dec << noshowbase << "] ";
if (w->isWindow())
str << "[top] ";
str << (w->testAttribute(Qt::WA_Mapped) ? "[mapped] " : "[not mapped] ");
if (w->testAttribute(Qt::WA_DontCreateNativeAncestors))
str << "[NoNativeAncestors] ";
formatRect(str, w->geometry());
if (!(options & DontPrintWindowFlags)) {
str << ' ';
formatWindowFlags(str, w->windowFlags());
}
str << '\n';
#if QT_VERSION > 0x050000
if (const QWindow *win = w->windowHandle()) {
indentStream(str, 2 * (1 + depth));
formatWindow(str, win, options);
str << '\n';
}
#endif // Qt 5
foreach (const QObject *co, w->children()) {
if (co->isWidgetType())
dumpWidgetRecursion(str, static_cast<const QWidget *>(co), options, depth + 1);
}
}
void dumpAllWidgets(FormatWindowOptions options)
{
QString d;
QTextStream str(&d);
str << "### QWidgets:\n";
foreach (QWidget *tw, QApplication::topLevelWidgets())
dumpWidgetRecursion(str, tw, options);
#if QT_VERSION > 0x050000
qDebug().noquote() << d;
#else
qDebug("%s", qPrintable(d));
#endif
}
} // namespace QtDiag

View File

@ -0,0 +1,45 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _WIDGETDUMP_
#define _WIDGETDUMP_
#include "qwindowdump.h"
namespace QtDiag {
void dumpAllWidgets(FormatWindowOptions options = 0);
} // namespace QtDiag
#endif

View File

@ -0,0 +1,176 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwindowdump.h"
#if QT_VERSION > 0x050000
# include <QtGui/QGuiApplication>
# include <QtGui/QScreen>
# include <QtGui/QWindow>
# include <qpa/qplatformwindow.h>
#endif
#include <QtCore/QMetaObject>
#include <QtCore/QRect>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
namespace QtDiag {
void indentStream(QTextStream &s, int indent)
{
for (int i = 0; i < indent; ++i)
s << ' ';
}
void formatObject(QTextStream &str, const QObject *o)
{
str << o->metaObject()->className();
const QString on = o->objectName();
if (!on.isEmpty())
str << "/\"" << on << '"';
}
void formatRect(QTextStream &str, const QRect &geom)
{
str << geom.width() << 'x' << geom.height()
<< forcesign << geom.x() << geom.y() << noforcesign;
}
#define debugType(s, type, typeConstant) \
if ((type & typeConstant) == typeConstant) \
s << ' ' << #typeConstant;
#define debugFlag(s, flags, flagConstant) \
if (flags & flagConstant) \
s << ' ' << #flagConstant;
void formatWindowFlags(QTextStream &str, const Qt::WindowFlags flags)
{
str << showbase << hex << unsigned(flags) << dec << noshowbase;
const Qt::WindowFlags windowType = flags & Qt::WindowType_Mask;
debugFlag(str, flags, Qt::Window)
debugType(str, windowType, Qt::Dialog)
debugType(str, windowType, Qt::Sheet)
debugType(str, windowType, Qt::Drawer)
debugType(str, windowType, Qt::Popup)
debugType(str, windowType, Qt::Tool)
debugType(str, windowType, Qt::ToolTip)
debugType(str, windowType, Qt::SplashScreen)
debugType(str, windowType, Qt::Desktop)
debugType(str, windowType, Qt::SubWindow)
#if QT_VERSION > 0x050000
debugType(str, windowType, Qt::ForeignWindow)
debugType(str, windowType, Qt::CoverWindow)
#endif
debugFlag(str, flags, Qt::MSWindowsFixedSizeDialogHint)
debugFlag(str, flags, Qt::MSWindowsOwnDC)
debugFlag(str, flags, Qt::X11BypassWindowManagerHint)
debugFlag(str, flags, Qt::FramelessWindowHint)
debugFlag(str, flags, Qt::WindowTitleHint)
debugFlag(str, flags, Qt::WindowSystemMenuHint)
debugFlag(str, flags, Qt::WindowMinimizeButtonHint)
debugFlag(str, flags, Qt::WindowMaximizeButtonHint)
debugFlag(str, flags, Qt::WindowContextHelpButtonHint)
debugFlag(str, flags, Qt::WindowShadeButtonHint)
debugFlag(str, flags, Qt::WindowStaysOnTopHint)
debugFlag(str, flags, Qt::CustomizeWindowHint)
#if QT_VERSION > 0x050000
debugFlag(str, flags, Qt::WindowTransparentForInput)
debugFlag(str, flags, Qt::WindowOverridesSystemGestures)
debugFlag(str, flags, Qt::WindowDoesNotAcceptFocus)
debugFlag(str, flags, Qt::NoDropShadowWindowHint)
debugFlag(str, flags, Qt::WindowFullscreenButtonHint)
#endif
debugFlag(str, flags, Qt::WindowStaysOnBottomHint)
debugFlag(str, flags, Qt::MacWindowToolBarButtonHint)
debugFlag(str, flags, Qt::BypassGraphicsProxyWidget)
debugFlag(str, flags, Qt::WindowOkButtonHint)
debugFlag(str, flags, Qt::WindowCancelButtonHint)
}
#if QT_VERSION > 0x050000
void formatWindow(QTextStream &str, const QWindow *w, FormatWindowOptions options)
{
const QPlatformWindow *pw = w->handle();
formatObject(str, w);
str << ' ' << (w->isVisible() ? "[visible] " : "[hidden] ");
if (const WId nativeWinId = pw ? pw->winId() : WId(0))
str << "[native: " << hex << showbase << nativeWinId << dec << noshowbase << "] ";
if (w->isTopLevel())
str << "[top] ";
if (w->isExposed())
str << "[exposed] ";
formatRect(str, w->geometry());
if (!(options & DontPrintWindowFlags)) {
str << ' ';
formatWindowFlags(str, w->flags());
}
str << '\n';
}
static void dumpWindowRecursion(QTextStream &str, const QWindow *w,
FormatWindowOptions options = 0, int depth = 0)
{
indentStream(str, 2 * depth);
formatWindow(str, w);
foreach (const QObject *co, w->children()) {
if (co->isWindowType())
dumpWindowRecursion(str, static_cast<const QWindow *>(co), options, depth + 1);
}
}
void dumpAllWindows(FormatWindowOptions options)
{
QString d;
QTextStream str(&d);
str << "### QWindows:\n";
foreach (QWindow *w, QGuiApplication::topLevelWindows())
dumpWindowRecursion(str, w, options);
qDebug().noquote() << d;
}
#else // Qt 5
class QWindow {};
void formatWindow(QTextStream &, const QWindow *, FormatWindowOptions)
{
}
void dumpAllWindows(FormatWindowOptions options)
{
}
#endif // Qt 4
} // namespace QtDiag

View File

@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _WINDOWDUMP_
#define _WINDOWDUMP_
#include <QtCore/qnamespace.h>
QT_FORWARD_DECLARE_CLASS(QRect)
QT_FORWARD_DECLARE_CLASS(QObject)
QT_FORWARD_DECLARE_CLASS(QWindow)
QT_FORWARD_DECLARE_CLASS(QTextStream)
namespace QtDiag {
enum FormatWindowOption {
DontPrintWindowFlags = 0x001
};
Q_DECLARE_FLAGS(FormatWindowOptions, FormatWindowOption)
Q_DECLARE_OPERATORS_FOR_FLAGS(FormatWindowOptions)
void indentStream(QTextStream &s, int indent);
void formatObject(QTextStream &str, const QObject *o);
void formatRect(QTextStream &str, const QRect &geom);
void formatWindowFlags(QTextStream &str, const Qt::WindowFlags flags);
void formatWindow(QTextStream &str, const QWindow *w, FormatWindowOptions options = 0);
void dumpAllWindows(FormatWindowOptions options = 0);
} // namespace QtDiag
#endif