From 034ff4deaf3e4c998f4572705a1c7624c8499c92 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 7 Nov 2014 15:57:25 +0100 Subject: 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 Reviewed-by: Shawn Rutledge --- tests/manual/diaglib/README.txt | 34 +++++ tests/manual/diaglib/diaglib.pri | 43 ++++++ tests/manual/diaglib/eventfilter.cpp | 113 ++++++++++++++ tests/manual/diaglib/eventfilter.h | 77 ++++++++++ tests/manual/diaglib/glinfo.cpp | 112 ++++++++++++++ tests/manual/diaglib/glinfo.h | 48 ++++++ tests/manual/diaglib/nativewindowdump.cpp | 46 ++++++ tests/manual/diaglib/nativewindowdump.h | 46 ++++++ tests/manual/diaglib/nativewindowdump_win.cpp | 207 ++++++++++++++++++++++++++ tests/manual/diaglib/qwidgetdump.cpp | 94 ++++++++++++ tests/manual/diaglib/qwidgetdump.h | 45 ++++++ tests/manual/diaglib/qwindowdump.cpp | 176 ++++++++++++++++++++++ tests/manual/diaglib/qwindowdump.h | 63 ++++++++ 13 files changed, 1104 insertions(+) create mode 100644 tests/manual/diaglib/README.txt create mode 100644 tests/manual/diaglib/diaglib.pri create mode 100644 tests/manual/diaglib/eventfilter.cpp create mode 100644 tests/manual/diaglib/eventfilter.h create mode 100644 tests/manual/diaglib/glinfo.cpp create mode 100644 tests/manual/diaglib/glinfo.h create mode 100644 tests/manual/diaglib/nativewindowdump.cpp create mode 100644 tests/manual/diaglib/nativewindowdump.h create mode 100644 tests/manual/diaglib/nativewindowdump_win.cpp create mode 100644 tests/manual/diaglib/qwidgetdump.cpp create mode 100644 tests/manual/diaglib/qwidgetdump.h create mode 100644 tests/manual/diaglib/qwindowdump.cpp create mode 100644 tests/manual/diaglib/qwindowdump.h diff --git a/tests/manual/diaglib/README.txt b/tests/manual/diaglib/README.txt new file mode 100644 index 0000000000..13387f5a2a --- /dev/null +++ b/tests/manual/diaglib/README.txt @@ -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. diff --git a/tests/manual/diaglib/diaglib.pri b/tests/manual/diaglib/diaglib.pri new file mode 100644 index 0000000000..138660f85e --- /dev/null +++ b/tests/manual/diaglib/diaglib.pri @@ -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 diff --git a/tests/manual/diaglib/eventfilter.cpp b/tests/manual/diaglib/eventfilter.cpp new file mode 100644 index 0000000000..f0573975f6 --- /dev/null +++ b/tests/manual/diaglib/eventfilter.cpp @@ -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 +#include +#include + +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 diff --git a/tests/manual/diaglib/eventfilter.h b/tests/manual/diaglib/eventfilter.h new file mode 100644 index 0000000000..d87ac68b07 --- /dev/null +++ b/tests/manual/diaglib/eventfilter.h @@ -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 +#include +#include + +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 m_eventTypes; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(EventFilter::EventCategories) + +} // namespace QtDiag + +#endif diff --git a/tests/manual/diaglib/glinfo.cpp b/tests/manual/diaglib/glinfo.cpp new file mode 100644 index 0000000000..cd30e46b45 --- /dev/null +++ b/tests/manual/diaglib/glinfo.cpp @@ -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 +#include +#if QT_VERSION > 0x050000 +# if QT_VERSION >= 0x050400 +# include +# include +# else // 5.4 +# include +# endif // 5.0..5.4 +# include +# include +# include +#endif +#include +#include +#include + +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(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(o)) + return glInfo(oglw->context()); + return QString(); + } +# endif // 5.4 + if (o->isWidgetType()) { + if (const QGLWidget *g = qobject_cast(o)) + return glInfo(g->context()); +# if QT_VERSION >= 0x050400 + if (const QOpenGLWidget *g = qobject_cast(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(p)); + return QString(); +} + +QString glInfo(const QWidget *) +{ + return getGlString(GL_VENDOR) + QLatin1Char('\n') + getGlString(GL_RENDERER); +} + +#endif + +} // namespace QtDiag diff --git a/tests/manual/diaglib/glinfo.h b/tests/manual/diaglib/glinfo.h new file mode 100644 index 0000000000..1f515267f2 --- /dev/null +++ b/tests/manual/diaglib/glinfo.h @@ -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 + +QT_FORWARD_DECLARE_CLASS(QObject) +QT_FORWARD_DECLARE_CLASS(QString) + +namespace QtDiag { + +QString glInfo(const QObject *o); + +} // namespace QtDiag + +#endif diff --git a/tests/manual/diaglib/nativewindowdump.cpp b/tests/manual/diaglib/nativewindowdump.cpp new file mode 100644 index 0000000000..a6c741a085 --- /dev/null +++ b/tests/manual/diaglib/nativewindowdump.cpp @@ -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 diff --git a/tests/manual/diaglib/nativewindowdump.h b/tests/manual/diaglib/nativewindowdump.h new file mode 100644 index 0000000000..405998feea --- /dev/null +++ b/tests/manual/diaglib/nativewindowdump.h @@ -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 + +namespace QtDiag { + +void dumpNativeWindows(WId root = 0); +void dumpNativeQtTopLevels(); + +} // namespace QtDiag + +#endif diff --git a/tests/manual/diaglib/nativewindowdump_win.cpp b/tests/manual/diaglib/nativewindowdump_win.cpp new file mode 100644 index 0000000000..814b580f4b --- /dev/null +++ b/tests/manual/diaglib/nativewindowdump_win.cpp @@ -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 +#include +#include +#include + +#include + +namespace QtDiag { + +struct DumpContext { + DumpContext() : indentation(0) {} + + int indentation; + QSharedPointer 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(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(&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 WIdVector; + +static void dumpNativeWindows(const WIdVector& wins) +{ + DumpContext dc; + QString s; + dc.stream = QSharedPointer(new QTextStream(&s)); + foreach (WId win, wins) + dumpNativeWindowRecursion(reinterpret_cast(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(GetDesktopWindow()); + dumpNativeWindows(WIdVector(1, root)); +} + +BOOL CALLBACK findQtTopLevelEnumChildProc(HWND hwnd, LPARAM lParam) +{ + WIdVector *v = reinterpret_cast(lParam); + wchar_t buf[512]; + if (GetClassName(hwnd, buf, sizeof(buf)/sizeof(buf[0]))) { + if (wcsstr(buf, L"Qt")) + v->append(reinterpret_cast(hwnd)); + } + return TRUE; +} + +static WIdVector findQtTopLevels() +{ + WIdVector result; + EnumChildWindows(GetDesktopWindow(), + findQtTopLevelEnumChildProc, + reinterpret_cast(&result)); + return result; +} + +void dumpNativeQtTopLevels() +{ + dumpNativeWindows(findQtTopLevels()); +} + +} // namespace QtDiag diff --git a/tests/manual/diaglib/qwidgetdump.cpp b/tests/manual/diaglib/qwidgetdump.cpp new file mode 100644 index 0000000000..d4f985c7c8 --- /dev/null +++ b/tests/manual/diaglib/qwidgetdump.cpp @@ -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 +#if QT_VERSION > 0x050000 +# include +# include +#endif +#include +#include +#include +#include + +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(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 diff --git a/tests/manual/diaglib/qwidgetdump.h b/tests/manual/diaglib/qwidgetdump.h new file mode 100644 index 0000000000..f9615b5d2f --- /dev/null +++ b/tests/manual/diaglib/qwidgetdump.h @@ -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 diff --git a/tests/manual/diaglib/qwindowdump.cpp b/tests/manual/diaglib/qwindowdump.cpp new file mode 100644 index 0000000000..2ecc52ca77 --- /dev/null +++ b/tests/manual/diaglib/qwindowdump.cpp @@ -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 +# include +# include +# include +#endif +#include +#include +#include +#include + +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(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 diff --git a/tests/manual/diaglib/qwindowdump.h b/tests/manual/diaglib/qwindowdump.h new file mode 100644 index 0000000000..ab7c0243e9 --- /dev/null +++ b/tests/manual/diaglib/qwindowdump.h @@ -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 + +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 -- cgit v1.2.3