iOS: Implement socket notifiers.

Create the QCFSocketNotifier class in platform support
which contains shared socket notifier support for
the Cocoa and iOS plugins. Remove the old code from
the Cocoa plugin.

The Cocoa code had one QCocoaEventDispatcher-specific
call: maybeCancelWaitForMoreEvents. Create a forwarding
function that is passed to QCFSocketNotifier.

Change-Id: Ibf9bd4745ba4f577a55f13d0cc00f5ae04447405
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
This commit is contained in:
Morten Johan Sørvig 2013-02-15 11:25:39 +01:00 committed by Tor Arne Vestbø
parent 0c1ae5f866
commit aa5528b050
8 changed files with 374 additions and 194 deletions

View File

@ -0,0 +1,4 @@
mac {
HEADERS += $$PWD/qcfsocketnotifier_p.h
SOURCES += $$PWD/qcfsocketnotifier.cpp
}

View File

@ -0,0 +1,255 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcfsocketnotifier_p.h"
#include <QtGui/qguiapplication.h>
#include <QtCore/qsocketnotifier.h>
#include <QtCore/qthread.h>
/**************************************************************************
Socket Notifiers
*************************************************************************/
void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef,
const void *, void *info)
{
QCFSocketNotifier *cfSocketNotifier = static_cast<QCFSocketNotifier *>(info);
int nativeSocket = CFSocketGetNative(s);
MacSocketInfo *socketInfo = cfSocketNotifier->macSockets.value(nativeSocket);
QEvent notifierEvent(QEvent::SockAct);
// There is a race condition that happen where we disable the notifier and
// the kernel still has a notification to pass on. We then get this
// notification after we've successfully disabled the CFSocket, but our Qt
// notifier is now gone. The upshot is we have to check the notifier
// every time.
if (callbackType == kCFSocketReadCallBack) {
if (socketInfo->readNotifier)
QGuiApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
} else if (callbackType == kCFSocketWriteCallBack) {
if (socketInfo->writeNotifier)
QGuiApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
}
if (cfSocketNotifier->maybeCancelWaitForMoreEvents)
cfSocketNotifier->maybeCancelWaitForMoreEvents(cfSocketNotifier->eventDispatcher);
}
/*
Adds a loop source for the given socket to the current run loop.
*/
CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket)
{
CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
if (!loopSource)
return 0;
CFRunLoopAddSource(CFRunLoopGetMain(), loopSource, kCFRunLoopCommonModes);
return loopSource;
}
/*
Removes the loop source for the given socket from the current run loop.
*/
void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop)
{
Q_ASSERT(runloop);
CFRunLoopRemoveSource(CFRunLoopGetMain(), runloop, kCFRunLoopCommonModes);
CFSocketDisableCallBacks(socket, kCFSocketReadCallBack);
CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack);
CFRunLoopSourceInvalidate(runloop);
}
QCFSocketNotifier::QCFSocketNotifier()
:eventDispatcher(0)
{
}
QCFSocketNotifier::~QCFSocketNotifier()
{
}
void QCFSocketNotifier::setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher)
{
eventDispatcher = hostEventDispacher;
}
void QCFSocketNotifier::setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack)
{
maybeCancelWaitForMoreEvents = callBack;
}
void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
int nativeSocket = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
qWarning("QSocketNotifier: Internal error");
return;
} else if (notifier->thread() != eventDispatcher->thread()
|| eventDispatcher->thread() != QThread::currentThread()) {
qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
return;
}
#endif
if (type == QSocketNotifier::Exception) {
qWarning("QSocketNotifier::Exception is not supported on iOS");
return;
}
// Check if we have a CFSocket for the native socket, create one if not.
MacSocketInfo *socketInfo = macSockets.value(nativeSocket);
if (!socketInfo) {
socketInfo = new MacSocketInfo();
// Create CFSocket, specify that we want both read and write callbacks (the callbacks
// are enabled/disabled later on).
const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
CFSocketContext context = {0, this, 0, 0, 0};
socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
if (CFSocketIsValid(socketInfo->socket) == false) {
qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket");
return;
}
CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket);
flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write
flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation
CFSocketSetSocketFlags(socketInfo->socket, flags);
// Add CFSocket to runloop.
if (!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) {
qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop");
CFSocketInvalidate(socketInfo->socket);
CFRelease(socketInfo->socket);
return;
}
// Disable both callback types by default. This must be done after
// we add the CFSocket to the runloop, or else these calls will have
// no effect.
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
macSockets.insert(nativeSocket, socketInfo);
}
// Increment read/write counters and select enable callbacks if necessary.
if (type == QSocketNotifier::Read) {
Q_ASSERT(socketInfo->readNotifier == 0);
socketInfo->readNotifier = notifier;
CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
} else if (type == QSocketNotifier::Write) {
Q_ASSERT(socketInfo->writeNotifier == 0);
socketInfo->writeNotifier = notifier;
CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
}
}
void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
int nativeSocket = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
qWarning("QSocketNotifier: Internal error");
return;
} else if (notifier->thread() != eventDispatcher->thread() || eventDispatcher->thread() != QThread::currentThread()) {
qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
return;
}
#endif
if (type == QSocketNotifier::Exception) {
qWarning("QSocketNotifier::Exception is not supported on iOS");
return;
}
MacSocketInfo *socketInfo = macSockets.value(nativeSocket);
if (!socketInfo) {
qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier");
return;
}
// Decrement read/write counters and disable callbacks if necessary.
if (type == QSocketNotifier::Read) {
Q_ASSERT(notifier == socketInfo->readNotifier);
socketInfo->readNotifier = 0;
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
} else if (type == QSocketNotifier::Write) {
Q_ASSERT(notifier == socketInfo->writeNotifier);
socketInfo->writeNotifier = 0;
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
}
// Remove CFSocket from runloop if this was the last QSocketNotifier.
if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) {
if (CFSocketIsValid(socketInfo->socket))
qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
CFRunLoopSourceInvalidate(socketInfo->runloop);
CFRelease(socketInfo->runloop);
CFSocketInvalidate(socketInfo->socket);
CFRelease(socketInfo->socket);
delete socketInfo;
macSockets.remove(nativeSocket);
}
}
void QCFSocketNotifier::removeSocketNotifiers()
{
// Remove CFSockets from the runloop.
for (MacSocketHash::ConstIterator it = macSockets.constBegin(); it != macSockets.constEnd(); ++it) {
MacSocketInfo *socketInfo = (*it);
if (CFSocketIsValid(socketInfo->socket)) {
qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
CFRunLoopSourceInvalidate(socketInfo->runloop);
CFRelease(socketInfo->runloop);
CFSocketInvalidate(socketInfo->socket);
CFRelease(socketInfo->socket);
}
}
}

