Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #ifndef QCORE_MAC_P_H
++ #define QCORE_MAC_P_H
++
++ //
++ // W A R N I N G
++ // -------------
++ //
++ // This file is not part of the Qt API. It exists for the convenience
++ // of other Qt classes. This header file may change from version to
++ // version without notice, or even be removed.
++ //
++ // We mean it.
++ //
++
++ #include "private/qglobal_p.h"
++
++ #include <QtCore/qoperatingsystemversion.h>
++
++ #include <optional>
++
++ #ifdef Q_OS_MACOS
++ #include <mach/port.h>
++ struct mach_header;
++ typedef int kern_return_t;
++ typedef mach_port_t io_object_t;
++ extern "C" {
++ kern_return_t IOObjectRetain(io_object_t object);
++ kern_return_t IOObjectRelease(io_object_t object);
++ }
++ #endif
++
++ #ifndef __IMAGECAPTURE__
++ # define __IMAGECAPTURE__
++ #endif
++
++ // --------------------------------------------------------------------------
++
++ #if defined(QT_BOOTSTRAPPED)
++ #include <ApplicationServices/ApplicationServices.h>
++ #else
++ #include <CoreFoundation/CoreFoundation.h>
++ #endif
++
++ #ifdef __OBJC__
++ #include <Foundation/Foundation.h>
++ #include <functional>
++ #endif
++
++ #include "qstring.h"
++ #include "qpair.h"
++
++ #if defined( __OBJC__) && defined(QT_NAMESPACE)
++ #define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__)
++ #else
++ #define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
++ #endif
++
++ #define QT_MAC_WEAK_IMPORT(symbol) extern "C" decltype(symbol) symbol __attribute__((weak_import));
++
++ #if defined(__OBJC__)
++ #define QT_DECLARE_NAMESPACED_OBJC_INTERFACE(classname, definition) \
++ @interface QT_MANGLE_NAMESPACE(classname) : \
++ definition \
++ @end \
++ QT_NAMESPACE_ALIAS_OBJC_CLASS(classname);
++ #else
++ #define QT_DECLARE_NAMESPACED_OBJC_INTERFACE(classname, definition) \
++ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(classname)); \
++ using classname = QT_MANGLE_NAMESPACE(classname);
++ #endif
++
++ #define QT_FORWARD_DECLARE_OBJC_ENUM(name, type) \
++ typedef type name;
++
++ Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
++ Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
++ Q_FORWARD_DECLARE_OBJC_CLASS(UTType);
++
++ struct CGPoint;
++ struct CGSize;
++ struct CGRect;
++ #if defined(Q_OS_MACOS)
++ struct NSEdgeInsets;
++ #else
++ struct UIEdgeInsets;
++ #endif
++
++ // @compatibility_alias doesn't work with categories or their methods
++ #define QtExtras QT_MANGLE_NAMESPACE(QtExtras)
++
++ QT_BEGIN_NAMESPACE
++ template <typename T, typename U, auto RetainFunction, auto ReleaseFunction>
++ class QAppleRefCounted
++ {
++ public:
++ Q_NODISCARD_CTOR QAppleRefCounted() : value() {}
++ Q_NODISCARD_CTOR QAppleRefCounted(const T &t) : value(t) {}
++ Q_NODISCARD_CTOR QAppleRefCounted(T &&t)
++ noexcept(std::is_nothrow_move_constructible<T>::value)
++ : value(std::move(t)) {}
++ Q_NODISCARD_CTOR QAppleRefCounted(QAppleRefCounted &&other)
++ noexcept(std::is_nothrow_move_assignable<T>::value &&
++ std::is_nothrow_move_constructible<T>::value)
++ : value(std::exchange(other.value, T())) {}
++ Q_NODISCARD_CTOR QAppleRefCounted(const QAppleRefCounted &other)
++ : value(other.value)
++ { if (value) RetainFunction(value); }
++ ~QAppleRefCounted() { if (value) ReleaseFunction(value); }
++ operator T() const { return value; }
++ void swap(QAppleRefCounted &other) noexcept(noexcept(qSwap(value, other.value)))
++ { qSwap(value, other.value); }
++ QAppleRefCounted &operator=(const QAppleRefCounted &other)
++ { QAppleRefCounted copy(other); swap(copy); return *this; }
++ QAppleRefCounted &operator=(QAppleRefCounted &&other)
++ noexcept(std::is_nothrow_move_assignable<T>::value &&
++ std::is_nothrow_move_constructible<T>::value)
++ { QAppleRefCounted moved(std::move(other)); swap(moved); return *this; }
++ T *operator&() { return &value; }
++ protected:
++ T value;
++ };
++
++ class QMacAutoReleasePool
++ {
++ public:
++ Q_NODISCARD_CTOR Q_CORE_EXPORT QMacAutoReleasePool();
++ Q_CORE_EXPORT ~QMacAutoReleasePool();
++ private:
++ Q_DISABLE_COPY(QMacAutoReleasePool)
++ void *pool;
++ };
++
++ #ifdef Q_OS_MACOS
++ class QMacRootLevelAutoReleasePool
++ {
++ public:
++ Q_NODISCARD_CTOR QMacRootLevelAutoReleasePool();
++ ~QMacRootLevelAutoReleasePool();
++ private:
++ std::optional<QMacAutoReleasePool> pool = std::nullopt;
++ };
++ #endif
++
++ /*
++ Helper class that automates reference counting for CFtypes.
++ After constructing the QCFType object, it can be copied like a
++ value-based type.
++
++ Note that you must own the object you are wrapping.
++ This is typically the case if you get the object from a Core
++ Foundation function with the word "Create" or "Copy" in it. If
++ you got the object from a "Get" function, either retain it or use
++ constructFromGet(). One exception to this rule is the
++ HIThemeGet*Shape functions, which in reality are "Copy" functions.
++ */
++ template <typename T>
++ class QCFType : public QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>
++ {
++ using Base = QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>;
++ public:
++ using Base::Base;
++ Q_NODISCARD_CTOR explicit QCFType(CFTypeRef r) : Base(static_cast<T>(r)) {}
++ template <typename X> X as() const { return reinterpret_cast<X>(this->value); }
++ static QCFType constructFromGet(const T &t)
++ {
++ if (t)
++ CFRetain(t);
++ return QCFType<T>(t);
++ }
++ };
++
++ #ifdef Q_OS_MACOS
++ template <typename T>
++ class QIOType : public QAppleRefCounted<T, io_object_t, IOObjectRetain, IOObjectRelease>
++ {
++ using QAppleRefCounted<T, io_object_t, IOObjectRetain, IOObjectRelease>::QAppleRefCounted;
++ };
++ #endif
++
++ class QCFString : public QCFType<CFStringRef>
++ {
++ public:
++ using QCFType<CFStringRef>::QCFType;
++ Q_NODISCARD_CTOR QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {}
++ Q_NODISCARD_CTOR QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {}
++ Q_NODISCARD_CTOR QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {}
++ Q_CORE_EXPORT operator QString() const;
++ Q_CORE_EXPORT operator CFStringRef() const;
++
++ private:
++ QString string;
++ };
++
++ class Q_CORE_EXPORT QObjCWeakPointerBase
++ {
++ public:
++ QObjCWeakPointerBase(NSObject *object = nil);
++ QObjCWeakPointerBase(const QObjCWeakPointerBase &other);
++ QObjCWeakPointerBase &operator=(const QObjCWeakPointerBase &other);
++
++ protected:
++ ~QObjCWeakPointerBase();
++ NSObject *get() const;
++ union {
++ NSObject *m_object = nil;
++ #if __has_feature(objc_arc_weak) && __has_feature(objc_arc_fields)
++ // Used by qcore_mac.mm, built with -fobjc-weak, to track lifetime
++ __weak id m_weakReference;
++ #endif
++ };
++ };
++
++ template <typename T>
++ class QObjCWeakPointer : public QObjCWeakPointerBase
++ {
++ public:
++ using QObjCWeakPointerBase::QObjCWeakPointerBase;
++ operator T*() const { return static_cast<T*>(get()); }
++ };
++
++ // -------------------------------------------------------------------------
++
++ #ifdef Q_OS_MACOS
++ Q_CORE_EXPORT bool qt_mac_runningUnderRosetta();
++ Q_CORE_EXPORT std::optional<uint32_t> qt_mac_sipConfiguration();
++ Q_CORE_EXPORT bool qt_mac_processHasEntitlement(const QString &entitlement);
++ #ifdef QT_BUILD_INTERNAL
++ Q_AUTOTEST_EXPORT void qt_mac_ensureResponsible();
++ #endif
++ #endif
++
++ #ifndef QT_NO_DEBUG_STREAM
++ Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool);
++ Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string);
++ Q_CORE_EXPORT QDebug operator<<(QDebug, CGPoint);
++ Q_CORE_EXPORT QDebug operator<<(QDebug, CGSize);
++ Q_CORE_EXPORT QDebug operator<<(QDebug, CGRect);
++ #if defined(Q_OS_MACOS)
++ Q_CORE_EXPORT QDebug operator<<(QDebug, NSEdgeInsets);
++ #else
++ Q_CORE_EXPORT QDebug operator<<(QDebug, UIEdgeInsets);
++ #endif
++ #endif
++
++ Q_CORE_EXPORT bool qt_apple_isApplicationExtension();
++ Q_CORE_EXPORT bool qt_apple_runningWithLiquidGlass();
++ Q_CORE_EXPORT std::optional<UTType *> qt_apple_bundleType(const QString &path);
++
++ #if !defined(QT_BOOTSTRAPPED)
++ Q_CORE_EXPORT bool qt_apple_isSandboxed();
++
++ #if defined(__OBJC__)
++ QT_END_NAMESPACE
++ @interface NSObject (QtExtras)
++ - (id)qt_valueForPrivateKey:(NSString *)key;
++ @end
++ QT_BEGIN_NAMESPACE
++ #endif
++ #endif // !QT_BOOTSTRAPPED
++
++ #if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
++ QT_END_NAMESPACE
++ # if defined(Q_OS_MACOS)
++ Q_FORWARD_DECLARE_OBJC_CLASS(NSApplication);
++ using AppleApplication = NSApplication;
++ # else
++ Q_FORWARD_DECLARE_OBJC_CLASS(UIApplication);
++ using AppleApplication = UIApplication;
++ # endif
++ QT_BEGIN_NAMESPACE
++ Q_CORE_EXPORT AppleApplication *qt_apple_sharedApplication();
++ #endif
++
++ // --------------------------------------------------------------------------
++
++ #if !defined(QT_BOOTSTRAPPED)
++ #define QT_USE_APPLE_UNIFIED_LOGGING
++
++ QT_END_NAMESPACE
++ #include <os/log.h>
++ QT_BEGIN_NAMESPACE
++
++ class Q_CORE_EXPORT AppleUnifiedLogger
++ {
++ public:
++ static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context,
++ const QString &message)
++ { return messageHandler(msgType, context, message, QString()); }
++ static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context,
++ const QString &message, const QString &subsystem);
++ static bool preventsStderrLogging();
++ private:
++ static os_log_type_t logTypeForMessageType(QtMsgType msgType);
++ static os_log_t cachedLog(const QString &subsystem, const QString &category);
++ };
++
++ #endif
++
++ // --------------------------------------------------------------------------
++
++ #if !defined(QT_BOOTSTRAPPED) && !__has_feature(objc_arc)
++
++ QT_END_NAMESPACE
++ #include <os/activity.h>
++ QT_BEGIN_NAMESPACE
++
++ template <typename T> using QAppleOsType = QAppleRefCounted<T, void *, os_retain, os_release>;
++
++ class Q_CORE_EXPORT QAppleLogActivity
++ {
++ public:
++ QAppleLogActivity() : activity(nullptr) {}
++ QAppleLogActivity(os_activity_t activity) : activity(activity) {}
++ ~QAppleLogActivity() { if (activity) leave(); }
++
++ Q_DISABLE_COPY(QAppleLogActivity)
++
++ QAppleLogActivity(QAppleLogActivity &&other)
++ : activity(std::exchange(other.activity, nullptr)), state(other.state)
++ {
++ }
++
++ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QAppleLogActivity)
++
++ QAppleLogActivity &&enter()
++ {
++ if (activity)
++ os_activity_scope_enter(static_cast<os_activity_t>(*this), &state);
++ return std::move(*this);
++ }
++
++ void leave()
++ {
++ if (activity)
++ os_activity_scope_leave(&state);
++ }
++
++ operator os_activity_t()
++ {
++ return reinterpret_cast<os_activity_t>(static_cast<void *>(activity));
++ }
++
++ void swap(QAppleLogActivity &other)
++ {
++ activity.swap(other.activity);
++ std::swap(state, other.state);
++ }
++
++ private:
++ // Work around API_AVAILABLE not working for templates by using void*
++ QAppleOsType<void *> activity;
++ os_activity_scope_state_s state;
++ };
++
++ #define QT_APPLE_LOG_ACTIVITY_CREATE(condition, description, parent) []() { \
++ if (!(condition)) \
++ return QAppleLogActivity(); \
++ return QAppleLogActivity(os_activity_create(description, parent, OS_ACTIVITY_FLAG_DEFAULT)); \
++ }()
++
++ #define QT_APPLE_LOG_ACTIVITY_WITH_PARENT_3(condition, description, parent) QT_APPLE_LOG_ACTIVITY_CREATE(condition, description, parent)
++ #define QT_APPLE_LOG_ACTIVITY_WITH_PARENT_2(description, parent) QT_APPLE_LOG_ACTIVITY_WITH_PARENT_3(true, description, parent)
++ #define QT_APPLE_LOG_ACTIVITY_WITH_PARENT(...) QT_OVERLOADED_MACRO(QT_APPLE_LOG_ACTIVITY_WITH_PARENT, __VA_ARGS__)
++
++ QT_MAC_WEAK_IMPORT(_os_activity_current);
++ #define QT_APPLE_LOG_ACTIVITY_2(condition, description) QT_APPLE_LOG_ACTIVITY_CREATE(condition, description, OS_ACTIVITY_CURRENT)
++ #define QT_APPLE_LOG_ACTIVITY_1(description) QT_APPLE_LOG_ACTIVITY_2(true, description)
++ #define QT_APPLE_LOG_ACTIVITY(...) QT_OVERLOADED_MACRO(QT_APPLE_LOG_ACTIVITY, __VA_ARGS__)
++
++ #define QT_APPLE_SCOPED_LOG_ACTIVITY(...) QAppleLogActivity scopedLogActivity = QT_APPLE_LOG_ACTIVITY(__VA_ARGS__).enter();
++
++ #endif // !defined(QT_BOOTSTRAPPED) && !__has_feature(objc_arc)
++
++ // -------------------------------------------------------------------------
++
++ class Q_CORE_EXPORT QMacNotificationObserver
++ {
++ public:
++ QMacNotificationObserver() {}
++
++ #if defined( __OBJC__)
++ template<typename Functor>
++ QMacNotificationObserver(NSObject *object, NSNotificationName name, Functor callback) {
++ observer = [[NSNotificationCenter defaultCenter] addObserverForName:name
++ object:object queue:nil usingBlock:^(NSNotification *notification) {
++ if constexpr (std::is_invocable_v<Functor, NSNotification *>)
++ callback(notification);
++ else
++ callback();
++ }
++ ];
++ }
++ #endif
++
++ QMacNotificationObserver(const QMacNotificationObserver &other) = delete;
++ QMacNotificationObserver(QMacNotificationObserver &&other)
++ : observer(std::exchange(other.observer, nullptr))
++ {
++ }
++
++ QMacNotificationObserver &operator=(const QMacNotificationObserver &other) = delete;
++ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QMacNotificationObserver)
++
++ void swap(QMacNotificationObserver &other) noexcept
++ {
++ std::swap(observer, other.observer);
++ }
++
++ void remove();
++ ~QMacNotificationObserver() { remove(); }
++
++ private:
++ NSObject *observer = nullptr;
++ };
++
++ QT_END_NAMESPACE
++ QT_DECLARE_NAMESPACED_OBJC_INTERFACE(KeyValueObserver, NSObject)
++ QT_BEGIN_NAMESPACE
++
++ class Q_CORE_EXPORT QMacKeyValueObserver
++ {
++ public:
++ using Callback = std::function<void()>;
++
++ QMacKeyValueObserver() = default;
++
++ #if defined( __OBJC__)
++ QMacKeyValueObserver(NSObject *object, NSString *keyPath, Callback callback,
++ NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew)
++ : object(object), keyPath(keyPath), callback(new Callback(callback))
++ {
++ addObserver(options);
++ }
++ #endif
++
++ QMacKeyValueObserver(const QMacKeyValueObserver &other);
++
++ QMacKeyValueObserver(QMacKeyValueObserver &&other) noexcept { swap(other); }
++
++ ~QMacKeyValueObserver() { removeObserver(); }
++
++ QMacKeyValueObserver &operator=(const QMacKeyValueObserver &other)
++ {
++ QMacKeyValueObserver tmp(other);
++ swap(tmp);
++ return *this;
++ }
++
++ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QMacKeyValueObserver)
++
++ void removeObserver();
++
++ void swap(QMacKeyValueObserver &other) noexcept
++ {
++ std::swap(object, other.object);
++ std::swap(keyPath, other.keyPath);
++ callback.swap(other.callback);
++ }
++
++ private:
++ #if defined( __OBJC__)
++ void addObserver(NSKeyValueObservingOptions options);
++ #endif
++
++ QObjCWeakPointer<NSObject> object;
++ NSString *keyPath = nullptr;
++ std::unique_ptr<Callback> callback;
++
++ static KeyValueObserver *observer;
++ };
++
++ // -------------------------------------------------------------------------
++
++ class Q_CORE_EXPORT QMacVersion
++ {
++ public:
++ enum VersionTarget {
++ ApplicationBinary,
++ QtLibraries
++ };
++
++ static QOperatingSystemVersion buildSDK(VersionTarget target = ApplicationBinary);
++ static QOperatingSystemVersion deploymentTarget(VersionTarget target = ApplicationBinary);
++ static QOperatingSystemVersion currentRuntime();
++
++ private:
++ QMacVersion() = default;
++ using VersionTuple = std::pair<QOperatingSystemVersion, QOperatingSystemVersion>;
++ static VersionTuple versionsForImage(const mach_header *machHeader);
++ static VersionTuple applicationVersion();
++ static VersionTuple libraryVersion();
++ };
++
++ // -------------------------------------------------------------------------
++
++ #ifdef __OBJC__
++ template <typename T>
++ typename std::enable_if<std::is_pointer<T>::value, T>::type
++ qt_objc_cast(id object)
++ {
++ if ([object isKindOfClass:[typename std::remove_pointer<T>::type class]])
++ return static_cast<T>(object);
++
++ return nil;
++ }
++ #endif
++
++ // -------------------------------------------------------------------------
++
++ QT_END_NAMESPACE
++
++ #endif // QCORE_MAC_P_H