Move QtX11Extras into QtGui as private API
from qt/qtx11extras 0e67fb41cfc4b4bfbaa7dc75f8ddebdf5a08e836. The plan is to expose these as native interfaces, so this is a first step. Task-number: QTBUG-83251 Change-Id: Iecba8db9a4f616a08a3750ddaae08cc30ec66f89 Reviewed-by: Liang Qi <liang.qi@qt.io>
This commit is contained in:
parent
066a1de8e7
commit
edceff30b4
@ -967,6 +967,11 @@ qt_internal_extend_target(Gui CONDITION UNIX AND (QT_FEATURE_xcb OR NOT UIKIT)
|
||||
platform/unix/qgenericunixservices.cpp platform/unix/qgenericunixservices_p.h
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Gui CONDITION UNIX AND (QT_FEATURE_xcb)
|
||||
SOURCES
|
||||
platform/unix/qtx11extras.cpp platform/unix/qtx11extras_p.h
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Gui CONDITION TARGET Qt::DBus AND UNIX AND (QT_FEATURE_xcb OR NOT UIKIT)
|
||||
LIBRARIES
|
||||
Qt::DBus
|
||||
|
548
src/gui/platform/unix/qtx11extras.cpp
Normal file
548
src/gui/platform/unix/qtx11extras.cpp
Normal file
@ -0,0 +1,548 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Richard Moore <rich@kde.org>
|
||||
** Copyright (C) 2016 David Faure <david.faure@kdab.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui 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 "qtx11extras_p.h"
|
||||
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <qpa/qplatformwindow.h>
|
||||
#include <qpa/qplatformscreen_p.h>
|
||||
#include <qpa/qplatformscreen.h>
|
||||
#include <qscreen.h>
|
||||
#include <qwindow.h>
|
||||
#include <qguiapplication.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static QScreen *findScreenForVirtualDesktop(int virtualDesktopNumber)
|
||||
{
|
||||
const auto screens = QGuiApplication::screens();
|
||||
for (QScreen *screen : screens) {
|
||||
auto *qxcbScreen = dynamic_cast<QNativeInterface::Private::QXcbScreen *>(screen->handle());
|
||||
if (qxcbScreen && qxcbScreen->virtualDesktopNumber() == virtualDesktopNumber)
|
||||
return screen;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QX11Info
|
||||
\inmodule QtGui
|
||||
\since 6.2
|
||||
\internal
|
||||
|
||||
\brief Provides information about the X display configuration.
|
||||
|
||||
The class provides two APIs: a set of non-static functions that
|
||||
provide information about a specific widget or pixmap, and a set
|
||||
of static functions that provide the default information for the
|
||||
application.
|
||||
|
||||
\warning This class is only available on X11. For querying
|
||||
per-screen information in a portable way, use QDesktopWidget.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an empty QX11Info object.
|
||||
*/
|
||||
QX11Info::QX11Info()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the application is currently running on X11.
|
||||
|
||||
\since 6.2
|
||||
*/
|
||||
bool QX11Info::isPlatformX11()
|
||||
{
|
||||
return QGuiApplication::platformName() == QLatin1String("xcb");
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the horizontal resolution of the given \a screen in terms of the
|
||||
number of dots per inch.
|
||||
|
||||
The \a screen argument is an X screen number. Be aware that if
|
||||
the user's system uses Xinerama (as opposed to traditional X11
|
||||
multiscreen), there is only one X screen. Use QDesktopWidget to
|
||||
query for information about Xinerama screens.
|
||||
|
||||
\sa appDpiY()
|
||||
*/
|
||||
int QX11Info::appDpiX(int screen)
|
||||
{
|
||||
if (screen == -1) {
|
||||
const QScreen *scr = QGuiApplication::primaryScreen();
|
||||
if (!scr)
|
||||
return 75;
|
||||
return qRound(scr->logicalDotsPerInchX());
|
||||
}
|
||||
|
||||
QScreen *scr = findScreenForVirtualDesktop(screen);
|
||||
if (!scr)
|
||||
return 0;
|
||||
|
||||
return scr->logicalDotsPerInchX();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the vertical resolution of the given \a screen in terms of the
|
||||
number of dots per inch.
|
||||
|
||||
The \a screen argument is an X screen number. Be aware that if
|
||||
the user's system uses Xinerama (as opposed to traditional X11
|
||||
multiscreen), there is only one X screen. Use QDesktopWidget to
|
||||
query for information about Xinerama screens.
|
||||
|
||||
\sa appDpiX()
|
||||
*/
|
||||
int QX11Info::appDpiY(int screen)
|
||||
{
|
||||
if (screen == -1) {
|
||||
const QScreen *scr = QGuiApplication::primaryScreen();
|
||||
if (!scr)
|
||||
return 75;
|
||||
return qRound(scr->logicalDotsPerInchY());
|
||||
}
|
||||
|
||||
QScreen *scr = findScreenForVirtualDesktop(screen);
|
||||
if (!scr)
|
||||
return 0;
|
||||
|
||||
return scr->logicalDotsPerInchY();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a handle for the applications root window on the given \a screen.
|
||||
|
||||
The \a screen argument is an X screen number. Be aware that if
|
||||
the user's system uses Xinerama (as opposed to traditional X11
|
||||
multiscreen), there is only one X screen. Use QDesktopWidget to
|
||||
query for information about Xinerama screens.
|
||||
*/
|
||||
quint32 QX11Info::appRootWindow(int screen)
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen *scr = screen == -1 ? QGuiApplication::primaryScreen() : findScreenForVirtualDesktop(screen);
|
||||
if (!scr)
|
||||
return 0;
|
||||
return static_cast<xcb_window_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen(QByteArrayLiteral("rootwindow"), scr)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the number of the screen where the application is being
|
||||
displayed.
|
||||
|
||||
This method refers to screens in the original X11 meaning with a
|
||||
different DISPLAY environment variable per screen.
|
||||
This information is only useful if your application needs to know
|
||||
on which X screen it is running.
|
||||
|
||||
In a typical multi-head configuration, multiple physical monitors
|
||||
are combined in one X11 screen. This means this method returns the
|
||||
same number for each of the physical monitors. In such a setup you
|
||||
are interested in the monitor information as provided by the X11
|
||||
RandR extension. This is available through QDesktopWidget and QScreen.
|
||||
|
||||
\sa display()
|
||||
*/
|
||||
int QX11Info::appScreen()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
return reinterpret_cast<qintptr>(native->nativeResourceForIntegration(QByteArrayLiteral("x11screen")));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the X11 time.
|
||||
|
||||
\sa setAppTime(), appUserTime()
|
||||
*/
|
||||
quint32 QX11Info::appTime()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
return static_cast<xcb_timestamp_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen("apptime", screen)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the X11 user time.
|
||||
|
||||
\sa setAppUserTime(), appTime()
|
||||
*/
|
||||
quint32 QX11Info::appUserTime()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
return static_cast<xcb_timestamp_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen("appusertime", screen)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the X11 time to the value specified by \a time.
|
||||
|
||||
\sa appTime(), setAppUserTime()
|
||||
*/
|
||||
void QX11Info::setAppTime(quint32 time)
|
||||
{
|
||||
if (!qApp)
|
||||
return;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return;
|
||||
typedef void (*SetAppTimeFunc)(QScreen *, xcb_timestamp_t);
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
SetAppTimeFunc func = reinterpret_cast<SetAppTimeFunc>(reinterpret_cast<void *>(native->nativeResourceFunctionForScreen("setapptime")));
|
||||
if (func)
|
||||
func(screen, time);
|
||||
else
|
||||
qWarning("Internal error: QPA plugin doesn't implement setAppTime");
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the X11 user time as specified by \a time.
|
||||
|
||||
\sa appUserTime(), setAppTime()
|
||||
*/
|
||||
void QX11Info::setAppUserTime(quint32 time)
|
||||
{
|
||||
if (!qApp)
|
||||
return;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return;
|
||||
typedef void (*SetAppUserTimeFunc)(QScreen *, xcb_timestamp_t);
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
SetAppUserTimeFunc func = reinterpret_cast<SetAppUserTimeFunc>(reinterpret_cast<void *>(native->nativeResourceFunctionForScreen("setappusertime")));
|
||||
if (func)
|
||||
func(screen, time);
|
||||
else
|
||||
qWarning("Internal error: QPA plugin doesn't implement setAppUserTime");
|
||||
}
|
||||
|
||||
/*!
|
||||
Fetches the current X11 time stamp from the X Server.
|
||||
|
||||
This method creates a property notify event and blocks till it is
|
||||
received back from the X Server.
|
||||
*/
|
||||
quint32 QX11Info::getTimestamp()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
return static_cast<xcb_timestamp_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen("gettimestamp", screen)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the startup ID that will be used for the next window to be shown by this process.
|
||||
|
||||
After the next window is shown, the next startup ID will be empty.
|
||||
|
||||
http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt
|
||||
|
||||
\sa setNextStartupId()
|
||||
*/
|
||||
QByteArray QX11Info::nextStartupId()
|
||||
{
|
||||
if (!qApp)
|
||||
return QByteArray();
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return QByteArray();
|
||||
return static_cast<char *>(native->nativeResourceForIntegration("startupid"));
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the next startup ID to \a id.
|
||||
|
||||
This is the startup ID that will be used for the next window to be shown by this process.
|
||||
|
||||
The startup ID of the first window comes from the environment variable DESKTOP_STARTUP_ID.
|
||||
This method is useful for subsequent windows, when the request comes from another process
|
||||
(e.g. via DBus).
|
||||
|
||||
\sa nextStartupId()
|
||||
*/
|
||||
void QX11Info::setNextStartupId(const QByteArray &id)
|
||||
{
|
||||
if (!qApp)
|
||||
return;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return;
|
||||
typedef void (*SetStartupIdFunc)(const char*);
|
||||
SetStartupIdFunc func = reinterpret_cast<SetStartupIdFunc>(reinterpret_cast<void *>(native->nativeResourceFunctionForIntegration("setstartupid")));
|
||||
if (func)
|
||||
func(id.constData());
|
||||
else
|
||||
qWarning("Internal error: QPA plugin doesn't implement setStartupId");
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default display for the application.
|
||||
|
||||
\sa appScreen()
|
||||
*/
|
||||
Display *QX11Info::display()
|
||||
{
|
||||
if (!qApp)
|
||||
return nullptr;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return nullptr;
|
||||
|
||||
void *display = native->nativeResourceForIntegration(QByteArray("display"));
|
||||
return reinterpret_cast<Display *>(display);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default XCB connection for the application.
|
||||
|
||||
\sa display()
|
||||
*/
|
||||
xcb_connection_t *QX11Info::connection()
|
||||
{
|
||||
if (!qApp)
|
||||
return nullptr;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return nullptr;
|
||||
|
||||
void *connection = native->nativeResourceForIntegration(QByteArray("connection"));
|
||||
return reinterpret_cast<xcb_connection_t *>(connection);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if there is a compositing manager running for the connection
|
||||
attached to \a screen.
|
||||
|
||||
If \a screen equals -1, the application's primary screen is used.
|
||||
*/
|
||||
bool QX11Info::isCompositingManagerRunning(int screen)
|
||||
{
|
||||
if (!qApp)
|
||||
return false;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return false;
|
||||
|
||||
QScreen *scr = screen == -1 ? QGuiApplication::primaryScreen() : findScreenForVirtualDesktop(screen);
|
||||
if (!scr) {
|
||||
qWarning() << "isCompositingManagerRunning: Could not find screen number" << screen;
|
||||
return false;
|
||||
}
|
||||
|
||||
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()
|
||||
*/
|
||||
qint32 QX11Info::generatePeekerId()
|
||||
{
|
||||
if (!qApp)
|
||||
return -1;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return -1;
|
||||
|
||||
typedef qint32 (*GeneratePeekerIdFunc)(void);
|
||||
GeneratePeekerIdFunc generatepeekerid = reinterpret_cast<GeneratePeekerIdFunc>(
|
||||
reinterpret_cast<void *>(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()
|
||||
*/
|
||||
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>(
|
||||
reinterpret_cast<void *>(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().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\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.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\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()
|
||||
*/
|
||||
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>(
|
||||
reinterpret_cast<void *>(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
|
110
src/gui/platform/unix/qtx11extras_p.h
Normal file
110
src/gui/platform/unix/qtx11extras_p.h
Normal file
@ -0,0 +1,110 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTX11EXTRAS_P_H
|
||||
#define QTX11EXTRAS_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <qtguiglobal.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
typedef struct _XDisplay Display;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_GUI_EXPORT QX11Info
|
||||
{
|
||||
public:
|
||||
enum PeekOption {
|
||||
PeekDefault = 0,
|
||||
PeekFromCachedIndex = 1
|
||||
};
|
||||
Q_DECLARE_FLAGS(PeekOptions, PeekOption)
|
||||
|
||||
static bool isPlatformX11();
|
||||
|
||||
static int appDpiX(int screen=-1);
|
||||
static int appDpiY(int screen=-1);
|
||||
|
||||
static quint32 appRootWindow(int screen=-1);
|
||||
static int appScreen();
|
||||
|
||||
static quint32 appTime();
|
||||
static quint32 appUserTime();
|
||||
|
||||
static void setAppTime(quint32 time);
|
||||
static void setAppUserTime(quint32 time);
|
||||
|
||||
static quint32 getTimestamp();
|
||||
|
||||
static QByteArray nextStartupId();
|
||||
static void setNextStartupId(const QByteArray &id);
|
||||
|
||||
static Display *display();
|
||||
static xcb_connection_t *connection();
|
||||
|
||||
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 // QTX11EXTRAS_P_H
|
||||
|
@ -17,3 +17,4 @@ endif()
|
||||
if(QT_FEATURE_vulkan AND NOT UIKIT)
|
||||
add_subdirectory(qvulkan)
|
||||
endif()
|
||||
add_subdirectory(platform)
|
||||
|
3
tests/auto/gui/platform/CMakeLists.txt
Normal file
3
tests/auto/gui/platform/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
if(QT_FEATURE_xcb)
|
||||
add_subdirectory(qx11info)
|
||||
endif()
|
7
tests/auto/gui/platform/qx11info/CMakeLists.txt
Normal file
7
tests/auto/gui/platform/qx11info/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
qt_internal_add_test(tst_qx11info
|
||||
SOURCES
|
||||
tst_qx11info.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::GuiPrivate
|
||||
XCB::XCB
|
||||
)
|
390
tests/auto/gui/platform/qx11info/tst_qx11info.cpp
Normal file
390
tests/auto/gui/platform/qx11info/tst_qx11info.cpp
Normal file
@ -0,0 +1,390 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 David Faure <david.faure@kdab.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** 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 General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** 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-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtGui>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include <QtGui/private/qtx11extras_p.h>
|
||||
|
||||
class tst_QX11Info : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void staticFunctionsBeforeQGuiApplication();
|
||||
void startupId();
|
||||
void isPlatformX11();
|
||||
void appTime();
|
||||
void peeker();
|
||||
void isCompositingManagerRunning();
|
||||
};
|
||||
|
||||
void tst_QX11Info::staticFunctionsBeforeQGuiApplication()
|
||||
{
|
||||
QVERIFY(!QGuiApplication::instance());
|
||||
|
||||
// none of these functions should crash if QGuiApplication hasn't
|
||||
// been constructed
|
||||
|
||||
Display *display = QX11Info::display();
|
||||
QCOMPARE(display, (Display *)0);
|
||||
|
||||
#if 0
|
||||
const char *appClass = QX11Info::appClass();
|
||||
QCOMPARE(appClass, (const char *)0);
|
||||
#endif
|
||||
int appScreen = QX11Info::appScreen();
|
||||
QCOMPARE(appScreen, 0);
|
||||
#if 0
|
||||
int appDepth = QX11Info::appDepth();
|
||||
QCOMPARE(appDepth, 32);
|
||||
int appCells = QX11Info::appCells();
|
||||
QCOMPARE(appCells, 0);
|
||||
Qt::HANDLE appColormap = QX11Info::appColormap();
|
||||
QCOMPARE(appColormap, static_cast<Qt::HANDLE>(0));
|
||||
void *appVisual = QX11Info::appVisual();
|
||||
QCOMPARE(appVisual, static_cast<void *>(0));
|
||||
#endif
|
||||
unsigned long appRootWindow = QX11Info::appRootWindow();
|
||||
QCOMPARE(appRootWindow, static_cast<unsigned long>(0));
|
||||
|
||||
#if 0
|
||||
bool appDefaultColormap = QX11Info::appDefaultColormap();
|
||||
QCOMPARE(appDefaultColormap, true);
|
||||
bool appDefaultVisual = QX11Info::appDefaultVisual();
|
||||
QCOMPARE(appDefaultVisual, true);
|
||||
#endif
|
||||
|
||||
int appDpiX = QX11Info::appDpiX();
|
||||
int appDpiY = QX11Info::appDpiY();
|
||||
QCOMPARE(appDpiX, 75);
|
||||
QCOMPARE(appDpiY, 75);
|
||||
|
||||
unsigned long appTime = QX11Info::appTime();
|
||||
unsigned long appUserTime = QX11Info::appUserTime();
|
||||
QCOMPARE(appTime, 0ul);
|
||||
QCOMPARE(appUserTime, 0ul);
|
||||
// setApp*Time do nothing without QGuiApplication
|
||||
QX11Info::setAppTime(1234);
|
||||
QX11Info::setAppUserTime(5678);
|
||||
appTime = QX11Info::appTime();
|
||||
appUserTime = QX11Info::appUserTime();
|
||||
QCOMPARE(appTime, 0ul);
|
||||
QCOMPARE(appTime, 0ul);
|
||||
|
||||
QX11Info::isCompositingManagerRunning();
|
||||
}
|
||||
|
||||
static const char idFromEnv[] = "startupid_TIME123456";
|
||||
void initialize()
|
||||
{
|
||||
qputenv("DESKTOP_STARTUP_ID", idFromEnv);
|
||||
}
|
||||
Q_CONSTRUCTOR_FUNCTION(initialize)
|
||||
|
||||
void tst_QX11Info::startupId()
|
||||
{
|
||||
int argc = 0;
|
||||
QGuiApplication app(argc, 0);
|
||||
|
||||
// This relies on the fact that no widget was shown yet,
|
||||
// so please make sure this method is always the first test.
|
||||
QCOMPARE(QString(QX11Info::nextStartupId()), QString(idFromEnv));
|
||||
QWindow w;
|
||||
w.show();
|
||||
QVERIFY(QX11Info::nextStartupId().isEmpty());
|
||||
|
||||
QByteArray idSecondWindow = "startupid2_TIME234567";
|
||||
QX11Info::setNextStartupId(idSecondWindow);
|
||||
QCOMPARE(QX11Info::nextStartupId(), idSecondWindow);
|
||||
|
||||
QWindow w2;
|
||||
w2.show();
|
||||
QVERIFY(QX11Info::nextStartupId().isEmpty());
|
||||
}
|
||||
|
||||
void tst_QX11Info::isPlatformX11()
|
||||
{
|
||||
int argc = 0;
|
||||
QGuiApplication app(argc, 0);
|
||||
|
||||
QVERIFY(QX11Info::isPlatformX11());
|
||||
}
|
||||
|
||||
void tst_QX11Info::appTime()
|
||||
{
|
||||
int argc = 0;
|
||||
QGuiApplication app(argc, 0);
|
||||
|
||||
// No X11 event received yet
|
||||
QCOMPARE(QX11Info::appTime(), 0ul);
|
||||
QCOMPARE(QX11Info::appUserTime(), 0ul);
|
||||
|
||||
// Trigger some X11 events
|
||||
QWindow window;
|
||||
window.show();
|
||||
QTest::qWait(100);
|
||||
QVERIFY(QX11Info::appTime() > 0);
|
||||
|
||||
unsigned long t0 = QX11Info::appTime();
|
||||
unsigned long t1 = t0 + 1;
|
||||
QX11Info::setAppTime(t1);
|
||||
QCOMPARE(QX11Info::appTime(), t1);
|
||||
|
||||
unsigned long u0 = QX11Info::appUserTime();
|
||||
unsigned long u1 = u0 + 1;
|
||||
QX11Info::setAppUserTime(u1);
|
||||
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 *) override
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
void tst_QX11Info::isCompositingManagerRunning()
|
||||
{
|
||||
int argc = 0;
|
||||
QGuiApplication app(argc, 0);
|
||||
const bool b = QX11Info::isCompositingManagerRunning();
|
||||
Q_UNUSED(b);
|
||||
const bool b2 = QX11Info::isCompositingManagerRunning(0);
|
||||
Q_UNUSED(b2);
|
||||
// just check that it didn't crash (QTBUG-91913)
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QX11Info)
|
||||
|
||||
#include "tst_qx11info.moc"
|
Loading…
Reference in New Issue
Block a user