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