diff options
author | Morten Sorvig <morten.sorvig@nokia.com> | 2011-06-21 13:40:57 +0200 |
---|---|---|
committer | Morten Sorvig <morten.sorvig@nokia.com> | 2011-06-22 09:47:49 +0200 |
commit | 4efaf305f51d09e214645a18a7bfa62bc36e2c61 (patch) | |
tree | 6454f785f42e1e2be1d1422f81e3bbe1ad8b1158 /src/gui/kernel | |
parent | 18c1d671371ef8d94506a9a6dd6ee3680ef80fd3 (diff) |
Add lighthouse event dispatcher API.
Platform plugin creation is now moved forward in
order to have a platform plugin instance at event
dispatcher creation time.
Plugins are now responsible for implementing
PlatformIntegration::createEventDispatcher and returning
an QAbstractEventDispatcher subclass.
Diffstat (limited to 'src/gui/kernel')
-rw-r--r-- | src/gui/kernel/kernel.pri | 19 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_glib_qpa.cpp | 133 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_glib_qpa_p.h | 86 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_mac.mm | 1135 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_mac_p.h | 233 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_qpa.cpp | 137 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_qpa_p.h | 97 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 76 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication_p.h | 1 | ||||
-rw-r--r-- | src/gui/kernel/qplatformintegration_qpa.cpp | 7 | ||||
-rw-r--r-- | src/gui/kernel/qplatformintegration_qpa.h | 4 | ||||
-rw-r--r-- | src/gui/kernel/qwindowsysteminterface_qpa_p.h | 2 |
12 files changed, 56 insertions, 1874 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 09df411404..bfc2e44deb 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -38,7 +38,6 @@ qpa { HEADERS += \ kernel/qgenericpluginfactory_qpa.h \ kernel/qgenericplugin_qpa.h \ - kernel/qeventdispatcher_qpa_p.h \ kernel/qwindowsysteminterface_qpa.h \ kernel/qwindowsysteminterface_qpa_p.h \ kernel/qplatformintegration_qpa.h \ @@ -63,7 +62,6 @@ qpa { kernel/qcursor_qpa.cpp \ kernel/qgenericpluginfactory_qpa.cpp \ kernel/qgenericplugin_qpa.cpp \ - kernel/qeventdispatcher_qpa.cpp \ kernel/qwindowsysteminterface_qpa.cpp \ kernel/qplatformintegration_qpa.cpp \ kernel/qplatformscreen_qpa.cpp \ @@ -79,23 +77,6 @@ qpa { kernel/qsurfaceformat.cpp \ kernel/qguiapplication.cpp \ kernel/qwindow.cpp - - contains(QT_CONFIG, glib) { - SOURCES += \ - kernel/qeventdispatcher_glib_qpa.cpp - HEADERS += \ - kernel/qeventdispatcher_glib_qpa_p.h - QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB - LIBS_PRIVATE +=$$QT_LIBS_GLIB - } -} - -mac { - HEADERS += \ - kernel/qeventdispatcher_mac_p.h - OBJECTIVE_SOURCES += \ - kernel/qeventdispatcher_mac.mm - LIBS += -framework CoreFoundation -framework Cocoa -framework Carbon } win32:HEADERS+=kernel/qwindowdefs_win.h diff --git a/src/gui/kernel/qeventdispatcher_glib_qpa.cpp b/src/gui/kernel/qeventdispatcher_glib_qpa.cpp deleted file mode 100644 index eea0b9333e..0000000000 --- a/src/gui/kernel/qeventdispatcher_glib_qpa.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qeventdispatcher_glib_qpa_p.h" - -#include "qguiapplication.h" - -#include "qplatformdefs.h" - -#include <glib.h> -#include "private/qguiapplication_p.h" - -#include <qdebug.h> - -QT_BEGIN_NAMESPACE - -struct GUserEventSource -{ - GSource source; - QPAEventDispatcherGlib *q; -}; - -static gboolean userEventSourcePrepare(GSource *s, gint *timeout) -{ - Q_UNUSED(s) - Q_UNUSED(timeout) - - return QWindowSystemInterfacePrivate::windowSystemEventsQueued() > 0; -} - -static gboolean userEventSourceCheck(GSource *source) -{ - return userEventSourcePrepare(source, 0); -} - -static gboolean userEventSourceDispatch(GSource *s, GSourceFunc, gpointer) -{ - GUserEventSource * source = reinterpret_cast<GUserEventSource *>(s); - - QWindowSystemInterfacePrivate::WindowSystemEvent * event; - while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) { - event = QWindowSystemInterfacePrivate::getWindowSystemEvent(); - if (!event) - break; - - // send through event filter - if (source->q->filterEvent(event)) { - delete event; - continue; - } - QGuiApplicationPrivate::processWindowSystemEvent(event); - delete event; - } - - return true; -} - - -static GSourceFuncs userEventSourceFuncs = { - userEventSourcePrepare, - userEventSourceCheck, - userEventSourceDispatch, - NULL, - NULL, - NULL -}; - -QPAEventDispatcherGlibPrivate::QPAEventDispatcherGlibPrivate(GMainContext *context) - : QEventDispatcherGlibPrivate(context) -{ - userEventSource = reinterpret_cast<GUserEventSource *>(g_source_new(&userEventSourceFuncs, - sizeof(GUserEventSource))); - userEventSource->q = 0; - g_source_set_can_recurse(&userEventSource->source, true); - g_source_attach(&userEventSource->source, mainContext); -} - - -QPAEventDispatcherGlib::QPAEventDispatcherGlib(QObject *parent) - : QEventDispatcherGlib(*new QPAEventDispatcherGlibPrivate, parent) -{ - Q_D(QPAEventDispatcherGlib); - d->userEventSource->q = this; -} - -QPAEventDispatcherGlib::~QPAEventDispatcherGlib() -{ - Q_D(QPAEventDispatcherGlib); - - g_source_destroy(&d->userEventSource->source); - g_source_unref(&d->userEventSource->source); - d->userEventSource = 0; -} - -QT_END_NAMESPACE diff --git a/src/gui/kernel/qeventdispatcher_glib_qpa_p.h b/src/gui/kernel/qeventdispatcher_glib_qpa_p.h deleted file mode 100644 index ec9bb5e0ef..0000000000 --- a/src/gui/kernel/qeventdispatcher_glib_qpa_p.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEVENTDISPATCHER_GLIB_QPA_P_H -#define QEVENTDISPATCHER_GLIB_QPA_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QLibrary class. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/private/qeventdispatcher_glib_p.h> - -typedef struct _GMainContext GMainContext; - -QT_BEGIN_NAMESPACE -class QPAEventDispatcherGlibPrivate; - -class QPAEventDispatcherGlib : public QEventDispatcherGlib -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QPAEventDispatcherGlib) - -public: - explicit QPAEventDispatcherGlib(QObject *parent = 0); - ~QPAEventDispatcherGlib(); -}; - -struct GUserEventSource; - -class QPAEventDispatcherGlibPrivate : public QEventDispatcherGlibPrivate -{ - Q_DECLARE_PUBLIC(QPAEventDispatcherGlib) -public: - QPAEventDispatcherGlibPrivate(GMainContext *context = 0); - GUserEventSource *userEventSource; -}; - - -QT_END_NAMESPACE - -#endif // QEVENTDISPATCHER_GLIB_QPA_P_H diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm deleted file mode 100644 index 7350984db7..0000000000 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ /dev/null @@ -1,1135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Copyright (c) 2007-2008, Apple, Inc. -** -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** -** * Redistributions of source code must retain the above copyright notice, -** this list of conditions and the following disclaimer. -** -** * Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation -** and/or other materials provided with the distribution. -** -** * Neither the name of Apple, Inc. nor the names of its contributors -** may be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -** -****************************************************************************/ - -#include "qeventdispatcher_mac_p.h" -#include "qguiapplication.h" -#include "qevent.h" -#include "qhash.h" -#include "qmutex.h" -#include "qsocketnotifier.h" -#include <qplatformwindow_qpa.h> -#include "private/qthread_p.h" -#include "private/qguiapplication_p.h" -#include <qdebug.h> - -//#include <private/qcocoaapplication_mac_p.h> -//#include "private/qt_cocoa_helpers_mac_p.h" -#include <Cocoa/Cocoa.h> -#include <Carbon/Carbon.h> - -QT_BEGIN_NAMESPACE - -QT_USE_NAMESPACE - -enum { - QtCocoaEventSubTypeWakeup = SHRT_MAX, - QtCocoaEventSubTypePostMessage = SHRT_MAX-1 -}; - -static inline CFRunLoopRef mainRunLoop() -{ - return CFRunLoopGetMain(); -} - -QMacCocoaAutoReleasePool::QMacCocoaAutoReleasePool() -{ - pool = (void*)[[NSAutoreleasePool alloc] init]; -} - -QMacCocoaAutoReleasePool::~QMacCocoaAutoReleasePool() -{ - [(NSAutoreleasePool*)pool release]; -} - - -/***************************************************************************** - Timers stuff - *****************************************************************************/ - -/* timer call back */ -void QEventDispatcherMacPrivate::activateTimer(CFRunLoopTimerRef, void *info) -{ - int timerID = -#ifdef Q_OS_MAC64 - qint64(info); -#else - int(info); -#endif - - MacTimerInfo *tmr; - tmr = macTimerHash.value(timerID); - if (tmr == 0 || tmr->pending == true) - return; // Can't send another timer event if it's pending. - - - if (blockSendPostedEvents) { - QCoreApplication::postEvent(tmr->obj, new QTimerEvent(tmr->id)); - } else { - tmr->pending = true; - QTimerEvent e(tmr->id); - - QCoreApplication::sendSpontaneousEvent(tmr->obj, &e); - // Get the value again in case the timer gets unregistered during the sendEvent. - tmr = macTimerHash.value(timerID); - if (tmr != 0) - tmr->pending = false; - } - -} - -void QEventDispatcherMac::registerTimer(int timerId, int interval, QObject *obj) -{ -#ifndef QT_NO_DEBUG - if (timerId < 1 || interval < 0 || !obj) { - qWarning("QEventDispatcherMac::registerTimer: invalid arguments"); - return; - } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::startTimer: timers cannot be started from another thread"); - return; - } -#endif - - MacTimerInfo *t = new MacTimerInfo(); - t->id = timerId; - t->interval = interval; - t->obj = obj; - t->runLoopTimer = 0; - t->pending = false; - - CFAbsoluteTime fireDate = CFAbsoluteTimeGetCurrent(); - CFTimeInterval cfinterval = qMax(CFTimeInterval(interval) / 1000, 0.0000001); - fireDate += cfinterval; - QEventDispatcherMacPrivate::macTimerHash.insert(timerId, t); - CFRunLoopTimerContext info = { 0, (void *)timerId, 0, 0, 0 }; - t->runLoopTimer = CFRunLoopTimerCreate(0, fireDate, cfinterval, 0, 0, - QEventDispatcherMacPrivate::activateTimer, &info); - if (t->runLoopTimer == 0) { - qFatal("QEventDispatcherMac::registerTimer: Cannot create timer"); - } - CFRunLoopAddTimer(mainRunLoop(), t->runLoopTimer, kCFRunLoopCommonModes); -} - -bool QEventDispatcherMac::unregisterTimer(int identifier) -{ -#ifndef QT_NO_DEBUG - if (identifier < 1) { - qWarning("QEventDispatcherMac::unregisterTimer: invalid argument"); - return false; - } else if (thread() != QThread::currentThread()) { - qWarning("QObject::killTimer: timers cannot be stopped from another thread"); - return false; - } -#endif - if (identifier <= 0) - return false; // not init'd or invalid timer - - MacTimerInfo *timerInfo = QEventDispatcherMacPrivate::macTimerHash.take(identifier); - if (timerInfo == 0) - return false; - - if (!QObjectPrivate::get(timerInfo->obj)->inThreadChangeEvent) - QAbstractEventDispatcherPrivate::releaseTimerId(identifier); - CFRunLoopTimerInvalidate(timerInfo->runLoopTimer); - CFRelease(timerInfo->runLoopTimer); - delete timerInfo; - - return true; -} - -bool QEventDispatcherMac::unregisterTimers(QObject *obj) -{ -#ifndef QT_NO_DEBUG - if (!obj) { - qWarning("QEventDispatcherMac::unregisterTimers: invalid argument"); - return false; - } else if (obj->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QObject::killTimers: timers cannot be stopped from another thread"); - return false; - } -#endif - - MacTimerHash::iterator it = QEventDispatcherMacPrivate::macTimerHash.begin(); - while (it != QEventDispatcherMacPrivate::macTimerHash.end()) { - MacTimerInfo *timerInfo = it.value(); - if (timerInfo->obj != obj) { - ++it; - } else { - if (!QObjectPrivate::get(timerInfo->obj)->inThreadChangeEvent) - QAbstractEventDispatcherPrivate::releaseTimerId(timerInfo->id); - CFRunLoopTimerInvalidate(timerInfo->runLoopTimer); - CFRelease(timerInfo->runLoopTimer); - delete timerInfo; - it = QEventDispatcherMacPrivate::macTimerHash.erase(it); - } - } - return true; -} - -QList<QEventDispatcherMac::TimerInfo> -QEventDispatcherMac::registeredTimers(QObject *object) const -{ - if (!object) { - qWarning("QEventDispatcherMac:registeredTimers: invalid argument"); - return QList<TimerInfo>(); - } - - QList<TimerInfo> list; - - MacTimerHash::const_iterator it = QEventDispatcherMacPrivate::macTimerHash.constBegin(); - while (it != QEventDispatcherMacPrivate::macTimerHash.constEnd()) { - MacTimerInfo *t = it.value(); - if (t->obj == object) - list << TimerInfo(t->id, t->interval); - ++it; - } - return list; -} - -/************************************************************************** - Socket Notifiers - *************************************************************************/ -void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef, - const void *, void *info) { - QEventDispatcherMacPrivate *const eventDispatcher - = static_cast<QEventDispatcherMacPrivate *>(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, ¬ifierEvent); - } else if (callbackType == kCFSocketWriteCallBack) { - if (socketInfo->writeNotifier) - QGuiApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); - } -} - -/* - 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. - - Qt has separate socket notifiers for reading and writing, but on the mac there is - a limitation of one CFSocket object for each native socket. -*/ -void QEventDispatcherMac::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(QEventDispatcherMac); - - 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); - } -} - -/* - Unregister QSocketNotifer. The CFSocket correspoding to this notifier is - removed from the runloop of this is the last notifier that users - that CFSocket. -*/ -void QEventDispatcherMac::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(QEventDispatcherMac); - - 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); - } -} - -bool QEventDispatcherMac::hasPendingEvents() -{ - extern uint qGlobalPostedEventsCount(); - extern bool qt_is_gui_used; //qapplication.cpp - return qGlobalPostedEventsCount() || (qt_is_gui_used && GetNumEventsInQueue(GetMainEventQueue())); -} - -static bool IsMouseOrKeyEvent( NSEvent* event ) -{ - bool result = false; - - switch( [event type] ) - { - case NSLeftMouseDown: - case NSLeftMouseUp: - case NSRightMouseDown: - case NSRightMouseUp: - case NSMouseMoved: // ?? - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSMouseEntered: - case NSMouseExited: - case NSKeyDown: - case NSKeyUp: - case NSFlagsChanged: // key modifiers changed? - case NSCursorUpdate: // ?? - case NSScrollWheel: - case NSTabletPoint: - case NSTabletProximity: - case NSOtherMouseDown: - case NSOtherMouseUp: - case NSOtherMouseDragged: -#ifndef QT_NO_GESTURES -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - case NSEventTypeGesture: // touch events - case NSEventTypeMagnify: - case NSEventTypeSwipe: - case NSEventTypeRotate: - case NSEventTypeBeginGesture: - case NSEventTypeEndGesture: -#endif -#endif // QT_NO_GESTURES - result = true; - break; - - default: - break; - } - return result; -} - -static inline void qt_mac_waitForMoreEvents() -{ - // If no event exist in the cocoa event que, wait - // (and free up cpu time) until at least one event occur. - // This implementation is a bit on the edge, but seems to - // work fine: - NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantFuture] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - if (event) - [NSApp postEvent:event atStart:YES]; -} - -static inline void qt_mac_waitForMoreModalSessionEvents() -{ - // If no event exist in the cocoa event que, wait - // (and free up cpu time) until at least one event occur. - // This implementation is a bit on the edge, but seems to - // work fine: - NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantFuture] - inMode:NSModalPanelRunLoopMode - dequeue:YES]; - if (event) - [NSApp postEvent:event atStart:YES]; -} - -bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) -{ - Q_D(QEventDispatcherMac); - d->interrupt = false; - - bool interruptLater = false; - QtMacInterruptDispatcherHelp::cancelInterruptLater(); - - // In case we end up recursing while we now process events, make sure - // that we send remaining posted Qt events before this call returns: - wakeUp(); - emit awake(); - - bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents; - bool retVal = false; - forever { - if (d->interrupt) - break; - - QMacCocoaAutoReleasePool pool; - NSEvent* event = 0; - - // First, send all previously excluded input events, if any: - if (!excludeUserEvents) { - while (!d->queuedUserInputEvents.isEmpty()) { - event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); - if (!filterEvent(event)) { - [NSApp sendEvent:event]; - retVal = true; - } - [event release]; - } - } - - // If Qt is used as a plugin, or as an extension in a native cocoa - // application, we should not run or stop NSApplication; This will be - // done from the application itself. And if processEvents is called - // manually (rather than from a QEventLoop), we cannot enter a tight - // loop and block this call, but instead we need to return after one flush. - // Finally, if we are to exclude user input events, we cannot call [NSApp run] - // as we then loose control over which events gets dispatched: - const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning]; - const bool canExec_Qt = !excludeUserEvents && - (flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec) ; - - if (canExec_Qt && canExec_3rdParty) { - // We can use exec-mode, meaning that we can stay in a tight loop until - // interrupted. This is mostly an optimization, but it allow us to use - // [NSApp run], which is the normal code path for cocoa applications. - if (NSModalSession session = d->currentModalSession()) { - QBoolBlocker execGuard(d->currentExecIsNSAppRun, false); - while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt) - qt_mac_waitForMoreModalSessionEvents(); - - if (!d->interrupt && session == d->currentModalSessionCached) { - // Someone called [NSApp stopModal:] from outside the event - // dispatcher (e.g to stop a native dialog). But that call wrongly stopped - // 'session' as well. As a result, we need to restart all internal sessions: - d->temporarilyStopAllModalSessions(); - } - } else { - d->nsAppRunCalledByQt = true; - QBoolBlocker execGuard(d->currentExecIsNSAppRun, true); - [NSApp run]; - } - retVal = true; - } else { - // We cannot block the thread (and run in a tight loop). - // Instead we will process all current pending events and return. - d->ensureNSAppInitialized(); - if (NSModalSession session = d->currentModalSession()) { - // INVARIANT: a modal window is executing. - if (!excludeUserEvents) { - // Since we can dispatch all kinds of events, we choose - // to use cocoa's native way of running modal sessions: - if (flags & QEventLoop::WaitForMoreEvents) - qt_mac_waitForMoreModalSessionEvents(); - NSInteger status = [NSApp runModalSession:session]; - if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) { - // INVARIANT: Someone called [NSApp stopModal:] from outside the event - // dispatcher (e.g to stop a native dialog). But that call wrongly stopped - // 'session' as well. As a result, we need to restart all internal sessions: - d->temporarilyStopAllModalSessions(); - } - retVal = true; - } else do { - // Dispatch all non-user events (but que non-user events up for later). In - // this case, we need more control over which events gets dispatched, and - // cannot use [NSApp runModalSession:session]: - event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSModalPanelRunLoopMode - dequeue: YES]; - - if (event) { - if (IsMouseOrKeyEvent(event)) { - [event retain]; - d->queuedUserInputEvents.append(event); - continue; - } - if (!filterEvent(event)) { - [NSApp sendEvent:event]; - retVal = true; - } - } - } while (!d->interrupt && event != nil); - } else do { - // INVARIANT: No modal window is executing. - event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue: YES]; - - if (event) { - if (flags & QEventLoop::ExcludeUserInputEvents) { - if (IsMouseOrKeyEvent(event)) { - [event retain]; - d->queuedUserInputEvents.append(event); - continue; - } - } - if (!filterEvent(event)) { - [NSApp sendEvent:event]; - retVal = true; - } - } - } while (!d->interrupt && event != nil); - - // Be sure to flush the Qt posted events when not using exec mode - // (exec mode will always do this call from the event loop source): - if (!d->interrupt) - QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); - - // Since the window that holds modality might have changed while processing - // events, we we need to interrupt when we return back the previous process - // event recursion to ensure that we spin the correct modal session. - // We do the interruptLater at the end of the function to ensure that we don't - // disturb the 'wait for more events' below (as deleteLater will post an event): - interruptLater = true; - } - bool canWait = (d->threadData->canWait - && !retVal - && !d->interrupt - && (flags & QEventLoop::WaitForMoreEvents)); - if (canWait) { - // INVARIANT: We haven't processed any events yet. And we're told - // to stay inside this function until at least one event is processed. - qt_mac_waitForMoreEvents(); - flags &= ~QEventLoop::WaitForMoreEvents; - } else { - // Done with event processing for now. - // Leave the function: - break; - } - } - - // If we're interrupted, we need to interrupt the _current_ - // recursion as well to check if it is still supposed to be - // executing. This way we wind down the stack until we land - // on a recursion that again calls processEvents (typically - // from QEventLoop), and set interrupt to false: - if (d->interrupt) - interrupt(); - - if (interruptLater) - QtMacInterruptDispatcherHelp::interruptLater(); - - return retVal; -} - -void QEventDispatcherMac::wakeUp() -{ - Q_D(QEventDispatcherMac); - d->serialNumber.ref(); - CFRunLoopSourceSignal(d->postedEventsSource); - CFRunLoopWakeUp(mainRunLoop()); -} - -/***************************************************************************** - QEventDispatcherMac Implementation - *****************************************************************************/ -MacTimerHash QEventDispatcherMacPrivate::macTimerHash; -bool QEventDispatcherMacPrivate::blockSendPostedEvents = false; -bool QEventDispatcherMacPrivate::interrupt = false; - - -QStack<QCocoaModalSessionInfo> QEventDispatcherMacPrivate::cocoaModalSessionStack; -bool QEventDispatcherMacPrivate::currentExecIsNSAppRun = false; -bool QEventDispatcherMacPrivate::nsAppRunCalledByQt = false; -bool QEventDispatcherMacPrivate::cleanupModalSessionsNeeded = false; -NSModalSession QEventDispatcherMacPrivate::currentModalSessionCached = 0; - -void QEventDispatcherMacPrivate::ensureNSAppInitialized() -{ - // Some elements in Cocoa require NSApplication to be running before - // they get fully initialized, in particular the menu bar. This - // function is intended for cases where a dialog is told to execute before - // QGuiApplication::exec is called, or the application spins the events loop - // manually rather than calling QGuiApplication:exec. - // The function makes sure that NSApplication starts running, but stops - // it again as soon as the send posted events callback is called. That way - // we let Cocoa finish the initialization it seems to need. We'll only - // apply this trick at most once for any application, and we avoid doing it - // for the common case where main just starts QGuiApplication::exec. - if (nsAppRunCalledByQt || [NSApp isRunning]) - return; - nsAppRunCalledByQt = true; - QBoolBlocker block1(interrupt, true); - QBoolBlocker block2(currentExecIsNSAppRun, true); - [NSApp run]; -} - -void QEventDispatcherMacPrivate::temporarilyStopAllModalSessions() -{ - // Flush, and Stop, all created modal session, and as - // such, make them pending again. The next call to - // currentModalSession will recreate them again. The - // reason to stop all session like this is that otherwise - // a call [NSApp stop] would not stop NSApp, but rather - // the current modal session. So if we need to stop NSApp - // we need to stop all the modal session first. To avoid changing - // the stacking order of the windows while doing so, we put - // up a block that is used in QCocoaWindow and QCocoaPanel: - int stackSize = cocoaModalSessionStack.size(); - for (int i=0; i<stackSize; ++i) { - QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; - if (info.session) { - [NSApp endModalSession:info.session]; - info.session = 0; - } - } - currentModalSessionCached = 0; -} - -NSModalSession QEventDispatcherMacPrivate::currentModalSession() -{ - // If we have one or more modal windows, this function will create - // a session for each of those, and return the one for the top. - if (currentModalSessionCached) - return currentModalSessionCached; - - if (cocoaModalSessionStack.isEmpty()) - return 0; - - int sessionCount = cocoaModalSessionStack.size(); - for (int i=0; i<sessionCount; ++i) { - QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; - if (!info.window) - continue; -// ### port -// if (info.window->testAttribute(Qt::WA_DontShowOnScreen)) -// continue; - - if (!info.session) { - QMacCocoaAutoReleasePool pool; - NSWindow *window = reinterpret_cast<NSWindow *>(info.window->handle()->winId()); - if (!window) - continue; - - ensureNSAppInitialized(); - QBoolBlocker block1(blockSendPostedEvents, true); - info.nswindow = window; - [(NSWindow*) info.nswindow retain]; - int levelBeforeEnterModal = [window level]; - info.session = [NSApp beginModalSessionForWindow:window]; - // Make sure we don't stack the window lower that it was before - // entering modal, in case it e.g. had the stays-on-top flag set: - if (levelBeforeEnterModal > [window level]) - [window setLevel:levelBeforeEnterModal]; - } - currentModalSessionCached = info.session; - cleanupModalSessionsNeeded = false; - } - return currentModalSessionCached; -} - -static void setChildrenWorksWhenModal(QWindow *window, bool worksWhenModal) -{ - // For NSPanels (but not NSWindows, sadly), we can set the flag - // worksWhenModal, so that they are active even when they are not modal. -/* - ### not ported - QList<QDialog *> dialogs = window->findChildren<QDialog *>(); - for (int i=0; i<dialogs.size(); ++i){ - NSWindow *window = qt_mac_window_for(dialogs[i]); - if (window && [window isKindOfClass:[NSPanel class]]) { - [static_cast<NSPanel *>(window) setWorksWhenModal:worksWhenModal]; - if (worksWhenModal && [window isVisible]){ - [window orderFront:window]; - } - } - } -*/ -} - -void QEventDispatcherMacPrivate::updateChildrenWorksWhenModal() -{ - // Make the dialog children of the window - // active. And make the dialog children of - // the previous modal dialog unactive again: - QMacCocoaAutoReleasePool pool; - int size = cocoaModalSessionStack.size(); - if (size > 0){ - if (QWindow *prevModal = cocoaModalSessionStack[size-1].window) - setChildrenWorksWhenModal(prevModal, true); - if (size > 1){ - if (QWindow *prevModal = cocoaModalSessionStack[size-2].window) - setChildrenWorksWhenModal(prevModal, false); - } - } -} - -void QEventDispatcherMacPrivate::cleanupModalSessions() -{ - // Go through the list of modal sessions, and end those - // that no longer has a window assosiated; no window means - // the the session has logically ended. The reason we wait like - // this to actually end the sessions for real (rather than at the - // point they were marked as stopped), is that ending a session - // when no other session runs below it on the stack will make cocoa - // drop some events on the floor. - QMacCocoaAutoReleasePool pool; - int stackSize = cocoaModalSessionStack.size(); - - for (int i=stackSize-1; i>=0; --i) { - QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; - if (info.window) { - // This session has a window, and is therefore not marked - // as stopped. So just make it current. There might still be other - // stopped sessions on the stack, but those will be stopped on - // a later "cleanup" call. - currentModalSessionCached = info.session; - break; - } - cocoaModalSessionStack.remove(i); - currentModalSessionCached = 0; - if (info.session) { - [NSApp endModalSession:info.session]; - [(NSWindow *)info.nswindow release]; - } - } - - updateChildrenWorksWhenModal(); - cleanupModalSessionsNeeded = false; -} - -void QEventDispatcherMacPrivate::beginModalSession(QWindow *window) -{ - // Add a new, empty (null), NSModalSession to the stack. - // It will become active the next time QEventDispatcher::processEvents is called. - // A QCocoaModalSessionInfo is considered pending to become active if the window pointer - // is non-zero, and the session pointer is zero (it will become active upon a call to - // currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if - // the window pointer is zero, and the session pointer is non-zero (it will be fully - // stopped in cleanupModalSessions()). - QCocoaModalSessionInfo info = {window, 0, 0}; - cocoaModalSessionStack.push(info); - updateChildrenWorksWhenModal(); - currentModalSessionCached = 0; -} - -void QEventDispatcherMacPrivate::endModalSession(QWindow *window) -{ - // Mark all sessions attached to window as pending to be stopped. We do this - // by setting the window pointer to zero, but leave the session pointer. - // We don't tell cocoa to stop any sessions just yet, because cocoa only understands - // when we stop the _current_ modal session (which is the session on top of - // the stack, and might not belong to 'window'). - int stackSize = cocoaModalSessionStack.size(); - for (int i=stackSize-1; i>=0; --i) { - QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; - if (info.window == window) { - info.window = 0; - if (i == stackSize-1) { - // The top sessions ended. Interrupt the event dispatcher - // to start spinning the correct session immidiatly: - currentModalSessionCached = 0; - cleanupModalSessionsNeeded = true; - QEventDispatcherMac::instance()->interrupt(); - } - } - } -} - -QEventDispatcherMacPrivate::QEventDispatcherMacPrivate() -{ -} - -QEventDispatcherMac::QEventDispatcherMac(QObject *parent) - : QEventDispatcherQPA(*new QEventDispatcherMacPrivate, parent) -{ - Q_D(QEventDispatcherMac); - CFRunLoopSourceContext context; - bzero(&context, sizeof(CFRunLoopSourceContext)); - context.info = d; - context.equal = QEventDispatcherMacPrivate::postedEventSourceEqualCallback; - context.perform = QEventDispatcherMacPrivate::postedEventsSourcePerformCallback; - d->postedEventsSource = CFRunLoopSourceCreate(0, 0, &context); - Q_ASSERT(d->postedEventsSource); - CFRunLoopAddSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes); - - CFRunLoopObserverContext observerContext; - bzero(&observerContext, sizeof(CFRunLoopObserverContext)); - observerContext.info = this; - d->waitingObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, - kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting, - true, 0, - QEventDispatcherMacPrivate::waitingObserverCallback, - &observerContext); - CFRunLoopAddObserver(mainRunLoop(), d->waitingObserver, kCFRunLoopCommonModes); - - /* The first cycle in the loop adds the source and the events of the source - are not processed. - We use an observer to process the posted events for the first - execution of the loop. */ - CFRunLoopObserverContext firstTimeObserverContext; - bzero(&firstTimeObserverContext, sizeof(CFRunLoopObserverContext)); - firstTimeObserverContext.info = d; - d->firstTimeObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, - kCFRunLoopEntry, - /* repeats = */ false, - 0, - QEventDispatcherMacPrivate::firstLoopEntry, - &firstTimeObserverContext); - CFRunLoopAddObserver(mainRunLoop(), d->firstTimeObserver, kCFRunLoopCommonModes); -} - -void QEventDispatcherMacPrivate::waitingObserverCallback(CFRunLoopObserverRef, - CFRunLoopActivity activity, void *info) -{ - if (activity == kCFRunLoopBeforeWaiting) - emit static_cast<QEventDispatcherMac*>(info)->aboutToBlock(); - else - emit static_cast<QEventDispatcherMac*>(info)->awake(); -} - -Boolean QEventDispatcherMacPrivate::postedEventSourceEqualCallback(const void *info1, const void *info2) -{ - return info1 == info2; -} - -void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents) -{ - if (blockSendPostedEvents) { - // We're told to not send posted events (because the event dispatcher - // is currently working on setting up the correct session to run). But - // we still need to make sure that we don't fall asleep until pending events - // are sendt, so we just signal this need, and return: - CFRunLoopSourceSignal(d->postedEventsSource); - return; - } - - if (d->cleanupModalSessionsNeeded) - d->cleanupModalSessions(); - - if (d->interrupt) { - if (d->currentExecIsNSAppRun) { - // The event dispatcher has been interrupted. But since - // [NSApplication run] is running the event loop, we - // delayed stopping it until now (to let cocoa process - // pending cocoa events first). - if (d->currentModalSessionCached) - d->temporarilyStopAllModalSessions(); - [NSApp stop:NSApp]; - d->cancelWaitForMoreEvents(); - } - return; - } - - if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) { - d->lastSerial = d->serialNumber; - // Call down to the base class event handler, which will send - // the window system events. - d->q_func()->QEventDispatcherQPA::processEvents(QEventLoop::AllEvents); - } -} - -void QEventDispatcherMacPrivate::firstLoopEntry(CFRunLoopObserverRef ref, - CFRunLoopActivity activity, - void *info) -{ - Q_UNUSED(ref); - Q_UNUSED(activity); -/* - // This function is called when NSApplication has finished initialization, - // which appears to be just after [NSApplication run] has started to execute. - // By setting up our apple events handlers this late, we override the ones - // set up by NSApplication. - - // If Qt is used as a plugin, we let the 3rd party application handle events - // like quit and open file events. Otherwise, if we install our own handlers, we - // easily end up breaking functionallity the 3rd party application depend on: - if (QGuiApplication::testAttribute(Qt::AA_MacPluginApplication)) - return; - - QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate]; - NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; - [eventManager setEventHandler:newDelegate andSelector:@selector(appleEventQuit:withReplyEvent:) - forEventClass:kCoreEventClass andEventID:kAEQuitApplication]; - [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:) - forEventClass:kInternetEventClass andEventID:kAEGetURL]; -*/ - - processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents); -} - -void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) -{ - processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents); -} - -void QEventDispatcherMacPrivate::cancelWaitForMoreEvents() -{ - // In case the event dispatcher is waiting for more - // events somewhere, we post a dummy event to wake it up: - QMacCocoaAutoReleasePool pool; - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint - modifierFlags:0 timestamp:0. windowNumber:0 context:0 - subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO]; -} - -void QEventDispatcherMac::interrupt() -{ - Q_D(QEventDispatcherMac); - d->interrupt = true; - wakeUp(); - - // We do nothing more here than setting d->interrupt = true, and - // poke the event loop if it is sleeping. Actually stopping - // NSApp, or the current modal session, is done inside the send - // posted events callback. We do this to ensure that all current pending - // cocoa events gets delivered before we stop. Otherwise, if we now stop - // the last event loop recursion, cocoa will just drop pending posted - // events on the floor before we get a chance to reestablish a new session. - d->cancelWaitForMoreEvents(); -} - -QEventDispatcherMac::~QEventDispatcherMac() -{ - Q_D(QEventDispatcherMac); - //timer cleanup - MacTimerHash::iterator it = QEventDispatcherMacPrivate::macTimerHash.begin(); - while (it != QEventDispatcherMacPrivate::macTimerHash.end()) { - MacTimerInfo *t = it.value(); - if (t->runLoopTimer) { - CFRunLoopTimerInvalidate(t->runLoopTimer); - CFRelease(t->runLoopTimer); - } - delete t; - ++it; - } - QEventDispatcherMacPrivate::macTimerHash.clear(); - - // 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); - } - } - CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes); - CFRelease(d->postedEventsSource); - - CFRunLoopObserverInvalidate(d->waitingObserver); - CFRelease(d->waitingObserver); - - CFRunLoopObserverInvalidate(d->firstTimeObserver); - CFRelease(d->firstTimeObserver); -} - -QtMacInterruptDispatcherHelp* QtMacInterruptDispatcherHelp::instance = 0; - -QtMacInterruptDispatcherHelp::QtMacInterruptDispatcherHelp() : cancelled(false) -{ - // The whole point of this class is that we enable a way to interrupt - // the event dispatcher when returning back to a lower recursion level - // than where interruptLater was called. This is needed to detect if - // [NSApp run] should still be running at the recursion level it is at. - // Since the interrupt is canceled if processEvents is called before - // this object gets deleted, we also avoid interrupting unnecessary. - deleteLater(); -} - -QtMacInterruptDispatcherHelp::~QtMacInterruptDispatcherHelp() -{ - if (cancelled) - return; - instance = 0; - QEventDispatcherMac::instance()->interrupt(); -} - -void QtMacInterruptDispatcherHelp::cancelInterruptLater() -{ - if (!instance) - return; - instance->cancelled = true; - delete instance; - instance = 0; -} - -void QtMacInterruptDispatcherHelp::interruptLater() -{ - cancelInterruptLater(); - instance = new QtMacInterruptDispatcherHelp; -} - -QT_END_NAMESPACE - diff --git a/src/gui/kernel/qeventdispatcher_mac_p.h b/src/gui/kernel/qeventdispatcher_mac_p.h deleted file mode 100644 index 21a3830a43..0000000000 --- a/src/gui/kernel/qeventdispatcher_mac_p.h +++ /dev/null @@ -1,233 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/**************************************************************************** -** -** Copyright (c) 2007-2008, Apple, Inc. -** -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** -** * Redistributions of source code must retain the above copyright notice, -** this list of conditions and the following disclaimer. -** -** * Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation -** and/or other materials provided with the distribution. -** -** * Neither the name of Apple, Inc. nor the names of its contributors -** may be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -** -****************************************************************************/ - -#ifndef QEVENTDISPATCHER_MAC_P_H -#define QEVENTDISPATCHER_MAC_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/qwindowdefs.h> -#include <QtCore/qhash.h> -#include <QtCore/qstack.h> -#include "private/qabstracteventdispatcher_p.h" -#include <private/qeventdispatcher_qpa_p.h> -//#include "private/qt_mac_p.h" - -#include <CoreFoundation/CoreFoundation.h> - -QT_BEGIN_NAMESPACE - -typedef struct _NSModalSession *NSModalSession; -typedef struct _QCocoaModalSessionInfo { - QPointer<QWindow> window; - NSModalSession session; - void *nswindow; -} QCocoaModalSessionInfo; - -class Q_GUI_EXPORT QMacCocoaAutoReleasePool -{ -private: - void *pool; -public: - QMacCocoaAutoReleasePool(); - ~QMacCocoaAutoReleasePool(); - - inline void *handle() const { return pool; } -}; - -class QEventDispatcherMacPrivate; -class QEventDispatcherMac : public QEventDispatcherQPA -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QEventDispatcherMac) - -public: - QEventDispatcherMac(QAbstractEventDispatcherPrivate &priv, QObject *parent = 0); - explicit QEventDispatcherMac(QObject *parent = 0); - ~QEventDispatcherMac(); - - - bool processEvents(QEventLoop::ProcessEventsFlags flags); - bool hasPendingEvents(); - - void registerSocketNotifier(QSocketNotifier *notifier); - void unregisterSocketNotifier(QSocketNotifier *notifier); - - void registerTimer(int timerId, int interval, QObject *object); - bool unregisterTimer(int timerId); - bool unregisterTimers(QObject *object); - QList<TimerInfo> registeredTimers(QObject *object) const; - - void wakeUp(); - void interrupt(); - -private: - //friend void qt_mac_select_timer_callbk(__EventLoopTimer*, void*); - friend class QApplicationPrivate; -}; - -struct MacTimerInfo { - int id; - int interval; - QObject *obj; - bool pending; - CFRunLoopTimerRef runLoopTimer; - bool operator==(const MacTimerInfo &other) - { - return (id == other.id); - } -}; -typedef QHash<int, MacTimerInfo *> MacTimerHash; - -struct MacSocketInfo { - MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {} - CFSocketRef socket; - CFRunLoopSourceRef runloop; - QObject *readNotifier; - QObject *writeNotifier; -}; -typedef QHash<int, MacSocketInfo *> MacSocketHash; - -class QEventDispatcherMacPrivate : public QEventDispatcherQPAPrivate -{ - Q_DECLARE_PUBLIC(QEventDispatcherMac) - -public: - QEventDispatcherMacPrivate(); - - static MacTimerHash macTimerHash; - // Set 'blockSendPostedEvents' to true if you _really_ need - // to make sure that qt events are not posted while calling - // low-level cocoa functions (like beginModalForWindow). And - // use a QBoolBlocker to be safe: - static bool blockSendPostedEvents; - // The following variables help organizing modal sessions: - static QStack<QCocoaModalSessionInfo> cocoaModalSessionStack; - static bool currentExecIsNSAppRun; - static bool nsAppRunCalledByQt; - static bool cleanupModalSessionsNeeded; - static NSModalSession currentModalSessionCached; - static NSModalSession currentModalSession(); - static void updateChildrenWorksWhenModal(); - static void temporarilyStopAllModalSessions(); - static void beginModalSession(QWindow *widget); - static void endModalSession(QWindow *widget); - static void cancelWaitForMoreEvents(); - static void cleanupModalSessions(); - static void ensureNSAppInitialized(); - - MacSocketHash macSockets; - QList<void *> queuedUserInputEvents; // List of EventRef in Carbon, and NSEvent * in Cocoa - CFRunLoopSourceRef postedEventsSource; - CFRunLoopObserverRef waitingObserver; - CFRunLoopObserverRef firstTimeObserver; - QAtomicInt serialNumber; - int lastSerial; - static bool interrupt; -private: - static Boolean postedEventSourceEqualCallback(const void *info1, const void *info2); - static void postedEventsSourcePerformCallback(void *info); - static void activateTimer(CFRunLoopTimerRef, void *info); - static void waitingObserverCallback(CFRunLoopObserverRef observer, - CFRunLoopActivity activity, void *info); - static void firstLoopEntry(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); - friend void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents); -}; - -class QtMacInterruptDispatcherHelp : public QObject -{ - static QtMacInterruptDispatcherHelp *instance; - bool cancelled; - - QtMacInterruptDispatcherHelp(); - ~QtMacInterruptDispatcherHelp(); - - public: - static void interruptLater(); - static void cancelInterruptLater(); -}; - -QT_END_NAMESPACE - -#endif // QEVENTDISPATCHER_MAC_P_H diff --git a/src/gui/kernel/qeventdispatcher_qpa.cpp b/src/gui/kernel/qeventdispatcher_qpa.cpp deleted file mode 100644 index e850dda97b..0000000000 --- a/src/gui/kernel/qeventdispatcher_qpa.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qplatformdefs.h" -#include "qcoreapplication.h" -#include "qeventdispatcher_qpa_p.h" -#include "private/qguiapplication_p.h" - -#include <QWindowSystemInterface> -#include <QtCore/QElapsedTimer> -#include <QtCore/QAtomicInt> -#include <QtCore/QSemaphore> - -#include <QtCore/QDebug> - -#include <errno.h> - -QT_BEGIN_NAMESPACE - -QT_USE_NAMESPACE - -QEventDispatcherQPAPrivate::QEventDispatcherQPAPrivate() -{ - -} - -QEventDispatcherQPAPrivate::~QEventDispatcherQPAPrivate() -{ - -} - -QEventDispatcherQPA::QEventDispatcherQPA(QObject *parent) - : EVENTDISPATCHERBASE(*new QEventDispatcherQPAPrivate, parent) -{ } - -QEventDispatcherQPA::QEventDispatcherQPA(EVENTDISPATCHERBASEPRIVATE &priv, QObject *parent) - : EVENTDISPATCHERBASE(priv, parent) -{ } - - -QEventDispatcherQPA::~QEventDispatcherQPA() -{ } - -bool QEventDispatcherQPA::processEvents(QEventLoop::ProcessEventsFlags flags) -{ - Q_D(QEventDispatcherQPA); - - int nevents = 0; - - // handle gui and posted events - d->interrupt = false; - QCoreApplication::sendPostedEvents(); - - while (!d->interrupt) { // also flushes output buffer ###can be optimized - QWindowSystemInterfacePrivate::WindowSystemEvent *event; - if (!(flags & QEventLoop::ExcludeUserInputEvents) - && QWindowSystemInterfacePrivate::windowSystemEventsQueued() > 0) { - // process a pending user input event - event = QWindowSystemInterfacePrivate::getWindowSystemEvent(); - if (!event) - break; - } else { - break; - } - - if (filterEvent(event)) { - delete event; - continue; - } - nevents++; - - QGuiApplicationPrivate::processWindowSystemEvent(event); - delete event; - } - -#ifdef Q_OS_MAC // (inverted inheritance on mac: QEventDispatcherMac calls QEventDispatcherQPA) - if (!d->interrupt) { - if (EVENTDISPATCHERBASE::processEvents(flags)) { - EVENTDISPATCHERBASE::processEvents(flags); - return true; - } - } -#endif - return (nevents > 0); -} - -bool QEventDispatcherQPA::hasPendingEvents() -{ - extern uint qGlobalPostedEventsCount(); // from qapplication.cpp - return qGlobalPostedEventsCount() || QWindowSystemInterfacePrivate::windowSystemEventsQueued(); -} - -void QEventDispatcherQPA::flush() -{ - if(qApp) - qApp->sendPostedEvents(); -} - -QT_END_NAMESPACE diff --git a/src/gui/kernel/qeventdispatcher_qpa_p.h b/src/gui/kernel/qeventdispatcher_qpa_p.h deleted file mode 100644 index fde3e47262..0000000000 --- a/src/gui/kernel/qeventdispatcher_qpa_p.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEVENTDISPATCHER_QPA_P_H -#define QEVENTDISPATCHER_QPA_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qglobal.h> -#if defined(Q_OS_UNIX) -#include "private/qeventdispatcher_unix_p.h" -#define EVENTDISPATCHERBASE QEventDispatcherUNIX -#define EVENTDISPATCHERBASEPRIVATE QEventDispatcherUNIXPrivate -#elif defined(Q_OS_WIN) -#include "private/qeventdispatcher_win_p.h" -#define EVENTDISPATCHERBASE QEventDispatcherWin32 -#define EVENTDISPATCHERBASEPRIVATE QEventDispatcherWin32Private -#endif - -QT_BEGIN_NAMESPACE - -class QEventDispatcherQPAPrivate; - -class QEventDispatcherQPA : public EVENTDISPATCHERBASE -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QEventDispatcherQPA) - -public: - explicit QEventDispatcherQPA(QObject *parent = 0); - QEventDispatcherQPA(EVENTDISPATCHERBASEPRIVATE &priv, QObject *parent); - ~QEventDispatcherQPA(); - - bool processEvents(QEventLoop::ProcessEventsFlags flags); - bool hasPendingEvents(); - - void flush(); -}; - -class QEventDispatcherQPAPrivate : public EVENTDISPATCHERBASEPRIVATE -{ - Q_DECLARE_PUBLIC(QEventDispatcherQPA) -public: - QEventDispatcherQPAPrivate(); - ~QEventDispatcherQPAPrivate(); -}; - -QT_END_NAMESPACE - -#endif // QEVENTDISPATCHER_QPA_P_H diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 4e53973568..e3a2b5877d 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -46,14 +46,6 @@ #include "private/qevent_p.h" #include "qfont.h" -#if !defined(QT_NO_GLIB) -#include "qeventdispatcher_glib_qpa_p.h" -#endif -#include "qeventdispatcher_qpa_p.h" -#ifdef Q_OS_MAC -#include "qeventdispatcher_mac_p.h" -#endif - #include <QtCore/QAbstractEventDispatcher> #include <QtCore/private/qcoreapplication_p.h> #include <QtCore/private/qabstracteventdispatcher_p.h> @@ -240,24 +232,9 @@ static void init_plugins(const QList<QByteArray> &pluginList) } } -void QGuiApplicationPrivate::createEventDispatcher() -{ - Q_Q(QGuiApplication); -#if !defined(QT_NO_GLIB) && !defined(Q_OS_WIN) - if (qgetenv("QT_NO_GLIB").isEmpty() && QEventDispatcherGlib::versionSupported()) - eventDispatcher = new QPAEventDispatcherGlib(q); - else -#endif -#ifdef Q_OS_MAC - eventDispatcher = new QEventDispatcherMac(q); -#else - eventDispatcher = new QEventDispatcherQPA(q); -#endif -} - -void QGuiApplicationPrivate::init() +void QGuiApplicationPrivate::createPlatformIntegration() { - QList<QByteArray> pluginList; + // Load the platform integration QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH")); QByteArray platformName; #ifdef QT_QPA_DEFAULT_PLATFORM_NAME @@ -283,7 +260,45 @@ void QGuiApplicationPrivate::init() } else if (arg == "-platform") { if (++i < argc) platformName = argv[i]; - } else if (arg == "-plugin") { + } else { + argv[j++] = argv[i]; + } + } + + if (j < argc) { + argv[j] = 0; + argc = j; + } + + init_platform(QLatin1String(platformName), platformPluginPath); + +} + +void QGuiApplicationPrivate::createEventDispatcher() +{ + Q_Q(QGuiApplication); + + if (platform_integration == 0) + createPlatformIntegration(); + + eventDispatcher = platform_integration->createEventDispatcher(); + eventDispatcher->setParent(q); +} + +void QGuiApplicationPrivate::init() +{ + qDebug() << "QGuiApplicationPrivate::init"; + QList<QByteArray> pluginList; + // Get command line params + + int j = argc ? 1 : 0; + for (int i=1; i<argc; i++) { + if (argv[i] && *argv[i] != '-') { + argv[j++] = argv[i]; + continue; + } + QByteArray arg = argv[i]; + if (arg == "-plugin") { if (++i < argc) pluginList << argv[i]; } else if (arg == "-reverse") { @@ -299,14 +314,9 @@ void QGuiApplicationPrivate::init() argc = j; } -#if 0 - QByteArray pluginEnv = qgetenv("QT_QPA_PLUGINS"); - if (!pluginEnv.isEmpty()) { - pluginList.append(pluginEnv.split(';')); - } -#endif + if (platform_integration == 0) + createPlatformIntegration(); - init_platform(QLatin1String(platformName), platformPluginPath); init_plugins(pluginList); // Set up which span functions should be used in raster engine... diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index c80212f8f9..6d44caa35a 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -67,6 +67,7 @@ public: QGuiApplicationPrivate(int &argc, char **argv, int flags); ~QGuiApplicationPrivate(); + void createPlatformIntegration(); void createEventDispatcher(); virtual void notifyLayoutDirectionChange(); diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index fe90ce86aa..773f1a31f6 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -214,6 +214,13 @@ QPlatformGLContext *QPlatformIntegration::createPlatformGLContext(const QSurface QRect(x,y,width,height). */ +/*! + \fn QAbstractEventDispatcher *createEventDispatcher() const + + Factory function for the event dispatcher. The platform plugin + must create and and return a QAbstractEventDispatcher subclass when + this function is called. +*/ bool QPlatformIntegration::hasCapability(Capability cap) const { diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index c1934ec83a..23353b715c 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -63,6 +63,7 @@ class QPlatformPrinterSupport; class QPlatformDrag; class QPlatformGLContext; class QGuiGLFormat; +class QAbstractEventDispatcher; class Q_GUI_EXPORT QPlatformIntegration { @@ -88,6 +89,9 @@ public: virtual bool isVirtualDesktop() { return false; } virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const; +// Event dispatcher: + virtual QAbstractEventDispatcher *createEventDispatcher() const = 0; + //Deeper window system integrations virtual QPlatformFontDatabase *fontDatabase() const; #ifndef QT_NO_CLIPBOARD diff --git a/src/gui/kernel/qwindowsysteminterface_qpa_p.h b/src/gui/kernel/qwindowsysteminterface_qpa_p.h index 912ac877fb..5c9a6b06b2 100644 --- a/src/gui/kernel/qwindowsysteminterface_qpa_p.h +++ b/src/gui/kernel/qwindowsysteminterface_qpa_p.h @@ -47,7 +47,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QWindowSystemInterfacePrivate { +class Q_GUI_EXPORT QWindowSystemInterfacePrivate { public: enum EventType { Close, |