source: trunk/src/corelib/kernel/qeventdispatcher_pm.cpp @ 67

Last change on this file since 67 was 67, checked in by Dmitry A. Kuminov, 11 years ago

corelib: OS/2: Initial port of QEventDispatcher.

File size: 30.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** Copyright (C) 2009 netlabs.org. OS/2 parts.
7**
8** This file is part of the QtCore module of the Qt Toolkit.
9**
10** $QT_BEGIN_LICENSE:LGPL$
11** Commercial Usage
12** Licensees holding valid Qt Commercial licenses may use this file in
13** accordance with the Qt Commercial License Agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and Nokia.
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 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file.  Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Nokia gives you certain
26** additional rights. These rights are described in the Nokia Qt LGPL
27** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28** package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file.  Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you are unsure which license is appropriate for your use, please
39** contact the sales department at qt-sales@nokia.com.
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qeventdispatcher_pm_p.h"
45
46#include "qcoreapplication.h"
47#include "qhash.h"
48#include "qlibrary.h"
49#include "qpair.h"
50#include "qset.h"
51#include "qsocketnotifier.h"
52#include "qvarlengtharray.h"
53
54#include "qabstracteventdispatcher_p.h"
55#include "qcoreapplication_p.h"
56
57#include <private/qthread_p.h>
58#include <private/qmutexpool_p.h>
59
60#include <Qt/qwindowdefs_pm.h> // for QPMObjectWindow declaration
61
62QT_BEGIN_NAMESPACE
63
64extern uint qGlobalPostedEventsCount();
65
66class QEventDispatcherPMPrivate;
67
68// @todo later: timers
69#if 0
70
71struct WinTimerInfo {                           // internal timer info
72    QObject *dispatcher;
73    int timerId;
74    int interval;
75    QObject *obj;                               // - object to receive events
76    bool inTimerEvent;
77    int fastTimerId;
78};
79
80class QZeroTimerEvent : public QTimerEvent
81{
82public:
83    inline QZeroTimerEvent(int timerId)
84        : QTimerEvent(timerId)
85    { t = QEvent::ZeroTimerEvent; }
86};
87
88typedef QList<WinTimerInfo*>  WinTimerVec;      // vector of TimerInfo structs
89typedef QHash<int, WinTimerInfo*> WinTimerDict; // fast dict of timers
90
91#if !defined(DWORD_PTR) && !defined(Q_WS_WIN64)
92#define DWORD_PTR DWORD
93#endif
94
95typedef MMRESULT(WINAPI *ptimeSetEvent)(UINT, UINT, LPTIMECALLBACK, DWORD_PTR, UINT);
96typedef MMRESULT(WINAPI *ptimeKillEvent)(UINT);
97
98static ptimeSetEvent qtimeSetEvent = 0;
99static ptimeKillEvent qtimeKillEvent = 0;
100
101LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
102
103static void resolveTimerAPI()
104{
105    static bool triedResolve = false;
106    if (!triedResolve) {
107#ifndef QT_NO_THREAD
108        QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
109        if (triedResolve)
110            return;
111#endif
112        triedResolve = true;
113#if !defined(Q_OS_WINCE)
114        qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("winmm"), "timeSetEvent");
115        qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("winmm"), "timeKillEvent");
116#else
117        qtimeSetEvent = (ptimeSetEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeSetEvent");
118        qtimeKillEvent = (ptimeKillEvent)QLibrary::resolve(QLatin1String("Mmtimer"), "timeKillEvent");
119#endif
120    }
121}
122
123#endif
124
125/*****************************************************************************
126  Auxiliary object window class for dedicated message processing.
127  Declared in qwindowdefs_pm.h
128 *****************************************************************************/
129
130/*!
131    \class QPMObjectWindow qwindowdefs.h
132
133    The QPMObjectWindow class is an auxiliary class for dedicated message
134    processing. Its functionality is based on PM object windows. Once an
135    instance of this class is created, PM window messages can be sent or posted
136    to it using send() or post() methods. Subclasses should override the
137    message() method to process sent or posted messages. The hwnd() method is
138    used whenever a PM window handle of this object window is necessary to be
139    passed as a HWND argument to other calls and/or messages.
140
141    Instances of this class may be created only on the main GUI thread or on a
142    thread that has created a PM message queue and runs the PM message loop
143    \b itself. If you create an instance on a thread other than main, make sure
144    you destroy it before destroying the thread's message queue.
145
146    \note WM_CREATE and WM_DESTROY messages are processed internally and not
147    delivered do the message() method. Instead, you can use the constructor and
148    the destructor of the subclass, respectively.
149
150    \note This class is OS/2 specific and not available in Qt for other
151    platforms!
152*/
153
154/// @todo remove?
155// returns HMQ of the current thread or NULL if no event queue has been created
156static HMQ qt_WinQueryQueue(HAB hab)
157{
158    PTIB ptib;
159    PPIB ppib;
160    DosGetInfoBlocks(&ptib, &ppib);
161    return WinQueueFromID(hab, ppib->pib_ulpid, ptib->tib_ptib2->tib2_ultid);
162}
163
164/*!
165    Constructs a new object window for the current thread.
166    If \a deferred is \c false, this method calls create() to create a PM object
167    window. Otherwise, you must call create() yourself before this object window
168    is able to process messages.
169*/
170QPMObjectWindow::QPMObjectWindow(bool deferred /* = false */) :
171    w(NULLHANDLE)
172{
173    if (!deferred)
174        create();
175}
176
177/*!
178    Destroys this object window.
179    This method calls destroy() to free the PM object window.
180*/
181QPMObjectWindow::~QPMObjectWindow()
182{
183    destroy();
184}
185
186/*!
187    Creates a PM object window.
188    Returns \c true on success or \c false otherwise.
189    The method does nothing but returns \c false if the window has been already
190    created. The handle of the successfully created object window can be obtained
191    using the hwnd() method.
192
193    \note Must be called on the same thread that cosnstructed this instance.
194*/
195bool QPMObjectWindow::create()
196{
197    if (w != NULLHANDLE)
198        return false;
199
200    static const char *ClassName = "QPMObjectWindow";
201    static bool classRegistered = FALSE;
202
203    if (!classRegistered) {
204        WinRegisterClass(0, ClassName, windowProc, 0, QWL_USER + sizeof(PVOID));
205        classRegistered = true;
206    }
207
208    w = WinCreateWindow(HWND_OBJECT, ClassName,
209                        NULL, 0, 0, 0, 0, 0, NULL,
210                        HWND_BOTTOM, 0, this, NULL);
211    if (w == NULLHANDLE)
212        qWarning("QPMObjectWindow::create: WinCreateWindow failed with 0x%08lX",
213                 WinGetLastError(0));
214
215    return w != NULLHANDLE;
216}
217
218/*!
219    Destroys the PM object window.
220    Returns \c TRUE on success or \c FALSE otherwise.
221    The method does nothing but returns \c FALSE  if the window has been
222    already destroyed (or never created).
223
224    \note Must be called on the same thread that cosnstructed this instance.
225*/
226bool QPMObjectWindow::destroy()
227{
228    if (w == NULLHANDLE)
229        return false;
230
231    HWND h = w;
232    w = NULLHANDLE; // tell windowProc() we're unsafe
233    WinDestroyWindow(h);
234
235    return true;
236}
237
238//static
239MRESULT EXPENTRY QPMObjectWindow::windowProc(HWND hwnd, ULONG msg,
240                                             MPARAM mp1, MPARAM mp2)
241{
242    if (msg == WM_CREATE) {
243        QPMObjectWindow *that = static_cast<QPMObjectWindow *>(mp1);
244        if (!that)
245            return (MRESULT) TRUE;
246        WinSetWindowPtr(hwnd, QWL_USER, that);
247        return (MRESULT) FALSE;
248    }
249
250    QPMObjectWindow *that =
251        static_cast<QPMObjectWindow *>(WinQueryWindowPtr(hwnd, QWL_USER));
252    Q_ASSERT(that);
253
254    // Note: before WinCreateWindow() returns to the constructor or after the
255    // destructor has been called, w is 0. We use this to determine that the
256    // object is in the unsafe state (VTBL is not yet initialized or has been
257    // already uninitialized), so message() points to never-never land.
258    if (!that || !that->w)
259        return (MRESULT) FALSE;
260
261    return that->message(msg, mp1, mp2);
262}
263
264/*!
265  \fn QPMObjectWindow::send(ULONG msg, MPARAM mp1, MPARAM mp2) const
266
267  Synchronously sends a message \a msg with the given parameters \a mp1 and
268  \a mp2 to this window handle and returns a reply from the message() function.
269
270  \note Must be called on the same thread that cosnstructed this instance.
271*/
272
273/*!
274  \fn QPMObjectWindow::post(ULONG msg, MPARAM mp1, MPARAM mp2) const
275
276  Asynchronously posts a message \a msg with the given parameters \a mp1 and
277  \a mp2 to this window handle. Returns \c TRUE on success and \c FALSE
278  otherwise.
279
280  \note Can be called on any thread.
281*/
282
283// socket select notification (highest priority)
284#define WM_U_SEM_SELECT     WM_SEM1
285// zero timer notification (lowest priority)
286#define WM_U_SEM_ZEROTIMER  WM_SEM4
287
288class QEventDispatcherPMPrivate : public QAbstractEventDispatcherPrivate
289{
290    Q_DECLARE_PUBLIC(QEventDispatcherPM)
291public:
292    QEventDispatcherPMPrivate();
293    ~QEventDispatcherPMPrivate();
294
295    void createMsgQueue();
296    void createAuxWnd();
297
298    // Auxiliary object window to process WM_U_SEM_SELECT and WM_TIMER messages.
299    // We need a dedicated window along with processing these messages directly in
300    // QEventLoop::processEvents() to make sure they are processed even if the
301    // current message loop is not run by Qt. This happens when a native modal
302    // dialog is shown or when a top-level Qt widget is being moved or resized
303    // using the mouse, or when a Qt-based DLL plugin is used by a non-Qt
304    // application.
305    class AuxWnd : public QPMObjectWindow
306    {
307    public:
308        AuxWnd() : QPMObjectWindow(true /* deferred */), dispatcher(0) {}
309        void setDispatcher(QEventDispatcherPMPrivate *d) { dispatcher = d; }
310        MRESULT message(ULONG msg, MPARAM mp1, MPARAM mp2);
311        QEventDispatcherPMPrivate *dispatcher;
312    } auxWnd;
313
314    HAB hab;
315    HMQ hmq;
316
317    bool interrupt;
318
319// @todo later
320//  DWORD threadId;
321//
322//  bool interrupt;
323//
324//  // internal window handle used for socketnotifiers/timers/etc
325//  HWND internalHwnd;
326//
327//  // timers
328//  WinTimerVec timerVec;
329//  WinTimerDict timerDict;
330//  void registerTimer(WinTimerInfo *t);
331//  void unregisterTimer(WinTimerInfo *t);
332//  void sendTimerEvent(int timerId);
333//
334//  // socket notifiers
335//  QSNDict sn_read;
336//  QSNDict sn_write;
337//  QSNDict sn_except;
338//  void doWsaAsyncSelect(int socket);
339//
340//  QList<QMSG> queuedUserInputEvents;
341//  QList<QMSG> queuedSocketEvents;
342};
343
344QEventDispatcherPMPrivate::QEventDispatcherPMPrivate()
345    : hab(NULLHANDLE), hmq(NULLHANDLE), interrupt(false)
346{
347}
348
349QEventDispatcherPMPrivate::~QEventDispatcherPMPrivate()
350{
351    auxWnd.setDispatcher(0);
352    auxWnd.destroy();
353    if (hmq != NULLHANDLE) {
354        WinDestroyMsgQueue(hmq);
355        WinTerminate(hab);
356    }
357}
358
359void QEventDispatcherPMPrivate::createMsgQueue()
360{
361    if (hmq == NULLHANDLE) {
362        // first, dynamically switch ("morph") to PM mode if we have been
363        // compiled as the console application. This is necessary to create the
364        // event queue, windows and other PM resources. As a side effect, the
365        // console remains attached after morphing which can be useful for
366        // debugging
367        PPIB ppib;
368        DosGetInfoBlocks(NULL, &ppib);
369        if (ppib->pib_ultype != 3)
370            ppib->pib_ultype = 3;
371        // then create the message queue
372        hab = WinInitialize(0);
373        hmq = WinCreateMsgQueue(hab, 0);
374        if (hmq == NULLHANDLE)
375            qWarning("QEventDispatcherPMPrivate::createMsgQueue: "
376                     "WinCreateMsgQueue failed with 0x%08lX",
377                     WinGetLastError(hab));
378    }
379}
380
381void QEventDispatcherPMPrivate::createAuxWnd()
382{
383    if (auxWnd.hwnd() == NULLHANDLE) {
384        createMsgQueue();
385        auxWnd.setDispatcher(this);
386        auxWnd.create();
387    }
388}
389
390MRESULT QEventDispatcherPMPrivate::AuxWnd::message(ULONG msg, MPARAM mp1, MPARAM mp2)
391{
392    QMSG qmsg = { hwnd(), msg, mp1, mp2 };
393
394    QCoreApplication *app = QCoreApplication::instance();
395    MRESULT result;
396    if (app && app->filterEvent(&qmsg, reinterpret_cast<long *>(&result)))
397        return result;
398
399    switch (msg) {
400        case WM_U_SEM_SELECT: {
401// @todo later
402//          if (eventLoop)
403//              eventLoop->activateSocketNotifiers();
404            break;
405        }
406        case WM_U_SEM_ZEROTIMER: {
407// @todo later
408//          if (numZeroTimers) {
409//              activateZeroTimers();
410//              // repost the message if there are still zero timers left
411//              if (numZeroTimers)
412//                  WinPostMsg(hwnd(), WM_U_SEM_ZEROTIMER, 0, 0);
413//          }
414            break;
415        }
416        case WM_TIMER: {
417// @todo later
418//          USHORT id = SHORT1FROMMP(mp1);
419//          dispatchTimer((uint) id, &qmsg);
420            break;
421        }
422    }
423
424    return FALSE;
425}
426
427// @todo remove
428#if 0
429
430LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
431{
432    if (message == WM_NCCREATE) {
433            return true;
434    } else if (message == WM_USER) {
435
436        // socket notifier message
437        MSG msg;
438        msg.hwnd = hwnd;
439        msg.message = message;
440        msg.wParam = wp;
441        msg.lParam = lp;
442
443        QCoreApplication *app = QCoreApplication::instance();
444        long result;
445        if (app && app->filterEvent(&msg, &result))
446            return result;
447
448        int type = -1;
449        switch (WSAGETSELECTEVENT(lp)) {
450        case FD_READ:
451        case FD_CLOSE:
452        case FD_ACCEPT:
453            type = 0;
454            break;
455        case FD_WRITE:
456        case FD_CONNECT:
457            type = 1;
458            break;
459        case FD_OOB:
460            type = 2;
461            break;
462        }
463        if (type >= 0) {
464
465    #ifdef GWLP_USERDATA
466            QEventDispatcherPM *eventDispatcher =
467                (QEventDispatcherPM *) GetWindowLongPtrA(hwnd, GWLP_USERDATA);
468    #else
469            QEventDispatcherPM *eventDispatcher =
470                (QEventDispatcherPM *) GetWindowLongA(hwnd, GWL_USERDATA);
471    #endif
472            if (eventDispatcher) {
473                QEventDispatcherPMPrivate *d = eventDispatcher->d_func();
474                QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
475                QSNDict *dict = sn_vec[type];
476
477                QSockNot *sn = dict ? dict->value(wp) : 0;
478                if (sn) {
479                    QEvent event(QEvent::SockAct);
480                    QCoreApplication::sendEvent(sn->obj, &event);
481                }
482            }
483        }
484        return 0;
485
486    } else if (message == WM_TIMER) {
487
488        MSG msg;
489        msg.hwnd = hwnd;
490        msg.message = message;
491        msg.wParam = wp;
492        msg.lParam = lp;
493
494        QCoreApplication *app = QCoreApplication::instance();
495        Q_ASSERT_X(app, "qt_interal_proc", "Timer fired, but no QCoreApplication");
496        if (!app) {
497            KillTimer(hwnd, wp);
498            return 0;
499        }
500
501        long result;
502        if (app->filterEvent(&msg, &result))
503            return result;
504
505        QEventDispatcherPM *eventDispatcher =
506            qobject_cast<QEventDispatcherPM *>(QAbstractEventDispatcher::instance());
507        Q_ASSERT(eventDispatcher != 0);
508        QEventDispatcherPMPrivate *d = eventDispatcher->d_func();
509        d->sendTimerEvent(wp);
510        return 0;
511    }
512
513    return  DefWindowProc(hwnd, message, wp, lp);
514}
515
516void QEventDispatcherPMPrivate::registerTimer(WinTimerInfo *t)
517{
518    Q_ASSERT(internalHwnd);
519
520    Q_Q(QEventDispatcherPM);
521
522    int ok = 0;
523
524    if (t->interval > 10 || !t->interval || !qtimeSetEvent) {
525        ok = 1;
526        if (!t->interval)  // optimization for single-shot-zero-timer
527            QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId));
528        else
529            ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
530    } else {
531        ok = t->fastTimerId = qtimeSetEvent(t->interval, 1, qt_fast_timer_proc, (DWORD_PTR)t,
532                                            TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
533        if (ok == 0) { // fall back to normal timer if no more multimedia timers avaiable
534            ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0);
535        }
536    }
537
538    if (ok == 0)
539        qErrnoWarning("QEventDispatcherPM::registerTimer: Failed to create a timer");
540}
541
542void QEventDispatcherPMPrivate::unregisterTimer(WinTimerInfo *t)
543{
544    // mark timer as unused
545    if (!QObjectPrivate::get(t->obj)->inThreadChangeEvent)
546        QAbstractEventDispatcherPrivate::releaseTimerId(t->timerId);
547
548    if (t->interval == 0) {
549        QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
550    } else if (t->fastTimerId != 0) {
551        qtimeKillEvent(t->fastTimerId);
552        QCoreApplicationPrivate::removePostedTimerEvent(t->dispatcher, t->timerId);
553    } else if (internalHwnd) {
554        KillTimer(internalHwnd, t->timerId);
555    }
556    delete t;
557}
558
559void QEventDispatcherPMPrivate::sendTimerEvent(int timerId)
560{
561    WinTimerInfo *t = timerDict.value(timerId);
562    if (t && !t->inTimerEvent) {
563        // send event, but don't allow it to recurse
564        t->inTimerEvent = true;
565
566        QTimerEvent e(t->timerId);
567        QCoreApplication::sendEvent(t->obj, &e);
568
569        // timer could have been removed
570        t = timerDict.value(timerId);
571        if (t) {
572            t->inTimerEvent = false;
573        }
574    }
575}
576
577void QEventDispatcherPMPrivate::doWsaAsyncSelect(int socket)
578{
579    Q_ASSERT(internalHwnd);
580    int sn_event = 0;
581    if (sn_read.contains(socket))
582        sn_event |= FD_READ | FD_CLOSE | FD_ACCEPT;
583    if (sn_write.contains(socket))
584        sn_event |= FD_WRITE | FD_CONNECT;
585    if (sn_except.contains(socket))
586        sn_event |= FD_OOB;
587    // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0
588    // This is a BoundsChecker bug and not a Qt bug
589    WSAAsyncSelect(socket, internalHwnd, sn_event ? WM_USER : 0, sn_event);
590}
591
592void QEventDispatcherPM::createInternalHwnd()
593{
594    Q_D(QEventDispatcherPM);
595
596    Q_ASSERT(!d->internalHwnd);
597    if (d->internalHwnd)
598        return;
599    d->internalHwnd = qt_create_internal_window(this);
600
601    // register all socket notifiers
602    QList<int> sockets = (d->sn_read.keys().toSet()
603                          + d->sn_write.keys().toSet()
604                          + d->sn_except.keys().toSet()).toList();
605    for (int i = 0; i < sockets.count(); ++i)
606        d->doWsaAsyncSelect(sockets.at(i));
607
608    // start all normal timers
609    for (int i = 0; i < d->timerVec.count(); ++i)
610        d->registerTimer(d->timerVec.at(i));
611}
612
613#endif
614
615QEventDispatcherPM::QEventDispatcherPM(QObject *parent)
616    : QAbstractEventDispatcher(*new QEventDispatcherPMPrivate, parent)
617{
618}
619
620QEventDispatcherPM::~QEventDispatcherPM()
621{
622}
623
624bool QEventDispatcherPM::processEvents(QEventLoop::ProcessEventsFlags flags)
625{
626    Q_D(QEventDispatcherPM);
627
628// @todo later
629#if 0
630    if (!d->internalHwnd)
631        createInternalHwnd();
632
633    d->interrupt = false;
634    emit awake();
635
636    bool canWait;
637    bool retVal = false;
638    do {
639        QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
640
641        DWORD waitRet = 0;
642        HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
643        QVarLengthArray<MSG> processedTimers;
644        while (!d->interrupt) {
645            MSG msg;
646            bool haveMessage;
647
648            if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
649                // process queued user input events
650                haveMessage = true;
651                msg = d->queuedUserInputEvents.takeFirst();
652            } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
653                // process queued socket events
654                haveMessage = true;
655                msg = d->queuedSocketEvents.takeFirst();
656            } else {
657                haveMessage = winPeekMessage(&msg, 0, 0, 0, PM_REMOVE);
658                if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents)
659                    && ((msg.message >= WM_KEYFIRST
660                         && msg.message <= WM_KEYLAST)
661                        || (msg.message >= WM_MOUSEFIRST
662                            && msg.message <= WM_MOUSELAST)
663                        || msg.message == WM_MOUSEWHEEL)) {
664                    // queue user input events for later processing
665                    haveMessage = false;
666                    d->queuedUserInputEvents.append(msg);
667                }
668                if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)
669                    && (msg.message == WM_USER && msg.hwnd == d->internalHwnd)) {
670                    // queue socket events for later processing
671                    haveMessage = false;
672                    d->queuedSocketEvents.append(msg);
673                }
674            }
675            if (haveMessage) {
676                if (msg.message == WM_TIMER) {
677                    // avoid live-lock by keeping track of the timers we've already sent
678                    bool found = false;
679                    for (int i = 0; !found && i < processedTimers.count(); ++i) {
680                        const MSG processed = processedTimers.constData()[i];
681                        found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
682                    }
683                    if (found)
684                        continue;
685                    processedTimers.append(msg);
686                } else if (msg.message == WM_QUIT) {
687                    if (QCoreApplication::instance())
688                        QCoreApplication::instance()->quit();
689                    return false;
690                }
691
692                if (!filterEvent(&msg)) {
693                    TranslateMessage(&msg);
694                    QT_WA({
695                        DispatchMessage(&msg);
696                    } , {
697                        DispatchMessageA(&msg);
698                    });
699                }
700            } else {
701                // nothing todo so break
702                break;
703            }
704            retVal = true;
705        }
706
707        // still nothing - wait for message or signalled objects
708        QThreadData *data = d->threadData;
709        canWait = (!retVal
710                   && data->canWait
711                   && !d->interrupt
712                   && (flags & QEventLoop::WaitForMoreEvents));
713        if (canWait) {
714            emit aboutToBlock();
715            waitRet = WinGetMsg(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
716            emit awake();
717        }
718    } while (canWait);
719
720    return retVal;
721#else
722    return false;
723#endif
724}
725
726bool QEventDispatcherPM::hasPendingEvents()
727{
728    QMSG msg;
729    return qGlobalPostedEventsCount() || WinPeekMsg(0, &msg, NULL, 0, 0, PM_NOREMOVE);
730}
731
732void QEventDispatcherPM::registerSocketNotifier(QSocketNotifier *notifier)
733{
734// @todo later
735#if 0
736    Q_ASSERT(notifier);
737    int sockfd = notifier->socket();
738    int type = notifier->type();
739#ifndef QT_NO_DEBUG
740    if (sockfd < 0) {
741        qWarning("QSocketNotifier: Internal error");
742        return;
743    } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
744        qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
745        return;
746    }
747#endif
748
749    Q_D(QEventDispatcherPM);
750    QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
751    QSNDict *dict = sn_vec[type];
752
753    if (QCoreApplication::closingDown()) // ### d->exitloop?
754        return; // after sn_cleanup, don't reinitialize.
755
756    if (dict->contains(sockfd)) {
757        const char *t[] = { "Read", "Write", "Exception" };
758    /* Variable "socket" below is a function pointer. */
759        qWarning("QSocketNotifier: Multiple socket notifiers for "
760                 "same socket %d and type %s", sockfd, t[type]);
761    }
762
763    QSockNot *sn = new QSockNot;
764    sn->obj = notifier;
765    sn->fd  = sockfd;
766    dict->insert(sn->fd, sn);
767
768    if (d->internalHwnd)
769        d->doWsaAsyncSelect(sockfd);
770#endif
771}
772
773void QEventDispatcherPM::unregisterSocketNotifier(QSocketNotifier *notifier)
774{
775// @todo later
776#if 0
777    Q_ASSERT(notifier);
778    int sockfd = notifier->socket();
779    int type = notifier->type();
780#ifndef QT_NO_DEBUG
781    if (sockfd < 0) {
782        qWarning("QSocketNotifier: Internal error");
783        return;
784    } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
785        qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
786        return;
787    }
788#endif
789
790    Q_D(QEventDispatcherPM);
791    QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };
792    QSNDict *dict = sn_vec[type];
793    QSockNot *sn = dict->value(sockfd);
794    if (!sn)
795        return;
796
797    dict->remove(sockfd);
798    delete sn;
799
800    if (d->internalHwnd)
801        d->doWsaAsyncSelect(sockfd);
802#endif
803}
804
805void QEventDispatcherPM::registerTimer(int timerId, int interval, QObject *object)
806{
807// @todo later
808#if 0
809    if (timerId < 1 || interval < 0 || !object) {
810        qWarning("QEventDispatcherPM::registerTimer: invalid arguments");
811        return;
812    } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
813        qWarning("QObject::startTimer: timers cannot be started from another thread");
814        return;
815    }
816
817    Q_D(QEventDispatcherPM);
818
819    register WinTimerInfo *t = new WinTimerInfo;
820    t->dispatcher = this;
821    t->timerId  = timerId;
822    t->interval = interval;
823    t->obj  = object;
824    t->inTimerEvent = false;
825    t->fastTimerId = 0;
826
827    if (d->internalHwnd)
828        d->registerTimer(t);
829
830    d->timerVec.append(t);                      // store in timer vector
831    d->timerDict.insert(t->timerId, t);          // store timers in dict
832#endif
833}
834
835bool QEventDispatcherPM::unregisterTimer(int timerId)
836{
837// @todo later
838#if 0
839    if (timerId < 1) {
840        qWarning("QEventDispatcherPM::unregisterTimer: invalid argument");
841        return false;
842    }
843    QThread *currentThread = QThread::currentThread();
844    if (thread() != currentThread) {
845        qWarning("QObject::killTimer: timers cannot be stopped from another thread");
846        return false;
847    }
848
849    Q_D(QEventDispatcherPM);
850    if (d->timerVec.isEmpty() || timerId <= 0)
851        return false;
852
853    WinTimerInfo *t = d->timerDict.value(timerId);
854    if (!t)
855        return false;
856
857    d->timerDict.remove(t->timerId);
858    d->timerVec.removeAll(t);
859    d->unregisterTimer(t);
860    return true;
861#else
862    return false;
863#endif
864}
865
866bool QEventDispatcherPM::unregisterTimers(QObject *object)
867{
868// @todo later
869#if 0
870    if (!object) {
871        qWarning("QEventDispatcherPM::unregisterTimers: invalid argument");
872        return false;
873    }
874    QThread *currentThread = QThread::currentThread();
875    if (object->thread() != thread() || thread() != currentThread) {
876        qWarning("QObject::killTimers: timers cannot be stopped from another thread");
877        return false;
878    }
879
880    Q_D(QEventDispatcherPM);
881    if (d->timerVec.isEmpty())
882        return false;
883    register WinTimerInfo *t;
884    for (int i=0; i<d->timerVec.size(); i++) {
885        t = d->timerVec.at(i);
886        if (t && t->obj == object) {                // object found
887            d->timerDict.remove(t->timerId);
888            d->timerVec.removeAt(i);
889            d->unregisterTimer(t);
890            --i;
891        }
892    }
893    return true;
894#else
895    return false;
896#endif
897}
898
899QList<QEventDispatcherPM::TimerInfo>
900QEventDispatcherPM::registeredTimers(QObject *object) const
901{
902// @todo later
903#if 0
904    if (!object) {
905        qWarning("QEventDispatcherPM:registeredTimers: invalid argument");
906        return QList<TimerInfo>();
907    }
908
909    Q_D(const QEventDispatcherPM);
910    QList<TimerInfo> list;
911    for (int i = 0; i < d->timerVec.size(); ++i) {
912        const WinTimerInfo *t = d->timerVec.at(i);
913        if (t && t->obj == object)
914            list << TimerInfo(t->timerId, t->interval);
915    }
916    return list;
917#else
918    return QList<TimerInfo>();
919#endif
920}
921
922void QEventDispatcherPM::wakeUp()
923{
924    Q_D(QEventDispatcherPM);
925    PTIB ptib;
926    DosGetInfoBlocks(&ptib, NULL);
927    MQINFO mqinfo;
928    WinQueryQueueInfo(d->hmq, &mqinfo, sizeof(MQINFO));
929    if (ptib->tib_ptib2->tib2_ultid != mqinfo.tid)
930        WinPostQueueMsg(d->hmq, WM_NULL, 0, 0);
931}
932
933void QEventDispatcherPM::interrupt()
934{
935    Q_D(QEventDispatcherPM);
936    d->interrupt = true;
937    wakeUp();
938}
939
940void QEventDispatcherPM::flush()
941{
942}
943
944void QEventDispatcherPM::startingUp()
945{
946}
947
948void QEventDispatcherPM::closingDown()
949{
950    Q_D(QEventDispatcherPM);
951
952// @todo remove later
953#if 0
954    // clean up any socketnotifiers
955    while (!d->sn_read.isEmpty())
956        unregisterSocketNotifier((*(d->sn_read.begin()))->obj);
957    while (!d->sn_write.isEmpty())
958        unregisterSocketNotifier((*(d->sn_write.begin()))->obj);
959    while (!d->sn_except.isEmpty())
960        unregisterSocketNotifier((*(d->sn_except.begin()))->obj);
961
962    // clean up any timers
963    while (!d->timerDict.isEmpty())
964        unregisterTimer((*(d->timerDict.begin()))->timerId);
965#endif
966}
967
968// @todo remove later
969#if 0
970bool QEventDispatcherPM::event(QEvent *e)
971{
972    Q_D(QEventDispatcherPM);
973    if (e->type() == QEvent::ZeroTimerEvent) {
974        QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e);
975        WinTimerInfo *t = d->timerDict.value(zte->timerId());
976        if (t) {
977            t->inTimerEvent = true;
978
979            QTimerEvent te(zte->timerId());
980            QCoreApplication::sendEvent(t->obj, &te);
981
982            t = d->timerDict.value(zte->timerId());
983            if (t) {
984                if (t->interval == 0 && t->inTimerEvent) {
985                    // post the next zero timer event as long as the timer was not restarted
986                    QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId()));
987                }
988
989                t->inTimerEvent = false;
990            }
991        }
992        return true;
993    } else if (e->type() == QEvent::Timer) {
994        QTimerEvent *te = static_cast<QTimerEvent*>(e);
995        d->sendTimerEvent(te->timerId());
996    }
997    return QAbstractEventDispatcher::event(e);
998}
999#endif
1000
1001QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.