1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the QtCore module of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 ** packaging of this file. Please review the following information to 22 ** ensure the GNU Lesser General Public License version 3 requirements 23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 2.0 or (at your option) the GNU General 28 ** Public license version 3 or any later version approved by the KDE Free 29 ** Qt Foundation. The licenses are as published by the Free Software 30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 ** included in the packaging of this file. Please review the following 32 ** information to ensure the GNU General Public License requirements will 33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 ** https://www.gnu.org/licenses/gpl-3.0.html. 35 ** 36 ** $QT_END_LICENSE$ 37 ** 38 ****************************************************************************/ 39 40 /**************************************************************************** 41 ** 42 ** Copyright (c) 2007-2008, Apple, Inc. 43 ** 44 ** All rights reserved. 45 ** 46 ** Redistribution and use in source and binary forms, with or without 47 ** modification, are permitted provided that the following conditions are met: 48 ** 49 ** * Redistributions of source code must retain the above copyright notice, 50 ** this list of conditions and the following disclaimer. 51 ** 52 ** * Redistributions in binary form must reproduce the above copyright notice, 53 ** this list of conditions and the following disclaimer in the documentation 54 ** and/or other materials provided with the distribution. 55 ** 56 ** * Neither the name of Apple, Inc. nor the names of its contributors 57 ** may be used to endorse or promote products derived from this software 58 ** without specific prior written permission. 59 ** 60 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 61 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 62 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 63 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 64 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 65 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 66 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 67 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 68 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 69 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 70 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 71 ** 72 ****************************************************************************/ 73 74 #ifndef QEVENTDISPATCHER_CF_P_H 75 #define QEVENTDISPATCHER_CF_P_H 76 77 // 78 // W A R N I N G 79 // ------------- 80 // 81 // This file is not part of the Qt API. It exists purely as an 82 // implementation detail. This header file may change from version to 83 // version without notice, or even be removed. 84 // 85 // We mean it. 86 // 87 88 #include <QtCore/qabstracteventdispatcher.h> 89 #include <QtCore/private/qtimerinfo_unix_p.h> 90 #include <QtCore/private/qcfsocketnotifier_p.h> 91 #include <QtCore/private/qcore_mac_p.h> 92 #include <QtCore/qdebug.h> 93 #include <QtCore/qloggingcategory.h> 94 95 #include <CoreFoundation/CoreFoundation.h> 96 97 Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(RunLoopModeTracker)); 98 99 QT_BEGIN_NAMESPACE 100 101 namespace QtPrivate { 102 Q_CORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher); 103 Q_CORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcherTimers) 104 } 105 106 class QEventDispatcherCoreFoundation; 107 108 template <class T = QEventDispatcherCoreFoundation> 109 class RunLoopSource 110 { 111 public: 112 typedef bool (T::*CallbackFunction)(); 113 114 enum { kHighestPriority = 0 } RunLoopSourcePriority; 115 RunLoopSource(T * delegate,CallbackFunction callback)116 RunLoopSource(T *delegate, CallbackFunction callback) 117 : m_delegate(delegate), m_callback(callback) 118 { 119 CFRunLoopSourceContext context = {}; 120 context.info = this; 121 context.perform = RunLoopSource::process; 122 123 m_source = CFRunLoopSourceCreate(kCFAllocatorDefault, kHighestPriority, &context); 124 Q_ASSERT(m_source); 125 } 126 ~RunLoopSource()127 ~RunLoopSource() 128 { 129 CFRunLoopSourceInvalidate(m_source); 130 CFRelease(m_source); 131 } 132 133 void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) 134 { 135 if (!runLoop) 136 runLoop = CFRunLoopGetCurrent(); 137 138 CFRunLoopAddSource(runLoop, m_source, mode); 139 } 140 signal()141 void signal() { CFRunLoopSourceSignal(m_source); } 142 143 private: process(void * info)144 static void process(void *info) 145 { 146 RunLoopSource *self = static_cast<RunLoopSource *>(info); 147 ((self->m_delegate)->*(self->m_callback))(); 148 } 149 150 T *m_delegate; 151 CallbackFunction m_callback; 152 CFRunLoopSourceRef m_source; 153 }; 154 155 template <class T = QEventDispatcherCoreFoundation> 156 class RunLoopObserver 157 { 158 public: 159 typedef void (T::*CallbackFunction) (CFRunLoopActivity activity); 160 RunLoopObserver(T * delegate,CallbackFunction callback,CFOptionFlags activities)161 RunLoopObserver(T *delegate, CallbackFunction callback, CFOptionFlags activities) 162 : m_delegate(delegate), m_callback(callback) 163 { 164 CFRunLoopObserverContext context = {}; 165 context.info = this; 166 167 m_observer = CFRunLoopObserverCreate(kCFAllocatorDefault, activities, true, 0, process, &context); 168 Q_ASSERT(m_observer); 169 } 170 ~RunLoopObserver()171 ~RunLoopObserver() 172 { 173 CFRunLoopObserverInvalidate(m_observer); 174 CFRelease(m_observer); 175 } 176 177 void addToMode(CFStringRef mode, CFRunLoopRef runLoop = 0) 178 { 179 if (!runLoop) 180 runLoop = CFRunLoopGetCurrent(); 181 182 if (!CFRunLoopContainsObserver(runLoop, m_observer, mode)) 183 CFRunLoopAddObserver(runLoop, m_observer, mode); 184 } 185 186 void removeFromMode(CFStringRef mode, CFRunLoopRef runLoop = 0) 187 { 188 if (!runLoop) 189 runLoop = CFRunLoopGetCurrent(); 190 191 if (CFRunLoopContainsObserver(runLoop, m_observer, mode)) 192 CFRunLoopRemoveObserver(runLoop, m_observer, mode); 193 } 194 195 private: process(CFRunLoopObserverRef,CFRunLoopActivity activity,void * info)196 static void process(CFRunLoopObserverRef, CFRunLoopActivity activity, void *info) 197 { 198 RunLoopObserver *self = static_cast<RunLoopObserver *>(info); 199 ((self->m_delegate)->*(self->m_callback))(activity); 200 } 201 202 T *m_delegate; 203 CallbackFunction m_callback; 204 CFRunLoopObserverRef m_observer; 205 }; 206 207 class Q_CORE_EXPORT QEventDispatcherCoreFoundation : public QAbstractEventDispatcher 208 { 209 Q_OBJECT 210 211 public: 212 explicit QEventDispatcherCoreFoundation(QObject *parent = 0); 213 void startingUp() override; 214 ~QEventDispatcherCoreFoundation(); 215 216 bool processEvents(QEventLoop::ProcessEventsFlags flags) override; 217 bool hasPendingEvents() override; 218 219 void registerSocketNotifier(QSocketNotifier *notifier) override; 220 void unregisterSocketNotifier(QSocketNotifier *notifier) override; 221 222 void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) override; 223 bool unregisterTimer(int timerId) override; 224 bool unregisterTimers(QObject *object) override; 225 QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const override; 226 227 int remainingTime(int timerId) override; 228 229 void wakeUp() override; 230 void interrupt() override; 231 void flush() override; 232 233 protected: 234 QEventLoop *currentEventLoop() const; 235 236 virtual bool processPostedEvents(); 237 238 struct ProcessEventsState 239 { ProcessEventsStateProcessEventsState240 ProcessEventsState(QEventLoop::ProcessEventsFlags f) 241 : flags(f), wasInterrupted(false) 242 , processedPostedEvents(false), processedTimers(false) 243 , deferredWakeUp(false), deferredUpdateTimers(false) {} 244 245 QAtomicInt flags; 246 QAtomicInteger<char> wasInterrupted; 247 QAtomicInteger<char> processedPostedEvents; 248 QAtomicInteger<char> processedTimers; 249 QAtomicInteger<char> deferredWakeUp; 250 bool deferredUpdateTimers; 251 }; 252 253 ProcessEventsState m_processEvents; 254 255 private: 256 RunLoopSource<> m_postedEventsRunLoopSource; 257 RunLoopObserver<> m_runLoopActivityObserver; 258 259 QT_MANGLE_NAMESPACE(RunLoopModeTracker) *m_runLoopModeTracker; 260 261 QTimerInfoList m_timerInfoList; 262 CFRunLoopTimerRef m_runLoopTimer; 263 CFRunLoopTimerRef m_blockedRunLoopTimer; 264 QCFType<CFRunLoopRef> m_runLoop; 265 bool m_overdueTimerScheduled; 266 267 QCFSocketNotifier m_cfSocketNotifier; 268 269 void processTimers(CFRunLoopTimerRef); 270 271 void handleRunLoopActivity(CFRunLoopActivity activity); 272 273 void updateTimers(); 274 void invalidateTimer(); 275 }; 276 277 QT_END_NAMESPACE 278 279 #endif // QEVENTDISPATCHER_CF_P_H 280