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