View File

@ -0,0 +1,90 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCFSOCKETNOTIFIER_P_H
#define QCFSOCKETNOTIFIER_P_H
#include <QtCore/qabstracteventdispatcher.h>
#include <QtCore/qhash.h>
#include <CoreFoundation/CoreFoundation.h>
QT_BEGIN_NAMESPACE
struct MacSocketInfo {
MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {}
CFSocketRef socket;
CFRunLoopSourceRef runloop;
QObject *readNotifier;
QObject *writeNotifier;
};
typedef QHash<int, MacSocketInfo *> MacSocketHash;
typedef void (*MaybeCancelWaitForMoreEventsFn)(QAbstractEventDispatcher *hostEventDispacher);
// The CoreFoundationSocketNotifier class implements socket notifiers support using
// CFSocket for event dispatchers running on top of the Core Foundation run loop system.
// (currently Mac and iOS)
//
// The principal functions are registerSocketNotifier() and unregisterSocketNotifier().
//
// setHostEventDispatcher() should be called at startup.
// removeSocketNotifiers() should be called at shutdown.
//
class QCFSocketNotifier
{
public:
QCFSocketNotifier();
~QCFSocketNotifier();
void setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher);
void setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack);
void registerSocketNotifier(QSocketNotifier *notifier);
void unregisterSocketNotifier(QSocketNotifier *notifier);
void removeSocketNotifiers();
MacSocketHash macSockets;
QAbstractEventDispatcher *eventDispatcher;
MaybeCancelWaitForMoreEventsFn maybeCancelWaitForMoreEvents;
};
QT_END_NAMESPACE
#endif

View File

@ -9,6 +9,7 @@ load(qt_module)
DEFINES += QT_NO_CAST_FROM_ASCII
PRECOMPILED_HEADER = ../corelib/global/qt_pch.h
include(cfsocketnotifier/cfsocketnotifier.pri)
include(cglconvenience/cglconvenience.pri)
include(dnd/dnd.pri)
include(eglconvenience/eglconvenience.pri)

View File

