1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtestsupport_widgets.h"
5
6#include "qwidget.h"
7
8#include <QtGui/qwindow.h>
9#include <QtCore/qtestsupport_core.h>
10#include <QtCore/qthread.h>
11#include <QtGui/qtestsupport_gui.h>
12#include <QtGui/private/qevent_p.h>
13#include <QtGui/private/qeventpoint_p.h>
14#include <private/qguiapplication_p.h>
15#include <qpa/qplatformintegration.h>
16
17QT_BEGIN_NAMESPACE
18
19template <typename Predicate>
20static bool qWaitForWidgetWindow(QWidget *w, Predicate predicate, QDeadlineTimer timeout)
21{
22 if (!w->window()->windowHandle())
23 return false;
24
25 return QTest::qWaitFor([&, wp = QPointer(w)]() {
26 if (QWidget *widget = wp.data(); !widget)
27 return false;
28 else if (QWindow *window = widget->window()->windowHandle())
29 return predicate(window);
30 return false;
31 }, timeout);
32}
33
34/*!
35 \since 5.0
36 \overload
37
38 The \a timeout is in milliseconds.
39*/
40bool QTest::qWaitForWindowActive(QWidget *widget, int timeout)
41{
42 return qWaitForWindowActive(widget, timeout: QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer});
43}
44
45/*!
46 \since 6.10
47
48 Returns \c true if \a widget is active within \a timeout milliseconds. Otherwise returns \c false.
49
50 The method is useful in tests that call QWidget::show() and rely on the widget actually being
51 active (i.e. being visible and having focus) before proceeding.
52
53 \note The method will time out and return \c false if another window prevents \a widget from
54 becoming active.
55
56 \note Since focus is an exclusive property, \a widget may loose its focus to another window at
57 any time - even after the method has returned \c true.
58
59 \sa qWaitForWindowExposed(), QWidget::isActiveWindow()
60*/
61bool QTest::qWaitForWindowActive(QWidget *widget, QDeadlineTimer timeout)
62{
63 if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) {
64 qWarning() << "qWaitForWindowActive was called on a platform that doesn't support window"
65 << "activation. This means there is an error in the test and it should either"
66 << "check for the WindowActivation platform capability before calling"
67 << "qWaitForWindowActivate, use qWaitForWindowExposed instead, or skip the test."
68 << "Falling back to qWaitForWindowExposed.";
69 return qWaitForWindowExposed(widget, timeout);
70 }
71 return qWaitForWidgetWindow(w: widget,
72 predicate: [&](QWindow *window) { return window->isActive(); },
73 timeout);
74}
75
76/*!
77 \since 6.10
78 \overload
79
80 This function uses the default timeout of 5 seconds.
81*/
82bool QTest::qWaitForWindowActive(QWidget *widget)
83{
84 return qWaitForWindowActive(widget, timeout: Internal::defaultTryTimeout);
85}
86
87/*!
88 \since 6.7
89
90 Returns \c true, if \a widget is the focus window within \a timeout. Otherwise returns \c false.
91
92 The method is useful in tests that call QWidget::show() and rely on the widget
93 having focus (for receiving keyboard events e.g.) before proceeding.
94
95 \note The method will time out and return \c false if another window prevents \a widget from
96 becoming focused.
97
98 \note Since focus is an exclusive property, \a widget may loose its focus to another window at
99 any time - even after the method has returned \c true.
100
101 \sa qWaitForWindowExposed(), qWaitForWindowActive(), QGuiApplication::focusWindow()
102*/
103Q_WIDGETS_EXPORT bool QTest::qWaitForWindowFocused(QWidget *widget, QDeadlineTimer timeout)
104{
105 return qWaitForWidgetWindow(w: widget,
106 predicate: [&](QWindow *window) {
107 return qGuiApp->focusWindow() == window;
108 }, timeout);
109}
110
111/*!
112 \since 6.10
113 \overload
114
115 This function uses the default timeout of 5 seconds.
116*/
117bool QTest::qWaitForWindowFocused(QWidget *widget)
118{
119 return qWaitForWindowFocused(widget, timeout: Internal::defaultTryTimeout);
120}
121
122/*!
123 \since 5.0
124 \overload
125
126 The \a timeout is in milliseconds.
127*/
128bool QTest::qWaitForWindowExposed(QWidget *widget, int timeout)
129{
130 return qWaitForWindowExposed(widget, timeout: std::chrono::milliseconds(timeout));
131}
132
133
134/*!
135 \since 6.10
136
137 Returns \c true if \a widget is exposed within \a timeout milliseconds. Otherwise returns \c false.
138
139 The method is useful in tests that call QWidget::show() and rely on the widget actually being
140 being visible before proceeding.
141
142 \note A window mapped to screen may still not be considered exposed, if the window client area is
143 not visible, e.g. because it is completely covered by other windows.
144 In such cases, the method will time out and return \c false.
145
146 \sa qWaitForWindowActive(), QWidget::isVisible(), QWindow::isExposed()
147*/
148bool QTest::qWaitForWindowExposed(QWidget *widget, QDeadlineTimer timeout)
149{
150 return qWaitForWidgetWindow(w: widget,
151 predicate: [&](QWindow *window) { return window->isExposed(); },
152 timeout);
153}
154
155/*!
156 \since 6.10
157 \overload
158
159 This function uses the default timeout of 5 seconds.
160*/
161bool QTest::qWaitForWindowExposed(QWidget *widget)
162{
163 return qWaitForWindowExposed(widget, timeout: Internal::defaultTryTimeout);
164}
165
166namespace QTest {
167
168QTouchEventWidgetSequence::~QTouchEventWidgetSequence()
169{
170 if (commitWhenDestroyed)
171 QTouchEventWidgetSequence::commit();
172}
173
174QTouchEventWidgetSequence& QTouchEventWidgetSequence::press(int touchId, const QPoint &pt, QWidget *widget)
175{
176 auto &p = point(touchId);
177 QMutableEventPoint::setGlobalPosition(p, arg: mapToScreen(widget, pt));
178 QMutableEventPoint::setState(p, arg: QEventPoint::State::Pressed);
179 return *this;
180}
181QTouchEventWidgetSequence& QTouchEventWidgetSequence::move(int touchId, const QPoint &pt, QWidget *widget)
182{
183 auto &p = point(touchId);
184 QMutableEventPoint::setGlobalPosition(p, arg: mapToScreen(widget, pt));
185 QMutableEventPoint::setState(p, arg: QEventPoint::State::Updated);
186 return *this;
187}
188QTouchEventWidgetSequence& QTouchEventWidgetSequence::release(int touchId, const QPoint &pt, QWidget *widget)
189{
190 auto &p = point(touchId);
191 QMutableEventPoint::setGlobalPosition(p, arg: mapToScreen(widget, pt));
192 QMutableEventPoint::setState(p, arg: QEventPoint::State::Released);
193 return *this;
194}
195
196QTouchEventWidgetSequence& QTouchEventWidgetSequence::stationary(int touchId)
197{
198 auto &p = pointOrPreviousPoint(touchId);
199 QMutableEventPoint::setState(p, arg: QEventPoint::State::Stationary);
200 return *this;
201}
202
203bool QTouchEventWidgetSequence::commit(bool processEvents)
204{
205 bool ret = false;
206 if (points.isEmpty())
207 return ret;
208 QThread::sleep(nsec: std::chrono::milliseconds{1});
209 if (targetWindow) {
210 ret = qt_handleTouchEventv2(w: targetWindow, device, points: points.values());
211 } else if (targetWidget) {
212 ret = qt_handleTouchEventv2(w: targetWidget->windowHandle(), device, points: points.values());
213 }
214 if (processEvents)
215 QCoreApplication::processEvents();
216 previousPoints = points;
217 points.clear();
218 return ret;
219}
220
221QTest::QTouchEventWidgetSequence::QTouchEventWidgetSequence(QWidget *widget, QPointingDevice *aDevice, bool autoCommit)
222 : QTouchEventSequence(nullptr, aDevice, autoCommit), targetWidget(widget)
223{
224}
225
226QPoint QTouchEventWidgetSequence::mapToScreen(QWidget *widget, const QPoint &pt)
227{
228 if (widget)
229 return widget->mapToGlobal(pt);
230 return targetWidget ? targetWidget->mapToGlobal(pt) : pt;
231}
232
233} // namespace QTest
234
235QT_END_NAMESPACE
236

source code of qtbase/src/widgets/kernel/qtestsupport_widgets.cpp