diff options
-rw-r--r-- | dist/changes-5.10.0 | 30 | ||||
-rw-r--r-- | dist/changes-5.6.3 | 12 | ||||
-rw-r--r-- | dist/changes-5.9.2 | 12 | ||||
-rw-r--r-- | src/x11extras/doc/src/qtx11extras-index.qdoc | 10 | ||||
-rw-r--r-- | src/x11extras/doc/src/qtx11extras-module.qdoc | 10 | ||||
-rw-r--r-- | src/x11extras/qx11info_x11.cpp | 158 | ||||
-rw-r--r-- | src/x11extras/qx11info_x11.h | 17 | ||||
-rw-r--r-- | tests/auto/qx11info/qx11info.pro | 1 | ||||
-rw-r--r-- | tests/auto/qx11info/tst_qx11info.cpp | 214 | ||||
-rw-r--r-- | tests/manual/manual.pro | 3 | ||||
-rw-r--r-- | tests/manual/peeker/main.cpp | 111 | ||||
-rw-r--r-- | tests/manual/peeker/peeker.pro | 6 | ||||
-rw-r--r-- | tests/tests.pro | 2 |
13 files changed, 573 insertions, 13 deletions
diff --git a/dist/changes-5.10.0 b/dist/changes-5.10.0 new file mode 100644 index 0000000..79bc713 --- /dev/null +++ b/dist/changes-5.10.0 @@ -0,0 +1,30 @@ +Qt 5.10 introduces many new features and improvements as well as bugfixes +over the 5.9.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.10 series is binary compatible with the 5.9.x series. +Applications compiled for 5.9 will continue to run with 5.10. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.10.0 Changes * +**************************************************************************** + + - This release contains only minor code improvements. + +QX11Info +-------- + + - [QTBUG-50358] Added new API to peek into the XCB event queue - + peekEventQueue(). This enables porting certain Qt4-based applications to + Qt5 (those using Xlib's event handling functions to peek into the X11 + event queue). diff --git a/dist/changes-5.6.3 b/dist/changes-5.6.3 new file mode 100644 index 0000000..285d4a8 --- /dev/null +++ b/dist/changes-5.6.3 @@ -0,0 +1,12 @@ +Qt 5.6.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.6.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://doc.qt.io/qt-5/index.html + +The Qt version 5.6 series is binary compatible with the 5.5.x series. +Applications compiled for 5.5 will continue to run with 5.6. + +There were no changes in this module since previous release. diff --git a/dist/changes-5.9.2 b/dist/changes-5.9.2 new file mode 100644 index 0000000..f4d7bdb --- /dev/null +++ b/dist/changes-5.9.2 @@ -0,0 +1,12 @@ +Qt 5.9.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +There were no changes in this module since previous release. diff --git a/src/x11extras/doc/src/qtx11extras-index.qdoc b/src/x11extras/doc/src/qtx11extras-index.qdoc index 0883593..e89d606 100644 --- a/src/x11extras/doc/src/qtx11extras-index.qdoc +++ b/src/x11extras/doc/src/qtx11extras-index.qdoc @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. ** @@ -11,8 +11,8 @@ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free @@ -20,7 +20,7 @@ ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements -** will be met: http://www.gnu.org/copyleft/fdl.html. +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/x11extras/doc/src/qtx11extras-module.qdoc b/src/x11extras/doc/src/qtx11extras-module.qdoc index 6854ae6..8eaecab 100644 --- a/src/x11extras/doc/src/qtx11extras-module.qdoc +++ b/src/x11extras/doc/src/qtx11extras-module.qdoc @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. ** @@ -11,8 +11,8 @@ ** 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. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free @@ -20,7 +20,7 @@ ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements -** will be met: http://www.gnu.org/copyleft/fdl.html. +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/x11extras/qx11info_x11.cpp b/src/x11extras/qx11info_x11.cpp index 6c40c63..9f5d8a2 100644 --- a/src/x11extras/qx11info_x11.cpp +++ b/src/x11extras/qx11info_x11.cpp @@ -403,4 +403,162 @@ bool QX11Info::isCompositingManagerRunning(int screen) return native->nativeResourceForScreen(QByteArray("compositingEnabled"), scr); } +/*! + Returns a new peeker id or -1 if some interal error has occurred. + Each peeker id is associated with an index in the buffered native + event queue. + + For more details see QX11Info::PeekOption and peekEventQueue(). + + \sa peekEventQueue(), removePeekerId() + \since 5.10 +*/ +qint32 QX11Info::generatePeekerId() +{ + if (!qApp) + return -1; + QPlatformNativeInterface *native = qApp->platformNativeInterface(); + if (!native) + return -1; + + typedef qint32 (*GeneratePeekerIdFunc)(void); + GeneratePeekerIdFunc generatepeekerid = reinterpret_cast<GeneratePeekerIdFunc>( + native->nativeResourceFunctionForIntegration("generatepeekerid")); + if (!generatepeekerid) { + qWarning("Internal error: QPA plugin doesn't implement generatePeekerId"); + return -1; + } + + return generatepeekerid(); +} + +/*! + Removes \a peekerId, which was earlier obtained via generatePeekerId(). + + Returns \c true on success or \c false if unknown peeker id was + provided or some interal error has occurred. + + \sa generatePeekerId() + \since 5.10 +*/ +bool QX11Info::removePeekerId(qint32 peekerId) +{ + if (!qApp) + return false; + QPlatformNativeInterface *native = qApp->platformNativeInterface(); + if (!native) + return false; + + typedef bool (*RemovePeekerIdFunc)(qint32); + RemovePeekerIdFunc removePeekerId = reinterpret_cast<RemovePeekerIdFunc>( + native->nativeResourceFunctionForIntegration("removepeekerid")); + if (!removePeekerId) { + qWarning("Internal error: QPA plugin doesn't implement removePeekerId"); + return false; + } + + return removePeekerId(peekerId); +} + +/*! + \enum QX11Info::PeekOption + \brief An enum to tune the behavior of QX11Info::peekEventQueue(). + + \value PeekDefault + Peek from the beginning of the buffered native event queue. A peeker + id is optional with PeekDefault. If a peeker id is provided to + peekEventQueue() when using PeekDefault, then peeking starts from + the beginning of the queue, not from the cached index; thus, this + can be used to manually reset a cached index to peek from the start + of the queue. When this operation completes, the associated index + will be updated to the new position in the queue. + + \value PeekFromCachedIndex + QX11Info::peekEventQueue() can optimize the peeking algorithm by + skipping events that it already has seen in earlier calls to + peekEventQueue(). When control returns to the main event loop, + which causes the buffered native event queue to be flushed to Qt's + event queue, the cached indices are marked invalid and will be + reset on the next access. The same is true if the program + explicitly flushes the buffered native event queue by + QCoreApplication::processEvents(). + + \since 5.10 +*/ + +/*! + \typedef QX11Info::PeekerCallback + Typedef for a pointer to a function with the following signature: + + \code + bool (*PeekerCallback)(xcb_generic_event_t *event, void *peekerData); + \endcode + + The \a event is a native XCB event. + The \a peekerData is a pointer to data, passed in via peekEventQueue(). + + Return \c true from this function to stop examining the buffered + native event queue or \c false to continue. + + \note A non-capturing lambda can serve as a PeekerCallback. + \since 5.10 +*/ + +/*! + \brief Peek into the buffered XCB event queue. + + You can call peekEventQueue() periodically, when your program is busy + performing a long-running operation, to peek into the buffered native + event queue. The more time the long-running operation blocks the + program from returning control to the main event loop, the more + events will accumulate in the buffered XCB event queue. Once control + returns to the main event loop these events will be flushed to Qt's + event queue, which is a separate event queue from the queue this + function is peeking into. + + \note It is usually better to run CPU-intensive operations in a + non-GUI thread, instead of blocking the main event loop. + + The buffered XCB event queue is populated from a non-GUI thread and + therefore might be ahead of the current GUI state. To handle native + events as they are processed by the GUI thread, see + QAbstractNativeEventFilter::nativeEventFilter(). + + The \a peeker is a callback function as documented in PeekerCallback. + The \a peekerData can be used to pass in arbitrary data to the \a + peeker callback. + The \a option is an enum that tunes the behavior of peekEventQueue(). + The \a peekerId is used to track an index in the queue, for more + details see QX11Info::PeekOption. There can be several indices, + each tracked individually by a peeker id obtained via generatePeekerId(). + + This function returns \c true when the peeker has stopped the event + proccesing by returning \c true from the callback. If there were no + events in the buffered native event queue to peek at or all the + events have been processed by the peeker, this function returns \c + false. + + \sa generatePeekerId(), QAbstractNativeEventFilter::nativeEventFilter() + \since 5.10 +*/ +bool QX11Info::peekEventQueue(PeekerCallback peeker, void *peekerData, PeekOptions option, + qint32 peekerId) +{ + if (!peeker || !qApp) + return false; + QPlatformNativeInterface *native = qApp->platformNativeInterface(); + if (!native) + return false; + + typedef bool (*PeekEventQueueFunc)(PeekerCallback, void *, PeekOptions, qint32); + PeekEventQueueFunc peekeventqueue = reinterpret_cast<PeekEventQueueFunc>( + native->nativeResourceFunctionForIntegration("peekeventqueue")); + if (!peekeventqueue) { + qWarning("Internal error: QPA plugin doesn't implement peekEventQueue"); + return false; + } + + return peekeventqueue(peeker, peekerData, option, peekerId); +} + QT_END_NAMESPACE diff --git a/src/x11extras/qx11info_x11.h b/src/x11extras/qx11info_x11.h index ab72686..c0bfbf8 100644 --- a/src/x11extras/qx11info_x11.h +++ b/src/x11extras/qx11info_x11.h @@ -43,14 +43,21 @@ #include <QtCore/qnamespace.h> #include "QtX11Extras/qtx11extrasglobal.h" +#include <xcb/xcb.h> + typedef struct _XDisplay Display; -struct xcb_connection_t; QT_BEGIN_NAMESPACE class Q_X11EXTRAS_EXPORT QX11Info { public: + enum PeekOption { + PeekDefault = 0, + PeekFromCachedIndex = 1 + }; + Q_DECLARE_FLAGS(PeekOptions, PeekOption) + static bool isPlatformX11(); static int appDpiX(int screen=-1); @@ -75,10 +82,18 @@ public: static bool isCompositingManagerRunning(int screen = -1); + static qint32 generatePeekerId(); + static bool removePeekerId(qint32 peekerId); + typedef bool (*PeekerCallback)(xcb_generic_event_t *event, void *peekerData); + static bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr, + PeekOptions option = PeekDefault, qint32 peekerId = -1); + private: QX11Info(); }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QX11Info::PeekOptions) + QT_END_NAMESPACE #endif // QX11INFO_X11_H diff --git a/tests/auto/qx11info/qx11info.pro b/tests/auto/qx11info/qx11info.pro index 9059baa..3a34ecd 100644 --- a/tests/auto/qx11info/qx11info.pro +++ b/tests/auto/qx11info/qx11info.pro @@ -2,3 +2,4 @@ CONFIG += testcase TARGET = tst_qx11info QT += x11extras widgets testlib SOURCES += tst_qx11info.cpp +LIBS += -lxcb diff --git a/tests/auto/qx11info/tst_qx11info.cpp b/tests/auto/qx11info/tst_qx11info.cpp index a27f443..e997832 100644 --- a/tests/auto/qx11info/tst_qx11info.cpp +++ b/tests/auto/qx11info/tst_qx11info.cpp @@ -27,7 +27,7 @@ ** ****************************************************************************/ - +#include <QtGui> #include <QtTest/QtTest> #include <QApplication> @@ -42,6 +42,7 @@ private slots: void startupId(); void isPlatformX11(); void appTime(); + void peeker(); }; void tst_QX11Info::staticFunctionsBeforeQApplication() @@ -162,6 +163,217 @@ void tst_QX11Info::appTime() QCOMPARE(QX11Info::appUserTime(), u1); } +class PeekerTest : public QWindow +{ +public: + PeekerTest() + { + setGeometry(100, 100, 400, 400); + m_peekerFirstId = QX11Info::generatePeekerId(); + QVERIFY(m_peekerFirstId >= 0); + m_peekerSecondId = QX11Info::generatePeekerId(); + QVERIFY(m_peekerSecondId == m_peekerFirstId + 1); + // Get X atoms + xcb_connection_t *c = QX11Info::connection(); + const char *first = "QT_XCB_PEEKER_TEST_FIRST"; + const char *second = "QT_XCB_PEEKER_TEST_SECOND"; + xcb_intern_atom_reply_t *reply = + xcb_intern_atom_reply(c, xcb_intern_atom(c, false, strlen(first), first), 0); + QVERIFY2(reply != nullptr, first); + m_atomFirst = reply->atom; + free(reply); + reply = xcb_intern_atom_reply(c, xcb_intern_atom(c, false, strlen(second), second), 0); + QVERIFY2(reply != nullptr, second); + m_atomSecond = reply->atom; + free(reply); + } + +protected: + void triggerPropertyNotifyEvents() + { + xcb_window_t rootWindow = QX11Info::appRootWindow(); + xcb_connection_t *connection = QX11Info::connection(); + xcb_change_property(connection, XCB_PROP_MODE_APPEND, rootWindow, m_atomFirst, + XCB_ATOM_INTEGER, 32, 0, nullptr); + xcb_change_property(connection, XCB_PROP_MODE_APPEND, rootWindow, m_atomSecond, + XCB_ATOM_INTEGER, 32, 0, nullptr); + xcb_flush(connection); + } + + static bool checkForPropertyNotifyByAtom(xcb_generic_event_t *event, void *data) + { + bool isPropertyNotify = (event->response_type & ~0x80) == XCB_PROPERTY_NOTIFY; + if (isPropertyNotify) { + xcb_property_notify_event_t *pn = + reinterpret_cast<xcb_property_notify_event_t *>(event); + xcb_atom_t *atom = static_cast<xcb_atom_t *>(data); + if (pn->atom == *atom) + return true; + } + return false; + } + + bool sanityCheckPeeking(xcb_generic_event_t *event) + { + m_countWithCaching++; + bool isPropertyNotify = (event->response_type & ~0x80) == XCB_PROPERTY_NOTIFY; + if (isPropertyNotify) { + xcb_property_notify_event_t *pn = + reinterpret_cast<xcb_property_notify_event_t *>(event); + if (pn->atom == m_atomFirst) { + if (m_indexFirst == -1) { + m_indexFirst = m_countWithCaching; + // continue peeking, maybe the second event is already in the queue + return false; + } + m_foundFirstEventAgain = true; + // Return so we can fail the test with QVERIFY2, for more details + // see QTBUG-62354 + return true; + } + // Let it peek to the end, even when the second event was found + if (pn->atom == m_atomSecond) { + m_indexSecond = m_countWithCaching; + if (m_indexFirst == -1) { + m_foundSecondBeforeFirst = true; + // Same as above, see QTBUG-62354 + return true; + } + } + } + return false; + } + + void exposeEvent(QExposeEvent *) + { + if (m_ignoreSubsequentExpose) + return; + // We don't want to execute this handler again in case there are more expose + // events after calling QCoreApplication::processEvents() later in this test + m_ignoreSubsequentExpose = true; + + xcb_flush(QX11Info::connection()); + bool found = QX11Info::peekEventQueue(checkForPropertyNotifyByAtom, &m_atomFirst); + QVERIFY2(!found, "Found m_atomFirst which should not be in the queue yet"); + found = QX11Info::peekEventQueue(checkForPropertyNotifyByAtom, &m_atomSecond); + QVERIFY2(!found, "Found m_atomSecond which should not be in the queue yet"); + + triggerPropertyNotifyEvents(); + + bool earlyExit = false; + while (!earlyExit && (m_indexFirst == -1 || m_indexSecond == -1)) { + + earlyExit = QX11Info::peekEventQueue([](xcb_generic_event_t *event, void *data) { + return static_cast<PeekerTest *>(data)->sanityCheckPeeking(event); + }, this, QX11Info::PeekFromCachedIndex, m_peekerFirstId); + + if (m_countWithCaching == -1) + QVERIFY2(!earlyExit, "Unexpected return value for an empty queue"); + } + + QVERIFY2(!m_foundFirstEventAgain, + "Found the same notify event twice, maybe broken index cache?"); + QVERIFY2(!m_foundSecondBeforeFirst, "Found second event before first"); + QVERIFY2(!earlyExit, + "Unexpected return value for a peeker that always scans to the end of the queue"); + + found = QX11Info::peekEventQueue(checkForPropertyNotifyByAtom, &m_atomFirst, + QX11Info::PeekDefault, m_peekerFirstId); + QVERIFY2(found, "Failed to find m_atomFirst, when peeking from start and ignoring " + "the cached index associated with the passed in peeker id"); + // The above call updated index cache for m_peekerFirstId to the position of + // event(m_atomFirst) + 1 + found = QX11Info::peekEventQueue(checkForPropertyNotifyByAtom, &m_atomSecond, + QX11Info::PeekFromCachedIndex, m_peekerFirstId); + QVERIFY2(found, "Unexpectedly failed to find m_atomSecond"); + + QVERIFY(m_indexFirst <= m_countWithCaching); + QVERIFY(m_indexSecond <= m_countWithCaching); + QVERIFY(m_indexFirst < m_indexSecond); + QX11Info::peekEventQueue([](xcb_generic_event_t *, void *data) { + static_cast<PeekerTest *>(data)->m_countFromStart++; + return false; + }, this); + QVERIFY(m_countWithCaching <= m_countFromStart); + found = QX11Info::peekEventQueue(checkForPropertyNotifyByAtom, &m_atomFirst, + QX11Info::PeekFromCachedIndex, m_peekerSecondId); + QVERIFY2(found, "m_peekerSecondId failed to find the event"); + + // Remove peeker id from within the peeker while using it for peeking + QX11Info::peekEventQueue([](xcb_generic_event_t *, void *data) { + PeekerTest *obj = static_cast<PeekerTest *>(data); + QX11Info::removePeekerId(obj->m_peekerSecondId); + return true; + }, this, QX11Info::PeekFromCachedIndex, m_peekerSecondId); + // Check that it really has been removed from the cache + bool ok = QX11Info::peekEventQueue([](xcb_generic_event_t *, void *) { + return true; + }, nullptr, QX11Info::PeekFromCachedIndex, m_peekerSecondId); + QVERIFY2(!ok, "Unexpected return value when attempting to peek from cached " + "index when peeker id has been removed from the cache"); + + // Sanity check other input combinations + QVERIFY(!QX11Info::removePeekerId(-99)); + ok = QX11Info::peekEventQueue([](xcb_generic_event_t *, void *) { + return true; + }, nullptr, QX11Info::PeekFromCachedIndex, -100); + QVERIFY2(!ok, "PeekFromCachedIndex with invalid peeker id unexpectedly succeeded"); + ok = QX11Info::peekEventQueue([](xcb_generic_event_t *, void *) { + return true; + }, nullptr, QX11Info::PeekDefault, -100); + QVERIFY2(!ok, "PeekDefault with invalid peeker id unexpectedly succeeded"); + ok = QX11Info::peekEventQueue([](xcb_generic_event_t *, void *) { + return true; + }, nullptr, QX11Info::PeekFromCachedIndex); + QVERIFY2(!ok, "PeekFromCachedIndex without peeker id unexpectedly succeeded"); + ok = QX11Info::peekEventQueue([](xcb_generic_event_t *, void *) { + return true; + }, nullptr, QX11Info::PeekDefault); + QVERIFY2(ok, "PeekDefault without peeker id unexpectedly failed"); + + QCoreApplication::processEvents(); // Flush buffered events + + found = QX11Info::peekEventQueue(checkForPropertyNotifyByAtom, &m_atomFirst); + QVERIFY2(!found, "Found m_atomFirst in the queue after flushing"); + found = QX11Info::peekEventQueue(checkForPropertyNotifyByAtom, &m_atomSecond); + QVERIFY2(!found, "Found m_atomSecond in the queue after flushing"); + + QVERIFY(QX11Info::removePeekerId(m_peekerFirstId)); + QVERIFY2(!QX11Info::removePeekerId(m_peekerFirstId), + "Removing the same peeker id twice unexpectedly succeeded"); +#if 0 + qDebug() << "Buffered event queue size (caching) : " << m_countWithCaching + 1; + qDebug() << "Buffered event queue size (from start) : " << m_countFromStart + 1; + qDebug() << "PropertyNotify[FIRST] at : " << m_indexFirst; + qDebug() << "PropertyNotify[SECOND] at : " << m_indexSecond; +#endif + } + +private: + xcb_atom_t m_atomFirst = -1; + xcb_atom_t m_atomSecond = -1; + qint32 m_peekerFirstId = -1; + qint32 m_peekerSecondId = -1; + qint32 m_indexFirst = -1; + qint32 m_indexSecond = -1; + bool m_foundFirstEventAgain = false; + qint32 m_countWithCaching = -1; + qint32 m_countFromStart = -1; + bool m_ignoreSubsequentExpose = false; + bool m_foundSecondBeforeFirst = false; +}; + +void tst_QX11Info::peeker() +{ + int argc = 0; + QGuiApplication app(argc, 0); + + PeekerTest test; + test.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&test)); +} + QTEST_APPLESS_MAIN(tst_QX11Info) #include "tst_qx11info.moc" diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro new file mode 100644 index 0000000..1ef0dcd --- /dev/null +++ b/tests/manual/manual.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS = peeker diff --git a/tests/manual/peeker/main.cpp b/tests/manual/peeker/main.cpp new file mode 100644 index 0000000..8c7b280 --- /dev/null +++ b/tests/manual/peeker/main.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> +#include <QtX11Extras/QX11Info> + +class IntensivePainter : public QWindow +{ +public: + IntensivePainter() : m_backingStore(new QBackingStore(this)) + { setGeometry(100, 100, 900, 600); } + +protected: + bool interrupted() const { return m_stopPainting; } + void stopPainting() { m_stopPainting = true; } + void beginPaining() { m_stopPainting = false; } + + void exposeEvent(QExposeEvent *) + { + bool useGreenColor = false; + QRect rect(0, 0, width(), height()); + m_backingStore->resize(QSize(width(), height())); + + qint32 peekerId = QX11Info::generatePeekerId(); + if (peekerId == -1) { + qWarning() << "Internal error: QX11Info::generatePeekerId() returned -1"; + exit(EXIT_FAILURE); + } + + while (!interrupted()) { // Begin a long operation + m_backingStore->beginPaint(rect); + QPaintDevice *device = m_backingStore->paintDevice(); + QPainter painter(device); + painter.fillRect(rect, useGreenColor ? Qt::green : Qt::red); + useGreenColor = !useGreenColor; + painter.drawText(rect, Qt::AlignCenter, QStringLiteral("Press any key to exit.\n" + "(make sure the window is in focus when testing)\n\n If key press does not " + "immediately exit the application,\n then that should be considered a bug/regression." + "\n\n A demo might appear frozen to some window managers\n and therefore " + "might get grayed out (e.g Unity), this is the expected behavior.\n On KWin, for " + "example, this demo does not get grayed out.\n Resizing the window on any system will " + "cause rendering artefacts, that is not a bug,\n but simply the way the test is " + "implemented.")); + m_backingStore->endPaint(); + m_backingStore->flush(rect); + QThread::msleep(500); // Reduce the speed of re-painting (blinking) + + QX11Info::peekEventQueue([](xcb_generic_event_t *event, void *data) { + bool isKeyPress = (event->response_type & ~0x80) == XCB_KEY_PRESS; + if (isKeyPress) { + IntensivePainter *painter = static_cast<IntensivePainter *>(data); + painter->stopPainting(); + } + return isKeyPress; + }, this, QX11Info::PeekOption::PeekFromCachedIndex, peekerId); + } + + QX11Info::removePeekerId(peekerId); + exit(EXIT_SUCCESS); + } + +private: + QBackingStore *m_backingStore; + bool m_stopPainting = false; +}; + +int main(int argc, char** argv) +{ + QGuiApplication app(argc, argv); + + IntensivePainter painterWindow; + painterWindow.show(); + + return app.exec(); +} diff --git a/tests/manual/peeker/peeker.pro b/tests/manual/peeker/peeker.pro new file mode 100644 index 0000000..aef58cd --- /dev/null +++ b/tests/manual/peeker/peeker.pro @@ -0,0 +1,6 @@ +QT += x11extras + +TARGET = peeker +TEMPLATE = app + +SOURCES += main.cpp diff --git a/tests/tests.pro b/tests/tests.pro index d1a5e17..3febcf1 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -2,5 +2,5 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private qtConfig(xcb) { - SUBDIRS += auto + SUBDIRS += auto manual } |