@ -93,6 +93,7 @@
#include <QtGui/qwindowdefs.h>
#include <QtCore/private/qabstracteventdispatcher_p.h>
#include <QtCore/private/qtimerinfo_unix_p.h>
#include <QtPlatformSupport/private/qcfsocketnotifier_p.h>
#include <CoreFoundation/CoreFoundation.h>
@ -132,16 +133,9 @@ public:
void wakeUp();
void interrupt();
void flush();
};
struct MacSocketInfo {
MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {}
CFSocketRef socket;
CFRunLoopSourceRef runloop;
QObject *readNotifier;
QObject *writeNotifier;
friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher);
};
typedef QHash<int, MacSocketInfo *> MacSocketHash;
class QCocoaEventDispatcherPrivate : public QAbstractEventDispatcherPrivate
{
@ -183,7 +177,7 @@ public:
void maybeCancelWaitForMoreEvents();
void ensureNSAppInitialized();
MacSocketHash macSockets;
QCFSocketNotifier cfSocketNotifier;
QList<void *> queuedUserInputEvents; // NSEvent *
CFRunLoopSourceRef postedEventsSource;
CFRunLoopObserverRef waitingObserver;

View File

@ -270,58 +270,6 @@ QCocoaEventDispatcher::registeredTimers(QObject *object) const
return d->timerInfoList.registeredTimers(object);
}
/**************************************************************************
Socket Notifiers
*************************************************************************/
void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef,
const void *, void *info) {
QCocoaEventDispatcherPrivate *const eventDispatcher
= static_cast<QCocoaEventDispatcherPrivate *>(info);
int nativeSocket = CFSocketGetNative(s);
MacSocketInfo *socketInfo = eventDispatcher->macSockets.value(nativeSocket);
QEvent notifierEvent(QEvent::SockAct);
// There is a race condition that happen where we disable the notifier and
// the kernel still has a notification to pass on. We then get this
// notification after we've successfully disabled the CFSocket, but our Qt
// notifier is now gone. The upshot is we have to check the notifier
// everytime.
if (callbackType == kCFSocketReadCallBack) {
if (socketInfo->readNotifier)
QGuiApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
} else if (callbackType == kCFSocketWriteCallBack) {
if (socketInfo->writeNotifier)
QGuiApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
}
eventDispatcher->maybeCancelWaitForMoreEvents();
}
/*
Adds a loop source for the given socket to the current run loop.
*/
CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket)
{
CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
if (!loopSource)
return 0;
CFRunLoopAddSource(mainRunLoop(), loopSource, kCFRunLoopCommonModes);
return loopSource;
}
/*
Removes the loop source for the given socket from the current run loop.
*/
void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop)
{
Q_ASSERT(runloop);
CFRunLoopRemoveSource(mainRunLoop(), runloop, kCFRunLoopCommonModes);
CFSocketDisableCallBacks(socket, kCFSocketReadCallBack);
CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack);
CFRunLoopSourceInvalidate(runloop);
}
/*
Register a QSocketNotifier with the mac event system by creating a CFSocket with
with a read/write callback.
@ -331,130 +279,14 @@ void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSource
*/
void QCocoaEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
int nativeSocket = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
qWarning("QSocketNotifier: Internal error");
return;
} else if (notifier->thread() != thread()
|| thread() != QThread::currentThread()) {
qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
return;
}
#endif
Q_D(QCocoaEventDispatcher);
if (type == QSocketNotifier::Exception) {
qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
return;
}
// Check if we have a CFSocket for the native socket, create one if not.
MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
if (!socketInfo) {
socketInfo = new MacSocketInfo();
// Create CFSocket, specify that we want both read and write callbacks (the callbacks
// are enabled/disabled later on).
const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
CFSocketContext context = {0, d, 0, 0, 0};
socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
if (CFSocketIsValid(socketInfo->socket) == false) {
qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket");
return;
}
CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket);
flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write
flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation
CFSocketSetSocketFlags(socketInfo->socket, flags);
// Add CFSocket to runloop.
if(!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) {
qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop");
CFSocketInvalidate(socketInfo->socket);
CFRelease(socketInfo->socket);
return;
}
// Disable both callback types by default. This must be done after
// we add the CFSocket to the runloop, or else these calls will have
// no effect.
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
d->macSockets.insert(nativeSocket, socketInfo);
}
// Increment read/write counters and select enable callbacks if necessary.
if (type == QSocketNotifier::Read) {
Q_ASSERT(socketInfo->readNotifier == 0);
socketInfo->readNotifier = notifier;
CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
} else if (type == QSocketNotifier::Write) {
Q_ASSERT(socketInfo->writeNotifier == 0);
socketInfo->writeNotifier = notifier;
CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
}
d->cfSocketNotifier.registerSocketNotifier(notifier);
}
/*
Unregister QSocketNotifer. The CFSocket correspoding to this notifier is
removed from the runloop of this is the last notifier that users
that CFSocket.
*/
void QCocoaEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
int nativeSocket = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
qWarning("QSocketNotifier: Internal error");
return;
} else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
return;
}
#endif
Q_D(QCocoaEventDispatcher);
if (type == QSocketNotifier::Exception) {
qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
return;
}
MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
if (!socketInfo) {
qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier");
return;
}
// Decrement read/write counters and disable callbacks if necessary.
if (type == QSocketNotifier::Read) {
Q_ASSERT(notifier == socketInfo->readNotifier);
socketInfo->readNotifier = 0;
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
} else if (type == QSocketNotifier::Write) {
Q_ASSERT(notifier == socketInfo->writeNotifier);
socketInfo->writeNotifier = 0;
CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
}
// Remove CFSocket from runloop if this was the last QSocketNotifier.
if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) {
if (CFSocketIsValid(socketInfo->socket))
qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
CFRunLoopSourceInvalidate(socketInfo->runloop);
CFRelease(socketInfo->runloop);
CFSocketInvalidate(socketInfo->socket);
CFRelease(socketInfo->socket);
delete socketInfo;
d->macSockets.remove(nativeSocket);
}
d->cfSocketNotifier.unregisterSocketNotifier(notifier);
}
bool QCocoaEventDispatcher::hasPendingEvents()
@ -940,11 +772,19 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
{
}
void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher)
{
static_cast<QCocoaEventDispatcher *>(eventDispatcher)->d_func()->maybeCancelWaitForMoreEvents();
}
QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent)
: QAbstractEventDispatcher(*new QCocoaEventDispatcherPrivate, parent)
{
Q_D(QCocoaEventDispatcher);
d->cfSocketNotifier.setHostEventDispatcher(this);
d->cfSocketNotifier.setMaybeCancelWaitForMoreEventsCallback(qt_mac_maybeCancelWaitForMoreEventsForwarder);
// keep our sources running when modal loops are running
CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
@ -1127,17 +967,8 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
[nsevent release];
}
// Remove CFSockets from the runloop.
for (MacSocketHash::ConstIterator it = d->macSockets.constBegin(); it != d->macSockets.constEnd(); ++it) {
MacSocketInfo *socketInfo = (*it);
if (CFSocketIsValid(socketInfo->socket)) {
qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
CFRunLoopSourceInvalidate(socketInfo->runloop);
CFRelease(socketInfo->runloop);
CFSocketInvalidate(socketInfo->socket);
CFRelease(socketInfo->socket);
}
}
d->cfSocketNotifier.removeSocketNotifiers();
CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes);
CFRelease(d->postedEventsSource);

