From 99a0cf14e599fff150a8e5471e9319e9a697ce7c Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Tue, 18 Aug 2026 12:23:04 -0700 Subject: [PATCH] [4.3] Allow compiling with min macOS version up to 14 --- drivers/coreaudio/audio_driver_coreaudio.cpp | 6 ++ modules/camera/camera_macos.mm | 8 ++- platform/macos/crash_handler_macos.mm | 14 ++--- platform/macos/detect.py | 2 + platform/macos/godot_open_save_delegate.h | 1 + platform/macos/godot_open_save_delegate.mm | 60 ++++++++++++++++---- platform/macos/os_macos.mm | 6 ++ platform/macos/tts_macos.mm | 15 +++++ 8 files changed, 91 insertions(+), 21 deletions(-) diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 98a8d4b2ef51..6546538f28e1 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -38,6 +38,10 @@ #define kOutputBus 0 #define kInputBus 1 +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 120000 +#define kAudioObjectPropertyElementMaster kAudioObjectPropertyElementMain +#endif + #ifdef MACOS_ENABLED OSStatus AudioDriverCoreAudio::input_device_address_cb(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, @@ -675,4 +679,6 @@ AudioDriverCoreAudio::AudioDriverCoreAudio() { samples_in.clear(); } +#undef kAudioObjectPropertyElementMaster + #endif // COREAUDIO_ENABLED diff --git a/modules/camera/camera_macos.mm b/modules/camera/camera_macos.mm index c0d8dc2cef20..d6c5cb22f729 100644 --- a/modules/camera/camera_macos.mm +++ b/modules/camera/camera_macos.mm @@ -308,7 +308,13 @@ - (void)dealloc { void CameraMacOS::update_feeds() { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101500 - AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:[NSArray arrayWithObjects:AVCaptureDeviceTypeExternalUnknown, AVCaptureDeviceTypeBuiltInWideAngleCamera, nil] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; + AVCaptureDeviceDiscoverySession *session; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 140000 + // Avoid deprecated warning if the minimum SDK is 14.0. + session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:[NSArray arrayWithObjects:AVCaptureDeviceTypeExternal, AVCaptureDeviceTypeBuiltInWideAngleCamera, nil] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; +#else + session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:[NSArray arrayWithObjects:AVCaptureDeviceTypeExternalUnknown, AVCaptureDeviceTypeBuiltInWideAngleCamera, nil] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; +#endif NSArray *devices = session.devices; #else NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; diff --git a/platform/macos/crash_handler_macos.mm b/platform/macos/crash_handler_macos.mm index c370422bfa73..88de9ed19811 100644 --- a/platform/macos/crash_handler_macos.mm +++ b/platform/macos/crash_handler_macos.mm @@ -54,17 +54,15 @@ #include static uint64_t load_address() { - const struct segment_command_64 *cmd = getsegbyname("__TEXT"); char full_path[1024]; uint32_t size = sizeof(full_path); - if (cmd && !_NSGetExecutablePath(full_path, &size)) { - uint32_t dyld_count = _dyld_image_count(); - for (uint32_t i = 0; i < dyld_count; i++) { - const char *image_name = _dyld_get_image_name(i); - if (image_name && strncmp(image_name, full_path, 1024) == 0) { - return cmd->vmaddr + _dyld_get_image_vmaddr_slide(i); - } + if (!_NSGetExecutablePath(full_path, &size)) { + void *handle = dlopen(full_path, RTLD_LAZY | RTLD_NOLOAD); + void *addr = dlsym(handle, "main"); + Dl_info info; + if (dladdr(addr, &info)) { + return (uint64_t)info.dli_fbase; } } diff --git a/platform/macos/detect.py b/platform/macos/detect.py index 1ce7c86c7b88..2123c851486e 100644 --- a/platform/macos/detect.py +++ b/platform/macos/detect.py @@ -223,6 +223,8 @@ def configure(env: "SConsEnvironment"): "QuartzCore", "-framework", "Security", + "-framework", + "UniformTypeIdentifiers", ] ) env.Append(LIBS=["pthread", "z"]) diff --git a/platform/macos/godot_open_save_delegate.h b/platform/macos/godot_open_save_delegate.h index 8857ef1fa95b..12349ef99010 100644 --- a/platform/macos/godot_open_save_delegate.h +++ b/platform/macos/godot_open_save_delegate.h @@ -33,6 +33,7 @@ #import #import +#import #include "core/templates/hash_map.h" #include "core/variant/typed_array.h" diff --git a/platform/macos/godot_open_save_delegate.mm b/platform/macos/godot_open_save_delegate.mm index 6ffd9395455d..0408f3e39da0 100644 --- a/platform/macos/godot_open_save_delegate.mm +++ b/platform/macos/godot_open_save_delegate.mm @@ -176,15 +176,33 @@ - (void)makeAccessoryView:(NSSavePanel *)p_panel filters:(const Vector & } if ([new_allowed_types count] > 0) { NSMutableArray *type_filters = [new_allowed_types objectAtIndex:0]; - if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) { - [p_panel setAllowedFileTypes:nil]; - [p_panel setAllowsOtherFileTypes:true]; + if (@available(macOS 11, *)) { + if (type_filters && [type_filters count] == 1 && [type_filters objectAtIndex:0] == UTTypeData) { + [p_panel setAllowedContentTypes:@[ UTTypeData ]]; + [p_panel setAllowsOtherFileTypes:true]; + } else { + [p_panel setAllowsOtherFileTypes:false]; + [p_panel setAllowedContentTypes:type_filters]; + } } else { - [p_panel setAllowsOtherFileTypes:false]; - [p_panel setAllowedFileTypes:type_filters]; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000 + if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) { + [p_panel setAllowedFileTypes:nil]; + [p_panel setAllowsOtherFileTypes:true]; + } else { + [p_panel setAllowsOtherFileTypes:false]; + [p_panel setAllowedFileTypes:type_filters]; + } +#endif } } else { - [p_panel setAllowedFileTypes:nil]; + if (@available(macOS 11, *)) { + [p_panel setAllowedContentTypes:@[ UTTypeData ]]; + } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000 + [p_panel setAllowedFileTypes:nil]; +#endif + } [p_panel setAllowsOtherFileTypes:true]; } } @@ -247,16 +265,34 @@ - (void)popupFileAction:(id)p_sender { NSUInteger index = [btn indexOfSelectedItem]; if (allowed_types && index < [allowed_types count]) { NSMutableArray *type_filters = [allowed_types objectAtIndex:index]; - if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) { - [dialog setAllowedFileTypes:nil]; - [dialog setAllowsOtherFileTypes:true]; + if (@available(macOS 11, *)) { + if (type_filters && [type_filters count] == 1 && [type_filters objectAtIndex:0] == UTTypeData) { + [dialog setAllowedContentTypes:@[ UTTypeData ]]; + [dialog setAllowsOtherFileTypes:true]; + } else { + [dialog setAllowsOtherFileTypes:false]; + [dialog setAllowedContentTypes:type_filters]; + } } else { - [dialog setAllowsOtherFileTypes:false]; - [dialog setAllowedFileTypes:type_filters]; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000 + if (type_filters && [type_filters count] == 1 && [[type_filters objectAtIndex:0] isEqualToString:@"*"]) { + [dialog setAllowedFileTypes:nil]; + [dialog setAllowsOtherFileTypes:true]; + } else { + [dialog setAllowsOtherFileTypes:false]; + [dialog setAllowedFileTypes:type_filters]; + } +#endif } cur_index = index; } else { - [dialog setAllowedFileTypes:nil]; + if (@available(macOS 11, *)) { + [dialog setAllowedContentTypes:@[ UTTypeData ]]; + } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000 + [dialog setAllowedFileTypes:nil]; +#endif + } [dialog setAllowsOtherFileTypes:true]; cur_index = -1; } diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index 3a8251476646..36035a4cb8da 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -635,6 +635,7 @@ #if defined(__x86_64__) } else { Error err = ERR_TIMEOUT; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 110000 NSError *error = nullptr; NSRunningApplication *app = [[NSWorkspace sharedWorkspace] launchApplicationAtURL:url options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error]; if (error) { @@ -646,6 +647,7 @@ } err = OK; } +#endif return err; } #endif @@ -679,7 +681,11 @@ static String serial_number; if (serial_number.is_empty()) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000 io_service_t platform_expert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); +#else + io_service_t platform_expert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice")); +#endif CFStringRef serial_number_cf_string = nullptr; if (platform_expert) { serial_number_cf_string = (CFStringRef)IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0); diff --git a/platform/macos/tts_macos.mm b/platform/macos/tts_macos.mm index 4e6744e2112e..ab0924118554 100644 --- a/platform/macos/tts_macos.mm +++ b/platform/macos/tts_macos.mm @@ -43,9 +43,11 @@ - (id)init { [self->synth setDelegate:self]; print_verbose("Text-to-Speech: AVSpeechSynthesizer initialized."); } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 140000 self->synth = [[NSSpeechSynthesizer alloc] init]; [self->synth setDelegate:self]; print_verbose("Text-to-Speech: NSSpeechSynthesizer initialized."); +#endif } return self; } @@ -88,6 +90,8 @@ - (void)speechSynthesizer:(AVSpeechSynthesizer *)av_synth didFinishSpeechUtteran // NSSpeechSynthesizer callback (macOS 10.4+) +// Deprecated in macOS 14.0, needs to be removed when compiling with min macOS 14.0. +#if MAC_OS_X_VERSION_MIN_REQUIRED < 140000 - (void)speechSynthesizer:(NSSpeechSynthesizer *)ns_synth willSpeakWord:(NSRange)characterRange ofString:(NSString *)string { if (!paused && have_utterance) { // Convert from UTF-16 to UTF-32 position. @@ -116,6 +120,7 @@ - (void)speechSynthesizer:(NSSpeechSynthesizer *)ns_synth didFinishSpeaking:(BOO speaking = false; [self update]; } +#endif - (void)update { if (!speaking && queue.size() > 0) { @@ -136,6 +141,7 @@ - (void)update { ids[new_utterance] = message.id; [av_synth speakUtterance:new_utterance]; } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 140000 NSSpeechSynthesizer *ns_synth = synth; [ns_synth setObject:nil forProperty:NSSpeechResetProperty error:nil]; [ns_synth setVoice:[NSString stringWithUTF8String:message.voice.utf8().get_data()]]; @@ -147,6 +153,7 @@ - (void)update { last_utterance = message.id; have_utterance = true; [ns_synth startSpeakingString:[NSString stringWithUTF8String:message.text.utf8().get_data()]]; +#endif } queue.pop_front(); @@ -160,8 +167,10 @@ - (void)pauseSpeaking { AVSpeechSynthesizer *av_synth = synth; [av_synth pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate]; } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 140000 NSSpeechSynthesizer *ns_synth = synth; [ns_synth pauseSpeakingAtBoundary:NSSpeechImmediateBoundary]; +#endif } paused = true; } @@ -171,8 +180,10 @@ - (void)resumeSpeaking { AVSpeechSynthesizer *av_synth = synth; [av_synth continueSpeaking]; } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 140000 NSSpeechSynthesizer *ns_synth = synth; [ns_synth continueSpeaking]; +#endif } paused = false; } @@ -186,11 +197,13 @@ - (void)stopSpeaking { AVSpeechSynthesizer *av_synth = synth; [av_synth stopSpeakingAtBoundary:AVSpeechBoundaryImmediate]; } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 140000 NSSpeechSynthesizer *ns_synth = synth; if (have_utterance) { DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, last_utterance); } [ns_synth stopSpeaking]; +#endif } have_utterance = false; speaking = false; @@ -250,6 +263,7 @@ - (Array)getVoices { list.push_back(voice_d); } } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 140000 for (NSString *voiceIdentifierString in [NSSpeechSynthesizer availableVoices]) { NSString *voiceLocaleIdentifier = [[NSSpeechSynthesizer attributesForVoice:voiceIdentifierString] objectForKey:NSVoiceLocaleIdentifier]; NSString *voiceName = [[NSSpeechSynthesizer attributesForVoice:voiceIdentifierString] objectForKey:NSVoiceName]; @@ -259,6 +273,7 @@ - (Array)getVoices { voice_d["language"] = String([voiceLocaleIdentifier UTF8String]); list.push_back(voice_d); } +#endif } return list; }