Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwineventnotifier.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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// Qt-Security score:significant reason:default
4
6
8#include "qthread.h"
9#include <QPointer>
10
12
13/*!
14 \class QWinEventNotifier
15 \inmodule QtCore
16 \since 5.0
17 \brief The QWinEventNotifier class provides support for the Windows Wait functions.
18
19 The QWinEventNotifier class makes it possible to use the wait
20 functions on windows in a asynchronous manner. With this class,
21 you can register a HANDLE to an event and get notification when
22 that event becomes signalled. The state of the event is not modified
23 in the process so if it is a manual reset event you will need to
24 reset it after the notification.
25
26 Once you have created a event object using Windows API such as
27 CreateEvent() or OpenEvent(), you can create an event notifier to
28 monitor the event handle. If the event notifier is enabled, it will
29 emit the activated() signal whenever the corresponding event object
30 is signalled.
31
32 The setEnabled() function allows you to disable as well as enable the
33 event notifier. It is generally advisable to explicitly enable or
34 disable the event notifier. A disabled notifier does nothing when the
35 event object is signalled (the same effect as not creating the
36 event notifier). Use the isEnabled() function to determine the
37 notifier's current status.
38
39 Finally, you can use the setHandle() function to register a new event
40 object, and the handle() function to retrieve the event handle.
41
42 \b{Further information:}
43 Although the class is called QWinEventNotifier, it can be used for
44 certain other objects which are so-called synchronization
45 objects, such as Processes, Threads, Waitable timers.
46
47 \warning This class is only available on Windows.
48*/
49
50/*!
51 \fn void QWinEventNotifier::activated(HANDLE hEvent)
52
53 This signal is emitted whenever the event notifier is enabled and
54 the corresponding HANDLE is signalled.
55
56 The state of the event is not modified in the process, so if it is a
57 manual reset event, you will need to reset it after the notification.
58
59 The object is passed in the \a hEvent parameter.
60
61 \sa handle()
62*/
63
64/*!
65 Constructs an event notifier with the given \a parent.
66*/
67
68QWinEventNotifier::QWinEventNotifier(QObject *parent)
69 : QObject(*new QWinEventNotifierPrivate, parent)
70{}
71
72/*!
73 Constructs an event notifier with the given \a parent. It enables
74 the notifier, and watches for the event \a hEvent.
75
76 The notifier is enabled by default, i.e. it emits the activated() signal
77 whenever the corresponding event is signalled. However, it is generally
78 advisable to explicitly enable or disable the event notifier.
79
80 \sa setEnabled(), isEnabled()
81*/
82
83QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent)
84 : QObject(*new QWinEventNotifierPrivate(hEvent, false), parent)
85{
86 setEnabled(true);
87}
88
89/*!
90 Destroys this notifier.
91*/
92
93QWinEventNotifier::~QWinEventNotifier()
94{
95 setEnabled(false);
96}
97
98/*!
99 Register the HANDLE \a hEvent. The old HANDLE will be automatically
100 unregistered.
101
102 \b Note: The notifier will be disabled as a side effect and needs
103 to be re-enabled.
104
105 \sa handle(), setEnabled()
106*/
107
108void QWinEventNotifier::setHandle(HANDLE hEvent)
109{
110 Q_D(QWinEventNotifier);
111 setEnabled(false);
112 d->handleToEvent = hEvent;
113}
114
115/*!
116 Returns the HANDLE that has been registered in the notifier.
117
118 \sa setHandle()
119*/
120
121HANDLE QWinEventNotifier::handle() const
122{
123 Q_D(const QWinEventNotifier);
124 return d->handleToEvent;
125}
126
127/*!
128 Returns \c true if the notifier is enabled; otherwise returns \c false.
129
130 \sa setEnabled()
131*/
132
133bool QWinEventNotifier::isEnabled() const
134{
135 Q_D(const QWinEventNotifier);
136 return d->enabled;
137}
138
139/*!
140 If \a enable is true, the notifier is enabled; otherwise the notifier
141 is disabled.
142
143 \sa isEnabled(), activated()
144*/
145
146void QWinEventNotifier::setEnabled(bool enable)
147{
148 Q_D(QWinEventNotifier);
149 if (d->enabled == enable) // no change
150 return;
151 d->enabled = enable;
152
153 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
154 qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread");
155 return;
156 }
157
158 if (enable) {
159 // It is possible that the notifier was disabled after an event was already
160 // posted. In that case we set a state that indicates that such an obsolete
161 // event shall be ignored.
162 d->winEventActPosted.testAndSetRelaxed(QWinEventNotifierPrivate::Posted,
163 QWinEventNotifierPrivate::IgnorePosted);
164 // The notifier can't be registered, if 'enabled' flag was false.
165 // The code in the else branch ensures that.
166 Q_ASSERT(!d->registered);
167 SetThreadpoolWait(d->waitObject, d->handleToEvent, NULL);
168 d->registered = true;
169 } else if (d->registered) {
170 // Stop waiting for an event. However, there may be a callback queued
171 // already after the call.
172 SetThreadpoolWait(d->waitObject, NULL, NULL);
173 // So, to avoid a race condition after a possible call to
174 // setEnabled(true), wait for a possibly outstanding callback
175 // to complete.
176 WaitForThreadpoolWaitCallbacks(d->waitObject, TRUE);
177 d->registered = false;
178 }
179}
180
181/*!
182 \reimp
183*/
184
185bool QWinEventNotifier::event(QEvent * e)
186{
187 Q_D(QWinEventNotifier);
188
189 switch (e->type()) {
190 case QEvent::ThreadChange:
191 if (d->enabled) {
192 QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection,
193 Q_ARG(bool, true));
194 setEnabled(false);
195 }
196 break;
197 case QEvent::WinEventAct:
198 // Emit notification, but only if the event has not been invalidated
199 // since by the notifier being disabled, even if it was re-enabled
200 // again.
201 if (d->winEventActPosted.fetchAndStoreRelaxed(QWinEventNotifierPrivate::NotPosted)
202 == QWinEventNotifierPrivate::Posted && d->enabled) {
203 // Clear the flag, as the wait object is implicitly unregistered
204 // when the callback is queued.
205 d->registered = false;
206
207 QPointer<QWinEventNotifier> alive(this);
208 emit activated(d->handleToEvent, QPrivateSignal());
209
210 if (alive && d->enabled && !d->registered) {
211 SetThreadpoolWait(d->waitObject, d->handleToEvent, NULL);
212 d->registered = true;
213 }
214 }
215 return true;
216 default:
217 break;
218 }
219 return QObject::event(e);
220}
221
222QWinEventNotifierPrivate::QWinEventNotifierPrivate(HANDLE h, bool e)
223 : handleToEvent(h), enabled(e), registered(false)
224{
225 waitObject = CreateThreadpoolWait(waitCallback, this, NULL);
226 if (waitObject == NULL)
227 qErrnoWarning("QWinEventNotifier:: CreateThreadpollWait failed.");
228}
229
230QWinEventNotifierPrivate::~QWinEventNotifierPrivate()
231{
232 CloseThreadpoolWait(waitObject);
233}
234
235void QWinEventNotifierPrivate::waitCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
236 PTP_WAIT wait, TP_WAIT_RESULT waitResult)
237{
238 Q_UNUSED(instance);
239 Q_UNUSED(wait);
240 Q_UNUSED(waitResult);
241 QWinEventNotifierPrivate *nd = reinterpret_cast<QWinEventNotifierPrivate *>(context);
242
243 // Do not post an event, if an event is already in the message queue. Note
244 // that an event that was previously invalidated will be reactivated.
245 if (nd->winEventActPosted.fetchAndStoreRelaxed(QWinEventNotifierPrivate::Posted)
246 == QWinEventNotifierPrivate::NotPosted) {
247 QCoreApplication::postEvent(nd->q_func(), new QEvent(QEvent::WinEventAct));
248 }
249}
250
251QT_END_NAMESPACE
252
253#include "moc_qwineventnotifier.cpp"
Combined button and popup list for selecting options.