View File

@ -78,6 +78,7 @@
#include <QtCore/qabstracteventdispatcher.h>
#include <QtCore/private/qtimerinfo_unix_p.h>
#include <QtPlatformSupport/private/qcfsocketnotifier_p.h>
#include <CoreFoundation/CoreFoundation.h>
QT_BEGIN_NAMESPACE
@ -116,6 +117,8 @@ private:
QTimerInfoList m_timerInfoList;
CFRunLoopTimerRef m_runLoopTimerRef;
QCFSocketNotifier m_cfSocketNotifier;
void processPostedEvents();
void maybeStartCFRunLoopTimer();
void maybeStopCFRunLoopTimer();

View File

@ -155,6 +155,8 @@ QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
, m_interrupted(false)
, m_runLoopTimerRef(0)
{
m_cfSocketNotifier.setHostEventDispatcher(this);
CFRunLoopRef mainRunLoop = CFRunLoopGetMain();
CFRunLoopSourceContext context;
bzero(&context, sizeof(CFRunLoopSourceContext));
@ -184,6 +186,8 @@ QIOSEventDispatcher::~QIOSEventDispatcher()
maybeStopCFRunLoopTimer();
CFRunLoopRemoveSource(CFRunLoopGetMain(), m_blockingTimerRunLoopSource, kCFRunLoopCommonModes);
CFRelease(m_blockingTimerRunLoopSource);
m_cfSocketNotifier.removeSocketNotifiers();
}
bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
@ -215,14 +219,12 @@ bool QIOSEventDispatcher::hasPendingEvents()
void QIOSEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
{
qDebug() << __FUNCTION__ << "not implemented";
Q_UNUSED(notifier);
m_cfSocketNotifier.registerSocketNotifier(notifier);
}
void QIOSEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
{
qDebug() << __FUNCTION__ << "not implemented";
Q_UNUSED(notifier);
m_cfSocketNotifier.unregisterSocketNotifier(notifier);
}
void QIOSEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)