5#include <private/qcore_mac_p.h>
11#if defined(QT_PLATFORM_UIKIT)
12#include <UIKit/UIKit.h>
19#include <objc/runtime.h>
20#include <mach-o/dyld.h>
21#include <sys/sysctl.h>
30#include "private/qlocking_p.h"
32#if !defined(QT_BOOTSTRAPPED)
36#if !defined(QT_APPLE_NO_PRIVATE_APIS)
41#ifdef QT_BUILD_INTERNAL
42int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t
attrs,
int disclaim)
43__attribute__((availability(macos,introduced=10.14),weak_import));
44pid_t responsibility_get_pid_responsible_for_pid(pid_t)
__attribute__((weak_import));
55#if defined(Q_OS_MACOS)
56static void initializeStandardUserDefaults()
65 Q_UNUSED(NSUserDefaults.standardUserDefaults);
74 if (
string.isEmpty() &&
value)
75 const_cast<QCFString*
>(
this)->
string = QString::fromCFString(
value);
79QCFString::operator CFStringRef()
const
88#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
118 return willMirror || disableStderr;
125 QString subsystem = optionalSubsystem;
126 if (subsystem.isNull()) {
127 static QString bundleIdentifier = []() {
128 if (CFBundleRef bundle = CFBundleGetMainBundle()) {
129 if (CFStringRef identifier = CFBundleGetIdentifier(bundle))
130 return QString::fromCFString(identifier);
134 subsystem = bundleIdentifier;
137 const bool isDefault = !
context.category || !strcmp(
context.category,
"default");
138 os_log_t log = isDefault ? OS_LOG_DEFAULT :
139 os_log_create(subsystem.toLatin1().constData(),
context.category);
140 os_log_type_t logType = logTypeForMessageType(msgType);
142 if (!os_log_type_enabled(log, logType))
162os_log_type_t AppleUnifiedLogger::logTypeForMessageType(
QtMsgType msgType)
172 return OS_LOG_TYPE_DEFAULT;
187 for (Class cls = object_getClass(
obj); cls; cls = class_getSuperclass(cls)) {
188 if (cls == NSObject.class) {
189 dbg << static_cast<NSObject*>(
obj);
196 dbg.nospace() <<
'<' << object_getClassName(
obj) <<
": " <<
static_cast<void*
>(
obj) <<
'>';
202 return dbg << (nsObject ?
203 dbg.verbosity() > 2 ?
204 nsObject.debugDescription.UTF8String :
205 nsObject.description.UTF8String
212 return dbg <<
"CFStringRef(0x0)";
214 if (
const UniChar *chars = CFStringGetCharactersPtr(stringRef))
215 dbg << QStringView(reinterpret_cast<const QChar *>(chars), CFStringGetLength(stringRef));
217 dbg << QString::fromCFString(stringRef);
224#define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
225 __attribute__((weak)) Q_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType)
238@interface QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) : NSObject
241@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker)
263 if (!debugAutoReleasePools)
266 Class trackerClass = [QMacAutoReleasePoolTracker class];
268 void *poolFrame =
nullptr;
270 if (backtrace_from_fp(__builtin_frame_address(0), frames, 2))
271 poolFrame = frames[1];
275 if (dladdr(poolFrame, &
info) &&
info.dli_sname) {
276 const char *symbolName =
info.dli_sname;
277 if (symbolName[0] ==
'_') {
279 if (
char *demangled = abi::__cxa_demangle(
info.dli_sname,
nullptr, 0, &status))
280 symbolName = demangled;
284 asprintf(&
className,
" ^-- allocated in function: %s", symbolName);
286 if (Class existingClass = objc_getClass(
className))
287 trackerClass = existingClass;
289 trackerClass = objc_duplicateClass(trackerClass,
className, 0);
293 if (symbolName !=
info.dli_sname)
294 free((
char*)symbolName);
298 [[trackerClass new] autorelease];
307#ifndef QT_NO_DEBUG_STREAM
312 debug <<
"QMacAutoReleasePool(" << (
const void *)
pool <<
')';
318 debug << static_cast<QString>(
string);
324bool qt_mac_applicationIsInDarkMode()
326 auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
327 @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
328 return [appearance isEqualToString:NSAppearanceNameDarkAqua];
331bool qt_mac_runningUnderRosetta()
334 auto size =
sizeof(translated);
335 if (sysctlbyname(
"sysctl.proc_translated", &translated, &
size,
nullptr, 0) == 0)
340std::optional<uint32_t> qt_mac_sipConfiguration()
342 static auto configuration = []() -> std::optional<uint32_t> {
343#if !defined(QT_APPLE_NO_PRIVATE_APIS)
349 QIOType<io_registry_entry_t> nvram = IORegistryEntryFromPath(kIOMainPortDefault,
"IODeviceTree:/options");
351 qWarning(
"Failed to locate NVRAM entry in IO registry");
355 QCFType<CFTypeRef> csrConfig = IORegistryEntryCreateCFProperty(nvram,
356 CFSTR(
"csr-active-config"), kCFAllocatorDefault, IOOptionBits{});
360 if (
auto type = CFGetTypeID(csrConfig);
type != CFDataGetTypeID()) {
361 qWarning() <<
"Unexpected SIP config type" << CFCopyTypeIDDescription(
type);
365 QByteArray data = QByteArray::fromRawCFData(csrConfig.as<CFDataRef>());
366 if (
data.size() !=
sizeof(uint32_t)) {
367 qWarning() <<
"Unexpected SIP config size" <<
data.size();
371 return qFromLittleEndian<uint32_t>(
data.constData());
373 return configuration;
376#define CHECK_SPAWN(expr) \
377 if (int err = (expr)) { \
378 posix_spawnattr_destroy(&attr); \
382#ifdef QT_BUILD_INTERNAL
383void qt_mac_ensureResponsible()
385#if !defined(QT_APPLE_NO_PRIVATE_APIS)
386 if (!responsibility_get_pid_responsible_for_pid || !responsibility_spawnattrs_setdisclaim)
390 if (responsibility_get_pid_responsible_for_pid(pid) == pid)
393 posix_spawnattr_t attr = {};
394 CHECK_SPAWN(posix_spawnattr_init(&attr));
397 short flags = POSIX_SPAWN_SETEXEC;
401 sigemptyset(&no_signals);
402 CHECK_SPAWN(posix_spawnattr_setsigmask(&attr, &no_signals));
403 flags |= POSIX_SPAWN_SETSIGMASK;
406 sigset_t all_signals;
407 sigfillset(&all_signals);
408 CHECK_SPAWN(posix_spawnattr_setsigdefault(&attr, &all_signals));
409 flags |= POSIX_SPAWN_SETSIGDEF;
411 CHECK_SPAWN(posix_spawnattr_setflags(&attr,
flags));
413 CHECK_SPAWN(responsibility_spawnattrs_setdisclaim(&attr, 1));
415 char **argv = *_NSGetArgv();
416 posix_spawnp(&pid, argv[0],
nullptr, &attr, argv,
environ);
417 posix_spawnattr_destroy(&attr);
426 static bool isExtension = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSExtension"];
430#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
435 qWarning() <<
"accessing the shared" << [AppleApplication class]
436 <<
"is not allowed in application extensions";
441#if QT_CONFIG(appstore_compliant)
448 return [[AppleApplication class] performSelector:@selector(sharedApplication)];
452#if !defined(QT_BOOTSTRAPPED)
454#if defined(Q_OS_MACOS)
458 SandboxChecker() : m_thread([
this]{
460 QCFType<SecStaticCodeRef> staticCode =
nullptr;
461 NSURL *executableUrl = NSBundle.mainBundle.executableURL;
462 if (SecStaticCodeCreateWithPath((__bridge CFURLRef)executableUrl,
463 kSecCSDefaultFlags, &staticCode) != errSecSuccess)
466 QCFType<SecRequirementRef> sandboxRequirement;
467 if (SecRequirementCreateWithString(CFSTR(
"entitlement[\"com.apple.security.app-sandbox\"] exists"),
468 kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
471 if (SecStaticCodeCheckValidityWithErrors(staticCode,
472 kSecCSBasicValidateOnly, sandboxRequirement,
nullptr) != errSecSuccess)
480 std::scoped_lock
lock(m_mutex);
481 if (m_thread.joinable())
484 bool isSandboxed()
const {
485 std::scoped_lock
lock(m_mutex);
486 if (m_thread.joinable())
488 return m_isSandboxed;
492 mutable std::thread m_thread;
493 mutable std::mutex m_mutex;
496static SandboxChecker sandboxChecker;
501#if defined(Q_OS_MACOS)
502 return sandboxChecker.isSandboxed();
509@implementation NSObject (QtExtras)
510- (
id)qt_valueForPrivateKey:(NSString *)key
515 return [
self valueForKey:key];
531#define ROOT_LEVEL_POOL_MARKER QT_ROOT_LEVEL_POOL__THESE_OBJECTS_WILL_BE_RELEASED_WHEN_QAPP_GOES_OUT_OF_SCOPE
532@interface QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) : NSObject @
end
533@implementation QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER)
@end
537const char ROOT_LEVEL_POOL_DISABLE_SWITCH[] =
"QT_DISABLE_ROOT_LEVEL_AUTORELEASE_POOL";
539QMacRootLevelAutoReleasePool::QMacRootLevelAutoReleasePool()
546 [[[ROOT_LEVEL_POOL_MARKER alloc] init] autorelease];
549 qDebug(
"QCoreApplication root level NSAutoreleasePool in place. Break on ~%s and use\n" \
550 "'p [NSAutoreleasePool showPools]' to show leaked objects, or set %s",
551 __FUNCTION__, ROOT_LEVEL_POOL_DISABLE_SWITCH);
555QMacRootLevelAutoReleasePool::~QMacRootLevelAutoReleasePool()
564#if defined(__WATCH_OS_VERSION_MIN_REQUIRED)
565 const char *os =
"watchOS";
566 const int version = __WATCH_OS_VERSION_MIN_REQUIRED;
567#elif defined(__TV_OS_VERSION_MIN_REQUIRED)
568 const char *os =
"tvOS";
569 const int version = __TV_OS_VERSION_MIN_REQUIRED;
570#elif defined(__VISION_OS_VERSION_MIN_REQUIRED)
571 const char *os =
"visionOS";
572 const int version = __VISION_OS_VERSION_MIN_REQUIRED;
573#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
574 const char *os =
"iOS";
575 const int version = __IPHONE_OS_VERSION_MIN_REQUIRED;
576#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
577 const char *os =
"macOS";
578 const int version = __MAC_OS_X_VERSION_MIN_REQUIRED;
581 const auto required =
QVersionNumber(version / 10000, version / 100 % 100, version % 100);
584#if defined(Q_OS_MACOS)
587 if (current.majorVersion() == 10 && current.minorVersion() >= 16)
591 if (current < required) {
592 NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
593 NSString *applicationName = plist[@"CFBundleDisplayName"];
594 if (!applicationName)
595 applicationName = plist[@"CFBundleName"];
596 if (!applicationName)
597 applicationName = NSProcessInfo.processInfo.processName;
599 fprintf(stderr,
"Sorry, \"%s\" cannot be run on this version of %s. "
600 "Qt requires %s %ld.%ld.%ld or later, you have %s %ld.%ld.%ld.\n",
601 applicationName.UTF8String, os,
602 os,
long(required.majorVersion()),
long(required.minorVersion()),
long(required.microVersion()),
603 os,
long(current.majorVersion()),
long(current.minorVersion()),
long(current.microVersion()));
615 [[NSNotificationCenter defaultCenter] removeObserver:observer];
626void QMacKeyValueObserver::addObserver(NSKeyValueObservingOptions options)
637KeyValueObserver *QMacKeyValueObserver::observer = [[KeyValueObserver alloc] init];
640@implementation QT_MANGLE_NAMESPACE(KeyValueObserver)
641- (
void)observeValueForKeyPath:(NSString *)keyPath ofObject:(
id)object
642 change:(NSDictionary<NSKeyValueChangeKey,
id> *)change context:(
void *)context
658 case ApplicationBinary:
return applicationVersion().second;
659 case QtLibraries:
return libraryVersion().second;
667 case ApplicationBinary:
return applicationVersion().first;
668 case QtLibraries:
return libraryVersion().first;
691QMacVersion::VersionTuple QMacVersion::versionsForImage(
const mach_header *machHeader)
693 static auto osForLoadCommand = [](uint32_t cmd) {
703 static auto osForPlatform = [](uint32_t
platform) {
705 case Platform::macOS:
708 case Platform::iOSSimulator:
711 case Platform::tvOSSimulator:
713 case Platform::watchOS:
714 case Platform::watchOSSimulator:
728 const bool is64Bit = machHeader->magic == MH_MAGIC_64 || machHeader->magic == MH_CIGAM_64;
729 auto commandCursor = uintptr_t(machHeader) + (is64Bit ? sizeof(mach_header_64) : sizeof(mach_header));
731 for (uint32_t
i = 0;
i < machHeader->ncmds; ++
i) {
732 load_command *loadCommand =
reinterpret_cast<load_command *
>(commandCursor);
733 if (loadCommand->cmd == LC_VERSION_MIN_MACOSX || loadCommand->cmd == LC_VERSION_MIN_IPHONEOS
734 || loadCommand->cmd == LC_VERSION_MIN_TVOS || loadCommand->cmd == LC_VERSION_MIN_WATCHOS) {
735 auto versionCommand =
reinterpret_cast<version_min_command *
>(loadCommand);
736 return makeVersionTuple(versionCommand->version, versionCommand->sdk, osForLoadCommand(loadCommand->cmd));
737 }
else if (loadCommand->cmd == LC_BUILD_VERSION) {
738 auto versionCommand =
reinterpret_cast<build_version_command *
>(loadCommand);
739 return makeVersionTuple(versionCommand->minos, versionCommand->sdk, osForPlatform(versionCommand->platform));
741 commandCursor += loadCommand->cmdsize;
743 Q_ASSERT_X(
false,
"QMacVersion",
"Could not find any version load command");
747QMacVersion::VersionTuple QMacVersion::applicationVersion()
749 static VersionTuple version = []() {
750 const mach_header *executableHeader =
nullptr;
751 for (uint32_t
i = 0;
i < _dyld_image_count(); ++
i) {
752 auto header = _dyld_get_image_header(
i);
753 if (
header->filetype == MH_EXECUTE) {
754 executableHeader =
header;
758 Q_ASSERT_X(executableHeader,
"QMacVersion",
"Failed to resolve Mach-O header of executable");
759 return versionsForImage(executableHeader);
764QMacVersion::VersionTuple QMacVersion::libraryVersion()
766 static VersionTuple version = []() {
768 dladdr((
const void *)&QMacVersion::libraryVersion, &qtCoreImage);
769 Q_ASSERT_X(qtCoreImage.dli_fbase,
"QMacVersion",
"Failed to resolve Mach-O header of QtCore");
770 return versionsForImage(
static_cast<mach_header*
>(qtCoreImage.dli_fbase));
struct capHdr __attribute__
static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
static bool preventsStderrLogging()
Q_CORE_EXPORT ~QMacAutoReleasePool()
Q_NODISCARD_CTOR Q_CORE_EXPORT QMacAutoReleasePool()
std::function< void()> Callback
QMacKeyValueObserver()=default
static QOperatingSystemVersion deploymentTarget(VersionTarget target=ApplicationBinary)
static QOperatingSystemVersion currentRuntime()
static QOperatingSystemVersion buildSDK(VersionTarget target=ApplicationBinary)
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
\macro QT_RESTRICTED_CAST_FROM_ASCII
Combined button and popup list for selecting options.
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
QT_FOR_EACH_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
#define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType)
QT_BEGIN_NAMESPACE void qt_apple_check_os_version()
bool qt_apple_isApplicationExtension()
QT_FOR_EACH_MUTABLE_CORE_FOUNDATION_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
QT_FOR_EACH_CORE_FOUNDATION_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
int csr_get_active_config(csr_config_t *) __attribute__((weak_import))
QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE)
bool qt_apple_isSandboxed()
void objc_autoreleasePoolPop(void *pool)
QT_END_NAMESPACE QT_USE_NAMESPACE void * objc_autoreleasePoolPush(void)
QDebug operator<<(QDebug dbg, id obj)
AppleApplication * qt_apple_sharedApplication()
Q_CONSTRUCTOR_FUNCTION(qt_apple_check_os_version)
#define QT_MAC_WEAK_IMPORT(symbol)
UIApplication AppleApplication
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static QDBusError::ErrorType get(const char *name)
static QString header(const QString &name)
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLsizei const GLchar * message
GLsizei const GLchar *const * string
[0]
#define Q_ASSERT_X(cond, x, msg)
static QString keyPath(const QString &rKey)
#define qPrintable(string)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
const char className[16]
[1]