summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2016-06-30 12:07:18 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2016-07-26 14:53:09 +0000
commit2ceccc6f7fd3e7496df26d16119e9b7693932658 (patch)
treee77e812d5beaeb41ef5a91d02dba7ee888342baf
parent79af4e1e31f4fadcd5b0546455894b098f1acc07 (diff)
Add manual test embeddedintoforeignwindow
Add a test for embedding Qt windows into foreign windows. Complements the existing "foreignwindows" test (which embeds foreign windows into Qt). The test has a simple UI based on QRasterWindow allowing for checking events and geometries. Task-number: QTBUG-41186 Change-Id: Ie62a3e250ca666e2fa5c2e3ef37ef0654829397c Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r--tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro7
-rw-r--r--tests/manual/embeddedintoforeignwindow/itemwindow.cpp72
-rw-r--r--tests/manual/embeddedintoforeignwindow/itemwindow.h126
-rw-r--r--tests/manual/embeddedintoforeignwindow/main.cpp287
-rw-r--r--tests/manual/manual.pro3
5 files changed, 494 insertions, 1 deletions
diff --git a/tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro b/tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro
new file mode 100644
index 0000000000..93da4b8c91
--- /dev/null
+++ b/tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+QT += gui-private
+CONFIG += console c++11
+CONFIG -= app_bundle
+SOURCES += main.cpp itemwindow.cpp
+HEADERS += itemwindow.h
+include(../diaglib/diaglib.pri)
diff --git a/tests/manual/embeddedintoforeignwindow/itemwindow.cpp b/tests/manual/embeddedintoforeignwindow/itemwindow.cpp
new file mode 100644
index 0000000000..32a2e6557c
--- /dev/null
+++ b/tests/manual/embeddedintoforeignwindow/itemwindow.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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/QPainter>
+#include <QtGui/QPaintEvent>
+
+void TextItem::paint(QPainter &painter)
+{
+ painter.fillRect(m_rect, m_col);
+ painter.drawRect(m_rect);
+ QTextOption textOption;
+ textOption.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ painter.drawText(m_rect, m_text, textOption);
+}
+
+void ButtonItem::mouseEvent(QMouseEvent *mouseEvent)
+{
+ if (mouseEvent->type() == QEvent::MouseButtonPress && rect().contains(mouseEvent->pos())) {
+ mouseEvent->accept();
+ emit clicked();
+ }
+}
+
+void ButtonItem::keyEvent(QKeyEvent *keyEvent)
+{
+ if (m_shortcut && keyEvent->type() == QEvent::KeyPress
+ && (keyEvent->key() + int(keyEvent->modifiers())) == m_shortcut) {
+ keyEvent->accept();
+ emit clicked();
+ }
+}
+
+void ItemWindow::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+ QRect rect(QPoint(0, 0), size());
+ painter.fillRect(rect, m_background);
+ foreach (Item *i, m_items)
+ i->paint(painter);
+}
diff --git a/tests/manual/embeddedintoforeignwindow/itemwindow.h b/tests/manual/embeddedintoforeignwindow/itemwindow.h
new file mode 100644
index 0000000000..8ea9adaa16
--- /dev/null
+++ b/tests/manual/embeddedintoforeignwindow/itemwindow.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef ITEMWINDOW_H
+#define ITEMWINDOW_H
+
+#include <QtGui/QKeySequence>
+#include <QtGui/QRasterWindow>
+
+QT_USE_NAMESPACE
+
+// ItemWindow: Primitive UI item classes for use with a ItemWindow based
+// on QRasterWindow without widgets allowing a simple UI without widgets.
+
+// Basic item to be used in a ItemWindow
+class Item : public QObject {
+ Q_OBJECT
+public:
+ explicit Item(QObject *parent = nullptr) : QObject(parent) {}
+
+ virtual void paint(QPainter &painter) = 0;
+ virtual void mouseEvent(QMouseEvent *) {}
+ virtual void keyEvent(QKeyEvent *) {}
+};
+
+// Positionable text item
+class TextItem : public Item {
+ Q_OBJECT
+public:
+ explicit TextItem(const QString &text, const QRect &rect, const QColor &col,
+ QObject *parent = nullptr)
+ : Item(parent), m_text(text), m_rect(rect), m_col(col) {}
+
+ void paint(QPainter &painter) override;
+
+ QRect rect() const { return m_rect; }
+
+private:
+ const QString m_text;
+ const QRect m_rect;
+ const QColor m_col;
+};
+
+// "button" item
+class ButtonItem : public TextItem {
+ Q_OBJECT
+public:
+ explicit ButtonItem(const QString &text, const QRect &rect, const QColor &col,
+ QObject *parent = nullptr)
+ : TextItem(text, rect, col, parent), m_shortcut(0) {}
+
+ void mouseEvent(QMouseEvent *mouseEvent) override;
+ void keyEvent(QKeyEvent *keyEvent) override;
+
+ int shortcut() const { return m_shortcut; }
+ void setShortcut(int shortcut) { m_shortcut = shortcut; }
+
+signals:
+ void clicked();
+
+private:
+ int m_shortcut;
+};
+
+#define PROPAGATE_EVENT(windowHandler, eventClass, itemHandler) \
+void windowHandler(eventClass *e) override \
+{ \
+ foreach (Item *i, m_items) \
+ i->itemHandler(e); \
+}
+
+class ItemWindow : public QRasterWindow {
+ Q_OBJECT
+public:
+ explicit ItemWindow(QWindow *parent = nullptr) : QRasterWindow(parent), m_background(Qt::white) {}
+
+ void addItem(Item *item) { m_items.append(item); }
+
+ QColor background() const { return m_background; }
+ void setBackground(const QColor &background) { m_background = background; }
+
+protected:
+ void paintEvent(QPaintEvent *) override;
+ PROPAGATE_EVENT(mousePressEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(mouseReleaseEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(mouseDoubleClickEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(mouseMoveEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(keyPressEvent, QKeyEvent, keyEvent)
+ PROPAGATE_EVENT(keyReleaseEvent, QKeyEvent, keyEvent)
+
+private:
+ QList<Item *> m_items;
+ QColor m_background;
+};
+
+#endif // ITEMWINDOW_H
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"
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index 8e77a321dd..34fd6662ec 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -2,6 +2,7 @@ TEMPLATE=subdirs
SUBDIRS = bearerex \
filetest \
+embeddedintoforeignwindow \
foreignwindows \
gestures \
inputmethodhints \
@@ -66,4 +67,4 @@ win32 {
lessThan(QT_MAJOR_VERSION, 5): SUBDIRS -= bearerex lance qnetworkaccessmanager/qget qmimedatabase qnetworkreply \
qpainfo qscreen socketengine xembed-raster xembed-widgets windowtransparency \
-foreignwindows
+embeddedintoforeignwindow foreignwindows