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

Last change on this file since 97 was 77, checked in by dmik, 19 years ago

Implemented the OS/2 version of the QSessionManager class (see ticket:15 for more details); QT_NO_SESSIONMANAGER is no more defined by default.

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