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>
31#include "private/qlocking_p.h"
33#if !defined(QT_BOOTSTRAPPED)
37#if !defined(QT_APPLE_NO_PRIVATE_APIS)
42#ifdef QT_BUILD_INTERNAL
43int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t
attrs,
int disclaim)
44__attribute__((availability(macos,introduced=10.14),weak_import));
45pid_t responsibility_get_pid_responsible_for_pid(pid_t)
__attribute__((weak_import));
65 Q_UNUSED(NSUserDefaults.standardUserDefaults);
73 if (
string.isEmpty() &&
value)
74 const_cast<QCFString*
>(
this)->
string = QString::fromCFString(
value);
78QCFString::operator CFStringRef()
const
87#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
117 return willMirror || disableStderr;
124 QString subsystem = optionalSubsystem;
126 static QString bundleIdentifier = []() {
127 if (CFBundleRef
bundle = CFBundleGetMainBundle()) {
128 if (CFStringRef identifier = CFBundleGetIdentifier(
bundle))
129 return QString::fromCFString(identifier);
133 subsystem = bundleIdentifier;
136 const bool isDefault = !
context.category || !strcmp(
context.category,
"default");
137 os_log_t log = isDefault ? OS_LOG_DEFAULT :
139 os_log_type_t logType = logTypeForMessageType(msgType);
141 if (!os_log_type_enabled(log, logType))
161os_log_type_t AppleUnifiedLogger::logTypeForMessageType(
QtMsgType msgType)
171 return OS_LOG_TYPE_DEFAULT;
186 for (Class cls = object_getClass(
obj); cls; cls = class_getSuperclass(cls)) {
187 if (cls == NSObject.class) {
188 dbg << static_cast<NSObject*>(
obj);
195 dbg.nospace() <<
'<' << object_getClassName(
obj) <<
": " <<
static_cast<void*
>(
obj) <<
'>';
201 return dbg << (nsObject ?
202 dbg.verbosity() > 2 ?
203 nsObject.debugDescription.UTF8String :
204 nsObject.description.UTF8String
211 return dbg <<
"CFStringRef(0x0)";
213 if (
const UniChar *chars = CFStringGetCharactersPtr(stringRef))
214 dbg << QStringView(reinterpret_cast<const QChar *>(chars), CFStringGetLength(stringRef));
216 dbg << QString::fromCFString(stringRef);
223#define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
224 __attribute__((weak)) Q_DECLARE_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType)
237@interface QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) : NSObject
240@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker)
262 if (!debugAutoReleasePools)
265 Class trackerClass = [QMacAutoReleasePoolTracker class];
267 void *poolFrame =
nullptr;
269 if (backtrace_from_fp(__builtin_frame_address(0), frames, 2))
270 poolFrame = frames[1];
274 if (dladdr(poolFrame, &
info) &&
info.dli_sname) {
275 const char *symbolName =
info.dli_sname;
276 if (symbolName[0] ==
'_') {
278 if (
char *demangled = abi::__cxa_demangle(
info.dli_sname,
nullptr, 0, &status))
279 symbolName = demangled;
283 asprintf(&
className,
" ^-- allocated in function: %s", symbolName);
285 if (Class existingClass = objc_getClass(
className))
286 trackerClass = existingClass;
288 trackerClass = objc_duplicateClass(trackerClass,
className, 0);
292 if (symbolName !=
info.dli_sname)
293 free((
char*)symbolName);
297 [[trackerClass new] autorelease];
306#ifndef QT_NO_DEBUG_STREAM
311 debug <<
"QMacAutoReleasePool(" << (
const void *)
pool <<
')';
317 debug << static_cast<QString>(
string);
323bool qt_mac_applicationIsInDarkMode()
325 auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
326 @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
327 return [appearance isEqualToString:NSAppearanceNameDarkAqua];
330bool qt_mac_runningUnderRosetta()
333 auto size =
sizeof(translated);
334 if (sysctlbyname(
"sysctl.proc_translated", &translated, &
size,
nullptr, 0) == 0)
339std::optional<uint32_t> qt_mac_sipConfiguration()
341 static auto configuration = []() -> std::optional<uint32_t> {
342#if !defined(QT_APPLE_NO_PRIVATE_APIS)
348 QIOType<io_registry_entry_t> nvram = IORegistryEntryFromPath(kIOMasterPortDefault,
"IODeviceTree:/options");
350 qWarning(
"Failed to locate NVRAM entry in IO registry");
355 CFSTR(
"csr-active-config"), kCFAllocatorDefault, IOOptionBits{});
359 if (
auto type = CFGetTypeID(csrConfig);
type != CFDataGetTypeID()) {
360 qWarning() <<
"Unexpected SIP config type" << CFCopyTypeIDDescription(
type);
365 if (
data.size() !=
sizeof(uint32_t)) {
366 qWarning() <<
"Unexpected SIP config size" <<
data.size();
370 return qFromLittleEndian<uint32_t>(
data.constData());
372 return configuration;
375#define CHECK_SPAWN(expr) \
376 if (int err = (expr)) { \
377 posix_spawnattr_destroy(&attr); \
381#ifdef QT_BUILD_INTERNAL
382void qt_mac_ensureResponsible()
384#if !defined(QT_APPLE_NO_PRIVATE_APIS)
385 if (!responsibility_get_pid_responsible_for_pid || !responsibility_spawnattrs_setdisclaim)
389 if (responsibility_get_pid_responsible_for_pid(pid) == pid)
392 posix_spawnattr_t attr = {};
393 CHECK_SPAWN(posix_spawnattr_init(&attr));
396 short flags = POSIX_SPAWN_SETEXEC;
400 sigemptyset(&no_signals);
401 CHECK_SPAWN(posix_spawnattr_setsigmask(&attr, &no_signals));
402 flags |= POSIX_SPAWN_SETSIGMASK;
405 sigset_t all_signals;
406 sigfillset(&all_signals);
407 CHECK_SPAWN(posix_spawnattr_setsigdefault(&attr, &all_signals));
408 flags |= POSIX_SPAWN_SETSIGDEF;
410 CHECK_SPAWN(posix_spawnattr_setflags(&attr,
flags));
412 CHECK_SPAWN(responsibility_spawnattrs_setdisclaim(&attr, 1));
414 char **argv = *_NSGetArgv();
415 posix_spawnp(&pid, argv[0],
nullptr, &attr, argv,
environ);
416 posix_spawnattr_destroy(&attr);
425 static bool isExtension = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSExtension"];
429#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
434 qWarning() <<
"accessing the shared" << [AppleApplication
class]
435 <<
"is not allowed in application extensions";
440#if QT_CONFIG(appstore_compliant)
447 return [[AppleApplication
class] performSelector:@selector(sharedApplication)];
451#if !defined(QT_BOOTSTRAPPED)
453#if defined(Q_OS_MACOS)
457 SandboxChecker() : m_thread([
this]{
460 NSURL *executableUrl = NSBundle.mainBundle.executableURL;
461 if (SecStaticCodeCreateWithPath((__bridge CFURLRef)executableUrl,
462 kSecCSDefaultFlags, &staticCode) != errSecSuccess)
466 if (SecRequirementCreateWithString(CFSTR(
"entitlement[\"com.apple.security.app-sandbox\"] exists"),
467 kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
470 if (SecStaticCodeCheckValidityWithErrors(staticCode,
471 kSecCSBasicValidateOnly, sandboxRequirement,
nullptr) != errSecSuccess)
479 std::scoped_lock
lock(m_mutex);
480 if (m_thread.joinable())
483 bool isSandboxed()
const {
484 std::scoped_lock
lock(m_mutex);
485 if (m_thread.joinable())
487 return m_isSandboxed;
491 mutable std::thread m_thread;
492 mutable std::mutex m_mutex;
495static SandboxChecker sandboxChecker;
500#if defined(Q_OS_MACOS)
501 return sandboxChecker.isSandboxed();
508@implementation NSObject (QtSandboxHelpers)
509- (
id)qt_valueForPrivateKey:(NSString *)key
514 return [
self valueForKey:key];
530#define ROOT_LEVEL_POOL_MARKER QT_ROOT_LEVEL_POOL__THESE_OBJECTS_WILL_BE_RELEASED_WHEN_QAPP_GOES_OUT_OF_SCOPE
531@interface QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) : NSObject @
end
532@implementation QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER)
@end
536const char ROOT_LEVEL_POOL_DISABLE_SWITCH[] =
"QT_DISABLE_ROOT_LEVEL_AUTORELEASE_POOL";
538QMacRootLevelAutoReleasePool::QMacRootLevelAutoReleasePool()
545 [[[ROOT_LEVEL_POOL_MARKER alloc] init] autorelease];
548 qDebug(
"QCoreApplication root level NSAutoreleasePool in place. Break on ~%s and use\n" \
549 "'p [NSAutoreleasePool showPools]' to show leaked objects, or set %s",
550 __FUNCTION__, ROOT_LEVEL_POOL_DISABLE_SWITCH);
554QMacRootLevelAutoReleasePool::~QMacRootLevelAutoReleasePool()
563#if defined(__WATCH_OS_VERSION_MIN_REQUIRED)
564 const char *os =
"watchOS";
565 const int version = __WATCH_OS_VERSION_MIN_REQUIRED;
566#elif defined(__TV_OS_VERSION_MIN_REQUIRED)
567 const char *os =
"tvOS";
568 const int version = __TV_OS_VERSION_MIN_REQUIRED;
569#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
570 const char *os =
"iOS";
571 const int version = __IPHONE_OS_VERSION_MIN_REQUIRED;
572#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
573 const char *os =
"macOS";
574 const int version = __MAC_OS_X_VERSION_MIN_REQUIRED;
577 const auto required =
QVersionNumber(version / 10000, version / 100 % 100, version % 100);
580#if defined(Q_OS_MACOS)
583 if (current.majorVersion() == 10 && current.minorVersion() >= 16)
587 if (current < required) {
588 NSDictionary *plist = NSBundle.mainBundle.infoDictionary;
589 NSString *applicationName = plist[@"CFBundleDisplayName"];
590 if (!applicationName)
591 applicationName = plist[@"CFBundleName"];
592 if (!applicationName)
593 applicationName = NSProcessInfo.processInfo.processName;
595 fprintf(stderr,
"Sorry, \"%s\" cannot be run on this version of %s. "
596 "Qt requires %s %ld.%ld.%ld or later, you have %s %ld.%ld.%ld.\n",
597 applicationName.UTF8String, os,
598 os,
long(required.majorVersion()),
long(required.minorVersion()),
long(required.microVersion()),
599 os,
long(current.majorVersion()),
long(current.minorVersion()),
long(current.microVersion()));
611 [[NSNotificationCenter defaultCenter] removeObserver:observer];
622void QMacKeyValueObserver::addObserver(NSKeyValueObservingOptions options)
633KeyValueObserver *QMacKeyValueObserver::observer = [[KeyValueObserver alloc] init];
636@implementation QT_MANGLE_NAMESPACE(KeyValueObserver)
637- (
void)observeValueForKeyPath:(NSString *)keyPath ofObject:(
id)object
638 change:(NSDictionary<NSKeyValueChangeKey,
id> *)change context:(
void *)context
654 case ApplicationBinary:
return applicationVersion().second;
655 case QtLibraries:
return libraryVersion().second;
663 case ApplicationBinary:
return applicationVersion().first;
664 case QtLibraries:
return libraryVersion().first;
687QMacVersion::VersionTuple QMacVersion::versionsForImage(
const mach_header *machHeader)
689 static auto osForLoadCommand = [](uint32_t cmd) {
699 static auto osForPlatform = [](uint32_t
platform) {
701 case Platform::macOS:
704 case Platform::iOSSimulator:
707 case Platform::tvOSSimulator:
709 case Platform::watchOS:
710 case Platform::watchOSSimulator:
724 const bool is64Bit = machHeader->magic == MH_MAGIC_64 || machHeader->magic == MH_CIGAM_64;
725 auto commandCursor = uintptr_t(machHeader) + (is64Bit ? sizeof(mach_header_64) : sizeof(mach_header));
727 for (uint32_t
i = 0;
i < machHeader->ncmds; ++
i) {
728 load_command *loadCommand =
reinterpret_cast<load_command *
>(commandCursor);
729 if (loadCommand->cmd == LC_VERSION_MIN_MACOSX || loadCommand->cmd == LC_VERSION_MIN_IPHONEOS
730 || loadCommand->cmd == LC_VERSION_MIN_TVOS || loadCommand->cmd == LC_VERSION_MIN_WATCHOS) {
731 auto versionCommand =
reinterpret_cast<version_min_command *
>(loadCommand);
732 return makeVersionTuple(versionCommand->version, versionCommand->sdk, osForLoadCommand(loadCommand->cmd));
733 }
else if (loadCommand->cmd == LC_BUILD_VERSION) {
734 auto versionCommand =
reinterpret_cast<build_version_command *
>(loadCommand);
735 return makeVersionTuple(versionCommand->minos, versionCommand->sdk, osForPlatform(versionCommand->platform));
737 commandCursor += loadCommand->cmdsize;
739 Q_ASSERT_X(
false,
"QMacVersion",
"Could not find any version load command");
743QMacVersion::VersionTuple QMacVersion::applicationVersion()
745 static VersionTuple version = []() {
746 const mach_header *executableHeader =
nullptr;
747 for (uint32_t
i = 0;
i < _dyld_image_count(); ++
i) {
748 auto header = _dyld_get_image_header(
i);
749 if (
header->filetype == MH_EXECUTE) {
750 executableHeader =
header;
754 Q_ASSERT_X(executableHeader,
"QMacVersion",
"Failed to resolve Mach-O header of executable");
755 return versionsForImage(executableHeader);
760QMacVersion::VersionTuple QMacVersion::libraryVersion()
762 static VersionTuple version = []() {
764 dladdr((
const void *)&QMacVersion::libraryVersion, &qtCoreImage);
765 Q_ASSERT_X(qtCoreImage.dli_fbase,
"QMacVersion",
"Failed to resolve Mach-O header of QtCore");
766 return versionsForImage(
static_cast<mach_header*
>(qtCoreImage.dli_fbase));
static bool preventsStderrLogging()
static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message, const QString &subsystem=QString())
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
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)
QVersionNumber version() const
static QOperatingSystemVersion current()
[0]
\macro QT_RESTRICTED_CAST_FROM_ASCII
QByteArray toLatin1() const &
bool isNull() const
Returns true if this string is null; otherwise returns false.
Combined button and popup list for selecting options.
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
Q_CONSTRUCTOR_FUNCTION(initializeStandardUserDefaults)
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))
static QT_BEGIN_NAMESPACE void initializeStandardUserDefaults()
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()
#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]
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei const GLchar *const * string
[0]
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
#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]
QFileInfo info(fileName)
[8]