diff options
Diffstat (limited to 'tests/manual/embeddedintoforeignwindow/main.cpp')
-rw-r--r-- | tests/manual/embeddedintoforeignwindow/main.cpp | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/tests/manual/embeddedintoforeignwindow/main.cpp b/tests/manual/embeddedintoforeignwindow/main.cpp new file mode 100644 index 0000000000..d7b33683a7 --- /dev/null +++ b/tests/manual/embeddedintoforeignwindow/main.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/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. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "itemwindow.h" + +#include <QtGui/QGuiApplication> + +#include <QtCore/QCommandLineOption> +#include <QtCore/QCommandLineParser> +#include <QtCore/QDebug> +#include <QtCore/QStringList> + +#ifdef Q_OS_WIN +# include <qpa/qplatformnativeinterface.h> +# include <QtCore/QMetaObject> +# include <QtCore/qt_windows.h> +#endif + +#include <eventfilter.h> // diaglib +#include <qwindowdump.h> + +#include <iostream> + +QT_USE_NAMESPACE + +static const char usage[] = + "\nEmbeds a QWindow into a native foreign window passed on the command line.\n" + "When no window ID is passed, a test window is created (Windows only)."; + +static QString windowTitle() +{ + return QLatin1String(QT_VERSION_STR) + QLatin1Char(' ') + QGuiApplication::platformName(); +} + +#ifdef Q_OS_WIN +// Helper to create a native test window (Windows) +static QString registerWindowClass(const QString &name) +{ + QString result; + void *proc = DefWindowProc; + QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface(); + if (!QMetaObject::invokeMethod(ni, "registerWindowClass", Qt::DirectConnection, + Q_RETURN_ARG(QString, result), + Q_ARG(QString, name), + Q_ARG(void *, proc))) { + qWarning("registerWindowClass failed"); + } + return result; +} + +static HWND createNativeWindow(const QString &name) +{ + const HWND hwnd = + CreateWindowEx(0, reinterpret_cast<const wchar_t *>(name.utf16()), + L"NativeWindow", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + 0, 0, GetModuleHandle(NULL), NULL); + + if (!hwnd) { + qErrnoWarning("Cannot create window \"%s\"", qPrintable(name)); + return 0; + } + + const QString text = windowTitle() + QLatin1String(" 0x") + QString::number(quint64(hwnd), 16); + SetWindowText(hwnd, reinterpret_cast<const wchar_t *>(text.utf16())); + return hwnd; +} +#endif // Q_OS_WIN + +// Helper functions for simple management of native windows. +static WId createNativeTestWindow() +{ + WId result = 0; +#ifdef Q_OS_WIN + const QString className = registerWindowClass(QLatin1String("TestClass") + windowTitle()); + const HWND nativeWin = createNativeWindow(className); + result = WId(nativeWin); +#else // Q_OS_WIN + Q_UNIMPLEMENTED(); +#endif + return result; +} + +static void showNativeWindow(WId wid) +{ +#ifdef Q_OS_WIN + ShowWindow(HWND(wid), SW_SHOW); +#else // Q_OS_WIN + Q_UNUSED(wid) + Q_UNIMPLEMENTED(); +#endif +} + +static void setFocusToNativeWindow(WId wid) +{ +#ifdef Q_OS_WIN + SetFocus(HWND(wid)); +#else // Q_OS_WIN + Q_UNUSED(wid) + Q_UNIMPLEMENTED(); +#endif +} + +static void destroyNativeWindow(WId wid) +{ +#ifdef Q_OS_WIN + DestroyWindow(HWND(wid)); +#else // Q_OS_WIN + Q_UNUSED(wid) + Q_UNIMPLEMENTED(); +#endif +} + +// Main test window to be embedded into foreign window with some buttons. +class EmbeddedTestWindow : public ItemWindow { + Q_OBJECT +public: + explicit EmbeddedTestWindow(QWindow *parent = nullptr) : ItemWindow(parent) + { + const int spacing = 10; + const QSize buttonSize(100, 30); + const int width = 3 * buttonSize.width() + 4 * spacing; + + QPoint pos(spacing, spacing); + addItem(new TextItem(::windowTitle(), QRect(pos, QSize(width - 2 * spacing, buttonSize.height())), + Qt::white)); + + pos.ry() += 2 * spacing + buttonSize.height(); + + ButtonItem *mgi = new ButtonItem("Map to global", QRect(pos, buttonSize), + QColor(Qt::yellow).lighter(), this); + connect(mgi, &ButtonItem::clicked, this, &EmbeddedTestWindow::testMapToGlobal); + addItem(mgi); + + pos.rx() += buttonSize.width() + spacing; + ButtonItem *di = new ButtonItem("Dump Wins", QRect(pos, buttonSize), + QColor(Qt::cyan).lighter(), this); + connect(di, &ButtonItem::clicked, this, [] () { QtDiag::dumpAllWindows(); }); + addItem(di); + + pos.rx() += buttonSize.width() + spacing; + ButtonItem *qi = new ButtonItem("Quit", QRect(pos, buttonSize), + QColor(Qt::red).lighter(), this); + qi->setShortcut(Qt::CTRL + Qt::Key_Q); + connect(qi, &ButtonItem::clicked, qApp, &QCoreApplication::quit); + addItem(qi); + + setBackground(Qt::lightGray); + resize(width, pos.y() + buttonSize.height() + spacing); + } + +public slots: + void testMapToGlobal(); +}; + +void EmbeddedTestWindow::testMapToGlobal() +{ + const QPoint globalPos = mapToGlobal(QPoint(0,0)); + qDebug() << "mapToGlobal(QPoint(0,0)" << globalPos + << "cursor at:" << QCursor::pos(); +} + +struct EventFilterOption +{ + const char *name; + const char *description; + QtDiag::EventFilter::EventCategories categories; +}; + +EventFilterOption eventFilterOptions[] = { +{"mouse-events", "Dump mouse events.", QtDiag::EventFilter::MouseEvents}, +{"keyboard-events", "Dump keyboard events.", QtDiag::EventFilter::KeyEvents}, +{"state-events", "Dump state/focus change events.", QtDiag::EventFilter::StateChangeEvents | QtDiag::EventFilter::FocusEvents} +}; + +static inline bool isOptionSet(int argc, char *argv[], const char *option) +{ + return (argv + argc) != + std::find_if(argv + 1, argv + argc, + [option] (const char *arg) { return !qstrcmp(arg, option); }); +} + +int main(int argc, char *argv[]) +{ + // Check for no scaling before QApplication is instantiated. + if (isOptionSet(argc, argv, "-s")) + QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); + QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); + QGuiApplication::setApplicationDisplayName("Foreign Window Embedding Tester"); + + QGuiApplication app(argc, argv); + + // Process command line + QCommandLineParser parser; + parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + parser.setApplicationDescription(QLatin1String(usage)); + parser.addHelpOption(); + parser.addVersionOption(); + QCommandLineOption noScalingDummy(QStringLiteral("s"), + QStringLiteral("Disable High DPI scaling.")); + parser.addOption(noScalingDummy); + const int eventFilterOptionCount = int(sizeof(eventFilterOptions) / sizeof(eventFilterOptions[0])); + for (int i = 0; i < eventFilterOptionCount; ++i) { + parser.addOption(QCommandLineOption(QLatin1String(eventFilterOptions[i].name), + QLatin1String(eventFilterOptions[i].description))); + } + parser.addPositionalArgument(QStringLiteral("[windows]"), QStringLiteral("Window ID.")); + + parser.process(QCoreApplication::arguments()); + + QtDiag::EventFilter::EventCategories eventCategories = 0; + for (int i = 0; i < eventFilterOptionCount; ++i) { + if (parser.isSet(QLatin1String(eventFilterOptions[i].name))) + eventCategories |= eventFilterOptions[i].categories; + } + if (eventCategories) + app.installEventFilter(new QtDiag::EventFilter(eventCategories, &app)); + + // Obtain foreign window to test with. + WId testForeignWinId = 0; + bool createdTestWindow = false; + if (parser.positionalArguments().isEmpty()) { + testForeignWinId = createNativeTestWindow(); + if (!testForeignWinId) + parser.showHelp(-1); + showNativeWindow(testForeignWinId); + createdTestWindow = true; + } else { + bool ok; + const QString &winIdArgument = parser.positionalArguments().constFirst(); + testForeignWinId = winIdArgument.toULongLong(&ok, 0); + if (!ok) { + std::cerr << "Invalid window id: \"" << qPrintable(winIdArgument) << "\"\n"; + return -1; + } + } + if (!testForeignWinId) + parser.showHelp(1); + + QWindow *foreignWindow = QWindow::fromWinId(testForeignWinId); + if (!foreignWindow) + return -2; + foreignWindow->setObjectName("ForeignWindow"); + EmbeddedTestWindow *embeddedTestWindow = new EmbeddedTestWindow(foreignWindow); + embeddedTestWindow->setObjectName("EmbeddedTestWindow"); + embeddedTestWindow->show(); + setFocusToNativeWindow(embeddedTestWindow->winId()); // Windows: Set keyboard focus. + + const int exitCode = app.exec(); + delete embeddedTestWindow; + delete foreignWindow; + if (createdTestWindow) + destroyNativeWindow(testForeignWinId); + return exitCode; +} + +#include "main.moc" |