src/corelib/kernel/qeventdispatcher_win.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtCore module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qeventdispatcher_win_p.h"
       
    43 
       
    44 #include "qcoreapplication.h"
       
    45 #include "qhash.h"
       
    46 #include "qlibrary.h"
       
    47 #include "qpair.h"
       
    48 #include "qset.h"
       
    49 #include "qsocketnotifier.h"
       
    50 #include "qvarlengtharray.h"
       
    51 #include "qwineventnotifier_p.h"
       
    52 
       
    53 #include "qabstracteventdispatcher_p.h"
       
    54 #include "qcoreapplication_p.h"
       
    55 #include <private/qthread_p.h>
       
    56 #include <private/qmutexpool_p.h>
       
    57 
       
    58 QT_BEGIN_NAMESPACE
       
    59 
       
    60 HINSTANCE qWinAppInst();
       
    61 extern uint qGlobalPostedEventsCount();
       
    62 
       
    63 #ifndef TIME_KILL_SYNCHRONOUS
       
    64 #  define TIME_KILL_SYNCHRONOUS 0x0100
       
    65 #endif
       
    66 
       
    67 #if defined(Q_OS_WINCE)
       
    68 QT_BEGIN_INCLUDE_NAMESPACE
       
    69 #include <winsock.h>
       
    70 // Asynchronous Winsocks ------------------------------------------
       
    71 #ifndef QT_NO_THREAD
       
    72 #include <qthread.h>
       
    73 #include <qmap.h>
       
    74 #include <qmutex.h>
       
    75 QT_END_INCLUDE_NAMESPACE
       
    76 
       
    77 //#define QCE_ASYNC_DEBUG
       
    78 
       
    79 namespace {
       
    80     class SocketAsyncHandler;
       
    81 
       
    82     class SocketAsyncHandler : public QThread
       
    83     {
       
    84     public:
       
    85         SocketAsyncHandler();
       
    86         ~SocketAsyncHandler();
       
    87         void run();
       
    88         void select(SOCKET sock, HWND handle, unsigned int msg, long ev);
       
    89         void removeSelect(SOCKET sock);
       
    90         void safeRemove(SOCKET sock);
       
    91     private:
       
    92         struct SockInfo {
       
    93             HWND handle;
       
    94             unsigned int msg;
       
    95             long ev;
       
    96         };
       
    97         QMap<SOCKET, SockInfo> sockets;
       
    98         QMutex mutex;
       
    99         QWaitCondition cond;
       
   100         bool supposedToDie;
       
   101     };
       
   102 
       
   103     SocketAsyncHandler::SocketAsyncHandler()
       
   104         : supposedToDie(false)
       
   105     {
       
   106     }
       
   107 
       
   108     SocketAsyncHandler::~SocketAsyncHandler()
       
   109     {
       
   110         mutex.lock();
       
   111         supposedToDie = true;
       
   112         mutex.unlock();
       
   113         cond.wakeOne();
       
   114         wait();
       
   115         while (sockets.size() > 0)
       
   116             removeSelect(sockets.begin().key());
       
   117     }
       
   118 
       
   119     void SocketAsyncHandler::removeSelect(SOCKET sock)
       
   120     {
       
   121         if (!sockets.contains(sock))
       
   122             return;
       
   123         sockets.remove(sock);
       
   124         return;
       
   125     }
       
   126 
       
   127     void SocketAsyncHandler::safeRemove(SOCKET sock)
       
   128     {
       
   129         QMutexLocker locker(&mutex);
       
   130         removeSelect(sock);
       
   131     }
       
   132 
       
   133     void SocketAsyncHandler::select(SOCKET sock, HWND handle, unsigned int msg, long ev)
       
   134     {
       
   135         QMutexLocker locker(&mutex);
       
   136 
       
   137         if (sockets.contains(sock))
       
   138             sockets.remove(sock);
       
   139 
       
   140         SockInfo info;
       
   141         info.handle = handle;
       
   142         info.msg = msg;
       
   143         info.ev = ev;
       
   144         sockets.insert(sock, info);
       
   145         cond.wakeOne();
       
   146     }
       
   147 
       
   148     void SocketAsyncHandler::run()
       
   149     {
       
   150         do {
       
   151             mutex.lock();
       
   152 
       
   153             while (!supposedToDie && sockets.isEmpty()) {
       
   154                 cond.wait(&mutex);
       
   155             }
       
   156 
       
   157             if (supposedToDie) {
       
   158                 mutex.unlock();
       
   159                 break;
       
   160             }
       
   161 
       
   162             // Copy current items to reduce lock time
       
   163             // and to be able to use SendMessage
       
   164             QMap<SOCKET, SockInfo> currentSockets = sockets;
       
   165             mutex.unlock();
       
   166 
       
   167             fd_set readS, writeS, exS;
       
   168             FD_ZERO(&readS);
       
   169             FD_ZERO(&writeS);
       
   170             FD_ZERO(&exS);
       
   171 
       
   172             int maxFd = 0;
       
   173 
       
   174             for (QMap<SOCKET, SockInfo>::iterator it = currentSockets.begin(); it != currentSockets.end(); ++it) {
       
   175                 const SockInfo &info = it.value();
       
   176                 int socket = it.key();
       
   177                 maxFd = qMax(maxFd, socket);
       
   178 
       
   179                 if ((info.ev & FD_READ) || (info.ev & FD_CLOSE) || (info.ev & FD_ACCEPT))
       
   180                     FD_SET(socket, &readS);
       
   181                 if ((info.ev & FD_WRITE)|| (info.ev & FD_CONNECT))
       
   182                     FD_SET(socket, &writeS);
       
   183                 if (info.ev & FD_OOB)
       
   184                     FD_SET(socket, &exS);
       
   185             }
       
   186 
       
   187             timeval timeout;
       
   188             timeout.tv_sec = 0;
       
   189             timeout.tv_usec = 50000;
       
   190             int result = ::select(maxFd + 1, &readS, &writeS, &exS, &timeout);
       
   191             if (result > 0) {
       
   192                 HWND handle;
       
   193                 unsigned int tmpMsg;
       
   194                 SOCKET sock;
       
   195                 HRESULT ret;
       
   196                 for (QMap<SOCKET, SockInfo>::const_iterator it = currentSockets.constBegin();
       
   197                     it != currentSockets.constEnd(); ++it) {
       
   198                         handle = (*it).handle;
       
   199                         tmpMsg = (*it).msg;
       
   200                         sock = it.key();
       
   201                         if (FD_ISSET(sock, &readS))
       
   202                             ret = SendMessage(handle, tmpMsg, sock, FD_READ);
       
   203 
       
   204                         if (FD_ISSET(sock, &writeS))
       
   205                             ret = SendMessage(handle, tmpMsg, sock, FD_WRITE);
       
   206 
       
   207                         if (FD_ISSET(sock, &exS))
       
   208                             ret = SendMessage(handle, tmpMsg, sock, FD_OOB);
       
   209                 }
       
   210             }
       
   211 
       
   212 #ifdef QCE_ASYNC_DEBUG
       
   213             else if (result == 0) { //timeout
       
   214                 qDebug("    WSAAsync select timeout");
       
   215             } else if (result < 0) { // SocketError
       
   216                 // This might happen because of two reasons
       
   217                 // 1. We already closed a socket in between the copy and the select
       
   218                 //    and thus select() returns an error
       
   219                 // 2. Something is really wrong, then
       
   220                 //    ### Loop on all descriptors, try to select and remove the
       
   221                 //    ### broken one.
       
   222                 qWarning("WSAAsync select error %d", WSAGetLastError());
       
   223             }
       
   224 #endif
       
   225         } while(true);
       
   226     }
       
   227 } // namespace
       
   228 
       
   229 Q_GLOBAL_STATIC(SocketAsyncHandler, qt_async_handler)
       
   230 
       
   231 int WSAAsyncSelect(SOCKET sock, HWND handle, unsigned int msg, long ev)
       
   232 {
       
   233     if (sock == 0 || handle == 0 || handle == INVALID_HANDLE_VALUE) {
       
   234         WSASetLastError(WSAEINVAL);
       
   235         return SOCKET_ERROR;
       
   236     }
       
   237 
       
   238     if (msg == 0 && ev == 0)
       
   239         qt_async_handler()->safeRemove(sock);
       
   240     else
       
   241         qt_async_handler()->select(sock, handle, msg, ev);
       
   242 
       
   243     qt_async_handler()->start(QThread::LowPriority);
       
   244     WSASetLastError(0);
       
   245     return 0;
       
   246 }
       
   247 #else // QT_NO_THREAD
       
   248 int WSAAsyncSelect(SOCKET, HWND, unsigned int, long)
       
   249 {
       
   250     return SOCKET_ERROR;
       
   251 }
       
   252 #endif
       
   253 #endif // Q_OS_WINCE
       
   254 
       
   255 class QEventDispatcherWin32Private;
       
   256 
       
   257 struct QSockNot {
       
   258     QSocketNotifier *obj;
       
   259     int fd;
       
   260 };
       
   261 typedef QHash<int, QSockNot *> QSNDict;
       
   262 
       
   263 struct WinTimerInfo {                           // internal timer info
       
   264     QObject *dispatcher;
       
   265     int timerId;
       
   266     int interval;
       
   267     QObject *obj;                               // - object to receive events
       
   268     bool inTimerEvent;
       
   269     int fastTimerId;
       
   270 };
       
   271 
       
   272 class QZeroTimerEvent : public QTimerEvent
       
   273 {
       
   274 public:
       
   275     inline QZeroTimerEvent(int timerId)
       
   276         : QTimerEvent(timerId)
       
   277     { t = QEvent::ZeroTimerEvent; }
       
   278 };
       
   279 
       
   280 typedef QList<WinTimerInfo*>  WinTimerVec;      // vector of TimerInfo structs
       
   281 typedef QHash<int, WinTimerInfo*> WinTimerDict; // fast dict of timers
       
   282 
       
   283 #if !defined(DWORD_PTR) && !defined(Q_WS_WIN64)
       
   284 #define DWORD_PTR DWORD
       
   285 #endif
       
   286 
       
   287 typedef MMRESULT(WINAPI *ptimeSetEvent)(UINT, UINT, LPTIMECALLBACK, DWORD_PTR, UINT);
       
   288 typedef MMRESULT(WINAPI *ptimeKillEvent)(UINT);
       
   289 
       
   290 static ptimeSetEvent qtimeSetEvent = 0;
       
   291 static ptimeKillEvent qtimeKillEvent = 0;
       
   292 
       
   293 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
       
   294 
       
   295 static void resolveTimerAPI()
       
   296 {
       
   297     static bool triedResolve = false;
       
   298     if (!triedResolve) {
       
   299 #ifndef QT_NO_THREAD
       
   300         QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
       
   301         if (triedResolve)
       
   302             return;
       
   303 #endif
       
   304         triedResolve = true;
       
   305 #if !defined(Q_OS_WINCE)
       
   306         qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("winmm"), "timeSetEvent");
       
   307         qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("winmm"), "timeKillEvent");
       
   308 #else
       
   309         qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent");
       
   310         qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent");
       
   311 #endif
       
   312     }
       
   313 }
       
   314 
       
   315 
       
   316 class QEventDispatcherWin32Private : public QAbstractEventDispatcherPrivate
       
   317 {
       
   318     Q_DECLARE_PUBLIC(QEventDispatcherWin32)
       
   319 public:
       
   320     QEventDispatcherWin32Private();
       
   321     ~QEventDispatcherWin32Private();
       
   322 
       
   323     DWORD threadId;
       
   324 
       
   325     bool interrupt;
       
   326 
       
   327     // internal window handle used for socketnotifiers/timers/etc
       
   328     HWND internalHwnd;
       
   329 
       
   330     // timers
       
   331     WinTimerVec timerVec;
       
   332     WinTimerDict timerDict;
       
   333     void registerTimer(WinTimerInfo *t);
       
   334     void unregisterTimer(WinTimerInfo *t, bool closingDown = false);
       
   335     void sendTimerEvent(int timerId);
       
   336 
       
   337     // socket notifiers
       
   338     QSNDict sn_read;
       
   339     QSNDict sn_write;
       
   340     QSNDict sn_except;
       
   341     void doWsaAsyncSelect(int socket);
       
   342 
       
   343     // event notifier
       
   344     QWinEventNotifier wakeUpNotifier;
       
   345 
       
   346     QList<QWinEventNotifier *> winEventNotifierList;
       
   347     void activateEventNotifier(QWinEventNotifier * wen);
       
   348 
       
   349     QList<MSG> queuedUserInputEvents;
       
   350     QList<MSG> queuedSocketEvents;
       
   351 };
       
   352 
       
   353 QEventDispatcherWin32Private::QEventDispatcherWin32Private()
       
   354     : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0)
       
   355 {
       
   356     resolveTimerAPI();
       
   357 
       
   358     wakeUpNotifier.setHandle(CreateEvent(0, FALSE, FALSE, 0));
       
   359     if (!wakeUpNotifier.handle())
       
   360         qWarning("QEventDispatcher: Creating QEventDispatcherWin32Private wakeup event failed");
       
   361 }
       
   362 
       
   363 QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
       
   364 {
       
   365     wakeUpNotifier.setEnabled(false);
       
   366     CloseHandle(wakeUpNotifier.handle());
       
   367     if (internalHwnd)
       
   368         DestroyWindow(internalHwnd);
       
   369     QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc));
       
   370     UnregisterClass((wchar_t*)className.utf16(), qWinAppInst());
       
   371 }
       
   372 
       
   373 void QEventDispatcherWin32Private::activateEventNotifier(QWinEventNotifier * wen)
       
   374 {
       
   375     QEvent event(QEvent::WinEventAct);
       
   376     QCoreApplication::sendEvent(wen, &event);
       
   377 }
       
   378 
       
   379 // ### Qt 5: remove
       
   380 Q_CORE_EXPORT bool winPeekMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin,
       
   381                      UINT wMsgFilterMax, UINT wRemoveMsg)
       
   382 {
       
   383     return PeekMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
       
   384 }
       
   385 
       
   386 // ### Qt 5: remove
       
   387 Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
       
   388 {
       
   389     return PostMessage(hWnd, msg, wParam, lParam);
       
   390 }
       
   391 
       
   392 // ### Qt 5: remove
       
   393 Q_CORE_EXPORT bool winGetMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin,
       
   394                      UINT wMsgFilterMax)
       
   395 {
       
   396     return GetMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax);
       
   397 }
       
   398 
       
   399 // This function is called by a workerthread
       
   400 void WINAPI CALLBACK qt_fast_timer_proc(uint timerId, uint /*reserved*/, DWORD_PTR user, DWORD_PTR /*reserved*/, DWORD_PTR /*reserved*/)
       
   401 {
       
   402     if (!timerId) // sanity check
       
   403         return;
       
   404     WinTimerInfo *t = (WinTimerInfo*)user;
       
   405     Q_ASSERT(t);
       
   406     QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId));
       
   407 }
       
   408 
       
   409 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
       
   410 {
       
   411     if (message == WM_NCCREATE) {
       
   412             return true;
       
   413     } else if (message == WM_USER) {
       
   414 
       
   415         // socket notifier message
       
   416         MSG msg;
       
   417         msg.hwnd = hwnd;
       
   418         msg.message = message;
       
   419         msg.wParam = wp;
       
   420         msg.lParam = lp;
       
   421 
       
   422         QCoreApplication *app = QCoreApplication::instance();
       
   423         long result;
       
   424         if (app && app->filterEvent(&msg, &result))
       
   425             return result;
       
   426 
       
   427         int type = -1;
       
   428         switch (WSAGETSELECTEVENT(lp)) {
       
   429         case FD_READ:
       
   430         case FD_CLOSE:
       
   431         case FD_ACCEPT:
       
   432             type = 0;
       
   433             break;
       
   434         case FD_WRITE:
       
   435         case FD_CONNECT:
       
   436             type = 1;
       
   437             break;
       
   438         case FD_OOB:
       
   439             type = 2;
       
   440             break;
       
   441         }
       
   442         if (type >= 0) {
       
   443 
       
   444     #ifdef GWLP_USERDATA
       
   445             QEventDispatcherWin32 *eventDispatcher =
       
   446                 (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
       
   447     #else
       
   448             QEventDispatcherWin32 *eventDispatcher =
       
   449                 (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA);
       
   450     #endif
       
   451             if (eventDispatcher) {
       
   452                 QEventDispatcherWin32Private *d = eventDispatcher->d_func();
       
   453                 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
       
   454                 QSNDict *dict = sn_vec[type];
       
   455 
       
   456                 QSockNot *sn = dict ? dict->value(wp) : 0;
       
   457                 if (sn) {
       
   458                     QEvent event(QEvent::SockAct);
       
   459                     QCoreApplication::sendEvent(sn->obj, &event);
       
   460                 }
       
   461             }
       
   462         }
       
   463         return 0;
       
   464 
       
   465     } else if (message == WM_TIMER) {
       
   466 
       
   467         MSG msg;
       
   468         msg.hwnd = hwnd;
       
   469         msg.message = message;
       
   470         msg.wParam = wp;
       
   471         msg.lParam = lp;
       
   472 
       
   473         QCoreApplication *app = QCoreApplication::instance();
       
   474         Q_ASSERT_X(app, "qt_interal_proc", "Timer fired, but no QCoreApplication");
       
   475         if (!app) {
       
   476             KillTimer(hwnd, wp);
       
   477             return 0;
       
   478         }
       
   479 
       
   480         long result;
       
   481         if (app->filterEvent(&msg, &result))
       
   482             return result;
       
   483 
       
   484         QEventDispatcherWin32 *eventDispatcher =
       
   485             qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
       
   486         Q_ASSERT(eventDispatcher != 0);
       
   487         QEventDispatcherWin32Private *d = eventDispatcher->d_func();
       
   488         d->sendTimerEvent(wp);
       
   489         return 0;
       
   490     }
       
   491 
       
   492     return  DefWindowProc(hwnd, message, wp, lp);
       
   493 }
       
   494 
       
   495 static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)
       
   496 {
       
   497     // make sure that multiple Qt's can coexist in the same process
       
   498     QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc));
       
   499 
       
   500     WNDCLASS wc;
       
   501     wc.style = 0;
       
   502     wc.lpfnWndProc = qt_internal_proc;
       
   503     wc.cbClsExtra = 0;
       
   504     wc.cbWndExtra = 0;
       
   505     wc.hInstance = qWinAppInst();
       
   506     wc.hIcon = 0;
       
   507     wc.hCursor = 0;
       
   508     wc.hbrBackground = 0;
       
   509     wc.lpszMenuName = NULL;
       
   510     wc.lpszClassName = reinterpret_cast<const wchar_t *> (className.utf16());
       
   511 
       
   512     RegisterClass(&wc);
       
   513     HWND wnd = CreateWindow(wc.lpszClassName,  // classname
       
   514                             wc.lpszClassName,  // window name
       
   515                             0,                 // style
       
   516                             0, 0, 0, 0,        // geometry
       
   517                             0,                 // parent
       
   518                             0,                 // menu handle
       
   519                             qWinAppInst(),     // application
       
   520                             0);                // windows creation data.
       
   521 
       
   522 #ifdef GWLP_USERDATA
       
   523     SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher);
       
   524 #else
       
   525     SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher);
       
   526 #endif
       
   527 
       
   528     if (!wnd) {
       
   529         qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError());
       
   530     }
       
   531     return wnd;
       
   532 }
       
   533 
       
   534 void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
       
   535 {
       
   536     Q_ASSERT(internalHwnd);
       
   537 
       
   538     Q_Q(QEventDispatcherWin32);
       
   539 
       
   540     int ok = 0;
       
   541 
       
   542     //in the animation api, we delay the start of the animation
       
   543     //for the dock widgets, we need to use a system timer because dragging a native window
       
   544     //makes Windows start its own event loop.
       
   545     //So if this threshold changes, please change STARTSTOP_TIMER_DELAY in qabstractanimation.cpp accordingly.
       
   546     if (t->interval > 15 || !t->interval || !qtimeSetEvent) {
       
   547         ok = 1;
       
   548         if (!t->interval)  // optimization for single-shot-zero-timer
       
   549             QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
       
   550         else
       
   551             ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
       
   552     } else {
       
   553         ok = t->fastTimerId = qtimeSetEvent(t->interval, 1, qt_fast_timer_proc, (DWORD_PTR)t,
       
   554                                             TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
       
   555         if (ok == 0) { // fall back to normal timer if no more multimedia timers avaiable
       
   556             ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
       
   557         }
       
   558     }
       
   559 
       
   560     if (ok == 0)
       
   561         qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
       
   562 }
       
   563 
       
   564 void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t, bool closingDown)
       
   565 {
       
   566     // mark timer as unused
       
   567     if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent && !closingDown)
       
   568         QAbstractEventDispatcherPrivate::releaseTimerId(t->timerId);
       
   569 
       
   570     if (t->interval == 0) {
       
   571         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
       
   572     } else if (t->fastTimerId != 0) {
       
   573         qtimeKillEvent(t->fastTimerId);
       
   574         QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
       
   575     } else if (internalHwnd) {
       
   576         KillTimer(internalHwnd, t->timerId);
       
   577     }
       
   578     delete t;
       
   579 }
       
   580 
       
   581 void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
       
   582 {
       
   583     WinTimerInfo *t = timerDict.value(timerId);
       
   584     if (t && !t->inTimerEvent) {
       
   585         // send event, but don't allow it to recurse
       
   586         t->inTimerEvent = true;
       
   587 
       
   588         QTimerEvent e(t->timerId);
       
   589         QCoreApplication::sendEvent(t->obj, &e);
       
   590 
       
   591         // timer could have been removed
       
   592         t = timerDict.value(timerId);
       
   593         if (t) {
       
   594             t->inTimerEvent = false;
       
   595         }
       
   596     }
       
   597 }
       
   598 
       
   599 void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket)
       
   600 {
       
   601     Q_ASSERT(internalHwnd);
       
   602     int sn_event = 0;
       
   603     if (sn_read.contains(socket))
       
   604         sn_event |= FD_READ | FD_CLOSE | FD_ACCEPT;
       
   605     if (sn_write.contains(socket))
       
   606         sn_event |= FD_WRITE | FD_CONNECT;
       
   607     if (sn_except.contains(socket))
       
   608         sn_event |= FD_OOB;
       
   609     // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0
       
   610     // This is a BoundsChecker bug and not a Qt bug
       
   611     WSAAsyncSelect(socket, internalHwnd, sn_event ? WM_USER : 0, sn_event);
       
   612 }
       
   613 
       
   614 void QEventDispatcherWin32::createInternalHwnd()
       
   615 {
       
   616     Q_D(QEventDispatcherWin32);
       
   617 
       
   618     Q_ASSERT(!d->internalHwnd);
       
   619     if (d->internalHwnd)
       
   620         return;
       
   621     d->internalHwnd = qt_create_internal_window(this);
       
   622 
       
   623     // register all socket notifiers
       
   624     QList<int> sockets = (d->sn_read.keys().toSet()
       
   625                           + d->sn_write.keys().toSet()
       
   626                           + d->sn_except.keys().toSet()).toList();
       
   627     for (int i = 0; i < sockets.count(); ++i)
       
   628         d->doWsaAsyncSelect(sockets.at(i));
       
   629 
       
   630     // start all normal timers
       
   631     for (int i = 0; i < d->timerVec.count(); ++i)
       
   632         d->registerTimer(d->timerVec.at(i));
       
   633 }
       
   634 
       
   635 QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
       
   636     : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent)
       
   637 {
       
   638 }
       
   639 
       
   640 QEventDispatcherWin32::~QEventDispatcherWin32()
       
   641 {
       
   642 }
       
   643 
       
   644 bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
       
   645 {
       
   646     Q_D(QEventDispatcherWin32);
       
   647 
       
   648     if (!d->internalHwnd)
       
   649         createInternalHwnd();
       
   650 
       
   651     d->interrupt = false;
       
   652     emit awake();
       
   653 
       
   654     bool canWait;
       
   655     bool retVal = false;
       
   656     do {
       
   657         QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
       
   658 
       
   659         DWORD waitRet = 0;
       
   660         HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
       
   661         QVarLengthArray<MSG> processedTimers;
       
   662         while (!d->interrupt) {
       
   663             DWORD nCount = d->winEventNotifierList.count();
       
   664             Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
       
   665 
       
   666             MSG msg;
       
   667             bool haveMessage;
       
   668 
       
   669             if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
       
   670                 // process queued user input events
       
   671                 haveMessage = true;
       
   672                 msg = d->queuedUserInputEvents.takeFirst();
       
   673             } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
       
   674                 // process queued socket events
       
   675                 haveMessage = true;
       
   676                 msg = d->queuedSocketEvents.takeFirst();
       
   677             } else {
       
   678                 haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
       
   679                 if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents)
       
   680                     && ((msg.message >= WM_KEYFIRST
       
   681                          && msg.message <= WM_KEYLAST)
       
   682                         || (msg.message >= WM_MOUSEFIRST
       
   683                             && msg.message <= WM_MOUSELAST)
       
   684                         || msg.message == WM_MOUSEWHEEL
       
   685                         || msg.message == WM_MOUSEHWHEEL
       
   686                         || msg.message == WM_CLOSE)) {
       
   687                     // queue user input events for later processing
       
   688                     haveMessage = false;
       
   689                     d->queuedUserInputEvents.append(msg);
       
   690                 }
       
   691                 if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)
       
   692                     && (msg.message == WM_USER && msg.hwnd == d->internalHwnd)) {
       
   693                     // queue socket events for later processing
       
   694                     haveMessage = false;
       
   695                     d->queuedSocketEvents.append(msg);
       
   696                 }
       
   697             }
       
   698             if (!haveMessage) {
       
   699                 // no message - check for signalled objects
       
   700                 for (int i=0; i<(int)nCount; i++)
       
   701                     pHandles[i] = d->winEventNotifierList.at(i)->handle();
       
   702                 waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
       
   703                 if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
       
   704                     // a new message has arrived, process it
       
   705                     continue;
       
   706                 }
       
   707             }
       
   708             if (haveMessage) {
       
   709                 if (msg.message == WM_TIMER) {
       
   710                     // avoid live-lock by keeping track of the timers we've already sent
       
   711                     bool found = false;
       
   712                     for (int i = 0; !found && i < processedTimers.count(); ++i) {
       
   713                         const MSG processed = processedTimers.constData()[i];
       
   714                         found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
       
   715                     }
       
   716                     if (found)
       
   717                         continue;
       
   718                     processedTimers.append(msg);
       
   719                 } else if (msg.message == WM_QUIT) {
       
   720                     if (QCoreApplication::instance())
       
   721                         QCoreApplication::instance()->quit();
       
   722                     return false;
       
   723                 }
       
   724 
       
   725                 if (!filterEvent(&msg)) {
       
   726                     TranslateMessage(&msg);
       
   727                     DispatchMessage(&msg);
       
   728                 }
       
   729             } else if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {
       
   730                 d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
       
   731             } else {
       
   732                 // nothing todo so break
       
   733                 break;
       
   734             }
       
   735             retVal = true;
       
   736         }
       
   737 
       
   738         // still nothing - wait for message or signalled objects
       
   739         QThreadData *data = d->threadData;
       
   740         canWait = (!retVal
       
   741                    && data->canWait
       
   742                    && !d->interrupt
       
   743                    && (flags & QEventLoop::WaitForMoreEvents));
       
   744         if (canWait) {
       
   745             DWORD nCount = d->winEventNotifierList.count();
       
   746             Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
       
   747             for (int i=0; i<(int)nCount; i++)
       
   748                 pHandles[i] = d->winEventNotifierList.at(i)->handle();
       
   749 
       
   750             emit aboutToBlock();
       
   751             waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
       
   752             emit awake();
       
   753             if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {
       
   754                 d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
       
   755                 retVal = true;
       
   756             }
       
   757         }
       
   758     } while (canWait);
       
   759 
       
   760     return retVal;
       
   761 }
       
   762 
       
   763 bool QEventDispatcherWin32::hasPendingEvents()
       
   764 {
       
   765     MSG msg;
       
   766     return qGlobalPostedEventsCount() || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
       
   767 }
       
   768 
       
   769 void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
       
   770 {
       
   771     Q_ASSERT(notifier);
       
   772     int sockfd = notifier->socket();
       
   773     int type = notifier->type();
       
   774 #ifndef QT_NO_DEBUG
       
   775     if (sockfd < 0) {
       
   776         qWarning("QSocketNotifier: Internal error");
       
   777         return;
       
   778     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
       
   779         qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
       
   780         return;
       
   781     }
       
   782 #endif
       
   783 
       
   784     Q_D(QEventDispatcherWin32);
       
   785     QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
       
   786     QSNDict *dict = sn_vec[type];
       
   787 
       
   788     if (QCoreApplication::closingDown()) // ### d->exitloop?
       
   789         return; // after sn_cleanup, don't reinitialize.
       
   790 
       
   791     if (dict->contains(sockfd)) {
       
   792         const char *t[] = { "Read", "Write", "Exception" };
       
   793     /* Variable "socket" below is a function pointer. */
       
   794         qWarning("QSocketNotifier: Multiple socket notifiers for "
       
   795                  "same socket %d and type %s", sockfd, t[type]);
       
   796     }
       
   797 
       
   798     QSockNot *sn = new QSockNot;
       
   799     sn->obj = notifier;
       
   800     sn->fd  = sockfd;
       
   801     dict->insert(sn->fd, sn);
       
   802 
       
   803     if (d->internalHwnd)
       
   804         d->doWsaAsyncSelect(sockfd);
       
   805 }
       
   806 
       
   807 void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
       
   808 {
       
   809     Q_ASSERT(notifier);
       
   810     int sockfd = notifier->socket();
       
   811     int type = notifier->type();
       
   812 #ifndef QT_NO_DEBUG
       
   813     if (sockfd < 0) {
       
   814         qWarning("QSocketNotifier: Internal error");
       
   815         return;
       
   816     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
       
   817         qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
       
   818         return;
       
   819     }
       
   820 #endif
       
   821 
       
   822     Q_D(QEventDispatcherWin32);
       
   823     QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
       
   824     QSNDict *dict = sn_vec[type];
       
   825     QSockNot *sn = dict->value(sockfd);
       
   826     if (!sn)
       
   827         return;
       
   828 
       
   829     dict->remove(sockfd);
       
   830     delete sn;
       
   831 
       
   832     if (d->internalHwnd)
       
   833         d->doWsaAsyncSelect(sockfd);
       
   834 }
       
   835 
       
   836 void QEventDispatcherWin32::registerTimer(int timerId, int interval, QObject *object)
       
   837 {
       
   838     if (timerId < 1 || interval < 0 || !object) {
       
   839         qWarning("QEventDispatcherWin32::registerTimer: invalid arguments");
       
   840         return;
       
   841     } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
       
   842         qWarning("QObject::startTimer: timers cannot be started from another thread");
       
   843         return;
       
   844     }
       
   845 
       
   846     Q_D(QEventDispatcherWin32);
       
   847 
       
   848     register WinTimerInfo *t = new WinTimerInfo;
       
   849     t->dispatcher = this;
       
   850     t->timerId  = timerId;
       
   851     t->interval = interval;
       
   852     t->obj  = object;
       
   853     t->inTimerEvent = false;
       
   854     t->fastTimerId = 0;
       
   855 
       
   856     if (d->internalHwnd)
       
   857         d->registerTimer(t);
       
   858 
       
   859     d->timerVec.append(t);                      // store in timer vector
       
   860     d->timerDict.insert(t->timerId, t);          // store timers in dict
       
   861 }
       
   862 
       
   863 bool QEventDispatcherWin32::unregisterTimer(int timerId)
       
   864 {
       
   865     if (timerId < 1) {
       
   866         qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument");
       
   867         return false;
       
   868     }
       
   869     QThread *currentThread = QThread::currentThread();
       
   870     if (thread() != currentThread) {
       
   871         qWarning("QObject::killTimer: timers cannot be stopped from another thread");
       
   872         return false;
       
   873     }
       
   874 
       
   875     Q_D(QEventDispatcherWin32);
       
   876     if (d->timerVec.isEmpty() || timerId <= 0)
       
   877         return false;
       
   878 
       
   879     WinTimerInfo *t = d->timerDict.value(timerId);
       
   880     if (!t)
       
   881         return false;
       
   882 
       
   883     d->timerDict.remove(t->timerId);
       
   884     d->timerVec.removeAll(t);
       
   885     d->unregisterTimer(t);
       
   886     return true;
       
   887 }
       
   888 
       
   889 bool QEventDispatcherWin32::unregisterTimers(QObject *object)
       
   890 {
       
   891     if (!object) {
       
   892         qWarning("QEventDispatcherWin32::unregisterTimers: invalid argument");
       
   893         return false;
       
   894     }
       
   895     QThread *currentThread = QThread::currentThread();
       
   896     if (object->thread() != thread() || thread() != currentThread) {
       
   897         qWarning("QObject::killTimers: timers cannot be stopped from another thread");
       
   898         return false;
       
   899     }
       
   900 
       
   901     Q_D(QEventDispatcherWin32);
       
   902     if (d->timerVec.isEmpty())
       
   903         return false;
       
   904     register WinTimerInfo *t;
       
   905     for (int i=0; i<d->timerVec.size(); i++) {
       
   906         t = d->timerVec.at(i);
       
   907         if (t && t->obj == object) {                // object found
       
   908             d->timerDict.remove(t->timerId);
       
   909             d->timerVec.removeAt(i);
       
   910             d->unregisterTimer(t);
       
   911             --i;
       
   912         }
       
   913     }
       
   914     return true;
       
   915 }
       
   916 
       
   917 QList<QEventDispatcherWin32::TimerInfo>
       
   918 QEventDispatcherWin32::registeredTimers(QObject *object) const
       
   919 {
       
   920     if (!object) {
       
   921         qWarning("QEventDispatcherWin32:registeredTimers: invalid argument");
       
   922         return QList<TimerInfo>();
       
   923     }
       
   924 
       
   925     Q_D(const QEventDispatcherWin32);
       
   926     QList<TimerInfo> list;
       
   927     for (int i = 0; i < d->timerVec.size(); ++i) {
       
   928         const WinTimerInfo *t = d->timerVec.at(i);
       
   929         if (t && t->obj == object)
       
   930             list << TimerInfo(t->timerId, t->interval);
       
   931     }
       
   932     return list;
       
   933 }
       
   934 
       
   935 bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier)
       
   936 {
       
   937     if (!notifier) {
       
   938         qWarning("QWinEventNotifier: Internal error");
       
   939         return false;
       
   940     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
       
   941         qWarning("QWinEventNotifier: event notifiers cannot be enabled from another thread");
       
   942         return false;
       
   943     }
       
   944 
       
   945     Q_D(QEventDispatcherWin32);
       
   946 
       
   947     if (d->winEventNotifierList.contains(notifier))
       
   948         return true;
       
   949 
       
   950     if (d->winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 2) {
       
   951         qWarning("QWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 2);
       
   952         return false;
       
   953     }
       
   954     d->winEventNotifierList.append(notifier);
       
   955     return true;
       
   956 }
       
   957 
       
   958 void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
       
   959 {
       
   960     if (!notifier) {
       
   961         qWarning("QWinEventNotifier: Internal error");
       
   962         return;
       
   963     } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
       
   964         qWarning("QWinEventNotifier: event notifiers cannot be disabled from another thread");
       
   965         return;
       
   966     }
       
   967 
       
   968     Q_D(QEventDispatcherWin32);
       
   969 
       
   970     int i = d->winEventNotifierList.indexOf(notifier);
       
   971     if (i != -1)
       
   972         d->winEventNotifierList.takeAt(i);
       
   973 }
       
   974 
       
   975 void QEventDispatcherWin32::activateEventNotifiers()
       
   976 {
       
   977     Q_D(QEventDispatcherWin32);
       
   978     //### this could break if events are removed/added in the activation
       
   979     for (int i=0; i<d->winEventNotifierList.count(); i++) {
       
   980 #if !defined(Q_OS_WINCE)
       
   981         if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0)
       
   982             d->activateEventNotifier(d->winEventNotifierList.at(i));
       
   983 #else
       
   984         if (WaitForSingleObject(d->winEventNotifierList.at(i)->handle(), 0) == WAIT_OBJECT_0)
       
   985             d->activateEventNotifier(d->winEventNotifierList.at(i));
       
   986 #endif
       
   987     }
       
   988 }
       
   989 
       
   990 void QEventDispatcherWin32::wakeUp()
       
   991 {
       
   992     Q_D(QEventDispatcherWin32);
       
   993     SetEvent(d->wakeUpNotifier.handle());
       
   994 }
       
   995 
       
   996 void QEventDispatcherWin32::interrupt()
       
   997 {
       
   998     Q_D(QEventDispatcherWin32);
       
   999     d->interrupt = true;
       
  1000     wakeUp();
       
  1001 }
       
  1002 
       
  1003 void QEventDispatcherWin32::flush()
       
  1004 { }
       
  1005 
       
  1006 
       
  1007 void QEventDispatcherWin32::startingUp()
       
  1008 {
       
  1009     Q_D(QEventDispatcherWin32);
       
  1010 
       
  1011     if (d->wakeUpNotifier.handle()) d->wakeUpNotifier.setEnabled(true);
       
  1012 }
       
  1013 
       
  1014 void QEventDispatcherWin32::closingDown()
       
  1015 {
       
  1016     Q_D(QEventDispatcherWin32);
       
  1017 
       
  1018     // clean up any socketnotifiers
       
  1019     while (!d->sn_read.isEmpty())
       
  1020         unregisterSocketNotifier((*(d->sn_read.begin()))->obj);
       
  1021     while (!d->sn_write.isEmpty())
       
  1022         unregisterSocketNotifier((*(d->sn_write.begin()))->obj);
       
  1023     while (!d->sn_except.isEmpty())
       
  1024         unregisterSocketNotifier((*(d->sn_except.begin()))->obj);
       
  1025 
       
  1026     // clean up any timers
       
  1027     for (int i = 0; i < d->timerVec.count(); ++i)
       
  1028         d->unregisterTimer(d->timerVec.at(i), true);
       
  1029     d->timerVec.clear();
       
  1030     d->timerDict.clear();
       
  1031 }
       
  1032 
       
  1033 bool QEventDispatcherWin32::event(QEvent *e)
       
  1034 {
       
  1035     Q_D(QEventDispatcherWin32);
       
  1036     if (e->type() == QEvent::ZeroTimerEvent) {
       
  1037         QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
       
  1038         WinTimerInfo *t = d->timerDict.value(zte->timerId());
       
  1039         if (t) {
       
  1040             t->inTimerEvent = true;
       
  1041 
       
  1042             QTimerEvent te(zte->timerId());
       
  1043             QCoreApplication::sendEvent(t->obj, &te);
       
  1044 
       
  1045             t = d->timerDict.value(zte->timerId());
       
  1046             if (t) {
       
  1047                 if (t->interval == 0 && t->inTimerEvent) {
       
  1048                     // post the next zero timer event as long as the timer was not restarted
       
  1049                     QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
       
  1050                 }
       
  1051 
       
  1052                 t->inTimerEvent = false;
       
  1053             }
       
  1054         }
       
  1055         return true;
       
  1056     } else if (e->type() == QEvent::Timer) {
       
  1057         QTimerEvent *te = static_cast<QTimerEvent*>(e);
       
  1058         d->sendTimerEvent(te->timerId());
       
  1059     }
       
  1060     return QAbstractEventDispatcher::event(e);
       
  1061 }
       
  1062 
       
  1063 QT_END_NAMESPACE