Typica is a free program for professional coffee roasters. https://typica.us
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

qextwineventnotifier_p.cpp 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /****************************************************************************
  2. ** Copyright (c) 2000-2003 Wayne Roth
  3. ** Copyright (c) 2004-2007 Stefan Sander
  4. ** Copyright (c) 2007 Michal Policht
  5. ** Copyright (c) 2008 Brandon Fosdick
  6. ** Copyright (c) 2009-2010 Liam Staskawicz
  7. ** Copyright (c) 2011 Debao Zhang
  8. ** All right reserved.
  9. ** Web: http://code.google.com/p/qextserialport/
  10. **
  11. ** Permission is hereby granted, free of charge, to any person obtaining
  12. ** a copy of this software and associated documentation files (the
  13. ** "Software"), to deal in the Software without restriction, including
  14. ** without limitation the rights to use, copy, modify, merge, publish,
  15. ** distribute, sublicense, and/or sell copies of the Software, and to
  16. ** permit persons to whom the Software is furnished to do so, subject to
  17. ** the following conditions:
  18. **
  19. ** The above copyright notice and this permission notice shall be
  20. ** included in all copies or substantial portions of the Software.
  21. **
  22. ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. **
  30. ****************************************************************************/
  31. #include "qextwineventnotifier_p.h"
  32. #include <QtCore/QThread>
  33. #include <QtCore/QList>
  34. #include <QtCore/QMutex>
  35. #include <QtCore/QMutexLocker>
  36. #include <QtCore/QEvent>
  37. #include <QtCore/QDebug>
  38. #include <QtCore/QCoreApplication>
  39. class QextWinEventNotifierPrivate
  40. {
  41. Q_DECLARE_PUBLIC(QextWinEventNotifier)
  42. public:
  43. QextWinEventNotifierPrivate(HANDLE hEvent, QextWinEventNotifier * q)
  44. :handleToEvent(hEvent), enabled(false), q_ptr(q)
  45. {}
  46. HANDLE handleToEvent;
  47. bool enabled;
  48. private:
  49. QextWinEventNotifier * q_ptr;
  50. };
  51. /*
  52. \internal
  53. \class QextWinEventNotifierThread
  54. This class works more or less like an EventDispatcher.
  55. The api function WaitForMultipleObjects() is used in the new thread
  56. to wait for the registered handle.
  57. */
  58. class QextWinEventNotifierThread:public QThread
  59. {
  60. public:
  61. explicit QextWinEventNotifierThread(QObject * parent=0);
  62. ~QextWinEventNotifierThread();
  63. void stop();
  64. bool registerEventNotifier(QextWinEventNotifier * notifier);
  65. void unregisterEventNotifier(QextWinEventNotifier * notifier);
  66. protected:
  67. void run();
  68. private:
  69. HANDLE hStopEvent; //stop thread when this event signaled.
  70. HANDLE hUpdateEvent; //make sure eventlist updated.
  71. QMutex mutex;
  72. QList<QextWinEventNotifier *> winEventNotifierList;
  73. };
  74. Q_GLOBAL_STATIC(QextWinEventNotifierThread, notifierThread)
  75. QextWinEventNotifierThread::QextWinEventNotifierThread(QObject * parent)
  76. :QThread(parent)
  77. {
  78. hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  79. hUpdateEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  80. start();
  81. }
  82. QextWinEventNotifierThread::~QextWinEventNotifierThread()
  83. {
  84. if (isRunning())
  85. stop();
  86. CloseHandle(hStopEvent);
  87. CloseHandle(hUpdateEvent);
  88. }
  89. void QextWinEventNotifierThread::stop()
  90. {
  91. {
  92. QMutexLocker locker(&mutex);
  93. SetEvent(hStopEvent);
  94. }
  95. wait(); /// Is this an good idea?
  96. }
  97. bool QextWinEventNotifierThread::registerEventNotifier(QextWinEventNotifier *notifier)
  98. {
  99. QMutexLocker locker(&mutex);
  100. if (!notifier) {
  101. QESP_WARNING("QextWinEventNotifier: Internal error");
  102. return false;
  103. }
  104. if (winEventNotifierList.contains(notifier))
  105. return true;
  106. if (winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 3) {
  107. QESP_WARNING("QextWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 3);
  108. return false;
  109. }
  110. winEventNotifierList.append(notifier);
  111. SetEvent(hUpdateEvent);
  112. return true;
  113. }
  114. void QextWinEventNotifierThread::unregisterEventNotifier(QextWinEventNotifier *notifier)
  115. {
  116. QMutexLocker locker(&mutex);
  117. if (!notifier) {
  118. QESP_WARNING("QextWinEventNotifier: Internal error");
  119. return;
  120. }
  121. int idx = winEventNotifierList.indexOf(notifier);
  122. if (idx != -1) {
  123. winEventNotifierList.takeAt(idx);
  124. SetEvent(hUpdateEvent);
  125. }
  126. }
  127. void QextWinEventNotifierThread::run()
  128. {
  129. forever{
  130. HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
  131. DWORD nCount = 0;
  132. {
  133. QMutexLocker locker(&mutex);
  134. nCount = winEventNotifierList.count();
  135. for (int i=0; i<(int)nCount; ++i)
  136. pHandles[i] = winEventNotifierList.at(i)->handle();
  137. pHandles[nCount] = hUpdateEvent;
  138. pHandles[nCount+1] = hStopEvent;
  139. }
  140. DWORD ret = WaitForMultipleObjects(nCount+2, pHandles, FALSE, INFINITE);
  141. if (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + nCount) {
  142. QEvent *evt = new QEvent(QEvent::User);
  143. QMutexLocker locker(&mutex);
  144. ResetEvent(pHandles[ret-WAIT_OBJECT_0]);
  145. QObject * notifier = winEventNotifierList[ret - WAIT_OBJECT_0];
  146. QCoreApplication::postEvent(notifier, evt);
  147. }
  148. else if (ret == WAIT_OBJECT_0 + nCount) {
  149. //ResetEvent(hUpdateEvent);
  150. }
  151. else if (ret == WAIT_OBJECT_0 + nCount + 1) {
  152. //qDebug()<<"quit...";
  153. return;
  154. }
  155. }
  156. }
  157. /*!
  158. \internal
  159. \class QextWinEventNotifier
  160. \brief The QextWinEventNotifier class provides support for the Windows Wait functions.
  161. The QextWinEventNotifier class makes it possible to use the wait
  162. functions on windows in a asynchronous manner. With this class
  163. you can register a HANDLE to an event and get notification when
  164. that event becomes signalled.
  165. \bold Note: If it is a manual reset event ,it will be reset before
  166. the notification. This is different from QWinEventNotifier.
  167. \bold Note: All the registered handles will be waited under a new thread.
  168. This is different from QWinEventNotifier whose event handle will be waited
  169. in its affinal thread.
  170. */
  171. QextWinEventNotifier::QextWinEventNotifier(QObject *parent)
  172. : QObject(parent), d_ptr(new QextWinEventNotifierPrivate(0, this))
  173. {}
  174. QextWinEventNotifier::QextWinEventNotifier(HANDLE hEvent, QObject *parent)
  175. : QObject(parent), d_ptr(new QextWinEventNotifierPrivate(hEvent, this))
  176. {
  177. setEnabled(true);
  178. }
  179. QextWinEventNotifier::~QextWinEventNotifier()
  180. {
  181. setEnabled(false);
  182. }
  183. void QextWinEventNotifier::setHandle(HANDLE hEvent)
  184. {
  185. setEnabled(false);
  186. Q_D(QextWinEventNotifier);
  187. d->handleToEvent = hEvent;
  188. }
  189. HANDLE QextWinEventNotifier::handle() const
  190. {
  191. return d_func()->handleToEvent;
  192. }
  193. bool QextWinEventNotifier::isEnabled() const
  194. {
  195. return d_func()->enabled;
  196. }
  197. void QextWinEventNotifier::setEnabled(bool enable)
  198. {
  199. Q_D(QextWinEventNotifier);
  200. if (d->enabled == enable)
  201. return;
  202. d->enabled = enable;
  203. if (d->enabled)
  204. notifierThread()->registerEventNotifier(this);
  205. else
  206. notifierThread()->unregisterEventNotifier(this);
  207. }
  208. bool QextWinEventNotifier::event(QEvent * e)
  209. {
  210. Q_D(QextWinEventNotifier);
  211. QObject::event(e);
  212. if (e->type() == QEvent::User) {
  213. emit activated(d->handleToEvent);
  214. return true;
  215. }
  216. return false;
  217. }