1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qwineventnotifier_p.h"
41
42 #ifdef Q_OS_WINRT
43 #include "qeventdispatcher_winrt_p.h"
44 #else
45 #include "qeventdispatcher_win_p.h"
46 #endif
47 #include "qcoreapplication.h"
48
49 #include <private/qthread_p.h>
50
51 QT_BEGIN_NAMESPACE
52
53 /*!
54 \class QWinEventNotifier
55 \inmodule QtCore
56 \since 5.0
57 \brief The QWinEventNotifier class provides support for the Windows Wait functions.
58
59 The QWinEventNotifier class makes it possible to use the wait
60 functions on windows in a asynchronous manner. With this class,
61 you can register a HANDLE to an event and get notification when
62 that event becomes signalled. The state of the event is not modified
63 in the process so if it is a manual reset event you will need to
64 reset it after the notification.
65
66 Once you have created a event object using Windows API such as
67 CreateEvent() or OpenEvent(), you can create an event notifier to
68 monitor the event handle. If the event notifier is enabled, it will
69 emit the activated() signal whenever the corresponding event object
70 is signalled.
71
72 The setEnabled() function allows you to disable as well as enable the
73 event notifier. It is generally advisable to explicitly enable or
74 disable the event notifier. A disabled notifier does nothing when the
75 event object is signalled (the same effect as not creating the
76 event notifier). Use the isEnabled() function to determine the
77 notifier's current status.
78
79 Finally, you can use the setHandle() function to register a new event
80 object, and the handle() function to retrieve the event handle.
81
82 \b{Further information:}
83 Although the class is called QWinEventNotifier, it can be used for
84 certain other objects which are so-called synchronization
85 objects, such as Processes, Threads, Waitable timers.
86
87 \warning This class is only available on Windows.
88 */
89
90 /*!
91 \fn void QWinEventNotifier::activated(HANDLE hEvent)
92
93 This signal is emitted whenever the event notifier is enabled and
94 the corresponding HANDLE is signalled.
95
96 The state of the event is not modified in the process, so if it is a
97 manual reset event, you will need to reset it after the notification.
98
99 The object is passed in the \a hEvent parameter.
100
101 \sa handle()
102 */
103
104 /*!
105 Constructs an event notifier with the given \a parent.
106 */
107
QWinEventNotifier(QObject * parent)108 QWinEventNotifier::QWinEventNotifier(QObject *parent)
109 : QObject(*new QWinEventNotifierPrivate, parent)
110 {}
111
112 /*!
113 Constructs an event notifier with the given \a parent. It enables
114 the notifier, and watches for the event \a hEvent.
115
116 The notifier is enabled by default, i.e. it emits the activated() signal
117 whenever the corresponding event is signalled. However, it is generally
118 advisable to explicitly enable or disable the event notifier.
119
120 \sa setEnabled(), isEnabled()
121 */
122
QWinEventNotifier(HANDLE hEvent,QObject * parent)123 QWinEventNotifier::QWinEventNotifier(HANDLE hEvent, QObject *parent)
124 : QObject(*new QWinEventNotifierPrivate(hEvent, false), parent)
125 {
126 Q_D(QWinEventNotifier);
127 QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
128 if (Q_UNLIKELY(!eventDispatcher)) {
129 qWarning("QWinEventNotifier: Can only be used with threads started with QThread");
130 return;
131 }
132 eventDispatcher->registerEventNotifier(this);
133 d->enabled = true;
134 }
135
136 /*!
137 Destroys this notifier.
138 */
139
~QWinEventNotifier()140 QWinEventNotifier::~QWinEventNotifier()
141 {
142 setEnabled(false);
143 }
144
145 /*!
146 Register the HANDLE \a hEvent. The old HANDLE will be automatically
147 unregistered.
148
149 \b Note: The notifier will be disabled as a side effect and needs
150 to be re-enabled.
151
152 \sa handle(), setEnabled()
153 */
154
setHandle(HANDLE hEvent)155 void QWinEventNotifier::setHandle(HANDLE hEvent)
156 {
157 Q_D(QWinEventNotifier);
158 setEnabled(false);
159 d->handleToEvent = hEvent;
160 }
161
162 /*!
163 Returns the HANDLE that has been registered in the notifier.
164
165 \sa setHandle()
166 */
167
handle() const168 HANDLE QWinEventNotifier::handle() const
169 {
170 Q_D(const QWinEventNotifier);
171 return d->handleToEvent;
172 }
173
174 /*!
175 Returns \c true if the notifier is enabled; otherwise returns \c false.
176
177 \sa setEnabled()
178 */
179
isEnabled() const180 bool QWinEventNotifier::isEnabled() const
181 {
182 Q_D(const QWinEventNotifier);
183 return d->enabled;
184 }
185
186 /*!
187 If \a enable is true, the notifier is enabled; otherwise the notifier
188 is disabled.
189
190 \sa isEnabled(), activated()
191 */
192
setEnabled(bool enable)193 void QWinEventNotifier::setEnabled(bool enable)
194 {
195 Q_D(QWinEventNotifier);
196 if (d->enabled == enable) // no change
197 return;
198 d->enabled = enable;
199
200 QAbstractEventDispatcher *eventDispatcher = d->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
201 if (!eventDispatcher) // perhaps application is shutting down
202 return;
203 if (Q_UNLIKELY(thread() != QThread::currentThread())) {
204 qWarning("QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread");
205 return;
206 }
207
208 if (enable) {
209 d->signaledCount = 0;
210 eventDispatcher->registerEventNotifier(this);
211 } else {
212 eventDispatcher->unregisterEventNotifier(this);
213 }
214 }
215
216 /*!
217 \reimp
218 */
219
event(QEvent * e)220 bool QWinEventNotifier::event(QEvent * e)
221 {
222 Q_D(QWinEventNotifier);
223 if (e->type() == QEvent::ThreadChange) {
224 if (d->enabled) {
225 QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection,
226 Q_ARG(bool, true));
227 setEnabled(false);
228 }
229 }
230 QObject::event(e); // will activate filters
231 if (e->type() == QEvent::WinEventAct) {
232 emit activated(d->handleToEvent, QPrivateSignal());
233 return true;
234 }
235 return false;
236 }
237
238 #if defined(Q_OS_WINRT)
239
registerWaitObject()240 bool QWinEventNotifierPrivate::registerWaitObject()
241 {
242 Q_UNIMPLEMENTED();
243 return false;
244 }
245
unregisterWaitObject()246 void QWinEventNotifierPrivate::unregisterWaitObject()
247 {
248 Q_UNIMPLEMENTED();
249 }
250
251 #else // defined(Q_OS_WINRT)
252
wfsoCallback(void * context,BOOLEAN)253 static void CALLBACK wfsoCallback(void *context, BOOLEAN /*ignore*/)
254 {
255 QWinEventNotifierPrivate *nd = reinterpret_cast<QWinEventNotifierPrivate *>(context);
256 QAbstractEventDispatcher *eventDispatcher = nd->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
257
258 // Happens when Q(Core)Application is destroyed before QWinEventNotifier.
259 // https://bugreports.qt.io/browse/QTBUG-70214
260 if (!eventDispatcher) { // perhaps application is shutting down
261 qWarning("QWinEventNotifier: no event dispatcher, application shutting down? Cannot deliver event.");
262 return;
263 }
264
265 QEventDispatcherWin32Private *edp = QEventDispatcherWin32Private::get(
266 static_cast<QEventDispatcherWin32 *>(eventDispatcher));
267 ++nd->signaledCount;
268 SetEvent(edp->winEventNotifierActivatedEvent);
269 }
270
registerWaitObject()271 bool QWinEventNotifierPrivate::registerWaitObject()
272 {
273 if (RegisterWaitForSingleObject(&waitHandle, handleToEvent, wfsoCallback, this,
274 INFINITE, WT_EXECUTEONLYONCE) == 0) {
275 qErrnoWarning("QWinEventNotifier: RegisterWaitForSingleObject failed.");
276 return false;
277 }
278 return true;
279 }
280
unregisterWaitObject()281 void QWinEventNotifierPrivate::unregisterWaitObject()
282 {
283 // Unregister the wait handle and wait for pending callbacks to finish.
284 if (UnregisterWaitEx(waitHandle, INVALID_HANDLE_VALUE))
285 waitHandle = NULL;
286 else
287 qErrnoWarning("QWinEventNotifier: UnregisterWaitEx failed.");
288 }
289
290 #endif // !defined(Q_OS_WINRT)
291
292 QT_END_NAMESPACE
293