61 extern uint qGlobalPostedEventsCount(); |
61 extern uint qGlobalPostedEventsCount(); |
62 |
62 |
63 #ifndef TIME_KILL_SYNCHRONOUS |
63 #ifndef TIME_KILL_SYNCHRONOUS |
64 # define TIME_KILL_SYNCHRONOUS 0x0100 |
64 # define TIME_KILL_SYNCHRONOUS 0x0100 |
65 #endif |
65 #endif |
|
66 |
|
67 #ifndef QS_RAWINPUT |
|
68 # define QS_RAWINPUT 0x0400 |
|
69 #endif |
|
70 |
|
71 enum { |
|
72 WM_QT_SOCKETNOTIFIER = WM_USER, |
|
73 WM_QT_SENDPOSTEDEVENTS = WM_USER + 1, |
|
74 SendPostedEventsTimerId = ~1u |
|
75 }; |
66 |
76 |
67 #if defined(Q_OS_WINCE) |
77 #if defined(Q_OS_WINCE) |
68 QT_BEGIN_INCLUDE_NAMESPACE |
78 QT_BEGIN_INCLUDE_NAMESPACE |
69 #include <winsock.h> |
79 #include <winsock.h> |
70 // Asynchronous Winsocks ------------------------------------------ |
80 // Asynchronous Winsocks ------------------------------------------ |
338 QSNDict sn_read; |
354 QSNDict sn_read; |
339 QSNDict sn_write; |
355 QSNDict sn_write; |
340 QSNDict sn_except; |
356 QSNDict sn_except; |
341 void doWsaAsyncSelect(int socket); |
357 void doWsaAsyncSelect(int socket); |
342 |
358 |
343 // event notifier |
|
344 QWinEventNotifier wakeUpNotifier; |
|
345 |
|
346 QList<QWinEventNotifier *> winEventNotifierList; |
359 QList<QWinEventNotifier *> winEventNotifierList; |
347 void activateEventNotifier(QWinEventNotifier * wen); |
360 void activateEventNotifier(QWinEventNotifier * wen); |
348 |
361 |
349 QList<MSG> queuedUserInputEvents; |
362 QList<MSG> queuedUserInputEvents; |
350 QList<MSG> queuedSocketEvents; |
363 QList<MSG> queuedSocketEvents; |
351 }; |
364 }; |
352 |
365 |
353 QEventDispatcherWin32Private::QEventDispatcherWin32Private() |
366 QEventDispatcherWin32Private::QEventDispatcherWin32Private() |
354 : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0) |
367 : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), getMessageHook(0), serialNumber(0), lastSerialNumber(0), wakeUps(0) |
355 { |
368 { |
356 resolveTimerAPI(); |
369 resolveTimerAPI(); |
357 |
|
358 wakeUpNotifier.setHandle(CreateEvent(0, FALSE, FALSE, 0)); |
|
359 if (!wakeUpNotifier.handle()) |
|
360 qWarning("QEventDispatcher: Creating QEventDispatcherWin32Private wakeup event failed"); |
|
361 } |
370 } |
362 |
371 |
363 QEventDispatcherWin32Private::~QEventDispatcherWin32Private() |
372 QEventDispatcherWin32Private::~QEventDispatcherWin32Private() |
364 { |
373 { |
365 wakeUpNotifier.setEnabled(false); |
|
366 CloseHandle(wakeUpNotifier.handle()); |
|
367 if (internalHwnd) |
374 if (internalHwnd) |
368 DestroyWindow(internalHwnd); |
375 DestroyWindow(internalHwnd); |
369 QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc)); |
376 QString className = QLatin1String("QEventDispatcherWin32_Internal_Widget") + QString::number(quintptr(qt_internal_proc)); |
370 UnregisterClass((wchar_t*)className.utf16(), qWinAppInst()); |
377 UnregisterClass((wchar_t*)className.utf16(), qWinAppInst()); |
371 } |
378 } |
406 QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId)); |
413 QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId)); |
407 } |
414 } |
408 |
415 |
409 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) |
416 LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) |
410 { |
417 { |
411 if (message == WM_NCCREATE) { |
418 if (message == WM_NCCREATE) |
412 return true; |
419 return true; |
413 } else if (message == WM_USER) { |
420 |
414 |
421 MSG msg; |
|
422 msg.hwnd = hwnd; |
|
423 msg.message = message; |
|
424 msg.wParam = wp; |
|
425 msg.lParam = lp; |
|
426 QCoreApplication *app = QCoreApplication::instance(); |
|
427 long result; |
|
428 if (!app) { |
|
429 if (message == WM_TIMER) |
|
430 KillTimer(hwnd, wp); |
|
431 return 0; |
|
432 } else if (app->filterEvent(&msg, &result)) { |
|
433 return result; |
|
434 } |
|
435 |
|
436 #ifdef GWLP_USERDATA |
|
437 QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA); |
|
438 #else |
|
439 QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA); |
|
440 #endif |
|
441 QEventDispatcherWin32Private *d = 0; |
|
442 if (q != 0) |
|
443 d = q->d_func(); |
|
444 |
|
445 if (message == WM_QT_SOCKETNOTIFIER) { |
415 // socket notifier message |
446 // 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; |
447 int type = -1; |
428 switch (WSAGETSELECTEVENT(lp)) { |
448 switch (WSAGETSELECTEVENT(lp)) { |
429 case FD_READ: |
449 case FD_READ: |
430 case FD_CLOSE: |
450 case FD_CLOSE: |
431 case FD_ACCEPT: |
451 case FD_ACCEPT: |
438 case FD_OOB: |
458 case FD_OOB: |
439 type = 2; |
459 type = 2; |
440 break; |
460 break; |
441 } |
461 } |
442 if (type >= 0) { |
462 if (type >= 0) { |
443 |
463 Q_ASSERT(d != 0); |
444 #ifdef GWLP_USERDATA |
464 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; |
445 QEventDispatcherWin32 *eventDispatcher = |
465 QSNDict *dict = sn_vec[type]; |
446 (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA); |
466 |
447 #else |
467 QSockNot *sn = dict ? dict->value(wp) : 0; |
448 QEventDispatcherWin32 *eventDispatcher = |
468 if (sn) { |
449 (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA); |
469 QEvent event(QEvent::SockAct); |
450 #endif |
470 QCoreApplication::sendEvent(sn->obj, &event); |
451 if (eventDispatcher) { |
471 } |
452 QEventDispatcherWin32Private *d = eventDispatcher->d_func(); |
472 } |
453 QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; |
473 return 0; |
454 QSNDict *dict = sn_vec[type]; |
474 } else if (message == WM_TIMER) { |
455 |
475 Q_ASSERT(d != 0); |
456 QSockNot *sn = dict ? dict->value(wp) : 0; |
476 d->sendTimerEvent(wp); |
457 if (sn) { |
477 return 0; |
458 QEvent event(QEvent::SockAct); |
478 } else if (message == WM_QT_SENDPOSTEDEVENTS) { |
459 QCoreApplication::sendEvent(sn->obj, &event); |
479 int localSerialNumber = d->serialNumber; |
|
480 if (localSerialNumber != d->lastSerialNumber) { |
|
481 d->lastSerialNumber = localSerialNumber; |
|
482 QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); |
|
483 } |
|
484 return 0; |
|
485 } |
|
486 |
|
487 return DefWindowProc(hwnd, message, wp, lp); |
|
488 } |
|
489 |
|
490 LRESULT CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) |
|
491 { |
|
492 if (wp == PM_REMOVE) { |
|
493 QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance()); |
|
494 Q_ASSERT(q != 0); |
|
495 if (q) { |
|
496 QEventDispatcherWin32Private *d = q->d_func(); |
|
497 int localSerialNumber = d->serialNumber; |
|
498 if (HIWORD(GetQueueStatus(QS_INPUT | QS_RAWINPUT | QS_TIMER)) == 0) { |
|
499 // no more input or timer events in the message queue, we can allow posted events to be |
|
500 // sent now |
|
501 (void) d->wakeUps.fetchAndStoreRelease(0); |
|
502 MSG *msg = (MSG *) lp; |
|
503 if (localSerialNumber != d->lastSerialNumber |
|
504 // if this message IS the one that triggers sendPostedEvents(), no need to post it again |
|
505 && msg->hwnd != d->internalHwnd |
|
506 && msg->message != WM_QT_SENDPOSTEDEVENTS) { |
|
507 PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); |
460 } |
508 } |
461 } |
509 } |
462 } |
510 } |
463 return 0; |
511 } |
464 |
512 #ifdef Q_OS_WINCE |
465 } else if (message == WM_TIMER) { |
513 return 0; |
466 |
514 #else |
467 MSG msg; |
515 return CallNextHookEx(0, code, wp, lp); |
468 msg.hwnd = hwnd; |
516 #endif |
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 } |
517 } |
494 |
518 |
495 static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher) |
519 static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher) |
496 { |
520 { |
497 // make sure that multiple Qt's can coexist in the same process |
521 // make sure that multiple Qt's can coexist in the same process |
517 0, // parent |
541 0, // parent |
518 0, // menu handle |
542 0, // menu handle |
519 qWinAppInst(), // application |
543 qWinAppInst(), // application |
520 0); // windows creation data. |
544 0); // windows creation data. |
521 |
545 |
|
546 if (!wnd) { |
|
547 qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError()); |
|
548 } |
|
549 |
522 #ifdef GWLP_USERDATA |
550 #ifdef GWLP_USERDATA |
523 SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher); |
551 SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher); |
524 #else |
552 #else |
525 SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher); |
553 SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher); |
526 #endif |
554 #endif |
527 |
555 |
528 if (!wnd) { |
|
529 qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError()); |
|
530 } |
|
531 return wnd; |
556 return wnd; |
532 } |
557 } |
533 |
558 |
534 void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) |
559 void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) |
535 { |
560 { |
536 Q_ASSERT(internalHwnd); |
561 Q_ASSERT(internalHwnd); |
537 |
562 |
538 Q_Q(QEventDispatcherWin32); |
563 Q_Q(QEventDispatcherWin32); |
539 |
564 |
540 int ok = 0; |
565 int ok = 0; |
541 |
566 if (t->interval > 20 || !t->interval || !qtimeSetEvent) { |
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; |
567 ok = 1; |
548 if (!t->interval) // optimization for single-shot-zero-timer |
568 if (!t->interval) // optimization for single-shot-zero-timer |
549 QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); |
569 QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); |
550 else |
570 else |
551 ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0); |
571 ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0); |
606 sn_event |= FD_WRITE | FD_CONNECT; |
626 sn_event |= FD_WRITE | FD_CONNECT; |
607 if (sn_except.contains(socket)) |
627 if (sn_except.contains(socket)) |
608 sn_event |= FD_OOB; |
628 sn_event |= FD_OOB; |
609 // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0 |
629 // BoundsChecker may emit a warning for WSAAsyncSelect when sn_event == 0 |
610 // This is a BoundsChecker bug and not a Qt bug |
630 // This is a BoundsChecker bug and not a Qt bug |
611 WSAAsyncSelect(socket, internalHwnd, sn_event ? WM_USER : 0, sn_event); |
631 WSAAsyncSelect(socket, internalHwnd, sn_event ? WM_QT_SOCKETNOTIFIER : 0, sn_event); |
612 } |
632 } |
613 |
633 |
614 void QEventDispatcherWin32::createInternalHwnd() |
634 void QEventDispatcherWin32::createInternalHwnd() |
615 { |
635 { |
616 Q_D(QEventDispatcherWin32); |
636 Q_D(QEventDispatcherWin32); |
617 |
637 |
618 Q_ASSERT(!d->internalHwnd); |
638 Q_ASSERT(!d->internalHwnd); |
619 if (d->internalHwnd) |
639 if (d->internalHwnd) |
620 return; |
640 return; |
621 d->internalHwnd = qt_create_internal_window(this); |
641 d->internalHwnd = qt_create_internal_window(this); |
|
642 |
|
643 #ifndef Q_OS_WINCE |
|
644 // setup GetMessage hook needed to drive our posted events |
|
645 d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); |
|
646 if (!d->getMessageHook) { |
|
647 qFatal("Qt: INTERNALL ERROR: failed to install GetMessage hook"); |
|
648 } |
|
649 #endif |
622 |
650 |
623 // register all socket notifiers |
651 // register all socket notifiers |
624 QList<int> sockets = (d->sn_read.keys().toSet() |
652 QList<int> sockets = (d->sn_read.keys().toSet() |
625 + d->sn_write.keys().toSet() |
653 + d->sn_write.keys().toSet() |
626 + d->sn_except.keys().toSet()).toList(); |
654 + d->sn_except.keys().toSet()).toList(); |
628 d->doWsaAsyncSelect(sockets.at(i)); |
656 d->doWsaAsyncSelect(sockets.at(i)); |
629 |
657 |
630 // start all normal timers |
658 // start all normal timers |
631 for (int i = 0; i < d->timerVec.count(); ++i) |
659 for (int i = 0; i < d->timerVec.count(); ++i) |
632 d->registerTimer(d->timerVec.at(i)); |
660 d->registerTimer(d->timerVec.at(i)); |
|
661 |
|
662 // trigger a call to sendPostedEvents() |
|
663 wakeUp(); |
633 } |
664 } |
634 |
665 |
635 QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent) |
666 QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent) |
636 : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent) |
667 : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent) |
637 { |
668 { |
704 // a new message has arrived, process it |
735 // a new message has arrived, process it |
705 continue; |
736 continue; |
706 } |
737 } |
707 } |
738 } |
708 if (haveMessage) { |
739 if (haveMessage) { |
709 if (msg.message == WM_TIMER) { |
740 #ifdef Q_OS_WINCE |
|
741 // WinCE doesn't support hooks at all, so we have to call this by hand :( |
|
742 (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg); |
|
743 #endif |
|
744 |
|
745 if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) { |
|
746 if (seenWM_QT_SENDPOSTEDEVENTS) { |
|
747 needWM_QT_SENDPOSTEDEVENTS = true; |
|
748 continue; |
|
749 } |
|
750 seenWM_QT_SENDPOSTEDEVENTS = true; |
|
751 } else if (msg.message == WM_TIMER) { |
710 // avoid live-lock by keeping track of the timers we've already sent |
752 // avoid live-lock by keeping track of the timers we've already sent |
711 bool found = false; |
753 bool found = false; |
712 for (int i = 0; !found && i < processedTimers.count(); ++i) { |
754 for (int i = 0; !found && i < processedTimers.count(); ++i) { |
713 const MSG processed = processedTimers.constData()[i]; |
755 const MSG processed = processedTimers.constData()[i]; |
714 found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam); |
756 found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam); |
988 } |
1036 } |
989 |
1037 |
990 void QEventDispatcherWin32::wakeUp() |
1038 void QEventDispatcherWin32::wakeUp() |
991 { |
1039 { |
992 Q_D(QEventDispatcherWin32); |
1040 Q_D(QEventDispatcherWin32); |
993 SetEvent(d->wakeUpNotifier.handle()); |
1041 d->serialNumber.ref(); |
|
1042 if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) { |
|
1043 // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending |
|
1044 PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); |
|
1045 } |
994 } |
1046 } |
995 |
1047 |
996 void QEventDispatcherWin32::interrupt() |
1048 void QEventDispatcherWin32::interrupt() |
997 { |
1049 { |
998 Q_D(QEventDispatcherWin32); |
1050 Q_D(QEventDispatcherWin32); |
1026 // clean up any timers |
1073 // clean up any timers |
1027 for (int i = 0; i < d->timerVec.count(); ++i) |
1074 for (int i = 0; i < d->timerVec.count(); ++i) |
1028 d->unregisterTimer(d->timerVec.at(i), true); |
1075 d->unregisterTimer(d->timerVec.at(i), true); |
1029 d->timerVec.clear(); |
1076 d->timerVec.clear(); |
1030 d->timerDict.clear(); |
1077 d->timerDict.clear(); |
|
1078 |
|
1079 #ifndef Q_OS_WINCE |
|
1080 if (d->getMessageHook) |
|
1081 UnhookWindowsHookEx(d->getMessageHook); |
|
1082 d->getMessageHook = 0; |
|
1083 #endif |
1031 } |
1084 } |
1032 |
1085 |
1033 bool QEventDispatcherWin32::event(QEvent *e) |
1086 bool QEventDispatcherWin32::event(QEvent *e) |
1034 { |
1087 { |
1035 Q_D(QEventDispatcherWin32); |
1088 Q_D(QEventDispatcherWin32); |