source: trunk/src/kernel/qeventloop_pm.cpp@ 10

Last change on this file since 10 was 8, checked in by dmik, 20 years ago

Transferred Qt for OS/2 version 3.3.1-rc5 sources from the CVS

  • Property svn:keywords set to Id
File size: 25.7 KB
Line 
1/****************************************************************************
2** $Id: qeventloop_pm.cpp 8 2005-11-16 19:36:46Z dmik $
3**
4** Implementation of OS/2 startup routines and event handling
5**
6** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qeventloop_p.h"
39#include "qeventloop.h"
40#include "qapplication.h"
41
42#include <sys/socket.h>
43
44#if defined(QT_THREAD_SUPPORT)
45# include "qmutex.h"
46# include "qthread.h"
47# include "qsemaphore.h"
48#endif // QT_THREAD_SUPPORT
49
50extern uint qGlobalPostedEventsCount();
51extern bool qt_pmEventFilter( QMSG* msg, MRESULT &result );
52
53static HAB qt_gui_hab = 0;
54static HMQ qt_gui_queue = 0;
55//@@TODO (dmik): later
56//// Simpler timers are needed when Qt does not have the event loop,
57//// such as for plugins.
58//#ifndef Q_OS_TEMP
59//Q_EXPORT bool qt_win_use_simple_timers = TRUE;
60//#else
61//Q_EXPORT bool qt_win_use_simple_timers = FALSE;
62//#endif
63//void CALLBACK qt_simple_timer_func( HWND, UINT, UINT, DWORD );
64
65static void initTimers();
66static void cleanupTimers();
67static bool dispatchTimer( uint, QMSG * );
68static bool activateTimer( uint );
69static void activateZeroTimers();
70
71static int numZeroTimers = 0; // number of full-speed timers
72
73// a flag to disable the warning when the console process dynamically
74// switches istelf to PM. Currently used by the UIC tool.
75bool qt_suppress_morph_warning = false;
76
77// Check that the current process is in PM mode. This is called by QEventLoop
78// and QApplication initialization routines and by initTimers() to ensure
79// that we are in PM mode and therefore it is possible to create the message
80// queue. "Morphing" to PM leaves the console attahed which can be used for
81// debugging.
82void qt_ensure_pm()
83{
84 PPIB ppib;
85 DosGetInfoBlocks( NULL, &ppib );
86 if( ppib->pib_ultype != 3 ) {
87#if defined(QT_CHECK_STATE)
88 if( !qt_suppress_morph_warning )
89 qWarning(
90 "Qt: the program has not been linked as the Presentation Manager application\n"
91 " but it uses GUI capabilities. Switching to PM mode dynamically."
92 );
93#endif
94 ppib->pib_ultype = 3;
95 }
96}
97
98/*****************************************************************************
99 Safe configuration (move,resize,setGeometry) mechanism to avoid
100 recursion when processing messages.
101 *****************************************************************************/
102
103#include "qptrqueue.h"
104
105struct QPMConfigRequest {
106 WId id; // widget to be configured
107 int req; // 0=move, 1=resize, 2=setGeo
108 int x, y, w, h; // request parameters
109};
110
111static QPtrQueue<QPMConfigRequest> *configRequests = 0;
112
113void qPMRequestConfig( WId id, int req, int x, int y, int w, int h )
114{
115 if ( !configRequests ) // create queue
116 configRequests = new QPtrQueue<QPMConfigRequest>;
117 QPMConfigRequest *r = new QPMConfigRequest;
118 r->id = id; // create new request
119 r->req = req;
120 r->x = x;
121 r->y = y;
122 r->w = w;
123 r->h = h;
124 configRequests->enqueue( r ); // store request in queue
125}
126
127Q_EXPORT void qPMProcessConfigRequests() // perform requests in queue
128{
129 if ( !configRequests )
130 return;
131 QPMConfigRequest *r;
132 for ( ;; ) {
133 if ( configRequests->isEmpty() )
134 break;
135 r = configRequests->dequeue();
136 QWidget *w = QWidget::find( r->id );
137 if ( w ) { // widget exists
138 if ( w->testWState(Qt::WState_ConfigPending) )
139 return; // biting our tail
140 if ( r->req == 0 )
141 w->move( r->x, r->y );
142 else if ( r->req == 1 )
143 w->resize( r->w, r->h );
144 else
145 w->setGeometry( r->x, r->y, r->w, r->h );
146 }
147 delete r;
148 }
149 delete configRequests;
150 configRequests = 0;
151}
152
153/*****************************************************************************
154 Timer handling; Our routines depend on OS/2 PM timer functions, but we
155 need some extra handling to activate objects at timeout.
156
157 Implementation note: There are two types of timer identifiers. PM
158 timer ids (internal use) are stored in TimerInfo. Qt timer ids are
159 indexes (+1) into the timerVec vector.
160
161 NOTE: These functions are for internal use. QObject::startTimer() and
162 QObject::killTimer() are for public use.
163 The QTimer class provides a high-level interface which translates
164 timer events into signals.
165
166 qStartTimer( interval, obj )
167 Starts a timer which will run until it is killed with qKillTimer()
168 Arguments:
169 int interval timer interval in milliseconds
170 QObject *obj where to send the timer event
171 Returns:
172 int timer identifier, or zero if not successful
173
174 qKillTimer( timerId )
175 Stops a timer specified by a timer identifier.
176 Arguments:
177 int timerId timer identifier
178 Returns:
179 bool TRUE if successful
180
181 qKillTimer( obj )
182 Stops all timers that are sent to the specified object.
183 Arguments:
184 QObject *obj object receiving timer events
185 Returns:
186 bool TRUE if successful
187 *****************************************************************************/
188
189//
190// Internal data structure for timers
191//
192
193#include "qptrvector.h"
194#include "qintdict.h"
195
196struct TimerInfo { // internal timer info
197 uint ind; // - Qt timer identifier - 1
198 ULONG id; // - PM timer identifier
199 bool zero; // - zero timing
200 QObject *obj; // - object to receive events
201};
202typedef QPtrVector<TimerInfo> TimerVec; // vector of TimerInfo structs
203typedef QIntDict<TimerInfo> TimerDict; // fast dict of timers
204
205static TimerVec *timerVec = 0; // timer vector
206static TimerDict *timerDict = 0; // timer dict
207
208
209//@@TODO (dmik): later (needed for plugin support)
210//void CALLBACK qt_simple_timer_func( HWND, UINT, UINT idEvent, DWORD )
211//{
212// dispatchTimer( idEvent, 0 );
213//}
214
215
216// Activate a timer, used by both event-loop based and simple timers.
217
218static bool dispatchTimer( uint timerId, QMSG *msg )
219{
220 MRESULT res = NULL;
221 if ( !msg || !qApp || !qt_pmEventFilter(msg,res) )
222 return activateTimer( timerId );
223 return TRUE;
224}
225
226
227//
228// Timer activation (called from the event loop when WM_TIMER arrives)
229//
230
231static bool activateTimer( uint id ) // activate timer
232{
233 if ( !timerVec ) // should never happen
234 return FALSE;
235 register TimerInfo *t = timerDict->find( id );
236 if ( !t ) // no such timer id
237 return FALSE;
238 QTimerEvent e( t->ind + 1 );
239 QApplication::sendEvent( t->obj, &e ); // send event
240 return TRUE; // timer event was processed
241}
242
243static void activateZeroTimers() // activate full-speed timers
244{
245 if ( !timerVec )
246 return;
247 uint i=0;
248 register TimerInfo *t = 0;
249 int n = numZeroTimers;
250 while ( n-- ) {
251 for ( ;; ) {
252 t = timerVec->at(i++);
253 if ( t && t->zero )
254 break;
255 else if ( i == timerVec->size() ) // should not happen
256 return;
257 }
258 QTimerEvent e( t->ind + 1 );
259 QApplication::sendEvent( t->obj, &e );
260 }
261}
262
263
264//
265// Timer initialization and cleanup routines
266//
267
268static void initTimers() // initialize timers
269{
270//@@TODO (dmik): qt_ensure_pm() should not be called when simple timers are
271// implemented to be used by plugins.
272 qt_ensure_pm();
273 timerVec = new TimerVec( 128 );
274 Q_CHECK_PTR( timerVec );
275 timerVec->setAutoDelete( TRUE );
276 timerDict = new TimerDict( 29 );
277 Q_CHECK_PTR( timerDict );
278}
279
280static void cleanupTimers() // remove pending timers
281{
282 register TimerInfo *t;
283 if ( !timerVec ) // no timers were used
284 return;
285 for ( uint i=0; i<timerVec->size(); i++ ) { // kill all pending timers
286 t = timerVec->at( i );
287 if ( t && !t->zero )
288 WinStopTimer( 0, 0, t->id );
289 }
290 delete timerDict;
291 timerDict = 0;
292 delete timerVec;
293 timerVec = 0;
294
295//@@TODO (dmik): later (needed for plugin support)
296// if ( qt_win_use_simple_timers ) {
297// // Dangerous to leave WM_TIMER events in the queue if they have our
298// // timerproc (eg. Qt-based DLL plugins may be unloaded)
299// MSG msg;
300// while (winPeekMessage( &msg, (HWND)-1, WM_TIMER, WM_TIMER, PM_REMOVE ))
301// continue;
302// }
303}
304
305
306//
307// Main timer functions for starting and killing timers
308//
309
310
311int qStartTimer( int interval, QObject *obj )
312{
313 register TimerInfo *t;
314 if ( !timerVec ) // initialize timer data
315 initTimers();
316 int ind = timerVec->findRef( 0 ); // get free timer
317 if ( ind == -1 || !obj ) {
318 ind = timerVec->size(); // increase the size
319 timerVec->resize( ind * 4 );
320 }
321 t = new TimerInfo; // create timer entry
322 Q_CHECK_PTR( t );
323 t->ind = ind;
324 t->obj = obj;
325
326//@@TODO (dmik): later (needed for plugin support)
327// if ( qt_win_use_simple_timers ) {
328// t->zero = FALSE;
329// t->id = SetTimer( 0, 0, (uint)interval,
330// (TIMERPROC)qt_simple_timer_func );
331// } else {
332 t->zero = interval == 0;
333 if ( t->zero ) { // add zero timer
334 t->id = 0;
335 numZeroTimers++;
336 // post WM_NULL to our message queue to let
337 // QEventLoop::processEvents() handle a newly created zero
338 // timer as soon as possible; otherwise we could get quite a
339 // noticeable delay between starting and emitting the first
340 // signal (longer than if we had started a regular 1 ms timer),
341 // due to the internal implementation of the WinGetMsg() function.
342 WinPostMsg( 0, WM_NULL, 0, 0 );
343 } else {
344 t->id = WinStartTimer( 0, 0, 0, (ULONG) interval );
345 }
346// }
347 if ( !t->zero && t->id == 0 ) {
348#if defined(QT_CHECK_STATE)
349 qSystemWarning( "qStartTimer: Failed to create a timer." );
350#endif
351 delete t; // could not set timer
352 return 0;
353 }
354 timerVec->insert( ind, t ); // store in timer vector
355 if ( !t->zero )
356 timerDict->insert( t->id, t ); // store in dict
357 return ind + 1; // return index in vector
358}
359
360bool qKillTimer( int ind )
361{
362 if ( !timerVec || ind <= 0 || (uint)ind > timerVec->size() )
363 return FALSE;
364 register TimerInfo *t = timerVec->at(ind-1);
365 if ( !t )
366 return FALSE;
367 if ( t->zero ) {
368 numZeroTimers--;
369 } else {
370 WinStopTimer( 0, 0, t->id );
371 timerDict->remove( t->id );
372 }
373 timerVec->remove( ind-1 );
374 return TRUE;
375}
376
377bool qKillTimer( QObject *obj )
378{
379 if ( !timerVec )
380 return FALSE;
381 register TimerInfo *t;
382 for ( uint i=0; i<timerVec->size(); i++ ) {
383 t = timerVec->at( i );
384 if ( t && t->obj == obj ) { // object found
385 if ( t->zero ) {
386 numZeroTimers--;
387 } else {
388 WinStopTimer( 0, 0, t->id );
389 timerDict->remove( t->id );
390 }
391 timerVec->remove( i );
392 }
393 }
394 return TRUE;
395}
396
397/*****************************************************************************
398 Socket notifier type
399 *****************************************************************************/
400
401QSockNotType::QSockNotType()
402 : list( 0 )
403{
404 FD_ZERO( &select_fds );
405 FD_ZERO( &enabled_fds );
406 FD_ZERO( &pending_fds );
407}
408
409QSockNotType::~QSockNotType()
410{
411 if ( list )
412 delete list;
413 list = 0;
414}
415
416/*****************************************************************************
417 socket select() thread
418 *****************************************************************************/
419
420#if defined(QT_THREAD_SUPPORT)
421
422static class QSockSelectThread : public QThread
423{
424public:
425 QSockSelectThread( QEventLoopPrivate *_d ) : d( _d ), exit( FALSE ) {};
426 void run();
427 void cancelSelectOrIdle( bool terminate = FALSE );
428private:
429 QEventLoopPrivate *d;
430 bool exit;
431} *ss_thread = 0;
432
433// recursive mutex to serialize access to socket notifier data
434static QMutex ss_mutex( TRUE );
435// flag to indicate a presence of sockets to do select() (we use QSemaphore
436// instead of QWaitCondition because we need the "level-triggered" semantics,
437// the "edge-triggered" one can produce deadlocks)
438static QSemaphore ss_flag( 1 );
439
440void QSockSelectThread::run()
441{
442 while ( !exit ) {
443 ss_mutex.lock();
444 if ( d->sn_highest >= 0 ) { // has socket notifier(s)
445 // read
446 if ( d->sn_vec[0].list && ! d->sn_vec[0].list->isEmpty() )
447 d->sn_vec[0].select_fds = d->sn_vec[0].enabled_fds;
448 else
449 FD_ZERO( &d->sn_vec[0].select_fds );
450 // write
451 if ( d->sn_vec[1].list && ! d->sn_vec[1].list->isEmpty() )
452 d->sn_vec[1].select_fds = d->sn_vec[1].enabled_fds;
453 else
454 FD_ZERO( &d->sn_vec[1].select_fds );
455 // except
456 if ( d->sn_vec[2].list && ! d->sn_vec[2].list->isEmpty() )
457 d->sn_vec[2].select_fds = d->sn_vec[2].enabled_fds;
458 else
459 FD_ZERO( &d->sn_vec[2].select_fds );
460 // do select
461 int nfds = d->sn_highest + 1;
462 ss_mutex.unlock();
463 int nsel = ::select( nfds,
464 &d->sn_vec[0].select_fds,
465 &d->sn_vec[1].select_fds,
466 &d->sn_vec[2].select_fds,
467 NULL );
468 if ( nsel > 0 ) {
469 ss_mutex.lock();
470 // if select says data is ready on any socket, then set
471 // the socket notifier to pending
472 int i;
473 for ( i=0; i<3; i++ ) {
474 if ( ! d->sn_vec[i].list )
475 continue;
476 QPtrList<QSockNot> *list = d->sn_vec[i].list;
477 QSockNot *sn = list->first();
478 while ( sn ) {
479 if ( FD_ISSET( sn->fd, &d->sn_vec[i].select_fds ) ) {
480 // see comments inside QEventLoop::setSocketNotifierPending()
481 if ( !FD_ISSET( sn->fd, sn->queue ) ) {
482 d->sn_pending_list.insert(
483 (rand() & 0xff) % (d->sn_pending_list.count()+1),
484 sn
485 );
486 FD_SET( sn->fd, sn->queue );
487 }
488 }
489 sn = list->next();
490 }
491 }
492 ss_mutex.unlock();
493 // wake up gui thread to let it activate notifiers
494 WinPostQueueMsg( qt_gui_queue, WM_NULL, 0, 0 );
495 }
496 } else {
497 // no sockets to select(), go to the idle state
498 ss_mutex.unlock();
499 // wait for the ability to capture the flag
500 ss_flag ++;
501 // release the flag before termination
502 if ( exit )
503 ss_flag --;
504 }
505 }
506}
507
508void QSockSelectThread::cancelSelectOrIdle( bool terminate )
509{
510 exit = terminate;
511 if ( d->sn_highest >= 0 ) {
512 // terminate select() execution
513 ::so_cancel( d->sn_highest );
514 } else {
515 // terminate the idle state by releasing the flag
516 if ( !ss_flag.available() )
517 ss_flag --;
518 }
519 // wait for this thread to end if the termination is requested
520 if ( exit )
521 wait();
522}
523
524static void ss_cleanup()
525{
526 ss_thread->cancelSelectOrIdle( TRUE );
527 delete ss_thread;
528}
529
530static void ss_init( QEventLoopPrivate *d )
531{
532 if ( ss_thread ) {
533 // the user has created a second QEventLoop instance, it should
534 // completely replace the previous (see also QEventLoop::QEventLoop()).
535 ss_cleanup();
536 } else {
537 qAddPostRoutine( ss_cleanup );
538 }
539 // capture the flag initially
540 ss_flag ++;
541 ss_thread = new QSockSelectThread( d );
542 ss_thread->start();
543}
544
545#endif // QT_THREAD_SUPPORT
546
547/*****************************************************************************
548 QEventLoop Implementation for OS/2 PM
549 *****************************************************************************/
550
551void QEventLoop::init()
552{
553 d->sn_highest = -1;
554
555 qt_ensure_pm();
556 d->hab = WinInitialize( 0 );
557 d->hmq = WinCreateMsgQueue( d->hab, 0 );
558 qt_gui_hab = d->hab;
559 qt_gui_queue = d->hmq;
560
561#if defined(QT_THREAD_SUPPORT)
562 ss_init( d );
563#else
564#if defined(QT_CHECK_STATE)
565 qWarning(
566 "QEventLoop::init: socket notifiers are not supported "
567 "for a single-threaded version of Qt."
568 );
569#endif
570#endif // QT_THREAD_SUPPORT
571}
572
573void QEventLoop::cleanup()
574{
575 cleanupTimers();
576
577 WinDestroyMsgQueue( d->hmq );
578 WinTerminate( d->hab );
579 qt_gui_queue = 0;
580 qt_gui_hab = 0;
581}
582
583void QEventLoop::registerSocketNotifier( QSocketNotifier *notifier )
584{
585#if defined(QT_THREAD_SUPPORT)
586 int sockfd = -1;
587 int type = -1;
588 if ( notifier ) {
589 sockfd = notifier->socket();
590 type = notifier->type();
591 }
592 if ( sockfd < 0 || sockfd >= FD_SETSIZE || type < 0 || type > 2 ) {
593#if defined(QT_CHECK_RANGE)
594 qWarning( "QSocketNotifier: Internal error" );
595#endif
596 return;
597 }
598
599 QMutexLocker locker( &ss_mutex );
600 ss_thread->cancelSelectOrIdle();
601
602 QPtrList<QSockNot> *list = d->sn_vec[type].list;
603 fd_set *fds = &d->sn_vec[type].enabled_fds;
604 QSockNot *sn;
605
606 if ( ! list ) {
607 // create new list, the QSockNotType destructor will delete it for us
608 list = new QPtrList<QSockNot>;
609 Q_CHECK_PTR( list );
610 list->setAutoDelete( TRUE );
611 d->sn_vec[type].list = list;
612 }
613
614 sn = new QSockNot;
615 Q_CHECK_PTR( sn );
616 sn->obj = notifier;
617 sn->fd = sockfd;
618 sn->queue = &d->sn_vec[type].pending_fds;
619
620 if ( list->isEmpty() ) {
621 list->insert( 0, sn );
622 } else { // sort list by fd, decreasing
623 QSockNot *p = list->first();
624 while ( p && p->fd > sockfd )
625 p = list->next();
626#if defined(QT_CHECK_STATE)
627 if ( p && p->fd == sockfd ) {
628 static const char *t[] = { "read", "write", "exception" };
629 qWarning( "QSocketNotifier: Multiple socket notifiers for "
630 "same socket %d and type %s", sockfd, t[type] );
631 }
632#endif
633 if ( p )
634 list->insert( list->at(), sn );
635 else
636 list->append( sn );
637 }
638
639 FD_SET( sockfd, fds );
640 d->sn_highest = QMAX( d->sn_highest, sockfd );
641#endif // QT_THREAD_SUPPORT
642}
643
644void QEventLoop::unregisterSocketNotifier( QSocketNotifier *notifier )
645{
646#if defined(QT_THREAD_SUPPORT)
647 int sockfd = -1;
648 int type = -1;
649 if ( notifier ) {
650 sockfd = notifier->socket();
651 type = notifier->type();
652 }
653 if ( sockfd < 0 || type < 0 || type > 2 ) {
654#if defined(QT_CHECK_RANGE)
655 qWarning( "QSocketNotifier: Internal error" );
656#endif
657 return;
658 }
659
660 QMutexLocker locker( &ss_mutex );
661 ss_thread->cancelSelectOrIdle();
662
663 QPtrList<QSockNot> *list = d->sn_vec[type].list;
664 fd_set *fds = &d->sn_vec[type].enabled_fds;
665 QSockNot *sn;
666 if ( ! list )
667 return;
668 sn = list->first();
669 while ( sn && !(sn->obj == notifier && sn->fd == sockfd) )
670 sn = list->next();
671 if ( !sn ) // not found
672 return;
673
674 FD_CLR( sockfd, fds ); // clear fd bit
675 FD_CLR( sockfd, sn->queue );
676 d->sn_pending_list.removeRef( sn ); // remove from activation list
677 list->remove(); // remove notifier found above
678
679 if ( d->sn_highest == sockfd ) { // find highest fd
680 d->sn_highest = -1;
681 for ( int i=0; i<3; i++ ) {
682 if ( d->sn_vec[i].list && ! d->sn_vec[i].list->isEmpty() )
683 d->sn_highest = QMAX( d->sn_highest, // list is fd-sorted
684 d->sn_vec[i].list->getFirst()->fd );
685 }
686 }
687#endif // QT_THREAD_SUPPORT
688}
689
690void QEventLoop::setSocketNotifierPending( QSocketNotifier *notifier )
691{
692#if defined(QT_THREAD_SUPPORT)
693 int sockfd = -1;
694 int type = -1;
695 if ( notifier ) {
696 sockfd = notifier->socket();
697 type = notifier->type();
698 }
699 if ( sockfd < 0 || type < 0 || type > 2 ) {
700#if defined(QT_CHECK_RANGE)
701 qWarning( "QSocketNotifier: Internal error" );
702#endif
703 return;
704 }
705
706 QMutexLocker locker( &ss_mutex );
707
708 QPtrList<QSockNot> *list = d->sn_vec[type].list;
709 QSockNot *sn;
710 if ( ! list )
711 return;
712 sn = list->first();
713 while ( sn && !(sn->obj == notifier && sn->fd == sockfd) )
714 sn = list->next();
715 if ( ! sn ) { // not found
716 return;
717 }
718
719 // We choose a random activation order to be more fair under high load.
720 // If a constant order is used and a peer early in the list can
721 // saturate the IO, it might grab our attention completely.
722 // Also, if we're using a straight list, the callback routines may
723 // delete other entries from the list before those other entries are
724 // processed.
725 if ( !FD_ISSET( sn->fd, sn->queue ) ) {
726 d->sn_pending_list.insert(
727 (rand() & 0xff) % (d->sn_pending_list.count()+1),
728 sn
729 );
730 FD_SET( sn->fd, sn->queue );
731 }
732#endif // QT_THREAD_SUPPORT
733}
734
735bool QEventLoop::hasPendingEvents() const
736{
737 QMSG msg;
738 return qGlobalPostedEventsCount() || WinPeekMsg( 0, &msg, NULL, 0, 0, PM_NOREMOVE );
739}
740
741bool QEventLoop::processEvents( ProcessEventsFlags flags )
742{
743 QMSG msg;
744
745#if defined(QT_THREAD_SUPPORT)
746 QMutexLocker locker( QApplication::qt_mutex );
747#endif
748 emit awake();
749 emit qApp->guiThreadAwake();
750
751 QApplication::sendPostedEvents();
752
753 if ( flags & ExcludeUserInput ) {
754 while ( WinPeekMsg( 0, &msg, 0, 0, 0, PM_NOREMOVE ) ) {
755 if ( msg.msg == WM_CHAR ||
756 (msg.msg >= WM_MOUSEFIRST &&
757 msg.msg <= WM_MOUSELAST) ||
758 (msg.msg >= WM_EXTMOUSEFIRST &&
759 msg.msg <= WM_EXTMOUSELAST) ||
760 msg.msg == WM_HSCROLL ||
761 msg.msg == WM_VSCROLL
762 ) {
763 WinPeekMsg( 0, &msg, 0, 0, 0, PM_REMOVE );
764 continue;
765 }
766 break;
767 }
768 }
769
770 bool canWait = d->exitloop || d->quitnow ? FALSE : (flags & WaitForMore);
771
772 if ( canWait ) { // can wait if necessary
773 if ( numZeroTimers ) { // activate full-speed timers
774 int ok = FALSE;
775 while ( numZeroTimers && !ok ) {
776 activateZeroTimers();
777 ok = WinPeekMsg( 0, &msg, 0, 0, 0, PM_REMOVE );
778 }
779 if ( !ok ) { // no event
780 return FALSE;
781 }
782 } else {
783 if ( !WinPeekMsg( 0, &msg, 0, 0, 0, PM_NOREMOVE ) )
784 emit aboutToBlock();
785#ifdef QT_THREAD_SUPPORT
786 locker.mutex()->unlock();
787#endif // QT_THREAD_SUPPORT
788 if ( !WinGetMsg( 0, &msg, 0, 0, 0 ) ) {
789#ifdef QT_THREAD_SUPPORT
790 locker.mutex()->lock();
791#endif // QT_THREAD_SUPPORT
792 exit( 0 ); // WM_QUIT received
793 return FALSE;
794 }
795#ifdef QT_THREAD_SUPPORT
796 locker.mutex()->lock();
797#endif // QT_THREAD_SUPPORT
798 }
799 } else { // no-wait mode
800 if ( !WinPeekMsg( 0, &msg, 0, 0, 0, PM_REMOVE ) ) { // no pending events
801 if ( numZeroTimers > 0 ) { // there are 0-timers
802 activateZeroTimers();
803 }
804 return FALSE;
805 }
806 }
807
808 bool handled = FALSE;
809 if ( msg.msg == WM_TIMER ) { // timer message received
810 if ( dispatchTimer( (uint)SHORT1FROMMP(msg.mp1), &msg ) )
811 return TRUE;
812 } else if ( msg.msg && (!msg.hwnd || !QWidget::find(msg.hwnd)) ) {
813 MRESULT res = 0;
814 handled = qt_pmEventFilter( &msg, res );
815 }
816
817 if ( !handled ) {
818 WinDispatchMsg( 0, &msg ); // send to QtWndProc
819 }
820
821 if ( !(flags & ExcludeSocketNotifiers) )
822 activateSocketNotifiers();
823
824 if ( configRequests ) // any pending configs?
825 qPMProcessConfigRequests();
826 QApplication::sendPostedEvents();
827
828 return TRUE;
829}
830
831void QEventLoop::wakeUp()
832{
833 PTIB ptib;
834 DosGetInfoBlocks( &ptib, NULL );
835 MQINFO mqinfo;
836 WinQueryQueueInfo( qt_gui_queue, &mqinfo, sizeof(MQINFO) );
837 if ( ptib->tib_ptib2->tib2_ultid != mqinfo.tid )
838 WinPostQueueMsg( qt_gui_queue, WM_NULL, 0, 0 );
839}
840
841int QEventLoop::timeToWait() const
842{
843 return -1;
844}
845
846int QEventLoop::activateTimers()
847{
848 return 0;
849}
850
851int QEventLoop::activateSocketNotifiers()
852{
853#if defined(QT_THREAD_SUPPORT)
854 if ( d->sn_pending_list.isEmpty() )
855 return 0;
856
857 // postpone activation if ss_thread is working with the list
858 if ( !ss_mutex.tryLock() )
859 return 0;
860
861 // activate entries
862 int n_act = 0;
863 QEvent event( QEvent::SockAct );
864 QPtrListIterator<QSockNot> it( d->sn_pending_list );
865 QSockNot *sn;
866 while ( (sn = it.current()) ) {
867 ++it;
868 d->sn_pending_list.removeRef( sn );
869 if ( FD_ISSET(sn->fd, sn->queue) ) {
870 FD_CLR( sn->fd, sn->queue );
871 QApplication::sendEvent( sn->obj, &event );
872 n_act++;
873 }
874 }
875
876 ss_mutex.unlock();
877
878 return n_act;
879#else
880 return 0;
881#endif // QT_THREAD_SUPPORT
882}
883
Note: See TracBrowser for help on using the repository browser.