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 #ifndef QCORE_MAC_P_H
41 #define QCORE_MAC_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists for the convenience
48 // of other Qt classes.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include "private/qglobal_p.h"
55 
56 #include <QtCore/qoperatingsystemversion.h>
57 struct mach_header;
58 
59 #ifndef __IMAGECAPTURE__
60 #  define __IMAGECAPTURE__
61 #endif
62 
63 // --------------------------------------------------------------------------
64 
65 #if defined(QT_BOOTSTRAPPED)
66 #include <ApplicationServices/ApplicationServices.h>
67 #else
68 #include <CoreFoundation/CoreFoundation.h>
69 #endif
70 
71 #ifdef __OBJC__
72 #include <Foundation/Foundation.h>
73 #include <functional>
74 #endif
75 
76 #include "qstring.h"
77 #include "qscopedpointer.h"
78 #include "qpair.h"
79 
80 #if defined( __OBJC__) && defined(QT_NAMESPACE)
81 #define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__)
82 #else
83 #define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
84 #endif
85 
86 #define QT_MAC_WEAK_IMPORT(symbol) extern "C" decltype(symbol) symbol __attribute__((weak_import));
87 
88 QT_BEGIN_NAMESPACE
89 template <typename T, typename U, U (*RetainFunction)(U), void (*ReleaseFunction)(U)>
90 class QAppleRefCounted
91 {
92 public:
QAppleRefCounted()93     QAppleRefCounted() : value() {}
QAppleRefCounted(const T & t)94     QAppleRefCounted(const T &t) : value(t) {}
noexcept(std::is_nothrow_move_constructible<T>::value)95     QAppleRefCounted(T &&t) noexcept(std::is_nothrow_move_constructible<T>::value)
96         : value(std::move(t)) {}
97     QAppleRefCounted(QAppleRefCounted &&other)
noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value)98             noexcept(std::is_nothrow_move_assignable<T>::value &&
99                      std::is_nothrow_move_constructible<T>::value)
100         : value(qExchange(other.value, T())) {}
QAppleRefCounted(const QAppleRefCounted & other)101     QAppleRefCounted(const QAppleRefCounted &other) : value(other.value) { if (value) RetainFunction(value); }
~QAppleRefCounted()102     ~QAppleRefCounted() { if (value) ReleaseFunction(value); }
T()103     operator T() const { return value; }
swap(QAppleRefCounted & other)104     void swap(QAppleRefCounted &other) noexcept(noexcept(qSwap(value, other.value)))
105     { qSwap(value, other.value); }
106     QAppleRefCounted &operator=(const QAppleRefCounted &other)
107     { QAppleRefCounted copy(other); swap(copy); return *this; }
108     QAppleRefCounted &operator=(QAppleRefCounted &&other)
noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value)109         noexcept(std::is_nothrow_move_assignable<T>::value &&
110                  std::is_nothrow_move_constructible<T>::value)
111     { QAppleRefCounted moved(std::move(other)); swap(moved); return *this; }
112     T *operator&() { return &value; }
113 protected:
114     T value;
115 };
116 
117 
118 #ifdef Q_OS_MACOS
119 class QMacRootLevelAutoReleasePool
120 {
121 public:
122     QMacRootLevelAutoReleasePool();
123     ~QMacRootLevelAutoReleasePool();
124 private:
125     QScopedPointer<QMacAutoReleasePool> pool;
126 };
127 #endif
128 
129 /*
130     Helper class that automates refernce counting for CFtypes.
131     After constructing the QCFType object, it can be copied like a
132     value-based type.
133 
134     Note that you must own the object you are wrapping.
135     This is typically the case if you get the object from a Core
136     Foundation function with the word "Create" or "Copy" in it. If
137     you got the object from a "Get" function, either retain it or use
138     constructFromGet(). One exception to this rule is the
139     HIThemeGet*Shape functions, which in reality are "Copy" functions.
140 */
141 template <typename T>
142 class QCFType : public QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>
143 {
144     using Base = QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>;
145 public:
146     using Base::Base;
QCFType(CFTypeRef r)147     explicit QCFType(CFTypeRef r) : Base(static_cast<T>(r)) {}
as()148     template <typename X> X as() const { return reinterpret_cast<X>(this->value); }
constructFromGet(const T & t)149     static QCFType constructFromGet(const T &t)
150     {
151         if (t)
152             CFRetain(t);
153         return QCFType<T>(t);
154     }
155 };
156 
157 class Q_CORE_EXPORT QCFString : public QCFType<CFStringRef>
158 {
159 public:
160     using QCFType<CFStringRef>::QCFType;
QCFString(const QString & str)161     inline QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {}
162     inline QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {}
QCFString(const QCFType<CFStringRef> & other)163     inline QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {}
164     operator QString() const;
165     operator CFStringRef() const;
166 
167 private:
168     QString string;
169 };
170 
171 #ifdef Q_OS_MACOS
172 Q_CORE_EXPORT QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
173 Q_CORE_EXPORT Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
174 Q_CORE_EXPORT bool qt_mac_applicationIsInDarkMode();
175 #endif
176 
177 #ifndef QT_NO_DEBUG_STREAM
178 Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool);
179 Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string);
180 #endif
181 
182 Q_CORE_EXPORT bool qt_apple_isApplicationExtension();
183 
184 #if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED)
185 Q_CORE_EXPORT bool qt_apple_isSandboxed();
186 # ifdef __OBJC__
187 QT_END_NAMESPACE
188 @interface NSObject (QtSandboxHelpers)
189 - (id)qt_valueForPrivateKey:(NSString *)key;
190 @end
191 QT_BEGIN_NAMESPACE
192 # endif
193 #endif
194 
195 #if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
196 QT_END_NAMESPACE
197 # if defined(Q_OS_MACOS)
198 Q_FORWARD_DECLARE_OBJC_CLASS(NSApplication);
199 using AppleApplication = NSApplication;
200 # else
201 Q_FORWARD_DECLARE_OBJC_CLASS(UIApplication);
202 using AppleApplication = UIApplication;
203 # endif
204 QT_BEGIN_NAMESPACE
205 Q_CORE_EXPORT AppleApplication *qt_apple_sharedApplication();
206 #endif
207 
208 // --------------------------------------------------------------------------
209 
210 #if !defined(QT_BOOTSTRAPPED)
211 #define QT_USE_APPLE_UNIFIED_LOGGING
212 
213 QT_END_NAMESPACE
214 #include <os/log.h>
215 QT_BEGIN_NAMESPACE
216 
217 class Q_CORE_EXPORT AppleUnifiedLogger
218 {
219 public:
220     static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message,
221         const QString &subsystem = QString());
222     static bool willMirrorToStderr();
223 private:
224     static os_log_type_t logTypeForMessageType(QtMsgType msgType);
225     static os_log_t cachedLog(const QString &subsystem, const QString &category);
226 };
227 
228 #endif
229 
230 // --------------------------------------------------------------------------
231 
232 #if !defined(QT_BOOTSTRAPPED)
233 
234 QT_END_NAMESPACE
235 #include <os/activity.h>
236 QT_BEGIN_NAMESPACE
237 
238 template <typename T> using QAppleOsType = QAppleRefCounted<T, void *, os_retain, os_release>;
239 
240 class Q_CORE_EXPORT QAppleLogActivity
241 {
242 public:
QAppleLogActivity()243     QAppleLogActivity() : activity(nullptr) {}
QAppleLogActivity(os_activity_t activity)244     QAppleLogActivity(os_activity_t activity) : activity(activity) {}
~QAppleLogActivity()245     ~QAppleLogActivity() { if (activity) leave(); }
246 
247     QAppleLogActivity(const QAppleLogActivity &) = delete;
248     QAppleLogActivity& operator=(const QAppleLogActivity &) = delete;
249 
QAppleLogActivity(QAppleLogActivity && other)250     QAppleLogActivity(QAppleLogActivity&& other)
251         : activity(other.activity), state(other.state) { other.activity = nullptr; }
252 
253     QAppleLogActivity& operator=(QAppleLogActivity &&other)
254     {
255         if (this != &other) {
256             activity = other.activity;
257             state = other.state;
258             other.activity = nullptr;
259         }
260         return *this;
261     }
262 
enter()263     QAppleLogActivity&& enter()
264     {
265         if (activity)
266             os_activity_scope_enter(static_cast<os_activity_t>(*this), &state);
267         return std::move(*this);
268     }
269 
leave()270     void leave() {
271         if (activity)
272             os_activity_scope_leave(&state);
273     }
274 
os_activity_t()275     operator os_activity_t()
276     {
277         return reinterpret_cast<os_activity_t>(static_cast<void *>(activity));
278     }
279 
280 private:
281     // Work around API_AVAILABLE not working for templates by using void*
282     QAppleOsType<void *> activity;
283     os_activity_scope_state_s state;
284 };
285 
286 #define QT_APPLE_LOG_ACTIVITY_CREATE(condition, description, parent) []() { \
287         if (!(condition)) \
288             return QAppleLogActivity(); \
289         return QAppleLogActivity(os_activity_create(description, parent, OS_ACTIVITY_FLAG_DEFAULT)); \
290     }()
291 
292 #define QT_VA_ARGS_CHOOSE(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N
293 #define QT_VA_ARGS_COUNT(...) QT_VA_ARGS_CHOOSE(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)
294 
295 #define QT_OVERLOADED_MACRO(MACRO, ...) _QT_OVERLOADED_MACRO(MACRO, QT_VA_ARGS_COUNT(__VA_ARGS__))(__VA_ARGS__)
296 #define _QT_OVERLOADED_MACRO(MACRO, ARGC) _QT_OVERLOADED_MACRO_EXPAND(MACRO, ARGC)
297 #define _QT_OVERLOADED_MACRO_EXPAND(MACRO, ARGC) MACRO##ARGC
298 
299 #define QT_APPLE_LOG_ACTIVITY_WITH_PARENT3(condition, description, parent) QT_APPLE_LOG_ACTIVITY_CREATE(condition, description, parent)
300 #define QT_APPLE_LOG_ACTIVITY_WITH_PARENT2(description, parent) QT_APPLE_LOG_ACTIVITY_WITH_PARENT3(true, description, parent)
301 #define QT_APPLE_LOG_ACTIVITY_WITH_PARENT(...) QT_OVERLOADED_MACRO(QT_APPLE_LOG_ACTIVITY_WITH_PARENT, __VA_ARGS__)
302 
303 QT_MAC_WEAK_IMPORT(_os_activity_current);
304 #define QT_APPLE_LOG_ACTIVITY2(condition, description) QT_APPLE_LOG_ACTIVITY_CREATE(condition, description, OS_ACTIVITY_CURRENT)
305 #define QT_APPLE_LOG_ACTIVITY1(description) QT_APPLE_LOG_ACTIVITY2(true, description)
306 #define QT_APPLE_LOG_ACTIVITY(...) QT_OVERLOADED_MACRO(QT_APPLE_LOG_ACTIVITY, __VA_ARGS__)
307 
308 #define QT_APPLE_SCOPED_LOG_ACTIVITY(...) QAppleLogActivity scopedLogActivity = QT_APPLE_LOG_ACTIVITY(__VA_ARGS__).enter();
309 
310 #endif // !defined(QT_BOOTSTRAPPED)
311 
312 // -------------------------------------------------------------------------
313 
314 #if defined( __OBJC__)
315 class QMacNotificationObserver
316 {
317 public:
QMacNotificationObserver()318     QMacNotificationObserver() {}
319 
320     template<typename Functor>
QMacNotificationObserver(id object,NSNotificationName name,Functor callback)321     QMacNotificationObserver(id object, NSNotificationName name, Functor callback) {
322         observer = [[NSNotificationCenter defaultCenter] addObserverForName:name
323             object:object queue:nil usingBlock:^(NSNotification *) {
324                 callback();
325             }
326         ];
327     }
328 
329     QMacNotificationObserver(const QMacNotificationObserver& other) = delete;
QMacNotificationObserver(QMacNotificationObserver && other)330     QMacNotificationObserver(QMacNotificationObserver&& other) : observer(other.observer) {
331         other.observer = nil;
332     }
333 
334     QMacNotificationObserver &operator=(const QMacNotificationObserver& other) = delete;
335     QMacNotificationObserver &operator=(QMacNotificationObserver&& other) {
336         if (this != &other) {
337             remove();
338             observer = other.observer;
339             other.observer = nil;
340         }
341         return *this;
342     }
343 
remove()344     void remove() {
345         if (observer)
346             [[NSNotificationCenter defaultCenter] removeObserver:observer];
347         observer = nil;
348     }
~QMacNotificationObserver()349     ~QMacNotificationObserver() { remove(); }
350 
351 private:
352     id observer = nil;
353 };
354 
355 QT_END_NAMESPACE
356 @interface QT_MANGLE_NAMESPACE(KeyValueObserver) : NSObject
357 @end
358 QT_NAMESPACE_ALIAS_OBJC_CLASS(KeyValueObserver);
359 QT_BEGIN_NAMESPACE
360 
361 class Q_CORE_EXPORT QMacKeyValueObserver
362 {
363 public:
364     using Callback = std::function<void()>;
365 
QMacKeyValueObserver()366     QMacKeyValueObserver() {}
367 
368     // Note: QMacKeyValueObserver must not outlive the object observed!
369     QMacKeyValueObserver(id object, NSString *keyPath, Callback callback,
370         NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew)
object(object)371         : object(object), keyPath(keyPath), callback(new Callback(callback))
372     {
373         addObserver(options);
374     }
375 
QMacKeyValueObserver(const QMacKeyValueObserver & other)376     QMacKeyValueObserver(const QMacKeyValueObserver &other)
377          : QMacKeyValueObserver(other.object, other.keyPath, *other.callback.get()) {}
378 
QMacKeyValueObserver(QMacKeyValueObserver && other)379     QMacKeyValueObserver(QMacKeyValueObserver &&other) { swap(other, *this); }
380 
~QMacKeyValueObserver()381     ~QMacKeyValueObserver() { removeObserver(); }
382 
383     QMacKeyValueObserver &operator=(const QMacKeyValueObserver &other) {
384         QMacKeyValueObserver tmp(other);
385         swap(tmp, *this);
386         return *this;
387     }
388 
389     QMacKeyValueObserver &operator=(QMacKeyValueObserver &&other) {
390         QMacKeyValueObserver tmp(std::move(other));
391         swap(tmp, *this);
392         return *this;
393     }
394 
395     void removeObserver();
396 
397 private:
swap(QMacKeyValueObserver & first,QMacKeyValueObserver & second)398     void swap(QMacKeyValueObserver &first, QMacKeyValueObserver &second) {
399         std::swap(first.object, second.object);
400         std::swap(first.keyPath, second.keyPath);
401         std::swap(first.callback, second.callback);
402     }
403 
404     void addObserver(NSKeyValueObservingOptions options);
405 
406     id object = nil;
407     NSString *keyPath = nullptr;
408     std::unique_ptr<Callback> callback;
409 
410     static KeyValueObserver *observer;
411 };
412 #endif
413 
414 // -------------------------------------------------------------------------
415 
416 class Q_CORE_EXPORT QMacVersion
417 {
418 public:
419     enum VersionTarget {
420         ApplicationBinary,
421         QtLibraries
422     };
423 
424     static QOperatingSystemVersion buildSDK(VersionTarget target = ApplicationBinary);
425     static QOperatingSystemVersion deploymentTarget(VersionTarget target = ApplicationBinary);
426     static QOperatingSystemVersion currentRuntime();
427 
428 private:
429     QMacVersion() = default;
430     using VersionTuple = QPair<QOperatingSystemVersion, QOperatingSystemVersion>;
431     static VersionTuple versionsForImage(const mach_header *machHeader);
432     static VersionTuple applicationVersion();
433     static VersionTuple libraryVersion();
434 };
435 
436 // -------------------------------------------------------------------------
437 
438 QT_END_NAMESPACE
439 
440 #endif // QCORE_MAC_P_H
441