From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- .../SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.h | 34 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.m | 262 -- .../SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.h | 33 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.m | 680 ---- .../SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.h | 36 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m | 604 ---- .../src/video/cocoa/SDL_cocoamessagebox.h | 27 - .../src/video/cocoa/SDL_cocoamessagebox.m | 145 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.h | 66 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m | 182 -- contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.h | 45 - contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.m | 716 ----- contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.h | 51 - contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m | 591 ---- .../SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.h | 88 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.m | 559 ---- .../SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.h | 48 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.m | 156 - contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.h | 32 - contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.m | 178 -- contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.h | 28 - contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.m | 54 - contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.h | 71 - contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.m | 337 -- .../SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.h | 52 - .../SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.m | 304 -- .../SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.h | 199 -- .../SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.m | 3277 -------------------- 28 files changed, 8855 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.m delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.h delete mode 100644 contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.m (limited to 'contrib/SDL-3.2.8/src/video/cocoa') diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.h deleted file mode 100644 index 758f45a..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoaclipboard_h_ -#define SDL_cocoaclipboard_h_ - -// Forward declaration -@class SDL_CocoaVideoData; - -extern void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data); -extern bool Cocoa_SetClipboardData(SDL_VideoDevice *_this); -extern void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size); -extern bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type); - -#endif // SDL_cocoaclipboard_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.m deleted file mode 100644 index 42c2ad6..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaclipboard.m +++ /dev/null @@ -1,262 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoavideo.h" -#include "../../events/SDL_events_c.h" -#include "../../events/SDL_clipboardevents_c.h" - -#include - -@interface Cocoa_PasteboardDataProvider : NSObject -{ - SDL_ClipboardDataCallback m_callback; - void *m_userdata; -} -@end - -@implementation Cocoa_PasteboardDataProvider - -- (nullable instancetype)initWith:(SDL_ClipboardDataCallback)callback - userData:(void *)userdata -{ - self = [super init]; - if (!self) { - return self; - } - m_callback = callback; - m_userdata = userdata; - return self; -} - -- (void)pasteboard:(NSPasteboard *)pasteboard - item:(NSPasteboardItem *)item -provideDataForType:(NSPasteboardType)type -{ - @autoreleasepool { - size_t size = 0; - CFStringRef mimeType; - const void *callbackData; - NSData *data; - mimeType = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)type, kUTTagClassMIMEType); - callbackData = m_callback(m_userdata, [(__bridge NSString *)mimeType UTF8String], &size); - CFRelease(mimeType); - if (callbackData == NULL || size == 0) { - return; - } - data = [NSData dataWithBytes: callbackData length: size]; - [item setData: data forType: type]; - } -} - -@end - -static char **GetMimeTypes(int *pnformats) -{ - char **new_mime_types = NULL; - - *pnformats = 0; - - int nformats = 0; - int formatsSz = 0; - NSArray *items = [[NSPasteboard generalPasteboard] pasteboardItems]; - NSUInteger nitems = [items count]; - if (nitems > 0) { - for (NSPasteboardItem *item in items) { - NSArray *types = [item types]; - for (NSString *type in types) { - if (@available(macOS 11.0, *)) { - UTType *uttype = [UTType typeWithIdentifier:type]; - NSString *mime_type = [uttype preferredMIMEType]; - if (mime_type) { - NSUInteger len = [mime_type lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - formatsSz += len; - ++nformats; - } - } - NSUInteger len = [type lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - formatsSz += len; - ++nformats; - } - } - - new_mime_types = SDL_AllocateTemporaryMemory((nformats + 1) * sizeof(char *) + formatsSz); - if (new_mime_types) { - int i = 0; - char *strPtr = (char *)(new_mime_types + nformats + 1); - for (NSPasteboardItem *item in items) { - NSArray *types = [item types]; - for (NSString *type in types) { - if (@available(macOS 11.0, *)) { - UTType *uttype = [UTType typeWithIdentifier:type]; - NSString *mime_type = [uttype preferredMIMEType]; - if (mime_type) { - NSUInteger len = [mime_type lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - SDL_memcpy(strPtr, [mime_type UTF8String], len); - new_mime_types[i++] = strPtr; - strPtr += len; - } - } - NSUInteger len = [type lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - SDL_memcpy(strPtr, [type UTF8String], len); - new_mime_types[i++] = strPtr; - strPtr += len; - } - } - - new_mime_types[nformats] = NULL; - *pnformats = nformats; - } - } - return new_mime_types; -} - - -void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data) -{ - @autoreleasepool { - NSPasteboard *pasteboard; - NSInteger count; - - pasteboard = [NSPasteboard generalPasteboard]; - count = [pasteboard changeCount]; - if (count != data.clipboard_count) { - if (count) { - int nformats = 0; - char **new_mime_types = GetMimeTypes(&nformats); - if (new_mime_types) { - SDL_SendClipboardUpdate(false, new_mime_types, nformats); - } - } - data.clipboard_count = count; - } - } -} - -bool Cocoa_SetClipboardData(SDL_VideoDevice *_this) -{ - @autoreleasepool { - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - NSPasteboardItem *newItem = [NSPasteboardItem new]; - NSMutableArray *utiTypes = [NSMutableArray new]; - Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata]; - BOOL itemResult = FALSE; - BOOL writeResult = FALSE; - - if (_this->clipboard_callback) { - for (int i = 0; i < _this->num_clipboard_mime_types; i++) { - CFStringRef mimeType = CFStringCreateWithCString(NULL, _this->clipboard_mime_types[i], kCFStringEncodingUTF8); - CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); - CFRelease(mimeType); - - [utiTypes addObject: (__bridge NSString *)utiType]; - CFRelease(utiType); - } - itemResult = [newItem setDataProvider: provider forTypes: utiTypes]; - if (itemResult == FALSE) { - return SDL_SetError("Unable to set clipboard item data"); - } - - [pasteboard clearContents]; - writeResult = [pasteboard writeObjects: @[newItem]]; - if (writeResult == FALSE) { - return SDL_SetError("Unable to set clipboard data"); - } - } else { - [pasteboard clearContents]; - } - data.clipboard_count = [pasteboard changeCount]; - } - return true; -} - -static bool IsMimeType(const char *tag) -{ - if (SDL_strchr(tag, '/')) { - // MIME types have slashes - return true; - } else if (SDL_strchr(tag, '.')) { - // UTI identifiers have periods - return false; - } else { - // Not sure, but it's not a UTI identifier - return true; - } -} - -static CFStringRef GetUTIType(const char *tag) -{ - CFStringRef utiType; - if (IsMimeType(tag)) { - CFStringRef mimeType = CFStringCreateWithCString(NULL, tag, kCFStringEncodingUTF8); - utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL); - CFRelease(mimeType); - } else { - utiType = CFStringCreateWithCString(NULL, tag, kCFStringEncodingUTF8); - } - return utiType; -} - -void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size) -{ - @autoreleasepool { - NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - void *data = NULL; - *size = 0; - for (NSPasteboardItem *item in [pasteboard pasteboardItems]) { - NSData *itemData; - CFStringRef utiType = GetUTIType(mime_type); - itemData = [item dataForType: (__bridge NSString *)utiType]; - CFRelease(utiType); - if (itemData != nil) { - NSUInteger length = [itemData length]; - *size = (size_t)length; - data = SDL_malloc(*size + sizeof(Uint32)); - if (data) { - [itemData getBytes: data length: length]; - SDL_memset((Uint8 *)data + length, 0, sizeof(Uint32)); - } - break; - } - } - return data; - } -} - -bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type) -{ - bool result = false; - @autoreleasepool { - NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - CFStringRef utiType = GetUTIType(mime_type); - if ([pasteboard canReadItemWithDataConformingToTypes: @[(__bridge NSString *)utiType]]) { - result = true; - } - CFRelease(utiType); - } - return result; - -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.h deleted file mode 100644 index 4944207..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoaevents_h_ -#define SDL_cocoaevents_h_ - -extern void Cocoa_RegisterApp(void); -extern Uint64 Cocoa_GetEventTimestamp(NSTimeInterval nsTimestamp); -extern void Cocoa_PumpEvents(SDL_VideoDevice *_this); -extern int Cocoa_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS); -extern void Cocoa_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_SuspendScreenSaver(SDL_VideoDevice *_this); - -#endif // SDL_cocoaevents_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.m deleted file mode 100644 index 58cae99..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaevents.m +++ /dev/null @@ -1,680 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoavideo.h" -#include "../../events/SDL_events_c.h" - -static SDL_Window *FindSDLWindowForNSWindow(NSWindow *win) -{ - SDL_Window *sdlwindow = NULL; - SDL_VideoDevice *device = SDL_GetVideoDevice(); - if (device && device->windows) { - for (sdlwindow = device->windows; sdlwindow; sdlwindow = sdlwindow->next) { - NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)sdlwindow->internal).nswindow; - if (win == nswindow) { - return sdlwindow; - } - } - } - - return sdlwindow; -} - -@interface SDL3Application : NSApplication - -- (void)terminate:(id)sender; -- (void)sendEvent:(NSEvent *)theEvent; - -+ (void)registerUserDefaults; - -@end - -@implementation SDL3Application - -// Override terminate to handle Quit and System Shutdown smoothly. -- (void)terminate:(id)sender -{ - SDL_SendQuit(); -} - -static bool s_bShouldHandleEventsInSDLApplication = false; - -static void Cocoa_DispatchEvent(NSEvent *theEvent) -{ - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - - switch ([theEvent type]) { - case NSEventTypeLeftMouseDown: - case NSEventTypeOtherMouseDown: - case NSEventTypeRightMouseDown: - case NSEventTypeLeftMouseUp: - case NSEventTypeOtherMouseUp: - case NSEventTypeRightMouseUp: - case NSEventTypeLeftMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeOtherMouseDragged: // usually middle mouse dragged - case NSEventTypeMouseMoved: - case NSEventTypeScrollWheel: - case NSEventTypeMouseEntered: - case NSEventTypeMouseExited: - Cocoa_HandleMouseEvent(_this, theEvent); - break; - case NSEventTypeKeyDown: - case NSEventTypeKeyUp: - case NSEventTypeFlagsChanged: - Cocoa_HandleKeyEvent(_this, theEvent); - break; - default: - break; - } -} - -// Dispatch events here so that we can handle events caught by -// nextEventMatchingMask in SDL, as well as events caught by other -// processes (such as CEF) that are passed down to NSApp. -- (void)sendEvent:(NSEvent *)theEvent -{ - if (s_bShouldHandleEventsInSDLApplication) { - Cocoa_DispatchEvent(theEvent); - } - - [super sendEvent:theEvent]; -} - -+ (void)registerUserDefaults -{ - BOOL momentumScrollSupported = (BOOL)SDL_GetHintBoolean(SDL_HINT_MAC_SCROLL_MOMENTUM, false); - - NSDictionary *appDefaults = [[NSDictionary alloc] initWithObjectsAndKeys: - [NSNumber numberWithBool:momentumScrollSupported], @"AppleMomentumScrollSupported", - [NSNumber numberWithBool:YES], @"ApplePressAndHoldEnabled", - [NSNumber numberWithBool:YES], @"ApplePersistenceIgnoreState", - nil]; - [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults]; -} - -@end // SDL3Application - -// setAppleMenu disappeared from the headers in 10.4 -@interface NSApplication (NSAppleMenu) -- (void)setAppleMenu:(NSMenu *)menu; -@end - -@interface SDL3AppDelegate : NSObject -{ - @public - BOOL seenFirstActivate; -} - -- (id)init; -- (void)localeDidChange:(NSNotification *)notification; -- (void)observeValueForKeyPath:(NSString *)keyPath - ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context; -- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app; -- (IBAction)menu:(id)sender; -@end - -@implementation SDL3AppDelegate : NSObject -- (id)init -{ - self = [super init]; - if (self) { - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - bool registerActivationHandlers = SDL_GetHintBoolean("SDL_MAC_REGISTER_ACTIVATION_HANDLERS", true); - - seenFirstActivate = NO; - - if (registerActivationHandlers) { - [center addObserver:self - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:nil]; - - [center addObserver:self - selector:@selector(focusSomeWindow:) - name:NSApplicationDidBecomeActiveNotification - object:nil]; - - [center addObserver:self - selector:@selector(screenParametersChanged:) - name:NSApplicationDidChangeScreenParametersNotification - object:nil]; - } - - [center addObserver:self - selector:@selector(localeDidChange:) - name:NSCurrentLocaleDidChangeNotification - object:nil]; - - [NSApp addObserver:self - forKeyPath:@"effectiveAppearance" - options:NSKeyValueObservingOptionInitial - context:nil]; - } - - return self; -} - -- (void)dealloc -{ - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - - [center removeObserver:self name:NSWindowWillCloseNotification object:nil]; - [center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil]; - [center removeObserver:self name:NSApplicationDidChangeScreenParametersNotification object:nil]; - [center removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil]; - [NSApp removeObserver:self forKeyPath:@"effectiveAppearance"]; - - // Remove our URL event handler only if we set it - if ([NSApp delegate] == self) { - [[NSAppleEventManager sharedAppleEventManager] - removeEventHandlerForEventClass:kInternetEventClass - andEventID:kAEGetURL]; - } -} - -- (void)windowWillClose:(NSNotification *)notification -{ - NSWindow *win = (NSWindow *)[notification object]; - - if (![win isKeyWindow]) { - return; - } - - // Don't do anything if this was not an SDL window that was closed - if (FindSDLWindowForNSWindow(win) == NULL) { - return; - } - - /* HACK: Make the next window in the z-order key when the key window is - * closed. The custom event loop and/or windowing code we have seems to - * prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825 - */ - - /* +[NSApp orderedWindows] never includes the 'About' window, but we still - * want to try its list first since the behavior in other apps is to only - * make the 'About' window key if no other windows are on-screen. - */ - for (NSWindow *window in [NSApp orderedWindows]) { - if (window != win && [window canBecomeKeyWindow]) { - if (![window isOnActiveSpace]) { - continue; - } - [window makeKeyAndOrderFront:self]; - return; - } - } - - /* If a window wasn't found above, iterate through all visible windows in - * the active Space in z-order (including the 'About' window, if it's shown) - * and make the first one key. - */ - for (NSNumber *num in [NSWindow windowNumbersWithOptions:0]) { - NSWindow *window = [NSApp windowWithWindowNumber:[num integerValue]]; - if (window && window != win && [window canBecomeKeyWindow]) { - [window makeKeyAndOrderFront:self]; - return; - } - } -} - -- (void)focusSomeWindow:(NSNotification *)aNotification -{ - SDL_VideoDevice *device; - /* HACK: Ignore the first call. The application gets a - * applicationDidBecomeActive: a little bit after the first window is - * created, and if we don't ignore it, a window that has been created with - * SDL_WINDOW_MINIMIZED will ~immediately be restored. - */ - if (!seenFirstActivate) { - seenFirstActivate = YES; - return; - } - - /* Don't do anything if the application already has a key window - * that is not an SDL window. - */ - if ([NSApp keyWindow] && FindSDLWindowForNSWindow([NSApp keyWindow]) == NULL) { - return; - } - - device = SDL_GetVideoDevice(); - if (device && device->windows) { - SDL_Window *window = device->windows; - int i; - for (i = 0; i < device->num_displays; ++i) { - SDL_Window *fullscreen_window = device->displays[i]->fullscreen_window; - if (fullscreen_window) { - if (fullscreen_window->flags & SDL_WINDOW_MINIMIZED) { - SDL_RestoreWindow(fullscreen_window); - } - return; - } - } - - if (window->flags & SDL_WINDOW_MINIMIZED) { - SDL_RestoreWindow(window); - } else { - SDL_RaiseWindow(window); - } - } -} - -- (void)screenParametersChanged:(NSNotification *)aNotification -{ - SDL_VideoDevice *device = SDL_GetVideoDevice(); - if (device) { - Cocoa_UpdateDisplays(device); - } -} - -- (void)localeDidChange:(NSNotification *)notification -{ - SDL_SendLocaleChangedEvent(); -} - -- (void)observeValueForKeyPath:(NSString *)keyPath - ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context -{ - SDL_SetSystemTheme(Cocoa_GetSystemTheme()); -} - -- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename -{ - return (BOOL)SDL_SendDropFile(NULL, NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL); -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification -{ - if (!SDL_GetHintBoolean("SDL_MAC_REGISTER_ACTIVATION_HANDLERS", true)) - return; - - /* The menu bar of SDL apps which don't have the typical .app bundle - * structure fails to work the first time a window is created (until it's - * de-focused and re-focused), if this call is in Cocoa_RegisterApp instead - * of here. https://bugzilla.libsdl.org/show_bug.cgi?id=3051 - */ - if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, false)) { - // Get more aggressive for Catalina: activate the Dock first so we definitely reset all activation state. - for (NSRunningApplication *i in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) { - [i activateWithOptions:NSApplicationActivateIgnoringOtherApps]; - break; - } - SDL_Delay(300); // !!! FIXME: this isn't right. - [NSApp activateIgnoringOtherApps:YES]; - } - - /* If we call this before NSApp activation, macOS might print a complaint - * about ApplePersistenceIgnoreState. */ - [SDL3Application registerUserDefaults]; -} - -- (void)handleURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent -{ - NSString *path = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; - SDL_SendDropFile(NULL, NULL, [path UTF8String]); - SDL_SendDropComplete(NULL); -} - -- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app -{ - // This just tells Cocoa that we didn't do any custom save state magic for the app, - // so the system is safe to use NSSecureCoding internally, instead of using unencrypted - // save states for backwards compatibility. If we don't return YES here, we'll get a - // warning on the console at startup: - // - // ``` - // WARNING: Secure coding is not enabled for restorable state! Enable secure coding by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState: and returning YES. - // ``` - // - // More-detailed explanation: - // https://stackoverflow.com/questions/77283578/sonoma-and-nsapplicationdelegate-applicationsupportssecurerestorablestate/77320845#77320845 - return YES; -} - -- (IBAction)menu:(id)sender -{ - SDL_TrayEntry *entry = [[sender representedObject] pointerValue]; - - SDL_ClickTrayEntry(entry); -} - -@end - -static SDL3AppDelegate *appDelegate = nil; - -static NSString *GetApplicationName(void) -{ - NSString *appName = nil; - - const char *metaname = SDL_GetStringProperty(SDL_GetGlobalProperties(), SDL_PROP_APP_METADATA_NAME_STRING, NULL); - if (metaname && *metaname) { - appName = [NSString stringWithUTF8String:metaname]; - } - - // Determine the application name - if (!appName) { - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - if (!appName) { - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; - } - } - - if (![appName length]) { - appName = [[NSProcessInfo processInfo] processName]; - } - - return appName; -} - -static bool LoadMainMenuNibIfAvailable(void) -{ - NSDictionary *infoDict; - NSString *mainNibFileName; - bool success = false; - - infoDict = [[NSBundle mainBundle] infoDictionary]; - if (infoDict) { - mainNibFileName = [infoDict valueForKey:@"NSMainNibFile"]; - - if (mainNibFileName) { - success = [[NSBundle mainBundle] loadNibNamed:mainNibFileName owner:[NSApplication sharedApplication] topLevelObjects:nil]; - } - } - - return success; -} - -static void CreateApplicationMenus(void) -{ - NSString *appName; - NSString *title; - NSMenu *appleMenu; - NSMenu *serviceMenu; - NSMenu *windowMenu; - NSMenuItem *menuItem; - NSMenu *mainMenu; - - if (NSApp == nil) { - return; - } - - mainMenu = [[NSMenu alloc] init]; - - // Create the main menu bar - [NSApp setMainMenu:mainMenu]; - - // Create the application menu - appName = GetApplicationName(); - appleMenu = [[NSMenu alloc] initWithTitle:@""]; - - // Add menu items - title = [@"About " stringByAppendingString:appName]; - - // !!! FIXME: Menu items can't take parameters, just a basic selector, so this should instead call a selector - // !!! FIXME: that itself calls -[NSApplication orderFrontStandardAboutPanelWithOptions:optionsDictionary], - // !!! FIXME: filling in that NSDictionary with SDL_GetAppMetadataProperty() - [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - [appleMenu addItemWithTitle:@"Preferences…" action:nil keyEquivalent:@","]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - serviceMenu = [[NSMenu alloc] initWithTitle:@""]; - menuItem = [appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:serviceMenu]; - - [NSApp setServicesMenu:serviceMenu]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Hide " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; - - menuItem = [appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)]; - - [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Quit " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; - - // Put menu into the menubar - menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:appleMenu]; - [[NSApp mainMenu] addItem:menuItem]; - - // Tell the application object that this is now the application menu - [NSApp setAppleMenu:appleMenu]; - - // Create the window menu - windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; - - // Add menu items - [windowMenu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"]; - - [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; - - [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; - - // Add the fullscreen toggle menu option. - /* Cocoa should update the title to Enter or Exit Full Screen automatically. - * But if not, then just fallback to Toggle Full Screen. - */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"]; - [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; - [windowMenu addItem:menuItem]; - - // Put menu into the menubar - menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:windowMenu]; - [[NSApp mainMenu] addItem:menuItem]; - - // Tell the application object that this is now the window menu - [NSApp setWindowsMenu:windowMenu]; -} - -void Cocoa_RegisterApp(void) -{ - @autoreleasepool { - // This can get called more than once! Be careful what you initialize! - - if (NSApp == nil) { - [SDL3Application sharedApplication]; - SDL_assert(NSApp != nil); - - s_bShouldHandleEventsInSDLApplication = true; - - if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, false)) { - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - } - - /* If there aren't already menus in place, look to see if there's - * a nib we should use. If not, then manually create the basic - * menus we meed. - */ - if ([NSApp mainMenu] == nil) { - bool nibLoaded; - - nibLoaded = LoadMainMenuNibIfAvailable(); - if (!nibLoaded) { - CreateApplicationMenus(); - } - } - [NSApp finishLaunching]; - if ([NSApp delegate]) { - /* The SDL app delegate calls this in didFinishLaunching if it's - * attached to the NSApp, otherwise we need to call it manually. - */ - [SDL3Application registerUserDefaults]; - } - } - if (NSApp && !appDelegate) { - appDelegate = [[SDL3AppDelegate alloc] init]; - - /* If someone else has an app delegate, it means we can't turn a - * termination into SDL_Quit, and we can't handle application:openFile: - */ - if (![NSApp delegate]) { - /* Only register the URL event handler if we are being set as the - * app delegate to avoid replacing any existing event handler. - */ - [[NSAppleEventManager sharedAppleEventManager] - setEventHandler:appDelegate - andSelector:@selector(handleURLEvent:withReplyEvent:) - forEventClass:kInternetEventClass - andEventID:kAEGetURL]; - - [(NSApplication *)NSApp setDelegate:appDelegate]; - } else { - appDelegate->seenFirstActivate = YES; - } - } - } -} - -Uint64 Cocoa_GetEventTimestamp(NSTimeInterval nsTimestamp) -{ - static Uint64 timestamp_offset; - Uint64 timestamp = (Uint64)(nsTimestamp * SDL_NS_PER_SECOND); - Uint64 now = SDL_GetTicksNS(); - - if (!timestamp_offset) { - timestamp_offset = (now - timestamp); - } - timestamp += timestamp_offset; - - if (timestamp > now) { - timestamp_offset -= (timestamp - now); - timestamp = now; - } - return timestamp; -} - -int Cocoa_PumpEventsUntilDate(SDL_VideoDevice *_this, NSDate *expiration, bool accumulate) -{ - // Run any existing modal sessions. - for (SDL_Window *w = _this->windows; w; w = w->next) { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)w->internal; - if (data.modal_session) { - [NSApp runModalSession:data.modal_session]; - } - } - - for (;;) { - NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:expiration inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event == nil) { - return 0; - } - - if (!s_bShouldHandleEventsInSDLApplication) { - Cocoa_DispatchEvent(event); - } - - // Pass events down to SDL3Application to be handled in sendEvent: - [NSApp sendEvent:event]; - if (!accumulate) { - break; - } - } - return 1; -} - -int Cocoa_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS) -{ - @autoreleasepool { - if (timeoutNS > 0) { - NSDate *limitDate = [NSDate dateWithTimeIntervalSinceNow:(double)timeoutNS / SDL_NS_PER_SECOND]; - return Cocoa_PumpEventsUntilDate(_this, limitDate, false); - } else if (timeoutNS == 0) { - return Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], false); - } else { - while (Cocoa_PumpEventsUntilDate(_this, [NSDate distantFuture], false) == 0) { - } - } - return 1; - } -} - -void Cocoa_PumpEvents(SDL_VideoDevice *_this) -{ - @autoreleasepool { - Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], true); - } -} - -void Cocoa_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined - location:NSMakePoint(0, 0) - modifierFlags:0 - timestamp:0.0 - windowNumber:((__bridge SDL_CocoaWindowData *)window->internal).window_number - context:nil - subtype:0 - data1:0 - data2:0]; - - [NSApp postEvent:event atStart:YES]; - } -} - -bool Cocoa_SuspendScreenSaver(SDL_VideoDevice *_this) -{ - @autoreleasepool { - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - - if (data.screensaver_assertion) { - IOPMAssertionRelease(data.screensaver_assertion); - data.screensaver_assertion = kIOPMNullAssertionID; - } - - if (_this->suspend_screensaver) { - /* FIXME: this should ideally describe the real reason why the game - * called SDL_DisableScreenSaver. Note that the name is only meant to be - * seen by macOS power users. there's an additional optional human-readable - * (localized) reason parameter which we don't set. - */ - IOPMAssertionID assertion = kIOPMNullAssertionID; - NSString *name = [GetApplicationName() stringByAppendingString:@" using SDL_DisableScreenSaver"]; - IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep, - (__bridge CFStringRef)name, - NULL, NULL, NULL, 0, NULL, - &assertion); - data.screensaver_assertion = assertion; - } - } - return true; -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.h deleted file mode 100644 index 145f6cf..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoakeyboard_h_ -#define SDL_cocoakeyboard_h_ - -extern void Cocoa_InitKeyboard(SDL_VideoDevice *_this); -extern void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event); -extern void Cocoa_QuitKeyboard(SDL_VideoDevice *_this); - -extern bool Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props); -extern bool Cocoa_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window); - -extern bool Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed); - -#endif // SDL_cocoakeyboard_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m deleted file mode 100644 index e458be9..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoakeyboard.m +++ /dev/null @@ -1,604 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoavideo.h" - -#include "../../events/SDL_events_c.h" -#include "../../events/SDL_keyboard_c.h" -#include "../../events/scancodes_darwin.h" - -#include - -#if 0 -#define DEBUG_IME NSLog -#else -#define DEBUG_IME(...) -#endif - -@interface SDL3TranslatorResponder : NSView -{ - NSString *_markedText; - NSRange _markedRange; - NSRange _selectedRange; - SDL_Rect _inputRect; - int _pendingRawCode; - SDL_Scancode _pendingScancode; - Uint64 _pendingTimestamp; -} -- (void)doCommandBySelector:(SEL)myselector; -- (void)setInputRect:(const SDL_Rect *)rect; -- (void)setPendingKey:(int)rawcode scancode:(SDL_Scancode)scancode timestamp:(Uint64)timestamp; -- (void)sendPendingKey; -- (void)clearPendingKey; -@end - -@implementation SDL3TranslatorResponder - -- (void)setInputRect:(const SDL_Rect *)rect -{ - SDL_copyp(&_inputRect, rect); -} - -- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange -{ - const char *str; - - DEBUG_IME(@"insertText: %@ replacementRange: (%d, %d)", aString, - (int)replacementRange.location, (int)replacementRange.length); - - /* Could be NSString or NSAttributedString, so we have - * to test and convert it before return as SDL event */ - if ([aString isKindOfClass:[NSAttributedString class]]) { - str = [[aString string] UTF8String]; - } else { - str = [aString UTF8String]; - } - - // We're likely sending the composed text, so we reset the IME status. - if ([self hasMarkedText]) { - [self unmarkText]; - } - - // Deliver the raw key event that generated this text - [self sendPendingKey]; - - if ((int)replacementRange.location != -1) { - // We're replacing the last character - SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_BACKSPACE, true); - SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_BACKSPACE, false); - } - - SDL_SendKeyboardText(str); -} - -- (void)doCommandBySelector:(SEL)myselector -{ - /* No need to do anything since we are not using Cocoa - selectors to handle special keys, instead we use SDL - key events to do the same job. - */ -} - -- (BOOL)hasMarkedText -{ - return _markedText != nil; -} - -- (NSRange)markedRange -{ - return _markedRange; -} - -- (NSRange)selectedRange -{ - return _selectedRange; -} - -- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange -{ - if ([aString isKindOfClass:[NSAttributedString class]]) { - aString = [aString string]; - } - - if ([aString length] == 0) { - [self unmarkText]; - return; - } - - if (_markedText != aString) { - _markedText = aString; - } - - _selectedRange = selectedRange; - _markedRange = NSMakeRange(0, [aString length]); - - // This key event was consumed by the IME - [self clearPendingKey]; - - NSUInteger utf32SelectedRangeLocation = [[aString substringToIndex:selectedRange.location] lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4; - NSUInteger utf32SelectionRangeEnd = [[aString substringToIndex:(selectedRange.location + selectedRange.length)] lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4; - NSUInteger utf32SelectionRangeLength = utf32SelectionRangeEnd - utf32SelectedRangeLocation; - - SDL_SendEditingText([aString UTF8String], - (int)utf32SelectedRangeLocation, (int)utf32SelectionRangeLength); - - DEBUG_IME(@"setMarkedText: %@, (%d, %d) replacement range (%d, %d)", _markedText, - (int)selectedRange.location, (int)selectedRange.length, - (int)replacementRange.location, (int)replacementRange.length); -} - -- (void)unmarkText -{ - _markedText = nil; - - // This key event was consumed by the IME - [self clearPendingKey]; - - SDL_SendEditingText("", 0, 0); -} - -- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange -{ - NSWindow *window = [self window]; - NSRect contentRect = [window contentRectForFrameRect:[window frame]]; - float windowHeight = contentRect.size.height; - NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h, - _inputRect.w, _inputRect.h); - - if (actualRange) { - *actualRange = aRange; - } - - DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@", - (int)aRange.location, (int)aRange.length, windowHeight, - NSStringFromRect(rect)); - - rect = [window convertRectToScreen:rect]; - - return rect; -} - -- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange -{ - DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", (int)aRange.location, (int)aRange.length); - return nil; -} - -- (NSInteger)conversationIdentifier -{ - return (NSInteger)self; -} - -/* This method returns the index for character that is - * nearest to thePoint. thPoint is in screen coordinate system. - */ -- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint -{ - DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y); - return 0; -} - -/* This method is the key to attribute extension. - * We could add new attributes through this method. - * NSInputServer examines the return value of this - * method & constructs appropriate attributed string. - */ -- (NSArray *)validAttributesForMarkedText -{ - return [NSArray array]; -} - -- (void)setPendingKey:(int)rawcode scancode:(SDL_Scancode)scancode timestamp:(Uint64)timestamp -{ - _pendingRawCode = rawcode; - _pendingScancode = scancode; - _pendingTimestamp = timestamp; -} - -- (void)sendPendingKey -{ - if (_pendingRawCode < 0) { - return; - } - - SDL_SendKeyboardKey(_pendingTimestamp, SDL_DEFAULT_KEYBOARD_ID, _pendingRawCode, _pendingScancode, true); - [self clearPendingKey]; -} - -- (void)clearPendingKey -{ - _pendingRawCode = -1; -} - -@end - -static bool IsModifierKeyPressed(unsigned int flags, - unsigned int target_mask, - unsigned int other_mask, - unsigned int either_mask) -{ - bool target_pressed = (flags & target_mask) != 0; - bool other_pressed = (flags & other_mask) != 0; - bool either_pressed = (flags & either_mask) != 0; - - if (either_pressed != (target_pressed || other_pressed)) - return either_pressed; - - return target_pressed; -} - -static void HandleModifiers(SDL_VideoDevice *_this, SDL_Scancode code, unsigned int modifierFlags) -{ - bool pressed = false; - - if (code == SDL_SCANCODE_LSHIFT) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELSHIFTKEYMASK, - NX_DEVICERSHIFTKEYMASK, NX_SHIFTMASK); - } else if (code == SDL_SCANCODE_LCTRL) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELCTLKEYMASK, - NX_DEVICERCTLKEYMASK, NX_CONTROLMASK); - } else if (code == SDL_SCANCODE_LALT) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELALTKEYMASK, - NX_DEVICERALTKEYMASK, NX_ALTERNATEMASK); - } else if (code == SDL_SCANCODE_LGUI) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELCMDKEYMASK, - NX_DEVICERCMDKEYMASK, NX_COMMANDMASK); - } else if (code == SDL_SCANCODE_RSHIFT) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERSHIFTKEYMASK, - NX_DEVICELSHIFTKEYMASK, NX_SHIFTMASK); - } else if (code == SDL_SCANCODE_RCTRL) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERCTLKEYMASK, - NX_DEVICELCTLKEYMASK, NX_CONTROLMASK); - } else if (code == SDL_SCANCODE_RALT) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERALTKEYMASK, - NX_DEVICELALTKEYMASK, NX_ALTERNATEMASK); - } else if (code == SDL_SCANCODE_RGUI) { - pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERCMDKEYMASK, - NX_DEVICELCMDKEYMASK, NX_COMMANDMASK); - } else { - return; - } - - if (pressed) { - SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, 0, code, true); - } else { - SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, 0, code, false); - } -} - -static void UpdateKeymap(SDL_CocoaVideoData *data, bool send_event) -{ - TISInputSourceRef key_layout; - UCKeyboardLayout *keyLayoutPtr = NULL; - CFDataRef uchrDataRef; - - // See if the keymap needs to be updated - key_layout = TISCopyCurrentKeyboardLayoutInputSource(); - if (key_layout == data.key_layout) { - return; - } - data.key_layout = key_layout; - - // Try Unicode data first - uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData); - if (uchrDataRef) { - keyLayoutPtr = (UCKeyboardLayout *)CFDataGetBytePtr(uchrDataRef); - } - - if (!keyLayoutPtr) { - CFRelease(key_layout); - return; - } - - static struct { - int flags; - SDL_Keymod modstate; - } mods[] = { - { 0, SDL_KMOD_NONE }, - { shiftKey, SDL_KMOD_SHIFT }, - { alphaLock, SDL_KMOD_CAPS }, - { (shiftKey | alphaLock), (SDL_KMOD_SHIFT | SDL_KMOD_CAPS) }, - { optionKey, SDL_KMOD_ALT }, - { (optionKey | shiftKey), (SDL_KMOD_ALT | SDL_KMOD_SHIFT) }, - { (optionKey | alphaLock), (SDL_KMOD_ALT | SDL_KMOD_CAPS) }, - { (optionKey | shiftKey | alphaLock), (SDL_KMOD_ALT | SDL_KMOD_SHIFT | SDL_KMOD_CAPS) } - }; - - UInt32 keyboard_type = LMGetKbdType(); - - SDL_Keymap *keymap = SDL_CreateKeymap(); - for (int m = 0; m < SDL_arraysize(mods); ++m) { - for (int i = 0; i < SDL_arraysize(darwin_scancode_table); i++) { - OSStatus err; - UniChar s[8]; - UniCharCount len; - UInt32 dead_key_state; - - // Make sure this scancode is a valid character scancode - SDL_Scancode scancode = darwin_scancode_table[i]; - if (scancode == SDL_SCANCODE_UNKNOWN || - scancode == SDL_SCANCODE_DELETE || - (SDL_GetKeymapKeycode(NULL, scancode, SDL_KMOD_NONE) & SDLK_SCANCODE_MASK)) { - continue; - } - - /* - * Swap the scancode for these two wrongly translated keys - * UCKeyTranslate() function does not do its job properly for ISO layout keyboards, where the key '@', - * which is located in the top left corner of the keyboard right under the Escape key, and the additional - * key '<', which is on the right of the Shift key, are inverted - */ - if ((scancode == SDL_SCANCODE_NONUSBACKSLASH || scancode == SDL_SCANCODE_GRAVE) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) { - // see comments in scancodes_darwin.h - scancode = (SDL_Scancode)((SDL_SCANCODE_NONUSBACKSLASH + SDL_SCANCODE_GRAVE) - scancode); - } - - dead_key_state = 0; - err = UCKeyTranslate(keyLayoutPtr, i, kUCKeyActionDown, - ((mods[m].flags >> 8) & 0xFF), keyboard_type, - kUCKeyTranslateNoDeadKeysMask, - &dead_key_state, 8, &len, s); - if (err != noErr) { - continue; - } - - if (len > 0 && s[0] != 0x10) { - SDL_SetKeymapEntry(keymap, scancode, mods[m].modstate, s[0]); - } else { - // The default keymap doesn't have any SDL_KMOD_ALT entries, so we don't need to override them - if (!(mods[m].modstate & SDL_KMOD_ALT)) { - SDL_SetKeymapEntry(keymap, scancode, mods[m].modstate, SDLK_UNKNOWN); - } - } - } - } - SDL_SetKeymap(keymap, send_event); -} - -static void SDLCALL SDL_MacOptionAsAltChanged(void *userdata, const char *name, const char *oldValue, const char *hint) -{ - SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata; - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - - if (hint && *hint) { - if (SDL_strcmp(hint, "none") == 0) { - data.option_as_alt = OptionAsAltNone; - } else if (SDL_strcmp(hint, "only_left") == 0) { - data.option_as_alt = OptionAsAltOnlyLeft; - } else if (SDL_strcmp(hint, "only_right") == 0) { - data.option_as_alt = OptionAsAltOnlyRight; - } else if (SDL_strcmp(hint, "both") == 0) { - data.option_as_alt = OptionAsAltBoth; - } - } else { - data.option_as_alt = OptionAsAltNone; - } -} - -void Cocoa_InitKeyboard(SDL_VideoDevice *_this) -{ - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - - UpdateKeymap(data, false); - - // Set our own names for the platform-dependent but layout-independent keys - // This key is NumLock on the MacBook keyboard. :) - // SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear"); - SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option"); - SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command"); - SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option"); - SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command"); - - data.modifierFlags = (unsigned int)[NSEvent modifierFlags]; - SDL_ToggleModState(SDL_KMOD_CAPS, (data.modifierFlags & NSEventModifierFlagCapsLock) ? true : false); - - SDL_AddHintCallback(SDL_HINT_MAC_OPTION_AS_ALT, SDL_MacOptionAsAltChanged, _this); -} - -bool Cocoa_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) -{ - @autoreleasepool { - NSView *parentView; - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow; - - parentView = [nswindow contentView]; - - /* We only keep one field editor per process, since only the front most - * window can receive text input events, so it make no sense to keep more - * than one copy. When we switched to another window and requesting for - * text input, simply remove the field editor from its superview then add - * it to the front most window's content view */ - if (!data.fieldEdit) { - data.fieldEdit = [[SDL3TranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)]; - } - - if (![[data.fieldEdit superview] isEqual:parentView]) { - // DEBUG_IME(@"add fieldEdit to window contentView"); - [data.fieldEdit removeFromSuperview]; - [parentView addSubview:data.fieldEdit]; - [nswindow makeFirstResponder:data.fieldEdit]; - } - } - return Cocoa_UpdateTextInputArea(_this, window); -} - -bool Cocoa_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - - if (data && data.fieldEdit) { - [data.fieldEdit removeFromSuperview]; - data.fieldEdit = nil; - } - } - return true; -} - -bool Cocoa_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window) -{ - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - if (data.fieldEdit) { - [data.fieldEdit setInputRect:&window->text_input_rect]; - } - return true; -} - -static NSEvent *ReplaceEvent(NSEvent *event, OptionAsAlt option_as_alt) -{ - if (option_as_alt == OptionAsAltNone) { - return event; - } - - const unsigned int modflags = (unsigned int)[event modifierFlags]; - - bool ignore_alt_characters = false; - - bool lalt_pressed = IsModifierKeyPressed(modflags, NX_DEVICELALTKEYMASK, - NX_DEVICERALTKEYMASK, NX_ALTERNATEMASK); - bool ralt_pressed = IsModifierKeyPressed(modflags, NX_DEVICERALTKEYMASK, - NX_DEVICELALTKEYMASK, NX_ALTERNATEMASK); - - if (option_as_alt == OptionAsAltOnlyLeft && lalt_pressed) { - ignore_alt_characters = true; - } else if (option_as_alt == OptionAsAltOnlyRight && ralt_pressed) { - ignore_alt_characters = true; - } else if (option_as_alt == OptionAsAltBoth && (lalt_pressed || ralt_pressed)) { - ignore_alt_characters = true; - } - - bool cmd_pressed = modflags & NX_COMMANDMASK; - bool ctrl_pressed = modflags & NX_CONTROLMASK; - - ignore_alt_characters = ignore_alt_characters && !cmd_pressed && !ctrl_pressed; - - if (ignore_alt_characters) { - NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers]; - return [NSEvent keyEventWithType:[event type] - location:[event locationInWindow] - modifierFlags:modflags - timestamp:[event timestamp] - windowNumber:[event windowNumber] - context:nil - characters:charactersIgnoringModifiers - charactersIgnoringModifiers:charactersIgnoringModifiers - isARepeat:[event isARepeat] - keyCode:[event keyCode]]; - } - - return event; -} - -void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event) -{ - unsigned short scancode; - SDL_Scancode code; - SDL_CocoaVideoData *data = _this ? ((__bridge SDL_CocoaVideoData *)_this->internal) : nil; - if (!data) { - return; // can happen when returning from fullscreen Space on shutdown - } - - if ([event type] == NSEventTypeKeyDown || [event type] == NSEventTypeKeyUp) { - event = ReplaceEvent(event, data.option_as_alt); - } - - scancode = [event keyCode]; - - if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) { - // see comments in scancodes_darwin.h - scancode = 60 - scancode; - } - - if (scancode < SDL_arraysize(darwin_scancode_table)) { - code = darwin_scancode_table[scancode]; - } else { - // Hmm, does this ever happen? If so, need to extend the keymap... - code = SDL_SCANCODE_UNKNOWN; - } - - switch ([event type]) { - case NSEventTypeKeyDown: - if (![event isARepeat]) { - // See if we need to rebuild the keyboard layout - UpdateKeymap(data, true); - } - -#ifdef DEBUG_SCANCODES - if (code == SDL_SCANCODE_UNKNOWN) { - SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL forums/mailing list or to Christian Walther . Mac virtual key code is %d.", scancode); - } -#endif - if (SDL_TextInputActive(SDL_GetKeyboardFocus())) { - [data.fieldEdit setPendingKey:scancode scancode:code timestamp:Cocoa_GetEventTimestamp([event timestamp])]; - [data.fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]]; - [data.fieldEdit sendPendingKey]; - } else if (SDL_GetKeyboardFocus()) { - SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_DEFAULT_KEYBOARD_ID, scancode, code, true); - } - break; - case NSEventTypeKeyUp: - SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_DEFAULT_KEYBOARD_ID, scancode, code, false); - break; - case NSEventTypeFlagsChanged: { - // see if the new modifierFlags mean any existing keys should be pressed/released... - const unsigned int modflags = (unsigned int)[event modifierFlags]; - HandleModifiers(_this, SDL_SCANCODE_LSHIFT, modflags); - HandleModifiers(_this, SDL_SCANCODE_LCTRL, modflags); - HandleModifiers(_this, SDL_SCANCODE_LALT, modflags); - HandleModifiers(_this, SDL_SCANCODE_LGUI, modflags); - HandleModifiers(_this, SDL_SCANCODE_RSHIFT, modflags); - HandleModifiers(_this, SDL_SCANCODE_RCTRL, modflags); - HandleModifiers(_this, SDL_SCANCODE_RALT, modflags); - HandleModifiers(_this, SDL_SCANCODE_RGUI, modflags); - break; - } - default: // just to avoid compiler warnings - break; - } -} - -void Cocoa_QuitKeyboard(SDL_VideoDevice *_this) -{ -} - -typedef int CGSConnection; -typedef enum -{ - CGSGlobalHotKeyEnable = 0, - CGSGlobalHotKeyDisable = 1, -} CGSGlobalHotKeyOperatingMode; - -extern CGSConnection _CGSDefaultConnection(void); -extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection connection, CGSGlobalHotKeyOperatingMode mode); - -bool Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed) -{ -#ifdef SDL_MAC_NO_SANDBOX - CGSSetGlobalHotKeyOperatingMode(_CGSDefaultConnection(), grabbed ? CGSGlobalHotKeyDisable : CGSGlobalHotKeyEnable); -#endif - return true; -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.h deleted file mode 100644 index ea02052..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -extern bool Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID); - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.m deleted file mode 100644 index d54adb1..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamessagebox.m +++ /dev/null @@ -1,145 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoavideo.h" - -@interface SDL3MessageBoxPresenter : NSObject -{ - @public - NSInteger clicked; - NSWindow *nswindow; -} -- (id)initWithParentWindow:(SDL_Window *)window; -@end - -@implementation SDL3MessageBoxPresenter -- (id)initWithParentWindow:(SDL_Window *)window -{ - self = [super init]; - if (self) { - clicked = -1; - - // Retain the NSWindow because we'll show the alert later on the main thread - if (window) { - nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow; - } else { - nswindow = nil; - } - } - - return self; -} - -- (void)showAlert:(NSAlert *)alert -{ - if (nswindow) { - [alert beginSheetModalForWindow:nswindow - completionHandler:^(NSModalResponse returnCode) { - [NSApp stopModalWithCode:returnCode]; - }]; - clicked = [NSApp runModalForWindow:nswindow]; - nswindow = nil; - } else { - clicked = [alert runModal]; - } -} -@end - -static void Cocoa_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonID, bool *result) -{ - NSAlert *alert; - const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; - SDL3MessageBoxPresenter *presenter; - NSInteger clicked; - int i; - Cocoa_RegisterApp(); - - alert = [[NSAlert alloc] init]; - - if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) { - [alert setAlertStyle:NSAlertStyleCritical]; - } else if (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) { - [alert setAlertStyle:NSAlertStyleWarning]; - } else { - [alert setAlertStyle:NSAlertStyleInformational]; - } - - [alert setMessageText:[NSString stringWithUTF8String:messageboxdata->title]]; - [alert setInformativeText:[NSString stringWithUTF8String:messageboxdata->message]]; - - for (i = 0; i < messageboxdata->numbuttons; ++i) { - const SDL_MessageBoxButtonData *sdlButton; - NSButton *button; - - if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) { - sdlButton = &messageboxdata->buttons[messageboxdata->numbuttons - 1 - i]; - } else { - sdlButton = &messageboxdata->buttons[i]; - } - - button = [alert addButtonWithTitle:[NSString stringWithUTF8String:sdlButton->text]]; - if (sdlButton->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) { - [button setKeyEquivalent:@"\r"]; - } else if (sdlButton->flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) { - [button setKeyEquivalent:@"\033"]; - } else { - [button setKeyEquivalent:@""]; - } - } - - presenter = [[SDL3MessageBoxPresenter alloc] initWithParentWindow:messageboxdata->window]; - - [presenter showAlert:alert]; - - clicked = presenter->clicked; - if (clicked >= NSAlertFirstButtonReturn) { - clicked -= NSAlertFirstButtonReturn; - if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) { - clicked = messageboxdata->numbuttons - 1 - clicked; - } - *buttonID = buttons[clicked].buttonID; - *result = true; - } else { - *result = SDL_SetError("Did not get a valid `clicked button' id: %ld", (long)clicked); - } -} - -// Display a Cocoa message box -bool Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID) -{ - @autoreleasepool { - __block bool result = 0; - - if ([NSThread isMainThread]) { - Cocoa_ShowMessageBoxImpl(messageboxdata, buttonID, &result); - } else { - dispatch_sync(dispatch_get_main_queue(), ^{ - Cocoa_ShowMessageBoxImpl(messageboxdata, buttonID, &result); - }); - } - return result; - } -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.h deleted file mode 100644 index 3b76836..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -/* - * @author Mark Callow, www.edgewise-consulting.com. - * - * Thanks to @slime73 on GitHub for their gist showing how to add a CAMetalLayer - * backed view. - */ -#include "SDL_internal.h" - -#ifndef SDL_cocoametalview_h_ -#define SDL_cocoametalview_h_ - -#if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL)) - -#import "../SDL_sysvideo.h" - -#import "SDL_cocoawindow.h" - -#import -#import -#import - -@interface SDL3_cocoametalview : NSView - -- (instancetype)initWithFrame:(NSRect)frame - highDPI:(BOOL)highDPI - windowID:(Uint32)windowID - opaque:(BOOL)opaque; - -- (void)updateDrawableSize; -- (NSView *)hitTest:(NSPoint)point; - -// Override superclass tag so this class can set it. -@property(assign, readonly) NSInteger tag; - -@property(nonatomic) BOOL highDPI; -@property(nonatomic) Uint32 sdlWindowID; - -@end - -SDL_MetalView Cocoa_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window); -void Cocoa_Metal_DestroyView(SDL_VideoDevice *_this, SDL_MetalView view); -void *Cocoa_Metal_GetLayer(SDL_VideoDevice *_this, SDL_MetalView view); - -#endif // SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) - -#endif // SDL_cocoametalview_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m deleted file mode 100644 index af84e93..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoametalview.m +++ /dev/null @@ -1,182 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -/* - * @author Mark Callow, www.edgewise-consulting.com. - * - * Thanks to @slime73 on GitHub for their gist showing how to add a CAMetalLayer - * backed view. - */ -#include "SDL_internal.h" - -#include "../../events/SDL_windowevents_c.h" - -#import "SDL_cocoametalview.h" - -#if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL)) - -static bool SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event) -{ - /* Update the drawable size when SDL receives a size changed event for - * the window that contains the metal view. It would be nice to use - * - (void)resizeWithOldSuperviewSize:(NSSize)oldSize and - * - (void)viewDidChangeBackingProperties instead, but SDL's size change - * events don't always happen in the same frame (for example when a - * resizable window exits a fullscreen Space via the user pressing the OS - * exit-space button). */ - if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { - @autoreleasepool { - SDL3_cocoametalview *view = (__bridge SDL3_cocoametalview *)userdata; - if (view.sdlWindowID == event->window.windowID) { - [view updateDrawableSize]; - } - } - } - return false; -} - -@implementation SDL3_cocoametalview - -// Return a Metal-compatible layer. -+ (Class)layerClass -{ - return NSClassFromString(@"CAMetalLayer"); -} - -// Indicate the view wants to draw using a backing layer instead of drawRect. -- (BOOL)wantsUpdateLayer -{ - return YES; -} - -/* When the wantsLayer property is set to YES, this method will be invoked to - * return a layer instance. - */ -- (CALayer *)makeBackingLayer -{ - return [self.class.layerClass layer]; -} - -- (instancetype)initWithFrame:(NSRect)frame - highDPI:(BOOL)highDPI - windowID:(Uint32)windowID - opaque:(BOOL)opaque -{ - self = [super initWithFrame:frame]; - if (self != nil) { - self.highDPI = highDPI; - self.sdlWindowID = windowID; - self.wantsLayer = YES; - - // Allow resize. - self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - - self.layer.opaque = opaque; - - SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); - - [self updateDrawableSize]; - } - - return self; -} - -- (void)dealloc -{ - SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self)); -} - -- (NSInteger)tag -{ - return SDL_METALVIEW_TAG; -} - -- (void)updateDrawableSize -{ - CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer; - NSSize size = self.bounds.size; - NSSize backingSize = size; - - if (self.highDPI) { - /* Note: NSHighResolutionCapable must be set to true in the app's - * Info.plist in order for the backing size to be high res. - */ - backingSize = [self convertSizeToBacking:size]; - } - - metalLayer.contentsScale = backingSize.height / size.height; - metalLayer.drawableSize = NSSizeToCGSize(backingSize); -} - -- (NSView *)hitTest:(NSPoint)point -{ - return nil; -} - -@end - -SDL_MetalView Cocoa_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSView *view = data.nswindow.contentView; - BOOL highDPI = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) != 0; - BOOL opaque = (window->flags & SDL_WINDOW_TRANSPARENT) == 0; - Uint32 windowID = SDL_GetWindowID(window); - SDL3_cocoametalview *newview; - SDL_MetalView metalview; - - newview = [[SDL3_cocoametalview alloc] initWithFrame:view.frame - highDPI:highDPI - windowID:windowID - opaque:opaque]; - if (newview == nil) { - SDL_OutOfMemory(); - return NULL; - } - - [view addSubview:newview]; - - // Make sure the drawable size is up to date after attaching the view. - [newview updateDrawableSize]; - - metalview = (SDL_MetalView)CFBridgingRetain(newview); - - return metalview; - } -} - -void Cocoa_Metal_DestroyView(SDL_VideoDevice *_this, SDL_MetalView view) -{ - @autoreleasepool { - SDL3_cocoametalview *metalview = CFBridgingRelease(view); - [metalview removeFromSuperview]; - } -} - -void *Cocoa_Metal_GetLayer(SDL_VideoDevice *_this, SDL_MetalView view) -{ - @autoreleasepool { - SDL3_cocoametalview *cocoaview = (__bridge SDL3_cocoametalview *)view; - return (__bridge void *)cocoaview.layer; - } -} - -#endif // SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.h deleted file mode 100644 index 37f3aa5..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoamodes_h_ -#define SDL_cocoamodes_h_ - -struct SDL_DisplayData -{ - CGDirectDisplayID display; -}; - -struct SDL_DisplayModeData -{ - CFMutableArrayRef modes; -}; - -extern void Cocoa_InitModes(SDL_VideoDevice *_this); -extern void Cocoa_UpdateDisplays(SDL_VideoDevice *_this); -extern bool Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect); -extern bool Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect); -extern bool Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display); -extern bool Cocoa_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode); -extern void Cocoa_QuitModes(SDL_VideoDevice *_this); -extern SDL_VideoDisplay *Cocoa_FindSDLDisplayByCGDirectDisplayID(SDL_VideoDevice *_this, CGDirectDisplayID displayid); - -#endif // SDL_cocoamodes_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.m deleted file mode 100644 index b3c34ba..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamodes.m +++ /dev/null @@ -1,716 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoavideo.h" -#include "../../events/SDL_events_c.h" - -// We need this for IODisplayCreateInfoDictionary and kIODisplayOnlyPreferredName -#include - -// We need this for CVDisplayLinkGetNominalOutputVideoRefreshPeriod -#include -#include - -#if (IOGRAPHICSTYPES_REV < 40) -#define kDisplayModeNativeFlag 0x02000000 -#endif - -static bool CG_SetError(const char *prefix, CGDisplayErr result) -{ - const char *error; - - switch (result) { - case kCGErrorFailure: - error = "kCGErrorFailure"; - break; - case kCGErrorIllegalArgument: - error = "kCGErrorIllegalArgument"; - break; - case kCGErrorInvalidConnection: - error = "kCGErrorInvalidConnection"; - break; - case kCGErrorInvalidContext: - error = "kCGErrorInvalidContext"; - break; - case kCGErrorCannotComplete: - error = "kCGErrorCannotComplete"; - break; - case kCGErrorNotImplemented: - error = "kCGErrorNotImplemented"; - break; - case kCGErrorRangeCheck: - error = "kCGErrorRangeCheck"; - break; - case kCGErrorTypeCheck: - error = "kCGErrorTypeCheck"; - break; - case kCGErrorInvalidOperation: - error = "kCGErrorInvalidOperation"; - break; - case kCGErrorNoneAvailable: - error = "kCGErrorNoneAvailable"; - break; - default: - error = "Unknown Error"; - break; - } - return SDL_SetError("%s: %s", prefix, error); -} - -static NSScreen *GetNSScreenForDisplayID(CGDirectDisplayID displayID) -{ - NSArray *screens = [NSScreen screens]; - - // !!! FIXME: maybe track the NSScreen in SDL_DisplayData? - for (NSScreen *screen in screens) { - const CGDirectDisplayID thisDisplay = (CGDirectDisplayID)[[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; - if (thisDisplay == displayID) { - return screen; - } - } - return nil; -} - -SDL_VideoDisplay *Cocoa_FindSDLDisplayByCGDirectDisplayID(SDL_VideoDevice *_this, CGDirectDisplayID displayid) -{ - for (int i = 0; i < _this->num_displays; i++) { - const SDL_DisplayData *displaydata = _this->displays[i]->internal; - if (displaydata && (displaydata->display == displayid)) { - return _this->displays[i]; - } - } - return NULL; -} - -static float GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link) -{ - float refreshRate = (float)CGDisplayModeGetRefreshRate(vidmode); - - // CGDisplayModeGetRefreshRate can return 0 (eg for built-in displays). - if (refreshRate == 0 && link != NULL) { - CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); - if ((time.flags & kCVTimeIsIndefinite) == 0 && time.timeValue != 0) { - refreshRate = (float)time.timeScale / time.timeValue; - } - } - - return refreshRate; -} - -static bool HasValidDisplayModeFlags(CGDisplayModeRef vidmode) -{ - uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode); - - // Filter out modes which have flags that we don't want. - if (ioflags & (kDisplayModeNeverShowFlag | kDisplayModeNotGraphicsQualityFlag)) { - return false; - } - - // Filter out modes which don't have flags that we want. - if (!(ioflags & kDisplayModeValidFlag) || !(ioflags & kDisplayModeSafeFlag)) { - return false; - } - - return true; -} - -static Uint32 GetDisplayModePixelFormat(CGDisplayModeRef vidmode) -{ - // This API is deprecated in 10.11 with no good replacement (as of 10.15). - CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode); - Uint32 pixelformat = SDL_PIXELFORMAT_UNKNOWN; - - if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - pixelformat = SDL_PIXELFORMAT_ARGB8888; - } else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - pixelformat = SDL_PIXELFORMAT_ARGB1555; - } else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - pixelformat = SDL_PIXELFORMAT_ARGB2101010; - } else { - // ignore 8-bit and such for now. - } - - CFRelease(fmt); - - return pixelformat; -} - -static bool GetDisplayMode(CGDisplayModeRef vidmode, bool vidmodeCurrent, CFArrayRef modelist, CVDisplayLinkRef link, SDL_DisplayMode *mode) -{ - SDL_DisplayModeData *data; - bool usableForGUI = CGDisplayModeIsUsableForDesktopGUI(vidmode); - size_t width = CGDisplayModeGetWidth(vidmode); - size_t height = CGDisplayModeGetHeight(vidmode); - size_t pixelW = width; - size_t pixelH = height; - uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode); - float refreshrate = GetDisplayModeRefreshRate(vidmode, link); - Uint32 format = GetDisplayModePixelFormat(vidmode); - bool interlaced = (ioflags & kDisplayModeInterlacedFlag) != 0; - CFMutableArrayRef modes; - - if (format == SDL_PIXELFORMAT_UNKNOWN) { - return false; - } - - /* Don't fail the current mode based on flags because this could prevent Cocoa_InitModes from - * succeeding if the current mode lacks certain flags (esp kDisplayModeSafeFlag). */ - if (!vidmodeCurrent && !HasValidDisplayModeFlags(vidmode)) { - return false; - } - - modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(modes, vidmode); - - /* If a list of possible display modes is passed in, use it to filter out - * modes that have duplicate sizes. We don't just rely on SDL's higher level - * duplicate filtering because this code can choose what properties are - * preferred, and it can add CGDisplayModes to the DisplayModeData's list of - * modes to try (see comment below for why that's necessary). */ - pixelW = CGDisplayModeGetPixelWidth(vidmode); - pixelH = CGDisplayModeGetPixelHeight(vidmode); - - if (modelist != NULL) { - CFIndex modescount = CFArrayGetCount(modelist); - int i; - - for (i = 0; i < modescount; i++) { - size_t otherW, otherH, otherpixelW, otherpixelH; - float otherrefresh; - Uint32 otherformat; - bool otherGUI; - CGDisplayModeRef othermode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modelist, i); - uint32_t otherioflags = CGDisplayModeGetIOFlags(othermode); - - if (CFEqual(vidmode, othermode)) { - continue; - } - - if (!HasValidDisplayModeFlags(othermode)) { - continue; - } - - otherW = CGDisplayModeGetWidth(othermode); - otherH = CGDisplayModeGetHeight(othermode); - otherpixelW = CGDisplayModeGetPixelWidth(othermode); - otherpixelH = CGDisplayModeGetPixelHeight(othermode); - otherrefresh = GetDisplayModeRefreshRate(othermode, link); - otherformat = GetDisplayModePixelFormat(othermode); - otherGUI = CGDisplayModeIsUsableForDesktopGUI(othermode); - - /* Ignore this mode if it's interlaced and there's a non-interlaced - * mode in the list with the same properties. - */ - if (interlaced && ((otherioflags & kDisplayModeInterlacedFlag) == 0) && width == otherW && height == otherH && pixelW == otherpixelW && pixelH == otherpixelH && refreshrate == otherrefresh && format == otherformat && usableForGUI == otherGUI) { - CFRelease(modes); - return false; - } - - /* Ignore this mode if it's not usable for desktop UI and its - * properties are equal to another GUI-capable mode in the list. - */ - if (width == otherW && height == otherH && pixelW == otherpixelW && pixelH == otherpixelH && !usableForGUI && otherGUI && refreshrate == otherrefresh && format == otherformat) { - CFRelease(modes); - return false; - } - - /* If multiple modes have the exact same properties, they'll all - * go in the list of modes to try when SetDisplayMode is called. - * This is needed because kCGDisplayShowDuplicateLowResolutionModes - * (which is used to expose highdpi display modes) can make the - * list of modes contain duplicates (according to their properties - * obtained via public APIs) which don't work with SetDisplayMode. - * Those duplicate non-functional modes *do* have different pixel - * formats according to their internal data structure viewed with - * NSLog, but currently no public API can detect that. - * https://bugzilla.libsdl.org/show_bug.cgi?id=4822 - * - * As of macOS 10.15.0, those duplicates have the exact same - * properties via public APIs in every way (even their IO flags and - * CGDisplayModeGetIODisplayModeID is the same), so we could test - * those for equality here too, but I'm intentionally not doing that - * in case there are duplicate modes with different IO flags or IO - * display mode IDs in the future. In that case I think it's better - * to try them all in SetDisplayMode than to risk one of them being - * correct but it being filtered out by SDL_AddFullscreenDisplayMode - * as being a duplicate. - */ - if (width == otherW && height == otherH && pixelW == otherpixelW && pixelH == otherpixelH && usableForGUI == otherGUI && refreshrate == otherrefresh && format == otherformat) { - CFArrayAppendValue(modes, othermode); - } - } - } - - SDL_zerop(mode); - data = (SDL_DisplayModeData *)SDL_malloc(sizeof(*data)); - if (!data) { - CFRelease(modes); - return false; - } - data->modes = modes; - mode->format = format; - mode->w = (int)width; - mode->h = (int)height; - mode->pixel_density = (float)pixelW / width; - mode->refresh_rate = refreshrate; - mode->internal = data; - return true; -} - -static char *Cocoa_GetDisplayName(CGDirectDisplayID displayID) -{ - if (@available(macOS 10.15, *)) { - NSScreen *screen = GetNSScreenForDisplayID(displayID); - if (screen) { - const char *name = [screen.localizedName UTF8String]; - if (name) { - return SDL_strdup(name); - } - } - } - - // This API is deprecated in 10.9 with no good replacement (as of 10.15). - io_service_t servicePort = CGDisplayIOServicePort(displayID); - CFDictionaryRef deviceInfo = IODisplayCreateInfoDictionary(servicePort, kIODisplayOnlyPreferredName); - NSDictionary *localizedNames = [(__bridge NSDictionary *)deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]]; - char *displayName = NULL; - - if ([localizedNames count] > 0) { - displayName = SDL_strdup([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]); - } - CFRelease(deviceInfo); - return displayName; -} - -static void Cocoa_GetHDRProperties(CGDirectDisplayID displayID, SDL_HDROutputProperties *HDR) -{ - HDR->SDR_white_level = 1.0f; - HDR->HDR_headroom = 1.0f; - - if (@available(macOS 10.15, *)) { - NSScreen *screen = GetNSScreenForDisplayID(displayID); - if (screen) { - if (screen.maximumExtendedDynamicRangeColorComponentValue > 1.0f) { - HDR->HDR_headroom = screen.maximumExtendedDynamicRangeColorComponentValue; - } else { - HDR->HDR_headroom = screen.maximumPotentialExtendedDynamicRangeColorComponentValue; - } - } - } -} - - -bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event) -{ - CGDisplayModeRef moderef = CGDisplayCopyDisplayMode(display); - if (!moderef) { - return false; - } - - SDL_DisplayData *displaydata = (SDL_DisplayData *)SDL_malloc(sizeof(*displaydata)); - if (!displaydata) { - CGDisplayModeRelease(moderef); - return false; - } - displaydata->display = display; - - CVDisplayLinkRef link = NULL; - CVDisplayLinkCreateWithCGDisplay(display, &link); - - SDL_VideoDisplay viddisplay; - SDL_zero(viddisplay); - viddisplay.name = Cocoa_GetDisplayName(display); // this returns a strdup'ed string - - SDL_DisplayMode mode; - if (!GetDisplayMode(moderef, true, NULL, link, &mode)) { - CVDisplayLinkRelease(link); - CGDisplayModeRelease(moderef); - SDL_free(viddisplay.name); - SDL_free(displaydata); - return false; - } - - CVDisplayLinkRelease(link); - CGDisplayModeRelease(moderef); - - Cocoa_GetHDRProperties(displaydata->display, &viddisplay.HDR); - - viddisplay.desktop_mode = mode; - viddisplay.internal = displaydata; - const bool retval = SDL_AddVideoDisplay(&viddisplay, send_event); - SDL_free(viddisplay.name); - return retval; -} - -static void Cocoa_DisplayReconfigurationCallback(CGDirectDisplayID displayid, CGDisplayChangeSummaryFlags flags, void *userInfo) -{ - #if 0 - SDL_Log("COCOA DISPLAY RECONFIG CALLBACK! display=%u", (unsigned int) displayid); - #define CHECK_DISPLAY_RECONFIG_FLAG(x) if (flags & x) { SDL_Log(" - " #x); } - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayBeginConfigurationFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayMovedFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplaySetMainFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplaySetModeFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayAddFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayRemoveFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayEnabledFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayDisabledFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayMirrorFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayUnMirrorFlag); - CHECK_DISPLAY_RECONFIG_FLAG(kCGDisplayDesktopShapeChangedFlag); - #undef CHECK_DISPLAY_RECONFIG_FLAG - #endif - - SDL_VideoDevice *_this = (SDL_VideoDevice *) userInfo; - SDL_VideoDisplay *display = Cocoa_FindSDLDisplayByCGDirectDisplayID(_this, displayid); // will be NULL for newly-added (or newly-unmirrored) displays! - - if (flags & kCGDisplayDisabledFlag) { - flags |= kCGDisplayRemoveFlag; // treat this like a display leaving, even though it's still plugged in. - } - - if (flags & kCGDisplayEnabledFlag) { - flags |= kCGDisplayAddFlag; // treat this like a display leaving, even though it's still plugged in. - } - - if (flags & kCGDisplayMirrorFlag) { - flags |= kCGDisplayRemoveFlag; // treat this like a display leaving, even though it's still actually here. - } - - if (flags & kCGDisplayUnMirrorFlag) { - flags |= kCGDisplayAddFlag; // treat this like a new display arriving, even though it was here all along. - } - - if ((flags & kCGDisplayAddFlag) && (flags & kCGDisplayRemoveFlag)) { - // sometimes you get a removed device that gets Add and Remove flags at the same time but the display dimensions are 0x0 or 1x1, hence the `> 1` test. - // Mirrored things are always removed, since they don't represent a discrete display in this state. - if (((flags & kCGDisplayMirrorFlag) == 0) && (CGDisplayPixelsWide(displayid) > 1)) { - // Final state is connected - flags &= ~kCGDisplayRemoveFlag; - } else { - // Final state is disconnected - flags &= ~kCGDisplayAddFlag; - } - } - - if (flags & kCGDisplayAddFlag) { - if (!display) { - if (!Cocoa_AddDisplay(displayid, true)) { - return; // oh well. - } - display = Cocoa_FindSDLDisplayByCGDirectDisplayID(_this, displayid); - SDL_assert(display != NULL); - } - } - - if (flags & kCGDisplayRemoveFlag) { - if (display) { - SDL_DelVideoDisplay(display->id, true); - display = NULL; - } - } - - if (flags & kCGDisplaySetModeFlag) { - if (display) { - CGDisplayModeRef moderef = CGDisplayCopyDisplayMode(displayid); - if (moderef) { - CVDisplayLinkRef link = NULL; - CVDisplayLinkCreateWithCGDisplay(displayid, &link); - if (link) { - SDL_DisplayMode mode; - if (GetDisplayMode(moderef, true, NULL, link, &mode)) { - SDL_SetDesktopDisplayMode(display, &mode); - } - CVDisplayLinkRelease(link); - } - CGDisplayModeRelease(moderef); - } - } - } - - if (flags & kCGDisplaySetMainFlag) { - if (display) { - for (int i = 0; i < _this->num_displays; i++) { - if (_this->displays[i] == display) { - if (i > 0) { - // move this display to the front of _this->displays so it's treated as primary. - SDL_memmove(&_this->displays[1], &_this->displays[0], sizeof (*_this->displays) * i); - _this->displays[0] = display; - } - flags |= kCGDisplayMovedFlag; // we don't have an SDL event atm for "this display became primary," so at least let everyone know it "moved". - break; - } - } - } - } - - if (flags & kCGDisplayMovedFlag) { - if (display) { - SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_MOVED, 0, 0); - } - } - - if (flags & kCGDisplayDesktopShapeChangedFlag) { - SDL_UpdateDesktopBounds(); - } -} - -void Cocoa_InitModes(SDL_VideoDevice *_this) -{ - @autoreleasepool { - CGDisplayErr result; - CGDisplayCount numDisplays = 0; - - result = CGGetOnlineDisplayList(0, NULL, &numDisplays); - if (result != kCGErrorSuccess) { - CG_SetError("CGGetOnlineDisplayList()", result); - return; - } - - bool isstack; - CGDirectDisplayID *displays = SDL_small_alloc(CGDirectDisplayID, numDisplays, &isstack); - - result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays); - if (result != kCGErrorSuccess) { - CG_SetError("CGGetOnlineDisplayList()", result); - SDL_small_free(displays, isstack); - return; - } - - // future updates to the display graph will come through this callback. - CGDisplayRegisterReconfigurationCallback(Cocoa_DisplayReconfigurationCallback, _this); - - // Pick up the primary display in the first pass, then get the rest - for (int pass = 0; pass < 2; ++pass) { - for (int i = 0; i < numDisplays; ++i) { - if (pass == 0) { - if (!CGDisplayIsMain(displays[i])) { - continue; - } - } else { - if (CGDisplayIsMain(displays[i])) { - continue; - } - } - - if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay) { - continue; - } - - Cocoa_AddDisplay(displays[i], false); - } - } - SDL_small_free(displays, isstack); - } -} - -void Cocoa_UpdateDisplays(SDL_VideoDevice *_this) -{ - SDL_HDROutputProperties HDR; - int i; - - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = _this->displays[i]; - SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal; - - Cocoa_GetHDRProperties(displaydata->display, &HDR); - SDL_SetDisplayHDRProperties(display, &HDR); - } -} - -bool Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect) -{ - SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal; - CGRect cgrect; - - cgrect = CGDisplayBounds(displaydata->display); - rect->x = (int)cgrect.origin.x; - rect->y = (int)cgrect.origin.y; - rect->w = (int)cgrect.size.width; - rect->h = (int)cgrect.size.height; - return true; -} - -bool Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect) -{ - SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal; - NSScreen *screen = GetNSScreenForDisplayID(displaydata->display); - - if (screen == nil) { - return SDL_SetError("Couldn't get NSScreen for display"); - } - - { - const NSRect frame = [screen visibleFrame]; - rect->x = (int)frame.origin.x; - rect->y = (int)(CGDisplayPixelsHigh(kCGDirectMainDisplay) - frame.origin.y - frame.size.height); - rect->w = (int)frame.size.width; - rect->h = (int)frame.size.height; - } - - return true; -} - -bool Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display) -{ - SDL_DisplayData *data = (SDL_DisplayData *)display->internal; - CVDisplayLinkRef link = NULL; - CFArrayRef modes; - CFDictionaryRef dict = NULL; - const CFStringRef dictkeys[] = { kCGDisplayShowDuplicateLowResolutionModes }; - const CFBooleanRef dictvalues[] = { kCFBooleanTrue }; - - CVDisplayLinkCreateWithCGDisplay(data->display, &link); - - /* By default, CGDisplayCopyAllDisplayModes will only get a subset of the - * system's available modes. For example on a 15" 2016 MBP, users can - * choose 1920x1080@2x in System Preferences but it won't show up here, - * unless we specify the option below. - * The display modes returned by CGDisplayCopyAllDisplayModes are also not - * high dpi-capable unless this option is set. - * macOS 10.15 also seems to have a bug where entering, exiting, and - * re-entering exclusive fullscreen with a low dpi display mode can cause - * the content of the screen to move up, which this setting avoids: - * https://bugzilla.libsdl.org/show_bug.cgi?id=4822 - */ - - dict = CFDictionaryCreate(NULL, - (const void **)dictkeys, - (const void **)dictvalues, - 1, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - modes = CGDisplayCopyAllDisplayModes(data->display, dict); - - if (dict) { - CFRelease(dict); - } - - if (modes) { - CFIndex i; - const CFIndex count = CFArrayGetCount(modes); - - for (i = 0; i < count; i++) { - CGDisplayModeRef moderef = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i); - SDL_DisplayMode mode; - - if (GetDisplayMode(moderef, false, modes, link, &mode)) { - if (!SDL_AddFullscreenDisplayMode(display, &mode)) { - CFRelease(mode.internal->modes); - SDL_free(mode.internal); - } - } - } - - CFRelease(modes); - } - - CVDisplayLinkRelease(link); - return true; -} - -static CGError SetDisplayModeForDisplay(CGDirectDisplayID display, SDL_DisplayModeData *data) -{ - /* SDL_DisplayModeData can contain multiple CGDisplayModes to try (with - * identical properties), some of which might not work. See GetDisplayMode. - */ - CGError result = kCGErrorFailure; - for (CFIndex i = 0; i < CFArrayGetCount(data->modes); i++) { - CGDisplayModeRef moderef = (CGDisplayModeRef)CFArrayGetValueAtIndex(data->modes, i); - result = CGDisplaySetDisplayMode(display, moderef, NULL); - if (result == kCGErrorSuccess) { - // If this mode works, try it first next time. - if (i > 0) { - CFArrayExchangeValuesAtIndices(data->modes, i, 0); - } - break; - } - } - return result; -} - -bool Cocoa_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode) -{ - SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal; - SDL_DisplayModeData *data = mode->internal; - CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken; - CGError result = kCGErrorSuccess; - - b_inModeTransition = true; - - // Fade to black to hide resolution-switching flicker - if (CGAcquireDisplayFadeReservation(5, &fade_token) == kCGErrorSuccess) { - CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE); - } - - if (data == display->desktop_mode.internal) { - // Restoring desktop mode - SetDisplayModeForDisplay(displaydata->display, data); - } else { - // Do the physical switch - result = SetDisplayModeForDisplay(displaydata->display, data); - } - - // Fade in again (asynchronously) - if (fade_token != kCGDisplayFadeReservationInvalidToken) { - CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE); - CGReleaseDisplayFadeReservation(fade_token); - } - - b_inModeTransition = false; - - if (result != kCGErrorSuccess) { - return CG_SetError("CGDisplaySwitchToMode()", result); - } - return true; -} - -void Cocoa_QuitModes(SDL_VideoDevice *_this) -{ - int i, j; - - CGDisplayRemoveReconfigurationCallback(Cocoa_DisplayReconfigurationCallback, _this); - - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = _this->displays[i]; - SDL_DisplayModeData *mode; - - if (display->current_mode->internal != display->desktop_mode.internal) { - Cocoa_SetDisplayMode(_this, display, &display->desktop_mode); - } - - mode = display->desktop_mode.internal; - CFRelease(mode->modes); - - for (j = 0; j < display->num_fullscreen_modes; j++) { - mode = display->fullscreen_modes[j].internal; - CFRelease(mode->modes); - } - } -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.h deleted file mode 100644 index 70282be..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoamouse_h_ -#define SDL_cocoamouse_h_ - -#include "SDL_cocoavideo.h" - -extern bool Cocoa_InitMouse(SDL_VideoDevice *_this); -extern NSWindow *Cocoa_GetMouseFocus(); -extern void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event); -extern void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event); -extern void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y); -extern void Cocoa_QuitMouse(SDL_VideoDevice *_this); - -typedef struct -{ - // Whether we've seen a cursor warp since the last move event. - bool seenWarp; - // What location our last cursor warp was to. - CGFloat lastWarpX; - CGFloat lastWarpY; - // What location we last saw the cursor move to. - CGFloat lastMoveX; - CGFloat lastMoveY; -} SDL_MouseData; - -@interface NSCursor (InvisibleCursor) -+ (NSCursor *)invisibleCursor; -@end - -#endif // SDL_cocoamouse_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m deleted file mode 100644 index 530ca0c..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoamouse.m +++ /dev/null @@ -1,591 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoamouse.h" -#include "SDL_cocoavideo.h" - -#include "../../events/SDL_mouse_c.h" - -#if 0 -#define DEBUG_COCOAMOUSE -#endif - -#ifdef DEBUG_COCOAMOUSE -#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__) -#else -#define DLog(...) \ - do { \ - } while (0) -#endif - -@implementation NSCursor (InvisibleCursor) -+ (NSCursor *)invisibleCursor -{ - static NSCursor *invisibleCursor = NULL; - if (!invisibleCursor) { - // RAW 16x16 transparent GIF - static unsigned char cursorBytes[] = { - 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04, - 0x01, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x8C, 0x8F, 0xA9, 0xCB, 0xED, - 0x0F, 0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B - }; - - NSData *cursorData = [NSData dataWithBytesNoCopy:&cursorBytes[0] - length:sizeof(cursorBytes) - freeWhenDone:NO]; - NSImage *cursorImage = [[NSImage alloc] initWithData:cursorData]; - invisibleCursor = [[NSCursor alloc] initWithImage:cursorImage - hotSpot:NSZeroPoint]; - } - - return invisibleCursor; -} -@end - -static SDL_Cursor *Cocoa_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) -{ - @autoreleasepool { - NSImage *nsimage; - NSCursor *nscursor = NULL; - SDL_Cursor *cursor = NULL; - - nsimage = Cocoa_CreateImage(surface); - if (nsimage) { - nscursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(hot_x, hot_y)]; - } - - if (nscursor) { - cursor = SDL_calloc(1, sizeof(*cursor)); - if (cursor) { - cursor->internal = (void *)CFBridgingRetain(nscursor); - } - } - - return cursor; - } -} - -/* there are .pdf files of some of the cursors we need, installed by default on macOS, but not available through NSCursor. - If we can load them ourselves, use them, otherwise fallback to something standard but not super-great. - Since these are under /System, they should be available even to sandboxed apps. */ -static NSCursor *LoadHiddenSystemCursor(NSString *cursorName, SEL fallback) -{ - NSString *cursorPath = [@"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors" stringByAppendingPathComponent:cursorName]; - NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"info.plist"]]; - // we can't do animation atm. :/ - const int frames = (int)[[info valueForKey:@"frames"] integerValue]; - NSCursor *cursor; - NSImage *image = [[NSImage alloc] initWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"cursor.pdf"]]; - if ((image == nil) || (image.isValid == NO)) { - return [NSCursor performSelector:fallback]; - } - - if (frames > 1) { -#ifdef MAC_OS_VERSION_12_0 // same value as deprecated symbol. - const NSCompositingOperation operation = NSCompositingOperationCopy; -#else - const NSCompositingOperation operation = NSCompositeCopy; -#endif - const NSSize cropped_size = NSMakeSize(image.size.width, (int)(image.size.height / frames)); - NSImage *cropped = [[NSImage alloc] initWithSize:cropped_size]; - if (cropped == nil) { - return [NSCursor performSelector:fallback]; - } - - [cropped lockFocus]; - { - const NSRect cropped_rect = NSMakeRect(0, 0, cropped_size.width, cropped_size.height); - [image drawInRect:cropped_rect fromRect:cropped_rect operation:operation fraction:1]; - } - [cropped unlockFocus]; - image = cropped; - } - - cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint([[info valueForKey:@"hotx"] doubleValue], [[info valueForKey:@"hoty"] doubleValue])]; - return cursor; -} - -static SDL_Cursor *Cocoa_CreateSystemCursor(SDL_SystemCursor id) -{ - @autoreleasepool { - NSCursor *nscursor = NULL; - SDL_Cursor *cursor = NULL; - - switch (id) { - case SDL_SYSTEM_CURSOR_DEFAULT: - nscursor = [NSCursor arrowCursor]; - break; - case SDL_SYSTEM_CURSOR_TEXT: - nscursor = [NSCursor IBeamCursor]; - break; - case SDL_SYSTEM_CURSOR_CROSSHAIR: - nscursor = [NSCursor crosshairCursor]; - break; - case SDL_SYSTEM_CURSOR_WAIT: // !!! FIXME: this is more like WAITARROW - nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor)); - break; - case SDL_SYSTEM_CURSOR_PROGRESS: // !!! FIXME: this is meant to be animated - nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor)); - break; - case SDL_SYSTEM_CURSOR_NWSE_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor)); - break; - case SDL_SYSTEM_CURSOR_NESW_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor)); - break; - case SDL_SYSTEM_CURSOR_EW_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor)); - break; - case SDL_SYSTEM_CURSOR_NS_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor)); - break; - case SDL_SYSTEM_CURSOR_MOVE: - nscursor = LoadHiddenSystemCursor(@"move", @selector(closedHandCursor)); - break; - case SDL_SYSTEM_CURSOR_NOT_ALLOWED: - nscursor = [NSCursor operationNotAllowedCursor]; - break; - case SDL_SYSTEM_CURSOR_POINTER: - nscursor = [NSCursor pointingHandCursor]; - break; - case SDL_SYSTEM_CURSOR_NW_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor)); - break; - case SDL_SYSTEM_CURSOR_N_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor)); - break; - case SDL_SYSTEM_CURSOR_NE_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor)); - break; - case SDL_SYSTEM_CURSOR_E_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor)); - break; - case SDL_SYSTEM_CURSOR_SE_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor)); - break; - case SDL_SYSTEM_CURSOR_S_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor)); - break; - case SDL_SYSTEM_CURSOR_SW_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor)); - break; - case SDL_SYSTEM_CURSOR_W_RESIZE: - nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor)); - break; - default: - SDL_assert(!"Unknown system cursor"); - return NULL; - } - - if (nscursor) { - cursor = SDL_calloc(1, sizeof(*cursor)); - if (cursor) { - // We'll free it later, so retain it here - cursor->internal = (void *)CFBridgingRetain(nscursor); - } - } - - return cursor; - } -} - -static SDL_Cursor *Cocoa_CreateDefaultCursor(void) -{ - SDL_SystemCursor id = SDL_GetDefaultSystemCursor(); - return Cocoa_CreateSystemCursor(id); -} - -static void Cocoa_FreeCursor(SDL_Cursor *cursor) -{ - @autoreleasepool { - CFBridgingRelease((void *)cursor->internal); - SDL_free(cursor); - } -} - -static bool Cocoa_ShowCursor(SDL_Cursor *cursor) -{ - @autoreleasepool { - SDL_VideoDevice *device = SDL_GetVideoDevice(); - SDL_Window *window = (device ? device->windows : NULL); - for (; window != NULL; window = window->next) { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - if (data) { - [data.nswindow performSelectorOnMainThread:@selector(invalidateCursorRectsForView:) - withObject:[data.nswindow contentView] - waitUntilDone:NO]; - } - } - return true; - } -} - -static SDL_Window *SDL_FindWindowAtPoint(const float x, const float y) -{ - const SDL_FPoint pt = { x, y }; - SDL_Window *i; - for (i = SDL_GetVideoDevice()->windows; i; i = i->next) { - const SDL_FRect r = { (float)i->x, (float)i->y, (float)i->w, (float)i->h }; - if (SDL_PointInRectFloat(&pt, &r)) { - return i; - } - } - - return NULL; -} - -static bool Cocoa_WarpMouseGlobal(float x, float y) -{ - CGPoint point; - SDL_Mouse *mouse = SDL_GetMouse(); - if (mouse->focus) { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)mouse->focus->internal; - if ([data.listener isMovingOrFocusClickPending]) { - DLog("Postponing warp, window being moved or focused."); - [data.listener setPendingMoveX:x Y:y]; - return true; - } - } - point = CGPointMake(x, y); - - Cocoa_HandleMouseWarp(point.x, point.y); - - CGWarpMouseCursorPosition(point); - - /* CGWarpMouse causes a short delay by default, which is preventable by - * Calling this directly after. CGSetLocalEventsSuppressionInterval can also - * prevent it, but it's deprecated as macOS 10.6. - */ - if (!mouse->relative_mode) { - CGAssociateMouseAndMouseCursorPosition(YES); - } - - /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our - * other implementations' APIs. Send what's appropriate. - */ - if (!mouse->relative_mode) { - SDL_Window *win = SDL_FindWindowAtPoint(x, y); - SDL_SetMouseFocus(win); - if (win) { - SDL_assert(win == mouse->focus); - SDL_SendMouseMotion(0, win, SDL_GLOBAL_MOUSE_ID, false, x - win->x, y - win->y); - } - } - - return true; -} - -static bool Cocoa_WarpMouse(SDL_Window *window, float x, float y) -{ - return Cocoa_WarpMouseGlobal(window->x + x, window->y + y); -} - -static bool Cocoa_SetRelativeMouseMode(bool enabled) -{ - CGError result; - - if (enabled) { - SDL_Window *window = SDL_GetKeyboardFocus(); - if (window) { - /* We will re-apply the relative mode when the window finishes being moved, - * if it is being moved right now. - */ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - if ([data.listener isMovingOrFocusClickPending]) { - return true; - } - - // make sure the mouse isn't at the corner of the window, as this can confuse things if macOS thinks a window resize is happening on the first click. - const CGPoint point = CGPointMake((float)(window->x + (window->w / 2)), (float)(window->y + (window->h / 2))); - Cocoa_HandleMouseWarp(point.x, point.y); - CGWarpMouseCursorPosition(point); - } - DLog("Turning on."); - result = CGAssociateMouseAndMouseCursorPosition(NO); - } else { - DLog("Turning off."); - result = CGAssociateMouseAndMouseCursorPosition(YES); - } - if (result != kCGErrorSuccess) { - return SDL_SetError("CGAssociateMouseAndMouseCursorPosition() failed"); - } - - /* The hide/unhide calls are redundant most of the time, but they fix - * https://bugzilla.libsdl.org/show_bug.cgi?id=2550 - */ - if (enabled) { - [NSCursor hide]; - } else { - [NSCursor unhide]; - } - return true; -} - -static bool Cocoa_CaptureMouse(SDL_Window *window) -{ - /* our Cocoa event code already tracks the mouse outside the window, - so all we have to do here is say "okay" and do what we always do. */ - return true; -} - -static SDL_MouseButtonFlags Cocoa_GetGlobalMouseState(float *x, float *y) -{ - const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons]; - const NSPoint cocoaLocation = [NSEvent mouseLocation]; - SDL_MouseButtonFlags result = 0; - - *x = cocoaLocation.x; - *y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - cocoaLocation.y); - - result |= (cocoaButtons & (1 << 0)) ? SDL_BUTTON_LMASK : 0; - result |= (cocoaButtons & (1 << 1)) ? SDL_BUTTON_RMASK : 0; - result |= (cocoaButtons & (1 << 2)) ? SDL_BUTTON_MMASK : 0; - result |= (cocoaButtons & (1 << 3)) ? SDL_BUTTON_X1MASK : 0; - result |= (cocoaButtons & (1 << 4)) ? SDL_BUTTON_X2MASK : 0; - - return result; -} - -bool Cocoa_InitMouse(SDL_VideoDevice *_this) -{ - NSPoint location; - SDL_Mouse *mouse = SDL_GetMouse(); - SDL_MouseData *internal = (SDL_MouseData *)SDL_calloc(1, sizeof(SDL_MouseData)); - if (internal == NULL) { - return false; - } - - mouse->internal = internal; - mouse->CreateCursor = Cocoa_CreateCursor; - mouse->CreateSystemCursor = Cocoa_CreateSystemCursor; - mouse->ShowCursor = Cocoa_ShowCursor; - mouse->FreeCursor = Cocoa_FreeCursor; - mouse->WarpMouse = Cocoa_WarpMouse; - mouse->WarpMouseGlobal = Cocoa_WarpMouseGlobal; - mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode; - mouse->CaptureMouse = Cocoa_CaptureMouse; - mouse->GetGlobalMouseState = Cocoa_GetGlobalMouseState; - - SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor()); - - location = [NSEvent mouseLocation]; - internal->lastMoveX = location.x; - internal->lastMoveY = location.y; - return true; -} - -static void Cocoa_HandleTitleButtonEvent(SDL_VideoDevice *_this, NSEvent *event) -{ - SDL_Window *window; - NSWindow *nswindow = [event window]; - - /* You might land in this function before SDL_Init if showing a message box. - Don't dereference a NULL pointer if that happens. */ - if (_this == NULL) { - return; - } - - for (window = _this->windows; window; window = window->next) { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - if (data && data.nswindow == nswindow) { - switch ([event type]) { - case NSEventTypeLeftMouseDown: - case NSEventTypeRightMouseDown: - case NSEventTypeOtherMouseDown: - [data.listener setFocusClickPending:[event buttonNumber]]; - break; - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseUp: - [data.listener clearFocusClickPending:[event buttonNumber]]; - break; - default: - break; - } - break; - } - } -} - -static NSWindow *Cocoa_MouseFocus; - -NSWindow *Cocoa_GetMouseFocus() -{ - return Cocoa_MouseFocus; -} - -void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event) -{ - SDL_MouseID mouseID = SDL_DEFAULT_MOUSE_ID; - SDL_Mouse *mouse; - SDL_MouseData *data; - NSPoint location; - CGFloat lastMoveX, lastMoveY; - float deltaX, deltaY; - bool seenWarp; - - // All events except NSEventTypeMouseExited can only happen if the window - // has mouse focus, so we'll always set the focus even if we happen to miss - // NSEventTypeMouseEntered, which apparently happens if the window is - // created under the mouse on macOS 12.7 - NSEventType event_type = [event type]; - if (event_type == NSEventTypeMouseExited) { - Cocoa_MouseFocus = NULL; - } else { - Cocoa_MouseFocus = [event window]; - } - - switch (event_type) { - case NSEventTypeMouseEntered: - case NSEventTypeMouseExited: - // Focus is handled above - return; - - case NSEventTypeMouseMoved: - case NSEventTypeLeftMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeOtherMouseDragged: - break; - - case NSEventTypeLeftMouseDown: - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseDown: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseDown: - case NSEventTypeOtherMouseUp: - if ([event window]) { - NSRect windowRect = [[[event window] contentView] frame]; - if (!NSMouseInRect([event locationInWindow], windowRect, NO)) { - Cocoa_HandleTitleButtonEvent(_this, event); - return; - } - } - return; - - default: - // Ignore any other events. - return; - } - - mouse = SDL_GetMouse(); - data = (SDL_MouseData *)mouse->internal; - if (!data) { - return; // can happen when returning from fullscreen Space on shutdown - } - - seenWarp = data->seenWarp; - data->seenWarp = NO; - - location = [NSEvent mouseLocation]; - lastMoveX = data->lastMoveX; - lastMoveY = data->lastMoveY; - data->lastMoveX = location.x; - data->lastMoveY = location.y; - DLog("Last seen mouse: (%g, %g)", location.x, location.y); - - // Non-relative movement is handled in -[SDL3Cocoa_WindowListener mouseMoved:] - if (!mouse->relative_mode) { - return; - } - - // Ignore events that aren't inside the client area (i.e. title bar.) - if ([event window]) { - NSRect windowRect = [[[event window] contentView] frame]; - if (!NSMouseInRect([event locationInWindow], windowRect, NO)) { - return; - } - } - - deltaX = [event deltaX]; - deltaY = [event deltaY]; - - if (seenWarp) { - deltaX += (lastMoveX - data->lastWarpX); - deltaY += ((CGDisplayPixelsHigh(kCGDirectMainDisplay) - lastMoveY) - data->lastWarpY); - - DLog("Motion was (%g, %g), offset to (%g, %g)", [event deltaX], [event deltaY], deltaX, deltaY); - } - - SDL_SendMouseMotion(Cocoa_GetEventTimestamp([event timestamp]), mouse->focus, mouseID, true, deltaX, deltaY); -} - -void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event) -{ - SDL_MouseID mouseID = SDL_DEFAULT_MOUSE_ID; - SDL_MouseWheelDirection direction; - CGFloat x, y; - - x = -[event deltaX]; - y = [event deltaY]; - direction = SDL_MOUSEWHEEL_NORMAL; - - if ([event isDirectionInvertedFromDevice] == YES) { - direction = SDL_MOUSEWHEEL_FLIPPED; - } - - /* For discrete scroll events from conventional mice, always send a full tick. - For continuous scroll events from trackpads, send fractional deltas for smoother scrolling. */ - if (![event hasPreciseScrollingDeltas]) { - if (x > 0) { - x = SDL_ceil(x); - } else if (x < 0) { - x = SDL_floor(x); - } - if (y > 0) { - y = SDL_ceil(y); - } else if (y < 0) { - y = SDL_floor(y); - } - } - - SDL_SendMouseWheel(Cocoa_GetEventTimestamp([event timestamp]), window, mouseID, x, y, direction); -} - -void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y) -{ - /* This makes Cocoa_HandleMouseEvent ignore the delta caused by the warp, - * since it gets included in the next movement event. - */ - SDL_MouseData *data = (SDL_MouseData *)SDL_GetMouse()->internal; - data->lastWarpX = x; - data->lastWarpY = y; - data->seenWarp = true; - - DLog("(%g, %g)", x, y); -} - -void Cocoa_QuitMouse(SDL_VideoDevice *_this) -{ - SDL_Mouse *mouse = SDL_GetMouse(); - if (mouse) { - if (mouse->internal) { - SDL_free(mouse->internal); - mouse->internal = NULL; - } - } -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.h deleted file mode 100644 index 33d7b0e..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoaopengl_h_ -#define SDL_cocoaopengl_h_ - -#ifdef SDL_VIDEO_OPENGL_CGL - -#import -#import - -// We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - -struct SDL_GLDriverData -{ - int initialized; -}; - -@interface SDL3OpenGLContext : NSOpenGLContext -{ - SDL_AtomicInt dirty; - SDL_Window *window; - CVDisplayLinkRef displayLink; - @public - SDL_Mutex *swapIntervalMutex; - @public - SDL_Condition *swapIntervalCond; - @public - SDL_AtomicInt swapIntervalSetting; - @public - SDL_AtomicInt swapIntervalsPassed; -} - -- (id)initWithFormat:(NSOpenGLPixelFormat *)format - shareContext:(NSOpenGLContext *)share; -- (void)scheduleUpdate; -- (void)updateIfNeeded; -- (void)movedToNewScreen; -- (void)setWindow:(SDL_Window *)window; -- (SDL_Window *)window; -- (void)explicitUpdate; -- (void)cleanup; - -@property(retain, nonatomic) NSOpenGLPixelFormat *openglPixelFormat; // macOS 10.10 has -[NSOpenGLContext pixelFormat] but this handles older OS releases. - -@end - -// OpenGL functions -extern bool Cocoa_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path); -extern SDL_FunctionPointer Cocoa_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc); -extern void Cocoa_GL_UnloadLibrary(SDL_VideoDevice *_this); -extern SDL_GLContext Cocoa_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context); -extern bool Cocoa_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval); -extern bool Cocoa_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval); -extern bool Cocoa_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context); - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif // SDL_VIDEO_OPENGL_CGL - -#endif // SDL_cocoaopengl_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.m deleted file mode 100644 index 34002ec..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengl.m +++ /dev/null @@ -1,559 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -// NSOpenGL implementation of SDL OpenGL support - -#ifdef SDL_VIDEO_OPENGL_CGL -#include "SDL_cocoavideo.h" -#include "SDL_cocoaopengl.h" -#include "SDL_cocoaopengles.h" - -#include -#include -#include - -#include -#include "../../SDL_hints_c.h" - -#define DEFAULT_OPENGL "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib" - -// We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - -// _Nullable is available starting Xcode 7 -#ifdef __has_feature -#if __has_feature(nullability) -#define HAS_FEATURE_NULLABLE -#endif -#endif -#ifndef HAS_FEATURE_NULLABLE -#define _Nullable -#endif - -static bool SDL_opengl_async_dispatch = false; - -static void SDLCALL SDL_OpenGLAsyncDispatchChanged(void *userdata, const char *name, const char *oldValue, const char *hint) -{ - SDL_opengl_async_dispatch = SDL_GetStringBoolean(hint, false); -} - -static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) -{ - SDL3OpenGLContext *nscontext = (__bridge SDL3OpenGLContext *)displayLinkContext; - - // printf("DISPLAY LINK! %u\n", (unsigned int) SDL_GetTicks()); - const int setting = SDL_GetAtomicInt(&nscontext->swapIntervalSetting); - if (setting != 0) { // nothing to do if vsync is disabled, don't even lock - SDL_LockMutex(nscontext->swapIntervalMutex); - SDL_AddAtomicInt(&nscontext->swapIntervalsPassed, 1); - SDL_SignalCondition(nscontext->swapIntervalCond); - SDL_UnlockMutex(nscontext->swapIntervalMutex); - } - - return kCVReturnSuccess; -} - -@implementation SDL3OpenGLContext : NSOpenGLContext - -- (id)initWithFormat:(NSOpenGLPixelFormat *)format - shareContext:(NSOpenGLContext *)share -{ - self = [super initWithFormat:format shareContext:share]; - if (self) { - self.openglPixelFormat = format; - SDL_SetAtomicInt(&self->dirty, 0); - self->window = NULL; - SDL_SetAtomicInt(&self->swapIntervalSetting, 0); - SDL_SetAtomicInt(&self->swapIntervalsPassed, 0); - self->swapIntervalCond = SDL_CreateCondition(); - self->swapIntervalMutex = SDL_CreateMutex(); - if (!self->swapIntervalCond || !self->swapIntervalMutex) { - return nil; - } - - // !!! FIXME: check return values. - CVDisplayLinkCreateWithActiveCGDisplays(&self->displayLink); - CVDisplayLinkSetOutputCallback(self->displayLink, &DisplayLinkCallback, (__bridge void *_Nullable)self); - CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink, [self CGLContextObj], [format CGLPixelFormatObj]); - CVDisplayLinkStart(displayLink); - } - - SDL_AddHintCallback(SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH, SDL_OpenGLAsyncDispatchChanged, NULL); - return self; -} - -- (void)movedToNewScreen -{ - if (self->displayLink) { - CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink, [self CGLContextObj], [[self openglPixelFormat] CGLPixelFormatObj]); - } -} - -- (void)scheduleUpdate -{ - SDL_AddAtomicInt(&self->dirty, 1); -} - -// This should only be called on the thread on which a user is using the context. -- (void)updateIfNeeded -{ - const int value = SDL_SetAtomicInt(&self->dirty, 0); - if (value > 0) { - // We call the real underlying update here, since -[SDL3OpenGLContext update] just calls us. - [self explicitUpdate]; - } -} - -// This should only be called on the thread on which a user is using the context. -- (void)update -{ - // This ensures that regular 'update' calls clear the atomic dirty flag. - [self scheduleUpdate]; - [self updateIfNeeded]; -} - -// Updates the drawable for the contexts and manages related state. -- (void)setWindow:(SDL_Window *)newWindow -{ - if (self->window) { - SDL_CocoaWindowData *oldwindowdata = (__bridge SDL_CocoaWindowData *)self->window->internal; - - // Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. - NSMutableArray *contexts = oldwindowdata.nscontexts; - @synchronized(contexts) { - [contexts removeObject:self]; - } - } - - self->window = newWindow; - - if (newWindow) { - SDL_CocoaWindowData *windowdata = (__bridge SDL_CocoaWindowData *)newWindow->internal; - NSView *contentview = windowdata.sdlContentView; - - // Now sign up for scheduled updates for the new window. - NSMutableArray *contexts = windowdata.nscontexts; - @synchronized(contexts) { - [contexts addObject:self]; - } - - if ([self view] != contentview) { - if ([NSThread isMainThread]) { - [self setView:contentview]; - } else { - dispatch_sync(dispatch_get_main_queue(), ^{ - [self setView:contentview]; - }); - } - if (self == [NSOpenGLContext currentContext]) { - [self explicitUpdate]; - } else { - [self scheduleUpdate]; - } - } - } else { - if ([NSThread isMainThread]) { - [self setView:nil]; - } else { - dispatch_sync(dispatch_get_main_queue(), ^{ [self setView:nil]; }); - } - } -} - -- (SDL_Window *)window -{ - return self->window; -} - -- (void)explicitUpdate -{ - if ([NSThread isMainThread]) { - [super update]; - } else { - if (SDL_opengl_async_dispatch) { - dispatch_async(dispatch_get_main_queue(), ^{ - [super update]; - }); - } else { - dispatch_sync(dispatch_get_main_queue(), ^{ - [super update]; - }); - } - } -} - -- (void)cleanup -{ - [self setWindow:NULL]; - - SDL_RemoveHintCallback(SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH, SDL_OpenGLAsyncDispatchChanged, NULL); - if (self->displayLink) { - CVDisplayLinkRelease(self->displayLink); - self->displayLink = nil; - } - if (self->swapIntervalCond) { - SDL_DestroyCondition(self->swapIntervalCond); - self->swapIntervalCond = NULL; - } - if (self->swapIntervalMutex) { - SDL_DestroyMutex(self->swapIntervalMutex); - self->swapIntervalMutex = NULL; - } -} - -@end - -bool Cocoa_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path) -{ - // Load the OpenGL library - if (path == NULL) { - path = SDL_GetHint(SDL_HINT_OPENGL_LIBRARY); - } - if (path == NULL) { - path = DEFAULT_OPENGL; - } - _this->gl_config.dll_handle = SDL_LoadObject(path); - if (!_this->gl_config.dll_handle) { - return false; - } - SDL_strlcpy(_this->gl_config.driver_path, path, - SDL_arraysize(_this->gl_config.driver_path)); - return true; -} - -SDL_FunctionPointer Cocoa_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc) -{ - return SDL_LoadFunction(_this->gl_config.dll_handle, proc); -} - -void Cocoa_GL_UnloadLibrary(SDL_VideoDevice *_this) -{ - SDL_UnloadObject(_this->gl_config.dll_handle); - _this->gl_config.dll_handle = NULL; -} - -SDL_GLContext Cocoa_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); - SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal; - NSOpenGLPixelFormatAttribute attr[32]; - NSOpenGLPixelFormat *fmt; - SDL3OpenGLContext *context; - SDL_GLContext sdlcontext; - NSOpenGLContext *share_context = nil; - int i = 0; - const char *glversion; - int glversion_major; - int glversion_minor; - NSOpenGLPixelFormatAttribute profile; - int interval; - int opaque; - - if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { -#ifdef SDL_VIDEO_OPENGL_EGL - // Switch to EGL based functions - Cocoa_GL_UnloadLibrary(_this); - _this->GL_LoadLibrary = Cocoa_GLES_LoadLibrary; - _this->GL_GetProcAddress = Cocoa_GLES_GetProcAddress; - _this->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary; - _this->GL_CreateContext = Cocoa_GLES_CreateContext; - _this->GL_MakeCurrent = Cocoa_GLES_MakeCurrent; - _this->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval; - _this->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval; - _this->GL_SwapWindow = Cocoa_GLES_SwapWindow; - _this->GL_DestroyContext = Cocoa_GLES_DestroyContext; - - if (!Cocoa_GLES_LoadLibrary(_this, NULL)) { - return NULL; - } - return Cocoa_GLES_CreateContext(_this, window); -#else - SDL_SetError("SDL not configured with EGL support"); - return NULL; -#endif - } - - attr[i++] = NSOpenGLPFAAllowOfflineRenderers; - - profile = NSOpenGLProfileVersionLegacy; - if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) { - profile = NSOpenGLProfileVersion3_2Core; - } - attr[i++] = NSOpenGLPFAOpenGLProfile; - attr[i++] = profile; - - attr[i++] = NSOpenGLPFAColorSize; - attr[i++] = SDL_BYTESPERPIXEL(display->current_mode->format) * 8; - - attr[i++] = NSOpenGLPFADepthSize; - attr[i++] = _this->gl_config.depth_size; - - if (_this->gl_config.double_buffer) { - attr[i++] = NSOpenGLPFADoubleBuffer; - } - - if (_this->gl_config.stereo) { - attr[i++] = NSOpenGLPFAStereo; - } - - if (_this->gl_config.stencil_size) { - attr[i++] = NSOpenGLPFAStencilSize; - attr[i++] = _this->gl_config.stencil_size; - } - - if ((_this->gl_config.accum_red_size + - _this->gl_config.accum_green_size + - _this->gl_config.accum_blue_size + - _this->gl_config.accum_alpha_size) > 0) { - attr[i++] = NSOpenGLPFAAccumSize; - attr[i++] = _this->gl_config.accum_red_size + _this->gl_config.accum_green_size + _this->gl_config.accum_blue_size + _this->gl_config.accum_alpha_size; - } - - if (_this->gl_config.multisamplebuffers) { - attr[i++] = NSOpenGLPFASampleBuffers; - attr[i++] = _this->gl_config.multisamplebuffers; - } - - if (_this->gl_config.multisamplesamples) { - attr[i++] = NSOpenGLPFASamples; - attr[i++] = _this->gl_config.multisamplesamples; - attr[i++] = NSOpenGLPFANoRecovery; - } - if (_this->gl_config.floatbuffers) { - attr[i++] = NSOpenGLPFAColorFloat; - } - - if (_this->gl_config.accelerated >= 0) { - if (_this->gl_config.accelerated) { - attr[i++] = NSOpenGLPFAAccelerated; - } else { - attr[i++] = NSOpenGLPFARendererID; - attr[i++] = kCGLRendererGenericFloatID; - } - } - - attr[i++] = NSOpenGLPFAScreenMask; - attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display); - attr[i] = 0; - - fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; - if (fmt == nil) { - SDL_SetError("Failed creating OpenGL pixel format"); - return NULL; - } - - if (_this->gl_config.share_with_current_context) { - share_context = (__bridge NSOpenGLContext *)SDL_GL_GetCurrentContext(); - } - - context = [[SDL3OpenGLContext alloc] initWithFormat:fmt shareContext:share_context]; - - if (context == nil) { - SDL_SetError("Failed creating OpenGL context"); - return NULL; - } - - sdlcontext = (SDL_GLContext)CFBridgingRetain(context); - - // vsync is handled separately by synchronizing with a display link. - interval = 0; - [context setValues:&interval forParameter:NSOpenGLCPSwapInterval]; - - opaque = (window->flags & SDL_WINDOW_TRANSPARENT) ? 0 : 1; - [context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity]; - - if (!Cocoa_GL_MakeCurrent(_this, window, sdlcontext)) { - SDL_GL_DestroyContext(sdlcontext); - SDL_SetError("Failed making OpenGL context current"); - return NULL; - } - - if (_this->gl_config.major_version < 3 && - _this->gl_config.profile_mask == 0 && - _this->gl_config.flags == 0) { - // This is a legacy profile, so to match other backends, we're done. - } else { - const GLubyte *(APIENTRY * glGetStringFunc)(GLenum); - - glGetStringFunc = (const GLubyte *(APIENTRY *)(GLenum))SDL_GL_GetProcAddress("glGetString"); - if (!glGetStringFunc) { - SDL_GL_DestroyContext(sdlcontext); - SDL_SetError("Failed getting OpenGL glGetString entry point"); - return NULL; - } - - glversion = (const char *)glGetStringFunc(GL_VERSION); - if (glversion == NULL) { - SDL_GL_DestroyContext(sdlcontext); - SDL_SetError("Failed getting OpenGL context version"); - return NULL; - } - - if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) { - SDL_GL_DestroyContext(sdlcontext); - SDL_SetError("Failed parsing OpenGL context version"); - return NULL; - } - - if ((glversion_major < _this->gl_config.major_version) || - ((glversion_major == _this->gl_config.major_version) && (glversion_minor < _this->gl_config.minor_version))) { - SDL_GL_DestroyContext(sdlcontext); - SDL_SetError("Failed creating OpenGL context at version requested"); - return NULL; - } - - /* In the future we'll want to do this, but to match other platforms - we'll leave the OpenGL version the way it is for now - */ - // _this->gl_config.major_version = glversion_major; - // _this->gl_config.minor_version = glversion_minor; - } - return sdlcontext; - } -} - -bool Cocoa_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) -{ - @autoreleasepool { - if (context) { - SDL3OpenGLContext *nscontext = (__bridge SDL3OpenGLContext *)context; - if ([nscontext window] != window) { - [nscontext setWindow:window]; - [nscontext updateIfNeeded]; - } - [nscontext makeCurrentContext]; - } else { - [NSOpenGLContext clearCurrentContext]; - } - - return true; - } -} - -bool Cocoa_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval) -{ - @autoreleasepool { - SDL3OpenGLContext *nscontext = (__bridge SDL3OpenGLContext *)SDL_GL_GetCurrentContext(); - bool result; - - if (nscontext == nil) { - result = SDL_SetError("No current OpenGL context"); - } else { - SDL_LockMutex(nscontext->swapIntervalMutex); - SDL_SetAtomicInt(&nscontext->swapIntervalsPassed, 0); - SDL_SetAtomicInt(&nscontext->swapIntervalSetting, interval); - SDL_UnlockMutex(nscontext->swapIntervalMutex); - result = true; - } - - return result; - } -} - -bool Cocoa_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval) -{ - @autoreleasepool { - SDL3OpenGLContext *nscontext = (__bridge SDL3OpenGLContext *)SDL_GL_GetCurrentContext(); - if (nscontext) { - *interval = SDL_GetAtomicInt(&nscontext->swapIntervalSetting); - return true; - } else { - return SDL_SetError("no OpenGL context"); - } - } -} - -bool Cocoa_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL3OpenGLContext *nscontext = (__bridge SDL3OpenGLContext *)SDL_GL_GetCurrentContext(); - SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)_this->internal; - const int setting = SDL_GetAtomicInt(&nscontext->swapIntervalSetting); - - if (setting == 0) { - // nothing to do if vsync is disabled, don't even lock - } else if (setting < 0) { // late swap tearing - SDL_LockMutex(nscontext->swapIntervalMutex); - while (SDL_GetAtomicInt(&nscontext->swapIntervalsPassed) == 0) { - SDL_WaitCondition(nscontext->swapIntervalCond, nscontext->swapIntervalMutex); - } - SDL_SetAtomicInt(&nscontext->swapIntervalsPassed, 0); - SDL_UnlockMutex(nscontext->swapIntervalMutex); - } else { - SDL_LockMutex(nscontext->swapIntervalMutex); - do { // always wait here so we know we just hit a swap interval. - SDL_WaitCondition(nscontext->swapIntervalCond, nscontext->swapIntervalMutex); - } while ((SDL_GetAtomicInt(&nscontext->swapIntervalsPassed) % setting) != 0); - SDL_SetAtomicInt(&nscontext->swapIntervalsPassed, 0); - SDL_UnlockMutex(nscontext->swapIntervalMutex); - } - - // { static Uint64 prev = 0; const Uint64 now = SDL_GetTicks(); const unsigned int diff = (unsigned int) (now - prev); prev = now; printf("GLSWAPBUFFERS TICKS %u\n", diff); } - - /* on 10.14 ("Mojave") and later, this deadlocks if two contexts in two - threads try to swap at the same time, so put a mutex around it. */ - SDL_LockMutex(videodata.swaplock); - [nscontext flushBuffer]; - [nscontext updateIfNeeded]; - SDL_UnlockMutex(videodata.swaplock); - return true; - } -} - -static void DispatchedDestroyContext(SDL_GLContext context) -{ - @autoreleasepool { - SDL3OpenGLContext *nscontext = (__bridge SDL3OpenGLContext *)context; - [nscontext cleanup]; - CFRelease(context); - } -} - -bool Cocoa_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) -{ - if ([NSThread isMainThread]) { - DispatchedDestroyContext(context); - } else { - if (SDL_opengl_async_dispatch) { - dispatch_async(dispatch_get_main_queue(), ^{ - DispatchedDestroyContext(context); - }); - } else { - dispatch_sync(dispatch_get_main_queue(), ^{ - DispatchedDestroyContext(context); - }); - } - } - - return true; -} - -// We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif // SDL_VIDEO_OPENGL_CGL diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.h deleted file mode 100644 index 5cf97e3..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoaopengles_h_ -#define SDL_cocoaopengles_h_ - -#ifdef SDL_VIDEO_OPENGL_EGL - -#include "../SDL_sysvideo.h" -#include "../SDL_egl_c.h" - -// OpenGLES functions -#define Cocoa_GLES_GetAttribute SDL_EGL_GetAttribute -#define Cocoa_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal -#define Cocoa_GLES_UnloadLibrary SDL_EGL_UnloadLibrary -#define Cocoa_GLES_GetSwapInterval SDL_EGL_GetSwapInterval -#define Cocoa_GLES_SetSwapInterval SDL_EGL_SetSwapInterval - -extern bool Cocoa_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path); -extern SDL_GLContext Cocoa_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context); -extern bool Cocoa_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context); -extern bool Cocoa_GLES_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern SDL_EGLSurface Cocoa_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window); - -#endif // SDL_VIDEO_OPENGL_EGL - -#endif // SDL_cocoaopengles_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.m deleted file mode 100644 index 053ddc9..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoaopengles.m +++ /dev/null @@ -1,156 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#if defined(SDL_VIDEO_DRIVER_COCOA) && defined(SDL_VIDEO_OPENGL_EGL) - -#include "SDL_cocoavideo.h" -#include "SDL_cocoaopengles.h" -#include "SDL_cocoaopengl.h" - -// EGL implementation of SDL OpenGL support - -bool Cocoa_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path) -{ - // If the profile requested is not GL ES, switch over to WIN_GL functions - if (_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES) { -#ifdef SDL_VIDEO_OPENGL_CGL - Cocoa_GLES_UnloadLibrary(_this); - _this->GL_LoadLibrary = Cocoa_GL_LoadLibrary; - _this->GL_GetProcAddress = Cocoa_GL_GetProcAddress; - _this->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary; - _this->GL_CreateContext = Cocoa_GL_CreateContext; - _this->GL_MakeCurrent = Cocoa_GL_MakeCurrent; - _this->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval; - _this->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval; - _this->GL_SwapWindow = Cocoa_GL_SwapWindow; - _this->GL_DestroyContext = Cocoa_GL_DestroyContext; - _this->GL_GetEGLSurface = NULL; - return Cocoa_GL_LoadLibrary(_this, path); -#else - return SDL_SetError("SDL not configured with OpenGL/CGL support"); -#endif - } - - if (_this->egl_data == NULL) { - return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform); - } - - return true; -} - -SDL_GLContext Cocoa_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_GLContext context; - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - -#ifdef SDL_VIDEO_OPENGL_CGL - if (_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES) { - // Switch to CGL based functions - Cocoa_GLES_UnloadLibrary(_this); - _this->GL_LoadLibrary = Cocoa_GL_LoadLibrary; - _this->GL_GetProcAddress = Cocoa_GL_GetProcAddress; - _this->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary; - _this->GL_CreateContext = Cocoa_GL_CreateContext; - _this->GL_MakeCurrent = Cocoa_GL_MakeCurrent; - _this->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval; - _this->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval; - _this->GL_SwapWindow = Cocoa_GL_SwapWindow; - _this->GL_DestroyContext = Cocoa_GL_DestroyContext; - _this->GL_GetEGLSurface = NULL; - - if (!Cocoa_GL_LoadLibrary(_this, NULL)) { - return NULL; - } - - return Cocoa_GL_CreateContext(_this, window); - } -#endif - - context = SDL_EGL_CreateContext(_this, data.egl_surface); - return context; - } -} - -bool Cocoa_GLES_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) -{ - @autoreleasepool { - SDL_EGL_DestroyContext(_this, context); - } - return true; -} - -bool Cocoa_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - return SDL_EGL_SwapBuffers(_this, ((__bridge SDL_CocoaWindowData *)window->internal).egl_surface); - } -} - -bool Cocoa_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) -{ - @autoreleasepool { - return SDL_EGL_MakeCurrent(_this, window ? ((__bridge SDL_CocoaWindowData *)window->internal).egl_surface : EGL_NO_SURFACE, context); - } -} - -bool Cocoa_GLES_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - NSView *v; - // The current context is lost in here; save it and reset it. - SDL_CocoaWindowData *windowdata = (__bridge SDL_CocoaWindowData *)window->internal; - SDL_Window *current_win = SDL_GL_GetCurrentWindow(); - SDL_GLContext current_ctx = SDL_GL_GetCurrentContext(); - - if (_this->egl_data == NULL) { -// !!! FIXME: commenting out this assertion is (I think) incorrect; figure out why driver_loaded is wrong for ANGLE instead. --ryan. -#if 0 // When hint SDL_HINT_OPENGL_ES_DRIVER is set to "1" (e.g. for ANGLE support), _this->gl_config.driver_loaded can be 1, while the below lines function. - SDL_assert(!_this->gl_config.driver_loaded); -#endif - if (!SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform)) { - SDL_EGL_UnloadLibrary(_this); - return false; - } - _this->gl_config.driver_loaded = 1; - } - - // Create the GLES window surface - v = windowdata.nswindow.contentView; - windowdata.egl_surface = SDL_EGL_CreateSurface(_this, window, (__bridge NativeWindowType)[v layer]); - - if (windowdata.egl_surface == EGL_NO_SURFACE) { - return SDL_SetError("Could not create GLES window surface"); - } - - return Cocoa_GLES_MakeCurrent(_this, current_win, current_ctx); - } -} - -SDL_EGLSurface Cocoa_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - return ((__bridge SDL_CocoaWindowData *)window->internal).egl_surface; - } -} - -#endif // SDL_VIDEO_DRIVER_COCOA && SDL_VIDEO_OPENGL_EGL diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.h deleted file mode 100644 index b659ba4..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoapen_h_ -#define SDL_cocoapenm_h_ - -#include "SDL_cocoavideo.h" - -extern bool Cocoa_InitPen(SDL_VideoDevice *_this); -extern bool Cocoa_HandlePenEvent(SDL_CocoaWindowData *_data, NSEvent *event); // return false if we didn't handle this event. -extern void Cocoa_QuitPen(SDL_VideoDevice *_this); - -#endif // SDL_cocoapen_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.m deleted file mode 100644 index 6c30bfb..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoapen.m +++ /dev/null @@ -1,178 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoapen.h" -#include "SDL_cocoavideo.h" - -#include "../../events/SDL_pen_c.h" - -bool Cocoa_InitPen(SDL_VideoDevice *_this) -{ - return true; -} - -typedef struct Cocoa_PenHandle -{ - NSUInteger deviceid; - NSUInteger toolid; - SDL_PenID pen; - bool is_eraser; -} Cocoa_PenHandle; - -typedef struct FindPenByDeviceAndToolIDData -{ - NSUInteger deviceid; - NSUInteger toolid; - void *handle; -} FindPenByDeviceAndToolIDData; - -static bool FindPenByDeviceAndToolID(void *handle, void *userdata) -{ - const Cocoa_PenHandle *cocoa_handle = (const Cocoa_PenHandle *) handle; - FindPenByDeviceAndToolIDData *data = (FindPenByDeviceAndToolIDData *) userdata; - - if (cocoa_handle->deviceid != data->deviceid) { - return false; - } else if (cocoa_handle->toolid != data->toolid) { - return false; - } - data->handle = handle; - return true; -} - -static Cocoa_PenHandle *Cocoa_FindPenByDeviceID(NSUInteger deviceid, NSUInteger toolid) -{ - FindPenByDeviceAndToolIDData data; - data.deviceid = deviceid; - data.toolid = toolid; - data.handle = NULL; - SDL_FindPenByCallback(FindPenByDeviceAndToolID, &data); - return (Cocoa_PenHandle *) data.handle; -} - -static void Cocoa_HandlePenProximityEvent(SDL_CocoaWindowData *_data, NSEvent *event) -{ - const NSUInteger devid = [event deviceID]; - const NSUInteger toolid = [event pointingDeviceID]; - - if (event.enteringProximity) { // new pen coming! - const NSPointingDeviceType devtype = [event pointingDeviceType]; - const bool is_eraser = (devtype == NSPointingDeviceTypeEraser); - const bool is_pen = (devtype == NSPointingDeviceTypePen); - if (!is_eraser && !is_pen) { - return; // we ignore other things, which hopefully is right. - } - - Cocoa_PenHandle *handle = (Cocoa_PenHandle *) SDL_calloc(1, sizeof (*handle)); - if (!handle) { - return; // oh well. - } - - // Cocoa offers almost none of this information as specifics, but can without warning offer any of these specific things. - SDL_PenInfo peninfo; - SDL_zero(peninfo); - peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ROTATION | SDL_PEN_CAPABILITY_XTILT | SDL_PEN_CAPABILITY_YTILT | SDL_PEN_CAPABILITY_TANGENTIAL_PRESSURE | (is_eraser ? SDL_PEN_CAPABILITY_ERASER : 0); - peninfo.max_tilt = 90.0f; - peninfo.num_buttons = 2; - peninfo.subtype = is_eraser ? SDL_PEN_TYPE_ERASER : SDL_PEN_TYPE_PEN; - - handle->deviceid = devid; - handle->toolid = toolid; - handle->is_eraser = is_eraser; - handle->pen = SDL_AddPenDevice(Cocoa_GetEventTimestamp([event timestamp]), NULL, &peninfo, handle); - if (!handle->pen) { - SDL_free(handle); // oh well. - } - } else { // old pen leaving! - Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID(devid, toolid); - if (handle) { - SDL_RemovePenDevice(Cocoa_GetEventTimestamp([event timestamp]), handle->pen); - SDL_free(handle); - } - } -} - -static void Cocoa_HandlePenPointEvent(SDL_CocoaWindowData *_data, NSEvent *event) -{ - const Uint64 timestamp = Cocoa_GetEventTimestamp([event timestamp]); - Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID([event deviceID], [event pointingDeviceID]); - if (!handle) { - return; - } - - const SDL_PenID pen = handle->pen; - const NSEventButtonMask buttons = [event buttonMask]; - const NSPoint tilt = [event tilt]; - const NSPoint point = [event locationInWindow]; - const bool is_touching = (buttons & NSEventButtonMaskPenTip) != 0; - SDL_Window *window = _data.window; - - SDL_SendPenTouch(timestamp, pen, window, handle->is_eraser, is_touching); - SDL_SendPenMotion(timestamp, pen, window, (float) point.x, (float) (window->h - point.y)); - SDL_SendPenButton(timestamp, pen, window, 1, ((buttons & NSEventButtonMaskPenLowerSide) != 0)); - SDL_SendPenButton(timestamp, pen, window, 2, ((buttons & NSEventButtonMaskPenUpperSide) != 0)); - SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_PRESSURE, [event pressure]); - SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_ROTATION, [event rotation]); - SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_XTILT, ((float) tilt.x) * 90.0f); - SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_YTILT, ((float) -tilt.y) * 90.0f); - SDL_SendPenAxis(timestamp, pen, window, SDL_PEN_AXIS_TANGENTIAL_PRESSURE, event.tangentialPressure); -} - -bool Cocoa_HandlePenEvent(SDL_CocoaWindowData *_data, NSEvent *event) -{ - NSEventType type = [event type]; - - if ((type != NSEventTypeTabletPoint) && (type != NSEventTypeTabletProximity)) { - const NSEventSubtype subtype = [event subtype]; - if (subtype == NSEventSubtypeTabletPoint) { - type = NSEventTypeTabletPoint; - } else if (subtype == NSEventSubtypeTabletProximity) { - type = NSEventTypeTabletProximity; - } else { - return false; // not a tablet event. - } - } - - if (type == NSEventTypeTabletPoint) { - Cocoa_HandlePenPointEvent(_data, event); - } else if (type == NSEventTypeTabletProximity) { - Cocoa_HandlePenProximityEvent(_data, event); - } else { - return false; // not a tablet event. - } - - return true; -} - -static void Cocoa_FreePenHandle(SDL_PenID instance_id, void *handle, void *userdata) -{ - SDL_free(handle); -} - -void Cocoa_QuitPen(SDL_VideoDevice *_this) -{ - SDL_RemoveAllPenDevices(Cocoa_FreePenHandle, NULL); -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.h deleted file mode 100644 index 9ca3c64..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoashape_h_ -#define SDL_cocoashape_h_ - -extern bool Cocoa_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape); - -#endif // SDL_cocoashape_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.m deleted file mode 100644 index 26081bd..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoashape.m +++ /dev/null @@ -1,54 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include "SDL_cocoavideo.h" -#include "SDL_cocoashape.h" - - -bool Cocoa_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape) -{ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - BOOL ignoresMouseEvents = NO; - - if (shape) { - SDL_FPoint point; - SDL_GetGlobalMouseState(&point.x, &point.y); - point.x -= window->x; - point.y -= window->y; - if (point.x >= 0.0f && point.x < window->w && - point.y >= 0.0f && point.y < window->h) { - int x = (int)SDL_roundf((point.x / (window->w - 1)) * (shape->w - 1)); - int y = (int)SDL_roundf((point.y / (window->h - 1)) * (shape->h - 1)); - Uint8 a; - - if (!SDL_ReadSurfacePixel(shape, x, y, NULL, NULL, NULL, &a) || a == SDL_ALPHA_TRANSPARENT) { - ignoresMouseEvents = YES; - } - } - } - data.nswindow.ignoresMouseEvents = ignoresMouseEvents; - return true; -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.h deleted file mode 100644 index 353fb43..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoavideo_h_ -#define SDL_cocoavideo_h_ - -#include - -#include -#include -#include - -#include "../SDL_sysvideo.h" - -#include "SDL_cocoaclipboard.h" -#include "SDL_cocoaevents.h" -#include "SDL_cocoakeyboard.h" -#include "SDL_cocoamodes.h" -#include "SDL_cocoamouse.h" -#include "SDL_cocoaopengl.h" -#include "SDL_cocoawindow.h" -#include "SDL_cocoapen.h" - -// Private display data - -@class SDL3TranslatorResponder; - -typedef enum -{ - OptionAsAltNone, - OptionAsAltOnlyLeft, - OptionAsAltOnlyRight, - OptionAsAltBoth, -} OptionAsAlt; - -@interface SDL_CocoaVideoData : NSObject -@property(nonatomic) int allow_spaces; -@property(nonatomic) int trackpad_is_touch_only; -@property(nonatomic) unsigned int modifierFlags; -@property(nonatomic) void *key_layout; -@property(nonatomic) SDL3TranslatorResponder *fieldEdit; -@property(nonatomic) NSInteger clipboard_count; -@property(nonatomic) IOPMAssertionID screensaver_assertion; -@property(nonatomic) SDL_Mutex *swaplock; -@property(nonatomic) OptionAsAlt option_as_alt; -@end - -// Utility functions -extern SDL_SystemTheme Cocoa_GetSystemTheme(void); -extern NSImage *Cocoa_CreateImage(SDL_Surface *surface); - -#endif // SDL_cocoavideo_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.m deleted file mode 100644 index 81baf78..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavideo.m +++ /dev/null @@ -1,337 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#if !__has_feature(objc_arc) -#error SDL must be built with Objective-C ARC (automatic reference counting) enabled -#endif - -#include "SDL_cocoavideo.h" -#include "SDL_cocoavulkan.h" -#include "SDL_cocoametalview.h" -#include "SDL_cocoaopengles.h" -#include "SDL_cocoamessagebox.h" -#include "SDL_cocoashape.h" - -#include "../../events/SDL_keyboard_c.h" -#include "../../events/SDL_mouse_c.h" - -@implementation SDL_CocoaVideoData - -@end - -// Initialization/Query functions -static bool Cocoa_VideoInit(SDL_VideoDevice *_this); -static void Cocoa_VideoQuit(SDL_VideoDevice *_this); - -// Cocoa driver bootstrap functions - -static void Cocoa_DeleteDevice(SDL_VideoDevice *device) -{ - @autoreleasepool { - if (device->wakeup_lock) { - SDL_DestroyMutex(device->wakeup_lock); - } - CFBridgingRelease(device->internal); - SDL_free(device); - } -} - -static SDL_VideoDevice *Cocoa_CreateDevice(void) -{ - @autoreleasepool { - SDL_VideoDevice *device; - SDL_CocoaVideoData *data; - - if (![NSThread isMainThread]) { - return NULL; // this doesn't SDL_SetError() because SDL_VideoInit is just going to overwrite it. - } - - Cocoa_RegisterApp(); - - // Initialize all variables that we clean on shutdown - device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); - if (device) { - data = [[SDL_CocoaVideoData alloc] init]; - } else { - data = nil; - } - if (!data) { - SDL_free(device); - return NULL; - } - device->internal = (SDL_VideoData *)CFBridgingRetain(data); - device->wakeup_lock = SDL_CreateMutex(); - device->system_theme = Cocoa_GetSystemTheme(); - - // Set the function pointers - device->VideoInit = Cocoa_VideoInit; - device->VideoQuit = Cocoa_VideoQuit; - device->GetDisplayBounds = Cocoa_GetDisplayBounds; - device->GetDisplayUsableBounds = Cocoa_GetDisplayUsableBounds; - device->GetDisplayModes = Cocoa_GetDisplayModes; - device->SetDisplayMode = Cocoa_SetDisplayMode; - device->PumpEvents = Cocoa_PumpEvents; - device->WaitEventTimeout = Cocoa_WaitEventTimeout; - device->SendWakeupEvent = Cocoa_SendWakeupEvent; - device->SuspendScreenSaver = Cocoa_SuspendScreenSaver; - - device->CreateSDLWindow = Cocoa_CreateWindow; - device->SetWindowTitle = Cocoa_SetWindowTitle; - device->SetWindowIcon = Cocoa_SetWindowIcon; - device->SetWindowPosition = Cocoa_SetWindowPosition; - device->SetWindowSize = Cocoa_SetWindowSize; - device->SetWindowMinimumSize = Cocoa_SetWindowMinimumSize; - device->SetWindowMaximumSize = Cocoa_SetWindowMaximumSize; - device->SetWindowAspectRatio = Cocoa_SetWindowAspectRatio; - device->SetWindowOpacity = Cocoa_SetWindowOpacity; - device->GetWindowSizeInPixels = Cocoa_GetWindowSizeInPixels; - device->ShowWindow = Cocoa_ShowWindow; - device->HideWindow = Cocoa_HideWindow; - device->RaiseWindow = Cocoa_RaiseWindow; - device->MaximizeWindow = Cocoa_MaximizeWindow; - device->MinimizeWindow = Cocoa_MinimizeWindow; - device->RestoreWindow = Cocoa_RestoreWindow; - device->SetWindowBordered = Cocoa_SetWindowBordered; - device->SetWindowResizable = Cocoa_SetWindowResizable; - device->SetWindowAlwaysOnTop = Cocoa_SetWindowAlwaysOnTop; - device->SetWindowFullscreen = Cocoa_SetWindowFullscreen; - device->GetWindowICCProfile = Cocoa_GetWindowICCProfile; - device->GetDisplayForWindow = Cocoa_GetDisplayForWindow; - device->SetWindowMouseRect = Cocoa_SetWindowMouseRect; - device->SetWindowMouseGrab = Cocoa_SetWindowMouseGrab; - device->SetWindowKeyboardGrab = Cocoa_SetWindowKeyboardGrab; - device->DestroyWindow = Cocoa_DestroyWindow; - device->SetWindowHitTest = Cocoa_SetWindowHitTest; - device->AcceptDragAndDrop = Cocoa_AcceptDragAndDrop; - device->UpdateWindowShape = Cocoa_UpdateWindowShape; - device->FlashWindow = Cocoa_FlashWindow; - device->SetWindowFocusable = Cocoa_SetWindowFocusable; - device->SetWindowParent = Cocoa_SetWindowParent; - device->SetWindowModal = Cocoa_SetWindowModal; - device->SyncWindow = Cocoa_SyncWindow; - -#ifdef SDL_VIDEO_OPENGL_CGL - device->GL_LoadLibrary = Cocoa_GL_LoadLibrary; - device->GL_GetProcAddress = Cocoa_GL_GetProcAddress; - device->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary; - device->GL_CreateContext = Cocoa_GL_CreateContext; - device->GL_MakeCurrent = Cocoa_GL_MakeCurrent; - device->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval; - device->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval; - device->GL_SwapWindow = Cocoa_GL_SwapWindow; - device->GL_DestroyContext = Cocoa_GL_DestroyContext; - device->GL_GetEGLSurface = NULL; -#endif -#ifdef SDL_VIDEO_OPENGL_EGL -#ifdef SDL_VIDEO_OPENGL_CGL - if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, false)) { -#endif - device->GL_LoadLibrary = Cocoa_GLES_LoadLibrary; - device->GL_GetProcAddress = Cocoa_GLES_GetProcAddress; - device->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary; - device->GL_CreateContext = Cocoa_GLES_CreateContext; - device->GL_MakeCurrent = Cocoa_GLES_MakeCurrent; - device->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval; - device->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval; - device->GL_SwapWindow = Cocoa_GLES_SwapWindow; - device->GL_DestroyContext = Cocoa_GLES_DestroyContext; - device->GL_GetEGLSurface = Cocoa_GLES_GetEGLSurface; -#ifdef SDL_VIDEO_OPENGL_CGL - } -#endif -#endif - -#ifdef SDL_VIDEO_VULKAN - device->Vulkan_LoadLibrary = Cocoa_Vulkan_LoadLibrary; - device->Vulkan_UnloadLibrary = Cocoa_Vulkan_UnloadLibrary; - device->Vulkan_GetInstanceExtensions = Cocoa_Vulkan_GetInstanceExtensions; - device->Vulkan_CreateSurface = Cocoa_Vulkan_CreateSurface; - device->Vulkan_DestroySurface = Cocoa_Vulkan_DestroySurface; -#endif - -#ifdef SDL_VIDEO_METAL - device->Metal_CreateView = Cocoa_Metal_CreateView; - device->Metal_DestroyView = Cocoa_Metal_DestroyView; - device->Metal_GetLayer = Cocoa_Metal_GetLayer; -#endif - - device->StartTextInput = Cocoa_StartTextInput; - device->StopTextInput = Cocoa_StopTextInput; - device->UpdateTextInputArea = Cocoa_UpdateTextInputArea; - - device->SetClipboardData = Cocoa_SetClipboardData; - device->GetClipboardData = Cocoa_GetClipboardData; - device->HasClipboardData = Cocoa_HasClipboardData; - - device->free = Cocoa_DeleteDevice; - - device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT | - VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS; - return device; - } -} - -VideoBootStrap COCOA_bootstrap = { - "cocoa", "SDL Cocoa video driver", - Cocoa_CreateDevice, - Cocoa_ShowMessageBox, - false -}; - -static bool Cocoa_VideoInit(SDL_VideoDevice *_this) -{ - @autoreleasepool { - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - - Cocoa_InitModes(_this); - Cocoa_InitKeyboard(_this); - if (!Cocoa_InitMouse(_this)) { - return false; - } - if (!Cocoa_InitPen(_this)) { - return false; - } - - // Assume we have a mouse and keyboard - // We could use GCMouse and GCKeyboard if we needed to, as is done in SDL_uikitevents.m - SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL, false); - SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL, false); - - data.allow_spaces = SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, true); - data.trackpad_is_touch_only = SDL_GetHintBoolean(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, false); - SDL_AddHintCallback(SDL_HINT_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY, Cocoa_MenuVisibilityCallback, NULL); - - data.swaplock = SDL_CreateMutex(); - if (!data.swaplock) { - return false; - } - - return true; - } -} - -void Cocoa_VideoQuit(SDL_VideoDevice *_this) -{ - @autoreleasepool { - SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal; - Cocoa_QuitModes(_this); - Cocoa_QuitKeyboard(_this); - Cocoa_QuitMouse(_this); - Cocoa_QuitPen(_this); - SDL_DestroyMutex(data.swaplock); - data.swaplock = NULL; - } -} - -// This function assumes that it's called from within an autorelease pool -SDL_SystemTheme Cocoa_GetSystemTheme(void) -{ - if (@available(macOS 10.14, *)) { - NSAppearance* appearance = [[NSApplication sharedApplication] effectiveAppearance]; - - if ([appearance.name containsString: @"Dark"]) { - return SDL_SYSTEM_THEME_DARK; - } - } - return SDL_SYSTEM_THEME_LIGHT; -} - -// This function assumes that it's called from within an autorelease pool -NSImage *Cocoa_CreateImage(SDL_Surface *surface) -{ - NSImage *img; - - img = [[NSImage alloc] initWithSize:NSMakeSize(surface->w, surface->h)]; - if (img == nil) { - return nil; - } - - SDL_Surface **images = SDL_GetSurfaceImages(surface, NULL); - if (!images) { - return nil; - } - - for (int i = 0; images[i]; ++i) { - SDL_Surface *converted = SDL_ConvertSurface(images[i], SDL_PIXELFORMAT_RGBA32); - if (!converted) { - SDL_free(images); - return nil; - } - - // Premultiply the alpha channel - SDL_PremultiplySurfaceAlpha(converted, false); - - NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:converted->w - pixelsHigh:converted->h - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:converted->pitch - bitsPerPixel:SDL_BITSPERPIXEL(converted->format)]; - if (imgrep == nil) { - SDL_free(images); - SDL_DestroySurface(converted); - return nil; - } - - // Copy the pixels - Uint8 *pixels = [imgrep bitmapData]; - SDL_memcpy(pixels, converted->pixels, (size_t)converted->h * converted->pitch); - SDL_DestroySurface(converted); - - // Add the image representation - [img addRepresentation:imgrep]; - } - SDL_free(images); - - return img; -} - -/* - * macOS log support. - * - * This doesn't really have anything to do with the interfaces of the SDL video - * subsystem, but we need to stuff this into an Objective-C source code file. - * - * NOTE: This is copypasted in src/video/uikit/SDL_uikitvideo.m! Be sure both - * versions remain identical! - */ - -void SDL_NSLog(const char *prefix, const char *text) -{ - @autoreleasepool { - NSString *nsText = [NSString stringWithUTF8String:text]; - if (prefix && *prefix) { - NSString *nsPrefix = [NSString stringWithUTF8String:prefix]; - NSLog(@"%@%@", nsPrefix, nsText); - } else { - NSLog(@"%@", nsText); - } - } -} - -#endif // SDL_VIDEO_DRIVER_COCOA diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.h deleted file mode 100644 index 86e634e..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/* - * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's - * SDL_x11vulkan.h. - */ - -#include "SDL_internal.h" - -#ifndef SDL_cocoavulkan_h_ -#define SDL_cocoavulkan_h_ - -#include "../SDL_vulkan_internal.h" -#include "../SDL_sysvideo.h" - -#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_COCOA) - -extern bool Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path); -extern void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this); -extern char const* const* Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count); -extern bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this, - SDL_Window *window, - VkInstance instance, - const struct VkAllocationCallbacks *allocator, - VkSurfaceKHR *surface); -extern void Cocoa_Vulkan_DestroySurface(SDL_VideoDevice *_this, - VkInstance instance, - VkSurfaceKHR surface, - const struct VkAllocationCallbacks *allocator); - -#endif - -#endif // SDL_cocoavulkan_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.m deleted file mode 100644 index a440627..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoavulkan.m +++ /dev/null @@ -1,304 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/* - * @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's - * SDL_x11vulkan.c. - */ -#include "SDL_internal.h" - -#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_COCOA) - -#include "SDL_cocoavideo.h" -#include "SDL_cocoawindow.h" - -#include "SDL_cocoametalview.h" -#include "SDL_cocoavulkan.h" - -#include - -const char *defaultPaths[] = { - "vulkan.framework/vulkan", - "libvulkan.1.dylib", - "libvulkan.dylib", - "MoltenVK.framework/MoltenVK", - "libMoltenVK.dylib" -}; - -// Since libSDL is most likely a .dylib, need RTLD_DEFAULT not RTLD_SELF. -#define DEFAULT_HANDLE RTLD_DEFAULT - -bool Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path) -{ - VkExtensionProperties *extensions = NULL; - Uint32 extensionCount = 0; - bool hasSurfaceExtension = false; - bool hasMetalSurfaceExtension = false; - bool hasMacOSSurfaceExtension = false; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; - - if (_this->vulkan_config.loader_handle) { - return SDL_SetError("Vulkan Portability library is already loaded."); - } - - // Load the Vulkan loader library - if (!path) { - path = SDL_GetHint(SDL_HINT_VULKAN_LIBRARY); - } - - if (!path) { - // Handle the case where Vulkan Portability is linked statically. - vkGetInstanceProcAddr = - (PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE, - "vkGetInstanceProcAddr"); - } - - if (vkGetInstanceProcAddr) { - _this->vulkan_config.loader_handle = DEFAULT_HANDLE; - } else { - const char **paths; - const char *foundPath = NULL; - int numPaths; - int i; - - if (path) { - paths = &path; - numPaths = 1; - } else { - /* Look for framework or .dylib packaged with the application - * instead. */ - paths = defaultPaths; - numPaths = SDL_arraysize(defaultPaths); - } - - for (i = 0; i < numPaths && _this->vulkan_config.loader_handle == NULL; i++) { - foundPath = paths[i]; - _this->vulkan_config.loader_handle = SDL_LoadObject(foundPath); - } - - if (_this->vulkan_config.loader_handle == NULL) { - return SDL_SetError("Failed to load Vulkan Portability library"); - } - - SDL_strlcpy(_this->vulkan_config.loader_path, foundPath, - SDL_arraysize(_this->vulkan_config.loader_path)); - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( - _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); - } - - if (!vkGetInstanceProcAddr) { - SDL_SetError("Failed to find %s in either executable or %s: %s", - "vkGetInstanceProcAddr", - _this->vulkan_config.loader_path, - (const char *)dlerror()); - goto fail; - } - - _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; - _this->vulkan_config.vkEnumerateInstanceExtensionProperties = - (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( - VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); - if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) { - goto fail; - } - extensions = SDL_Vulkan_CreateInstanceExtensionsList( - (PFN_vkEnumerateInstanceExtensionProperties) - _this->vulkan_config.vkEnumerateInstanceExtensionProperties, - &extensionCount); - if (!extensions) { - goto fail; - } - for (Uint32 i = 0; i < extensionCount; i++) { - if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) { - hasSurfaceExtension = true; - } else if (SDL_strcmp(VK_EXT_METAL_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) { - hasMetalSurfaceExtension = true; - } else if (SDL_strcmp(VK_MVK_MACOS_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) { - hasMacOSSurfaceExtension = true; - } - } - SDL_free(extensions); - if (!hasSurfaceExtension) { - SDL_SetError("Installed Vulkan Portability library doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension"); - goto fail; - } else if (!hasMetalSurfaceExtension && !hasMacOSSurfaceExtension) { - SDL_SetError("Installed Vulkan Portability library doesn't implement the " VK_EXT_METAL_SURFACE_EXTENSION_NAME " or " VK_MVK_MACOS_SURFACE_EXTENSION_NAME " extensions"); - goto fail; - } - return true; - -fail: - SDL_UnloadObject(_this->vulkan_config.loader_handle); - _this->vulkan_config.loader_handle = NULL; - return false; -} - -void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this) -{ - if (_this->vulkan_config.loader_handle) { - if (_this->vulkan_config.loader_handle != DEFAULT_HANDLE) { - SDL_UnloadObject(_this->vulkan_config.loader_handle); - } - _this->vulkan_config.loader_handle = NULL; - } -} - -char const* const* Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, - Uint32 *count) -{ - static const char *const extensionsForCocoa[] = { - VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_EXTENSION_NAME, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME - }; - if(count) { - *count = SDL_arraysize(extensionsForCocoa); - } - return extensionsForCocoa; -} - -static bool Cocoa_Vulkan_CreateSurfaceViaMetalView(SDL_VideoDevice *_this, - SDL_Window *window, - VkInstance instance, - const struct VkAllocationCallbacks *allocator, - VkSurfaceKHR *surface, - PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT, - PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK) -{ - VkResult rc; - SDL_MetalView metalview = Cocoa_Metal_CreateView(_this, window); - if (metalview == NULL) { - return false; - } - - if (vkCreateMetalSurfaceEXT) { - VkMetalSurfaceCreateInfoEXT createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - createInfo.pNext = NULL; - createInfo.flags = 0; - createInfo.pLayer = (__bridge const CAMetalLayer *) - Cocoa_Metal_GetLayer(_this, metalview); - rc = vkCreateMetalSurfaceEXT(instance, &createInfo, allocator, surface); - if (rc != VK_SUCCESS) { - Cocoa_Metal_DestroyView(_this, metalview); - return SDL_SetError("vkCreateMetalSurfaceEXT failed: %s", SDL_Vulkan_GetResultString(rc)); - } - } else { - VkMacOSSurfaceCreateInfoMVK createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - createInfo.pNext = NULL; - createInfo.flags = 0; - createInfo.pView = (const void *)metalview; - rc = vkCreateMacOSSurfaceMVK(instance, &createInfo, - NULL, surface); - if (rc != VK_SUCCESS) { - Cocoa_Metal_DestroyView(_this, metalview); - return SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s", SDL_Vulkan_GetResultString(rc)); - } - } - - /* Unfortunately there's no SDL_Vulkan_DestroySurface function we can call - * Metal_DestroyView from. Right now the metal view's ref count is +2 (one - * from returning a new view object in CreateView, and one because it's - * a subview of the window.) If we release the view here to make it +1, it - * will be destroyed when the window is destroyed. - * - * TODO: Now that we have SDL_Vulkan_DestroySurface someone with enough - * knowledge of Metal can proceed. */ - CFBridgingRelease(metalview); - - return true; // success! -} - -bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this, - SDL_Window *window, - VkInstance instance, - const struct VkAllocationCallbacks *allocator, - VkSurfaceKHR *surface) -{ - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = - (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; - PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT = - (PFN_vkCreateMetalSurfaceEXT)vkGetInstanceProcAddr( - instance, - "vkCreateMetalSurfaceEXT"); - PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = - (PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr( - instance, - "vkCreateMacOSSurfaceMVK"); - VkResult rc; - - if (!_this->vulkan_config.loader_handle) { - return SDL_SetError("Vulkan is not loaded"); - } - - if (!vkCreateMetalSurfaceEXT && !vkCreateMacOSSurfaceMVK) { - return SDL_SetError(VK_EXT_METAL_SURFACE_EXTENSION_NAME " or " VK_MVK_MACOS_SURFACE_EXTENSION_NAME - " extensions are not enabled in the Vulkan instance."); - } - - if (window->flags & SDL_WINDOW_EXTERNAL) { - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - if (![data.sdlContentView.layer isKindOfClass:[CAMetalLayer class]]) { - [data.sdlContentView setLayer:[CAMetalLayer layer]]; - } - - if (vkCreateMetalSurfaceEXT) { - VkMetalSurfaceCreateInfoEXT createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - createInfo.pNext = NULL; - createInfo.flags = 0; - createInfo.pLayer = (CAMetalLayer *)data.sdlContentView.layer; - rc = vkCreateMetalSurfaceEXT(instance, &createInfo, allocator, surface); - if (rc != VK_SUCCESS) { - return SDL_SetError("vkCreateMetalSurfaceEXT failed: %s", SDL_Vulkan_GetResultString(rc)); - } - } else { - VkMacOSSurfaceCreateInfoMVK createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - createInfo.pNext = NULL; - createInfo.flags = 0; - createInfo.pView = (__bridge const void *)data.sdlContentView; - rc = vkCreateMacOSSurfaceMVK(instance, &createInfo, - allocator, surface); - if (rc != VK_SUCCESS) { - return SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s", SDL_Vulkan_GetResultString(rc)); - } - } - } - } else { - return Cocoa_Vulkan_CreateSurfaceViaMetalView(_this, window, instance, allocator, surface, vkCreateMetalSurfaceEXT, vkCreateMacOSSurfaceMVK); - } - - return true; -} - -void Cocoa_Vulkan_DestroySurface(SDL_VideoDevice *_this, - VkInstance instance, - VkSurfaceKHR surface, - const struct VkAllocationCallbacks *allocator) -{ - if (_this->vulkan_config.loader_handle) { - SDL_Vulkan_DestroySurface_Internal(_this->vulkan_config.vkGetInstanceProcAddr, instance, surface, allocator); - // TODO: Add CFBridgingRelease(metalview) here perhaps? - } -} - -#endif diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.h b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.h deleted file mode 100644 index 6df69f4..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifndef SDL_cocoawindow_h_ -#define SDL_cocoawindow_h_ - -#import - -#ifdef SDL_VIDEO_OPENGL_EGL -#include "../SDL_egl_c.h" -#endif - -#define SDL_METALVIEW_TAG 255 - -@class SDL_CocoaWindowData; - -typedef enum -{ - PENDING_OPERATION_NONE = 0x00, - PENDING_OPERATION_ENTER_FULLSCREEN = 0x01, - PENDING_OPERATION_LEAVE_FULLSCREEN = 0x02, - PENDING_OPERATION_MINIMIZE = 0x04, - PENDING_OPERATION_ZOOM = 0x08 -} PendingWindowOperation; - -@interface SDL3Cocoa_WindowListener : NSResponder -{ - /* SDL_CocoaWindowData owns this Listener and has a strong reference to it. - * To avoid reference cycles, we could have either a weak or an - * unretained ref to the WindowData. */ - __weak SDL_CocoaWindowData *_data; - BOOL observingVisible; - BOOL wasCtrlLeft; - BOOL wasVisible; - BOOL isFullscreenSpace; - BOOL inFullscreenTransition; - PendingWindowOperation pendingWindowOperation; - BOOL isMoving; - BOOL isMiniaturizing; - NSInteger focusClickPending; - float pendingWindowWarpX, pendingWindowWarpY; - BOOL isDragAreaRunning; - NSTimer *liveResizeTimer; -} - -- (BOOL)isTouchFromTrackpad:(NSEvent *)theEvent; -- (void)listen:(SDL_CocoaWindowData *)data; -- (void)pauseVisibleObservation; -- (void)resumeVisibleObservation; -- (BOOL)setFullscreenSpace:(BOOL)state; -- (BOOL)isInFullscreenSpace; -- (BOOL)isInFullscreenSpaceTransition; -- (void)addPendingWindowOperation:(PendingWindowOperation)operation; -- (void)close; - -- (BOOL)isMoving; -- (BOOL)isMovingOrFocusClickPending; -- (void)setFocusClickPending:(NSInteger)button; -- (void)clearFocusClickPending:(NSInteger)button; -- (void)updateIgnoreMouseState:(NSEvent *)theEvent; -- (void)setPendingMoveX:(float)x Y:(float)y; -- (void)windowDidFinishMoving; -- (void)onMovingOrFocusClickPendingStateCleared; - -// Window delegate functionality -- (BOOL)windowShouldClose:(id)sender; -- (void)windowDidExpose:(NSNotification *)aNotification; -- (void)windowDidChangeOcclusionState:(NSNotification *)aNotification; -- (void)windowWillStartLiveResize:(NSNotification *)aNotification; -- (void)windowDidEndLiveResize:(NSNotification *)aNotification; -- (void)windowDidMove:(NSNotification *)aNotification; -- (void)windowDidResize:(NSNotification *)aNotification; -- (void)windowDidMiniaturize:(NSNotification *)aNotification; -- (void)windowDidDeminiaturize:(NSNotification *)aNotification; -- (void)windowDidBecomeKey:(NSNotification *)aNotification; -- (void)windowDidResignKey:(NSNotification *)aNotification; -- (void)windowDidChangeBackingProperties:(NSNotification *)aNotification; -- (void)windowDidChangeScreenProfile:(NSNotification *)aNotification; -- (void)windowDidChangeScreen:(NSNotification *)aNotification; -- (void)windowWillEnterFullScreen:(NSNotification *)aNotification; -- (void)windowDidEnterFullScreen:(NSNotification *)aNotification; -- (void)windowWillExitFullScreen:(NSNotification *)aNotification; -- (void)windowDidExitFullScreen:(NSNotification *)aNotification; -- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions; - -// See if event is in a drag area, toggle on window dragging. -- (void)updateHitTest; -- (BOOL)processHitTest:(NSEvent *)theEvent; - -// Window event handling -- (void)mouseDown:(NSEvent *)theEvent; -- (void)rightMouseDown:(NSEvent *)theEvent; -- (void)otherMouseDown:(NSEvent *)theEvent; -- (void)mouseUp:(NSEvent *)theEvent; -- (void)rightMouseUp:(NSEvent *)theEvent; -- (void)otherMouseUp:(NSEvent *)theEvent; -- (void)mouseMoved:(NSEvent *)theEvent; -- (void)mouseDragged:(NSEvent *)theEvent; -- (void)rightMouseDragged:(NSEvent *)theEvent; -- (void)otherMouseDragged:(NSEvent *)theEvent; -- (void)scrollWheel:(NSEvent *)theEvent; -- (void)touchesBeganWithEvent:(NSEvent *)theEvent; -- (void)touchesMovedWithEvent:(NSEvent *)theEvent; -- (void)touchesEndedWithEvent:(NSEvent *)theEvent; -- (void)touchesCancelledWithEvent:(NSEvent *)theEvent; - -// Touch event handling -- (void)handleTouches:(NSTouchPhase)phase withEvent:(NSEvent *)theEvent; - -// Tablet event handling (but these also come through on mouse events sometimes!) -- (void)tabletProximity:(NSEvent *)theEvent; -- (void)tabletPoint:(NSEvent *)theEvent; - -@end -/* *INDENT-ON* */ - -@class SDL3OpenGLContext; -@class SDL_CocoaVideoData; - -@interface SDL_CocoaWindowData : NSObject -@property(nonatomic) SDL_Window *window; -@property(nonatomic) NSWindow *nswindow; -@property(nonatomic) NSView *sdlContentView; -@property(nonatomic) NSMutableArray *nscontexts; -@property(nonatomic) BOOL in_blocking_transition; -@property(nonatomic) BOOL fullscreen_space_requested; -@property(nonatomic) BOOL was_zoomed; -@property(nonatomic) NSInteger window_number; -@property(nonatomic) NSInteger flash_request; -@property(nonatomic) SDL_Window *keyboard_focus; -@property(nonatomic) SDL3Cocoa_WindowListener *listener; -@property(nonatomic) NSModalSession modal_session; -@property(nonatomic) SDL_CocoaVideoData *videodata; -@property(nonatomic) bool pending_size; -@property(nonatomic) bool pending_position; -@property(nonatomic) bool border_toggled; - -#ifdef SDL_VIDEO_OPENGL_EGL -@property(nonatomic) EGLSurface egl_surface; -#endif -@end - -extern bool b_inModeTransition; - -extern bool Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props); -extern void Cocoa_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon); -extern bool Cocoa_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_SetWindowAspectRatio(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h); -extern bool Cocoa_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity); -extern void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern void Cocoa_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, bool bordered); -extern void Cocoa_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable); -extern void Cocoa_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, bool on_top); -extern SDL_FullscreenResult Cocoa_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen); -extern void *Cocoa_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size); -extern SDL_DisplayID Cocoa_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed); -extern void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); -extern bool Cocoa_SetWindowHitTest(SDL_Window *window, bool enabled); -extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, bool accept); -extern bool Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation); -extern bool Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable); -extern bool Cocoa_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal); -extern bool Cocoa_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent); -extern bool Cocoa_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window); - -extern void Cocoa_MenuVisibilityCallback(void *userdata, const char *name, const char *oldValue, const char *newValue); - -#endif // SDL_cocoawindow_h_ diff --git a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.m b/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.m deleted file mode 100644 index 52943e8..0000000 --- a/contrib/SDL-3.2.8/src/video/cocoa/SDL_cocoawindow.m +++ /dev/null @@ -1,3277 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_internal.h" - -#ifdef SDL_VIDEO_DRIVER_COCOA - -#include // For FLT_MAX - -#include "../../events/SDL_dropevents_c.h" -#include "../../events/SDL_keyboard_c.h" -#include "../../events/SDL_mouse_c.h" -#include "../../events/SDL_touch_c.h" -#include "../../events/SDL_windowevents_c.h" -#include "../SDL_sysvideo.h" - -#include "SDL_cocoamouse.h" -#include "SDL_cocoaopengl.h" -#include "SDL_cocoaopengles.h" -#include "SDL_cocoavideo.h" - -#if 0 -#define DEBUG_COCOAWINDOW -#endif - -#ifdef DEBUG_COCOAWINDOW -#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__) -#else -#define DLog(...) \ - do { \ - } while (0) -#endif - -#ifndef MAC_OS_X_VERSION_10_12 -#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask -#endif -#ifndef NSAppKitVersionNumber10_13_2 -#define NSAppKitVersionNumber10_13_2 1561.2 -#endif -#ifndef NSAppKitVersionNumber10_14 -#define NSAppKitVersionNumber10_14 1671 -#endif - -@implementation SDL_CocoaWindowData - -@end - -@interface NSScreen (SDL) -#if MAC_OS_X_VERSION_MAX_ALLOWED < 120000 // Added in the 12.0 SDK -@property(readonly) NSEdgeInsets safeAreaInsets; -#endif -@end - -@interface NSWindow (SDL) -// This is available as of 10.13.2, but isn't in public headers -@property(nonatomic) NSRect mouseConfinementRect; -@end - -@interface SDL3Window : NSWindow -// These are needed for borderless/fullscreen windows -- (BOOL)canBecomeKeyWindow; -- (BOOL)canBecomeMainWindow; -- (void)sendEvent:(NSEvent *)event; -- (void)doCommandBySelector:(SEL)aSelector; - -// Handle drag-and-drop of files onto the SDL window. -- (NSDragOperation)draggingEntered:(id)sender; -- (void)draggingExited:(id)sender; -- (NSDragOperation)draggingUpdated:(id)sender; -- (BOOL)performDragOperation:(id)sender; -- (BOOL)wantsPeriodicDraggingUpdates; -- (BOOL)validateMenuItem:(NSMenuItem *)menuItem; - -- (SDL_Window *)findSDLWindow; -@end - -@implementation SDL3Window - -- (BOOL)validateMenuItem:(NSMenuItem *)menuItem -{ - /* Only allow using the macOS native fullscreen toggle menubar item if the - * window is resizable and not in a SDL fullscreen mode. - */ - if ([menuItem action] == @selector(toggleFullScreen:)) { - SDL_Window *window = [self findSDLWindow]; - if (!window) { - return NO; - } - - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - if ((window->flags & SDL_WINDOW_FULLSCREEN) && ![data.listener isInFullscreenSpace]) { - return NO; - } else if (!(window->flags & SDL_WINDOW_RESIZABLE)) { - return NO; - } - } - return [super validateMenuItem:menuItem]; -} - -- (BOOL)canBecomeKeyWindow -{ - SDL_Window *window = [self findSDLWindow]; - if (window && !(window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_NOT_FOCUSABLE))) { - return YES; - } else { - return NO; - } -} - -- (BOOL)canBecomeMainWindow -{ - SDL_Window *window = [self findSDLWindow]; - if (window && !(window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_NOT_FOCUSABLE)) && !SDL_WINDOW_IS_POPUP(window)) { - return YES; - } else { - return NO; - } -} - -- (void)sendEvent:(NSEvent *)event -{ - id delegate; - [super sendEvent:event]; - - if ([event type] != NSEventTypeLeftMouseUp) { - return; - } - - delegate = [self delegate]; - if (![delegate isKindOfClass:[SDL3Cocoa_WindowListener class]]) { - return; - } - - if ([delegate isMoving]) { - [delegate windowDidFinishMoving]; - } -} - -/* We'll respond to selectors by doing nothing so we don't beep. - * The escape key gets converted to a "cancel" selector, etc. - */ -- (void)doCommandBySelector:(SEL)aSelector -{ - // NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector)); -} - -- (NSDragOperation)draggingEntered:(id)sender -{ - if (([sender draggingSourceOperationMask] & NSDragOperationGeneric) == NSDragOperationGeneric) { - return NSDragOperationGeneric; - } else if (([sender draggingSourceOperationMask] & NSDragOperationCopy) == NSDragOperationCopy) { - return NSDragOperationCopy; - } - - return NSDragOperationNone; // no idea what to do with this, reject it. -} - -- (void)draggingExited:(id)sender -{ - SDL_Window *sdlwindow = [self findSDLWindow]; - SDL_SendDropComplete(sdlwindow); -} - -- (NSDragOperation)draggingUpdated:(id)sender -{ - if (([sender draggingSourceOperationMask] & NSDragOperationGeneric) == NSDragOperationGeneric) { - SDL_Window *sdlwindow = [self findSDLWindow]; - NSPoint point = [sender draggingLocation]; - float x, y; - x = point.x; - y = (sdlwindow->h - point.y); - SDL_SendDropPosition(sdlwindow, x, y); - return NSDragOperationGeneric; - } else if (([sender draggingSourceOperationMask] & NSDragOperationCopy) == NSDragOperationCopy) { - SDL_Window *sdlwindow = [self findSDLWindow]; - NSPoint point = [sender draggingLocation]; - float x, y; - x = point.x; - y = (sdlwindow->h - point.y); - SDL_SendDropPosition(sdlwindow, x, y); - return NSDragOperationCopy; - } - - return NSDragOperationNone; // no idea what to do with this, reject it. -} - -- (BOOL)performDragOperation:(id)sender -{ - SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". [SDL] In performDragOperation, draggingSourceOperationMask %lx, " - "expected Generic %lx, others Copy %lx, Link %lx, Private %lx, Move %lx, Delete %lx\n", - (unsigned long)[sender draggingSourceOperationMask], - (unsigned long)NSDragOperationGeneric, - (unsigned long)NSDragOperationCopy, - (unsigned long)NSDragOperationLink, - (unsigned long)NSDragOperationPrivate, - (unsigned long)NSDragOperationMove, - (unsigned long)NSDragOperationDelete); - if ([sender draggingPasteboard]) { - SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". [SDL] In performDragOperation, valid draggingPasteboard, " - "name [%s] '%s', changeCount %ld\n", - [[[[sender draggingPasteboard] name] className] UTF8String], - [[[[sender draggingPasteboard] name] description] UTF8String], - (long)[[sender draggingPasteboard] changeCount]); - } - @autoreleasepool { - NSPasteboard *pasteboard = [sender draggingPasteboard]; - NSString *desiredType = [pasteboard availableTypeFromArray:@[ NSFilenamesPboardType, NSPasteboardTypeString ]]; - SDL_Window *sdlwindow = [self findSDLWindow]; - NSData *pboardData; - id pboardPlist; - NSString *pboardString; - NSPoint point; - float x, y; - - for (NSString *supportedType in [pasteboard types]) { - NSString *typeString = [pasteboard stringForType:supportedType]; - SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". [SDL] In performDragOperation, Pasteboard type '%s', stringForType (%lu) '%s'\n", - [[supportedType description] UTF8String], - (unsigned long)[[typeString description] length], - [[typeString description] UTF8String]); - } - - if (desiredType == nil) { - return NO; // can't accept anything that's being dropped here. - } - pboardData = [pasteboard dataForType:desiredType]; - if (pboardData == nil) { - return NO; - } - SDL_assert([desiredType isEqualToString:NSFilenamesPboardType] || - [desiredType isEqualToString:NSPasteboardTypeString]); - - pboardString = [pasteboard stringForType:desiredType]; - pboardPlist = [pasteboard propertyListForType:desiredType]; - - // Use SendDropPosition to update the mouse location - point = [sender draggingLocation]; - x = point.x; - y = (sdlwindow->h - point.y); - if (x >= 0.0f && x < (float)sdlwindow->w && y >= 0.0f && y < (float)sdlwindow->h) { - SDL_SendDropPosition(sdlwindow, x, y); - } - // Use SendDropPosition to update the mouse location - - if ([desiredType isEqualToString:NSFilenamesPboardType]) { - for (NSString *path in (NSArray *)pboardPlist) { - NSURL *fileURL = [NSURL fileURLWithPath:path]; - NSNumber *isAlias = nil; - - [fileURL getResourceValue:&isAlias forKey:NSURLIsAliasFileKey error:nil]; - - // If the URL is an alias, resolve it. - if ([isAlias boolValue]) { - NSURLBookmarkResolutionOptions opts = NSURLBookmarkResolutionWithoutMounting | - NSURLBookmarkResolutionWithoutUI; - NSData *bookmark = [NSURL bookmarkDataWithContentsOfURL:fileURL error:nil]; - if (bookmark != nil) { - NSURL *resolvedURL = [NSURL URLByResolvingBookmarkData:bookmark - options:opts - relativeToURL:nil - bookmarkDataIsStale:nil - error:nil]; - if (resolvedURL != nil) { - fileURL = resolvedURL; - } - } - } - SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". [SDL] In performDragOperation, desiredType '%s', " - "Submitting DropFile as (%lu) '%s'\n", - [[desiredType description] UTF8String], - (unsigned long)[[[fileURL path] description] length], - [[[fileURL path] description] UTF8String]); - if (!SDL_SendDropFile(sdlwindow, NULL, [[[fileURL path] description] UTF8String])) { - return NO; - } - } - } else if ([desiredType isEqualToString:NSPasteboardTypeString]) { - char *buffer = SDL_strdup([[pboardString description] UTF8String]); - char *saveptr = NULL; - char *token = SDL_strtok_r(buffer, "\r\n", &saveptr); - while (token) { - SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". [SDL] In performDragOperation, desiredType '%s', " - "Submitting DropText as (%lu) '%s'\n", - [[desiredType description] UTF8String], - SDL_strlen(token), token); - if (!SDL_SendDropText(sdlwindow, token)) { - SDL_free(buffer); - return NO; - } - token = SDL_strtok_r(NULL, "\r\n", &saveptr); - } - SDL_free(buffer); - } - - SDL_SendDropComplete(sdlwindow); - return YES; - } -} - -- (BOOL)wantsPeriodicDraggingUpdates -{ - return NO; -} - -- (SDL_Window *)findSDLWindow -{ - SDL_Window *sdlwindow = NULL; - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - - // !!! FIXME: is there a better way to do this? - if (_this) { - for (sdlwindow = _this->windows; sdlwindow; sdlwindow = sdlwindow->next) { - NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)sdlwindow->internal).nswindow; - if (nswindow == self) { - break; - } - } - } - - return sdlwindow; -} - -@end - -bool b_inModeTransition; - -static CGFloat SqDistanceToRect(const NSPoint *point, const NSRect *rect) -{ - NSPoint edge = *point; - CGFloat left = NSMinX(*rect), right = NSMaxX(*rect); - CGFloat bottom = NSMinX(*rect), top = NSMaxY(*rect); - NSPoint delta; - - if (point->x < left) { - edge.x = left; - } else if (point->x > right) { - edge.x = right; - } - - if (point->y < bottom) { - edge.y = bottom; - } else if (point->y > top) { - edge.y = top; - } - - delta = NSMakePoint(edge.x - point->x, edge.y - point->y); - return delta.x * delta.x + delta.y * delta.y; -} - -static NSScreen *ScreenForPoint(const NSPoint *point) -{ - NSScreen *screen; - - // Do a quick check first to see if the point lies on a specific screen - for (NSScreen *candidate in [NSScreen screens]) { - if (NSPointInRect(*point, [candidate frame])) { - screen = candidate; - break; - } - } - - // Find the screen the point is closest to - if (!screen) { - CGFloat closest = MAXFLOAT; - for (NSScreen *candidate in [NSScreen screens]) { - NSRect screenRect = [candidate frame]; - - CGFloat sqdist = SqDistanceToRect(point, &screenRect); - if (sqdist < closest) { - screen = candidate; - closest = sqdist; - } - } - } - - return screen; -} - -bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - if ([data.listener isInFullscreenSpace]) { - return true; - } else { - return false; - } - } -} - -bool Cocoa_IsWindowZoomed(SDL_Window *window) -{ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = data.nswindow; - bool zoomed = false; - - // isZoomed always returns true if the window is not resizable or the window is fullscreen - if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed] && - !(window->flags & SDL_WINDOW_FULLSCREEN) && !Cocoa_IsWindowInFullscreenSpace(window)) { - // If we are at our desired floating area, then we're not zoomed - bool floating = (window->x == window->floating.x && - window->y == window->floating.y && - window->w == window->floating.w && - window->h == window->floating.h); - if (!floating) { - zoomed = true; - } - } - return zoomed; -} - -typedef enum CocoaMenuVisibility -{ - COCOA_MENU_VISIBILITY_AUTO = 0, - COCOA_MENU_VISIBILITY_NEVER, - COCOA_MENU_VISIBILITY_ALWAYS -} CocoaMenuVisibility; - -static CocoaMenuVisibility menu_visibility_hint = COCOA_MENU_VISIBILITY_AUTO; - -static void Cocoa_ToggleFullscreenSpaceMenuVisibility(SDL_Window *window) -{ - if (window && Cocoa_IsWindowInFullscreenSpace(window)) { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - // 'Auto' sets the menu to visible if fullscreen wasn't explicitly entered via SDL_SetWindowFullscreen(). - if ((menu_visibility_hint == COCOA_MENU_VISIBILITY_AUTO && !data.fullscreen_space_requested) || - menu_visibility_hint == COCOA_MENU_VISIBILITY_ALWAYS) { - [NSMenu setMenuBarVisible:YES]; - } else { - [NSMenu setMenuBarVisible:NO]; - } - } -} - -void Cocoa_MenuVisibilityCallback(void *userdata, const char *name, const char *oldValue, const char *newValue) -{ - if (newValue) { - if (*newValue == '0' || SDL_strcasecmp(newValue, "false") == 0) { - menu_visibility_hint = COCOA_MENU_VISIBILITY_NEVER; - } else if (*newValue == '1' || SDL_strcasecmp(newValue, "true") == 0) { - menu_visibility_hint = COCOA_MENU_VISIBILITY_ALWAYS; - } else { - menu_visibility_hint = COCOA_MENU_VISIBILITY_AUTO; - } - } else { - menu_visibility_hint = COCOA_MENU_VISIBILITY_AUTO; - } - - // Update the current menu visibility. - Cocoa_ToggleFullscreenSpaceMenuVisibility(SDL_GetKeyboardFocus()); -} - -static NSScreen *ScreenForRect(const NSRect *rect) -{ - NSPoint center = NSMakePoint(NSMidX(*rect), NSMidY(*rect)); - return ScreenForPoint(¢er); -} - -static void ConvertNSRect(NSRect *r) -{ - r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height; -} - -static void ScheduleContextUpdates(SDL_CocoaWindowData *data) -{ -// We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. -#ifdef SDL_VIDEO_OPENGL - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - - NSOpenGLContext *currentContext; - NSMutableArray *contexts; - if (!data || !data.nscontexts) { - return; - } - - currentContext = [NSOpenGLContext currentContext]; - contexts = data.nscontexts; - @synchronized(contexts) { - for (SDL3OpenGLContext *context in contexts) { - if (context == currentContext) { - [context update]; - } else { - [context scheduleUpdate]; - } - } - } - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif // SDL_VIDEO_OPENGL -} - -// !!! FIXME: this should use a hint callback. -static bool GetHintCtrlClickEmulateRightClick(void) -{ - return SDL_GetHintBoolean(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, false); -} - -static NSUInteger GetWindowWindowedStyle(SDL_Window *window) -{ - /* IF YOU CHANGE ANY FLAGS IN HERE, PLEASE READ - the NSWindowStyleMaskBorderless comments in SetupWindowData()! */ - - /* always allow miniaturization, otherwise you can't programmatically - minimize the window, whether there's a title bar or not */ - NSUInteger style = NSWindowStyleMaskMiniaturizable; - - if (!SDL_WINDOW_IS_POPUP(window)) { - if (window->flags & SDL_WINDOW_BORDERLESS) { - style |= NSWindowStyleMaskBorderless; - } else { - style |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); - } - if (window->flags & SDL_WINDOW_RESIZABLE) { - style |= NSWindowStyleMaskResizable; - } - } else { - style |= NSWindowStyleMaskBorderless; - } - return style; -} - -static NSUInteger GetWindowStyle(SDL_Window *window) -{ - NSUInteger style = 0; - - if (window->flags & SDL_WINDOW_FULLSCREEN) { - style = NSWindowStyleMaskBorderless; - } else { - style = GetWindowWindowedStyle(window); - } - return style; -} - -static bool SetWindowStyle(SDL_Window *window, NSUInteger style) -{ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = data.nswindow; - - // The view responder chain gets messed with during setStyleMask - if ([data.sdlContentView nextResponder] == data.listener) { - [data.sdlContentView setNextResponder:nil]; - } - - [nswindow setStyleMask:style]; - - // The view responder chain gets messed with during setStyleMask - if ([data.sdlContentView nextResponder] != data.listener) { - [data.sdlContentView setNextResponder:data.listener]; - } - - return true; -} - -static bool ShouldAdjustCoordinatesForGrab(SDL_Window *window) -{ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - if (!data || [data.listener isMovingOrFocusClickPending]) { - return false; - } - - if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) { - return false; - } - - if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) || (window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) { - return true; - } - return false; -} - -static bool AdjustCoordinatesForGrab(SDL_Window *window, float x, float y, CGPoint *adjusted) -{ - if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) { - SDL_Rect window_rect; - SDL_Rect mouse_rect; - - window_rect.x = 0; - window_rect.y = 0; - window_rect.w = window->w; - window_rect.h = window->h; - - if (SDL_GetRectIntersection(&window->mouse_rect, &window_rect, &mouse_rect)) { - float left = (float)window->x + mouse_rect.x; - float right = left + mouse_rect.w - 1; - float top = (float)window->y + mouse_rect.y; - float bottom = top + mouse_rect.h - 1; - if (x < left || x > right || y < top || y > bottom) { - adjusted->x = SDL_clamp(x, left, right); - adjusted->y = SDL_clamp(y, top, bottom); - return true; - } - return false; - } - } - - if (window->flags & SDL_WINDOW_MOUSE_GRABBED) { - float left = (float)window->x; - float right = left + window->w - 1; - float top = (float)window->y; - float bottom = top + window->h - 1; - if (x < left || x > right || y < top || y > bottom) { - adjusted->x = SDL_clamp(x, left, right); - adjusted->y = SDL_clamp(y, top, bottom); - return true; - } - } - return false; -} - -static void Cocoa_UpdateClipCursor(SDL_Window *window) -{ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_13_2) { - NSWindow *nswindow = data.nswindow; - SDL_Rect mouse_rect; - - SDL_zero(mouse_rect); - - if (ShouldAdjustCoordinatesForGrab(window)) { - SDL_Rect window_rect; - - window_rect.x = 0; - window_rect.y = 0; - window_rect.w = window->w; - window_rect.h = window->h; - - if (window->mouse_rect.w > 0 && window->mouse_rect.h > 0) { - SDL_GetRectIntersection(&window->mouse_rect, &window_rect, &mouse_rect); - } - - if ((window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0 && - SDL_RectEmpty(&mouse_rect)) { - SDL_memcpy(&mouse_rect, &window_rect, sizeof(mouse_rect)); - } - } - - if (SDL_RectEmpty(&mouse_rect)) { - nswindow.mouseConfinementRect = NSZeroRect; - } else { - NSRect rect; - rect.origin.x = mouse_rect.x; - rect.origin.y = [nswindow contentLayoutRect].size.height - mouse_rect.y - mouse_rect.h; - rect.size.width = mouse_rect.w; - rect.size.height = mouse_rect.h; - nswindow.mouseConfinementRect = rect; - } - } else { - // Move the cursor to the nearest point in the window - if (ShouldAdjustCoordinatesForGrab(window)) { - float x, y; - CGPoint cgpoint; - - SDL_GetGlobalMouseState(&x, &y); - if (AdjustCoordinatesForGrab(window, x, y, &cgpoint)) { - Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y); - CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); - } - } - } -} - -static SDL_Window *GetParentToplevelWindow(SDL_Window *window) -{ - SDL_Window *toplevel = window; - - // Find the topmost parent - while (SDL_WINDOW_IS_POPUP(toplevel)) { - toplevel = toplevel->parent; - } - - return toplevel; -} - -static void Cocoa_SetKeyboardFocus(SDL_Window *window, bool set_active_focus) -{ - SDL_Window *toplevel = GetParentToplevelWindow(window); - SDL_CocoaWindowData *toplevel_data; - - toplevel_data = (__bridge SDL_CocoaWindowData *)toplevel->internal; - toplevel_data.keyboard_focus = window; - - if (set_active_focus && !window->is_hiding && !window->is_destroying) { - SDL_SetKeyboardFocus(window); - } -} - -static void Cocoa_SendExposedEventIfVisible(SDL_Window *window) -{ - NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow; - if ([nswindow occlusionState] & NSWindowOcclusionStateVisible) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); - } -} - -static void Cocoa_WaitForMiniaturizable(SDL_Window *window) -{ - NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow; - NSButton *button = [nswindow standardWindowButton:NSWindowMiniaturizeButton]; - if (button) { - int iterations = 0; - while (![button isEnabled] && (iterations < 100)) { - SDL_Delay(10); - SDL_PumpEvents(); - iterations++; - } - } -} - -static NSCursor *Cocoa_GetDesiredCursor(void) -{ - SDL_Mouse *mouse = SDL_GetMouse(); - - if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) { - return (__bridge NSCursor *)mouse->cur_cursor->internal; - } - - return [NSCursor invisibleCursor]; -} - -@implementation SDL3Cocoa_WindowListener - -- (void)listen:(SDL_CocoaWindowData *)data -{ - NSNotificationCenter *center; - NSWindow *window = data.nswindow; - NSView *view = data.sdlContentView; - - _data = data; - observingVisible = YES; - wasCtrlLeft = NO; - wasVisible = [window isVisible]; - isFullscreenSpace = NO; - inFullscreenTransition = NO; - pendingWindowOperation = PENDING_OPERATION_NONE; - isMoving = NO; - isMiniaturizing = NO; - isDragAreaRunning = NO; - pendingWindowWarpX = pendingWindowWarpY = FLT_MAX; - liveResizeTimer = nil; - - center = [NSNotificationCenter defaultCenter]; - - if ([window delegate] != nil) { - [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window]; - [center addObserver:self selector:@selector(windowDidChangeOcclusionState:) name:NSWindowDidChangeOcclusionStateNotification object:window]; - [center addObserver:self selector:@selector(windowWillStartLiveResize:) name:NSWindowWillStartLiveResizeNotification object:window]; - [center addObserver:self selector:@selector(windowDidEndLiveResize:) name:NSWindowDidEndLiveResizeNotification object:window]; - [center addObserver:self selector:@selector(windowWillMove:) name:NSWindowWillMoveNotification object:window]; - [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window]; - [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window]; - [center addObserver:self selector:@selector(windowWillMiniaturize:) name:NSWindowWillMiniaturizeNotification object:window]; - [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window]; - [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window]; - [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window]; - [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window]; - [center addObserver:self selector:@selector(windowDidChangeBackingProperties:) name:NSWindowDidChangeBackingPropertiesNotification object:window]; - [center addObserver:self selector:@selector(windowDidChangeScreenProfile:) name:NSWindowDidChangeScreenProfileNotification object:window]; - [center addObserver:self selector:@selector(windowDidChangeScreen:) name:NSWindowDidChangeScreenNotification object:window]; - [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window]; - [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window]; - [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window]; - [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window]; - [center addObserver:self selector:@selector(windowDidFailToEnterFullScreen:) name:@"NSWindowDidFailToEnterFullScreenNotification" object:window]; - [center addObserver:self selector:@selector(windowDidFailToExitFullScreen:) name:@"NSWindowDidFailToExitFullScreenNotification" object:window]; - } else { - [window setDelegate:self]; - } - - /* Haven't found a delegate / notification that triggers when the window is - * ordered out (is not visible any more). You can be ordered out without - * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:]) - */ - [window addObserver:self - forKeyPath:@"visible" - options:NSKeyValueObservingOptionNew - context:NULL]; - - [window setNextResponder:self]; - [window setAcceptsMouseMovedEvents:YES]; - - [view setNextResponder:self]; - - [view setAcceptsTouchEvents:YES]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath - ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context -{ - if (!observingVisible) { - return; - } - - if (object == _data.nswindow && [keyPath isEqualToString:@"visible"]) { - int newVisibility = [[change objectForKey:@"new"] intValue]; - if (newVisibility) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_SHOWN, 0, 0); - } else if (![_data.nswindow isMiniaturized]) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_HIDDEN, 0, 0); - } - } -} - -- (void)pauseVisibleObservation -{ - observingVisible = NO; - wasVisible = [_data.nswindow isVisible]; -} - -- (void)resumeVisibleObservation -{ - BOOL isVisible = [_data.nswindow isVisible]; - observingVisible = YES; - if (wasVisible != isVisible) { - if (isVisible) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_SHOWN, 0, 0); - } else if (![_data.nswindow isMiniaturized]) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_HIDDEN, 0, 0); - } - - wasVisible = isVisible; - } -} - -- (BOOL)setFullscreenSpace:(BOOL)state -{ - SDL_Window *window = _data.window; - NSWindow *nswindow = _data.nswindow; - SDL_CocoaVideoData *videodata = ((__bridge SDL_CocoaWindowData *)window->internal).videodata; - - if (!videodata.allow_spaces) { - return NO; // Spaces are forcibly disabled. - } else if (state && window->fullscreen_exclusive) { - return NO; // we only allow you to make a Space on fullscreen desktop windows. - } else if (!state && window->last_fullscreen_exclusive_display) { - return NO; // we only handle leaving the Space on windows that were previously fullscreen desktop. - } else if (state == isFullscreenSpace) { - return YES; // already there. - } - - if (inFullscreenTransition) { - if (state) { - [self addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN]; - } else { - [self addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN]; - } - return YES; - } - inFullscreenTransition = YES; - - // you need to be FullScreenPrimary, or toggleFullScreen doesn't work. Unset it again in windowDidExitFullScreen. - [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - [nswindow performSelectorOnMainThread:@selector(toggleFullScreen:) withObject:nswindow waitUntilDone:NO]; - return YES; -} - -- (BOOL)isInFullscreenSpace -{ - return isFullscreenSpace; -} - -- (BOOL)isInFullscreenSpaceTransition -{ - return inFullscreenTransition; -} - -- (void)clearPendingWindowOperation:(PendingWindowOperation)operation -{ - pendingWindowOperation &= ~operation; -} - -- (void)addPendingWindowOperation:(PendingWindowOperation)operation -{ - pendingWindowOperation |= operation; -} - -- (BOOL)windowOperationIsPending:(PendingWindowOperation)operation -{ - return !!(pendingWindowOperation & operation); -} - -- (BOOL)hasPendingWindowOperation -{ - // A pending zoom may be deferred until leaving fullscreen, so don't block on it. - return (pendingWindowOperation & ~PENDING_OPERATION_ZOOM) != PENDING_OPERATION_NONE || - isMiniaturizing || inFullscreenTransition; -} - -- (void)close -{ - NSNotificationCenter *center; - NSWindow *window = _data.nswindow; - NSView *view = [window contentView]; - - center = [NSNotificationCenter defaultCenter]; - - if ([window delegate] != self) { - [center removeObserver:self name:NSWindowDidExposeNotification object:window]; - [center removeObserver:self name:NSWindowDidChangeOcclusionStateNotification object:window]; - [center removeObserver:self name:NSWindowWillStartLiveResizeNotification object:window]; - [center removeObserver:self name:NSWindowDidEndLiveResizeNotification object:window]; - [center removeObserver:self name:NSWindowWillMoveNotification object:window]; - [center removeObserver:self name:NSWindowDidMoveNotification object:window]; - [center removeObserver:self name:NSWindowDidResizeNotification object:window]; - [center removeObserver:self name:NSWindowWillMiniaturizeNotification object:window]; - [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window]; - [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window]; - [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window]; - [center removeObserver:self name:NSWindowDidResignKeyNotification object:window]; - [center removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window]; - [center removeObserver:self name:NSWindowDidChangeScreenProfileNotification object:window]; - [center removeObserver:self name:NSWindowDidChangeScreenNotification object:window]; - [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window]; - [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window]; - [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window]; - [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window]; - [center removeObserver:self name:@"NSWindowDidFailToEnterFullScreenNotification" object:window]; - [center removeObserver:self name:@"NSWindowDidFailToExitFullScreenNotification" object:window]; - } else { - [window setDelegate:nil]; - } - - [window removeObserver:self forKeyPath:@"visible"]; - - if ([window nextResponder] == self) { - [window setNextResponder:nil]; - } - if ([view nextResponder] == self) { - [view setNextResponder:nil]; - } -} - -- (BOOL)isMoving -{ - return isMoving; -} - -- (BOOL)isMovingOrFocusClickPending -{ - return isMoving || (focusClickPending != 0); -} - -- (void)setFocusClickPending:(NSInteger)button -{ - focusClickPending |= (1 << button); -} - -- (void)clearFocusClickPending:(NSInteger)button -{ - if (focusClickPending & (1 << button)) { - focusClickPending &= ~(1 << button); - if (focusClickPending == 0) { - [self onMovingOrFocusClickPendingStateCleared]; - } - } -} - -- (void)updateIgnoreMouseState:(NSEvent *)theEvent -{ - SDL_Window *window = _data.window; - SDL_Surface *shape = (SDL_Surface *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_SHAPE_POINTER, NULL); - BOOL ignoresMouseEvents = NO; - - if (shape) { - NSPoint point = [theEvent locationInWindow]; - NSRect windowRect = [[_data.nswindow contentView] frame]; - if (NSMouseInRect(point, windowRect, NO)) { - int x = (int)SDL_roundf((point.x / (window->w - 1)) * (shape->w - 1)); - int y = (int)SDL_roundf(((window->h - point.y) / (window->h - 1)) * (shape->h - 1)); - Uint8 a; - - if (!SDL_ReadSurfacePixel(shape, x, y, NULL, NULL, NULL, &a) || a == SDL_ALPHA_TRANSPARENT) { - ignoresMouseEvents = YES; - } - } - } - _data.nswindow.ignoresMouseEvents = ignoresMouseEvents; -} - -- (void)setPendingMoveX:(float)x Y:(float)y -{ - pendingWindowWarpX = x; - pendingWindowWarpY = y; -} - -- (void)windowDidFinishMoving -{ - if (isMoving) { - isMoving = NO; - [self onMovingOrFocusClickPendingStateCleared]; - } -} - -- (void)onMovingOrFocusClickPendingStateCleared -{ - if (![self isMovingOrFocusClickPending]) { - SDL_Mouse *mouse = SDL_GetMouse(); - if (pendingWindowWarpX != FLT_MAX && pendingWindowWarpY != FLT_MAX) { - mouse->WarpMouseGlobal(pendingWindowWarpX, pendingWindowWarpY); - pendingWindowWarpX = pendingWindowWarpY = FLT_MAX; - } - if (mouse->relative_mode && mouse->focus == _data.window) { - // Move the cursor to the nearest point in the window - { - float x, y; - CGPoint cgpoint; - - SDL_GetMouseState(&x, &y); - cgpoint.x = _data.window->x + x; - cgpoint.y = _data.window->y + y; - - Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y); - - DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y); - CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); - } - - mouse->SetRelativeMouseMode(true); - } else { - Cocoa_UpdateClipCursor(_data.window); - } - } -} - -- (BOOL)windowShouldClose:(id)sender -{ - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_CLOSE_REQUESTED, 0, 0); - return NO; -} - -- (void)windowDidExpose:(NSNotification *)aNotification -{ - Cocoa_SendExposedEventIfVisible(_data.window); -} - -- (void)windowDidChangeOcclusionState:(NSNotification *)aNotification -{ - if ([_data.nswindow occlusionState] & NSWindowOcclusionStateVisible) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_EXPOSED, 0, 0); - } else { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_OCCLUDED, 0, 0); - } -} - -- (void)windowWillStartLiveResize:(NSNotification *)aNotification -{ - // We'll try to maintain 60 FPS during live resizing - const NSTimeInterval interval = 1.0 / 60.0; - liveResizeTimer = [NSTimer scheduledTimerWithTimeInterval:interval - repeats:TRUE - block:^(NSTimer *unusedTimer) - { - SDL_OnWindowLiveResizeUpdate(_data.window); - }]; - - [[NSRunLoop currentRunLoop] addTimer:liveResizeTimer forMode:NSRunLoopCommonModes]; -} - -- (void)windowDidEndLiveResize:(NSNotification *)aNotification -{ - [liveResizeTimer invalidate]; - liveResizeTimer = nil; -} - -- (void)windowWillMove:(NSNotification *)aNotification -{ - if ([_data.nswindow isKindOfClass:[SDL3Window class]]) { - pendingWindowWarpX = pendingWindowWarpY = FLT_MAX; - isMoving = YES; - } -} - -- (void)windowDidMove:(NSNotification *)aNotification -{ - int x, y; - SDL_Window *window = _data.window; - NSWindow *nswindow = _data.nswindow; - NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - ConvertNSRect(&rect); - - if (inFullscreenTransition || b_inModeTransition) { - // We'll take care of this at the end of the transition - return; - } - - x = (int)rect.origin.x; - y = (int)rect.origin.y; - - ScheduleContextUpdates(_data); - - // Get the parent-relative coordinates for child windows. - SDL_GlobalToRelativeForWindow(window, x, y, &x, &y); - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, x, y); -} - -- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize -{ - SDL_Window *window = _data.window; - - if (window->min_aspect != window->max_aspect) { - NSWindow *nswindow = _data.nswindow; - NSRect newContentRect = [nswindow contentRectForFrameRect:NSMakeRect(0, 0, frameSize.width, frameSize.height)]; - NSSize newSize = newContentRect.size; - CGFloat minAspectRatio = window->min_aspect; - CGFloat maxAspectRatio = window->max_aspect; - CGFloat aspectRatio; - - if (newSize.height > 0) { - aspectRatio = newSize.width / newSize.height; - - if (maxAspectRatio > 0.0f && aspectRatio > maxAspectRatio) { - newSize.width = SDL_roundf(newSize.height * maxAspectRatio); - } else if (minAspectRatio > 0.0f && aspectRatio < minAspectRatio) { - newSize.height = SDL_roundf(newSize.width / minAspectRatio); - } - - NSRect newFrameRect = [nswindow frameRectForContentRect:NSMakeRect(0, 0, newSize.width, newSize.height)]; - frameSize = newFrameRect.size; - } - } - return frameSize; -} - -- (void)windowDidResize:(NSNotification *)aNotification -{ - SDL_Window *window; - NSWindow *nswindow; - NSRect rect; - int x, y, w, h; - BOOL zoomed; - - if (inFullscreenTransition || b_inModeTransition) { - // We'll take care of this at the end of the transition - return; - } - - if (focusClickPending) { - focusClickPending = 0; - [self onMovingOrFocusClickPendingStateCleared]; - } - window = _data.window; - nswindow = _data.nswindow; - rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - ConvertNSRect(&rect); - x = (int)rect.origin.x; - y = (int)rect.origin.y; - w = (int)rect.size.width; - h = (int)rect.size.height; - - ScheduleContextUpdates(_data); - - /* isZoomed always returns true if the window is not resizable - * and fullscreen windows are considered zoomed. - */ - if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed] && - !(window->flags & SDL_WINDOW_FULLSCREEN) && ![self isInFullscreenSpace]) { - zoomed = YES; - } else { - zoomed = NO; - } - if (!zoomed) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESTORED, 0, 0); - } else { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0); - if ([self windowOperationIsPending:PENDING_OPERATION_MINIMIZE]) { - [nswindow miniaturize:nil]; - } - } - - /* The window can move during a resize event, such as when maximizing - or resizing from a corner */ - SDL_GlobalToRelativeForWindow(window, x, y, &x, &y); - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, x, y); - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, w, h); -} - -- (void)windowWillMiniaturize:(NSNotification *)aNotification -{ - isMiniaturizing = YES; - Cocoa_WaitForMiniaturizable(_data.window); -} - -- (void)windowDidMiniaturize:(NSNotification *)aNotification -{ - if (focusClickPending) { - focusClickPending = 0; - [self onMovingOrFocusClickPendingStateCleared]; - } - isMiniaturizing = NO; - [self clearPendingWindowOperation:PENDING_OPERATION_MINIMIZE]; - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0); -} - -- (void)windowDidDeminiaturize:(NSNotification *)aNotification -{ - // Always send restored before maximized. - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_RESTORED, 0, 0); - - if (Cocoa_IsWindowZoomed(_data.window)) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0); - } - - if ([self windowOperationIsPending:PENDING_OPERATION_ENTER_FULLSCREEN]) { - SDL_UpdateFullscreenMode(_data.window, true, true); - } -} - -- (void)windowDidBecomeKey:(NSNotification *)aNotification -{ - SDL_Window *window = _data.window; - - // We're going to get keyboard events, since we're key. - // This needs to be done before restoring the relative mouse mode. - Cocoa_SetKeyboardFocus(_data.keyboard_focus ? _data.keyboard_focus : window, true); - - // If we just gained focus we need the updated mouse position - if (!(window->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE)) { - NSPoint point; - float x, y; - - point = [_data.nswindow mouseLocationOutsideOfEventStream]; - x = point.x; - y = (window->h - point.y); - - if (x >= 0.0f && x < (float)window->w && y >= 0.0f && y < (float)window->h) { - SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, x, y); - } - } - - // Check to see if someone updated the clipboard - Cocoa_CheckClipboardUpdate(_data.videodata); - - if (isFullscreenSpace && !window->fullscreen_exclusive) { - Cocoa_ToggleFullscreenSpaceMenuVisibility(window); - } - { - const unsigned int newflags = [NSEvent modifierFlags] & NSEventModifierFlagCapsLock; - _data.videodata.modifierFlags = (_data.videodata.modifierFlags & ~NSEventModifierFlagCapsLock) | newflags; - SDL_ToggleModState(SDL_KMOD_CAPS, newflags ? true : false); - } - - /* Restore fullscreen mode unless the window is deminiaturizing. - * If it is, fullscreen will be restored when deminiaturization is complete. - */ - if (!(window->flags & SDL_WINDOW_MINIMIZED) && - [self windowOperationIsPending:PENDING_OPERATION_ENTER_FULLSCREEN]) { - SDL_UpdateFullscreenMode(window, true, true); - } -} - -- (void)windowDidResignKey:(NSNotification *)aNotification -{ - // Some other window will get mouse events, since we're not key. - if (SDL_GetMouseFocus() == _data.window) { - SDL_SetMouseFocus(NULL); - } - - // Some other window will get keyboard events, since we're not key. - if (SDL_GetKeyboardFocus() == _data.window) { - SDL_SetKeyboardFocus(NULL); - } - - if (isFullscreenSpace) { - [NSMenu setMenuBarVisible:YES]; - } -} - -- (void)windowDidChangeBackingProperties:(NSNotification *)aNotification -{ - NSNumber *oldscale = [[aNotification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey]; - - if (inFullscreenTransition) { - return; - } - - if ([oldscale doubleValue] != [_data.nswindow backingScaleFactor]) { - // Send a resize event when the backing scale factor changes. - [self windowDidResize:aNotification]; - } -} - -- (void)windowDidChangeScreenProfile:(NSNotification *)aNotification -{ - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_ICCPROF_CHANGED, 0, 0); -} - -- (void)windowDidChangeScreen:(NSNotification *)aNotification -{ - // printf("WINDOWDIDCHANGESCREEN\n"); - -#ifdef SDL_VIDEO_OPENGL - - if (_data && _data.nscontexts) { - for (SDL3OpenGLContext *context in _data.nscontexts) { - [context movedToNewScreen]; - } - } - -#endif // SDL_VIDEO_OPENGL -} - -- (void)windowWillEnterFullScreen:(NSNotification *)aNotification -{ - SDL_Window *window = _data.window; - const NSUInteger flags = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | NSWindowStyleMaskTitled; - - /* For some reason, the fullscreen window won't get any mouse button events - * without the NSWindowStyleMaskTitled flag being set when entering fullscreen, - * so it's needed even if the window is borderless. - */ - SetWindowStyle(window, flags); - - _data.was_zoomed = !!(window->flags & SDL_WINDOW_MAXIMIZED); - - isFullscreenSpace = YES; - inFullscreenTransition = YES; -} - -- (void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification -{ - SDL_Window *window = _data.window; - - if (window->is_destroying) { - return; - } - - SetWindowStyle(window, GetWindowStyle(window)); - - [self clearPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN]; - isFullscreenSpace = NO; - inFullscreenTransition = NO; - - [self windowDidExitFullScreen:nil]; -} - -- (void)windowDidEnterFullScreen:(NSNotification *)aNotification -{ - SDL_Window *window = _data.window; - - inFullscreenTransition = NO; - [self clearPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN]; - - if ([self windowOperationIsPending:PENDING_OPERATION_LEAVE_FULLSCREEN]) { - [self setFullscreenSpace:NO]; - } else { - Cocoa_ToggleFullscreenSpaceMenuVisibility(window); - - /* Don't recurse back into UpdateFullscreenMode() if this was hit in - * a blocking transition, as the caller is already waiting in - * UpdateFullscreenMode(). - */ - if (!_data.in_blocking_transition) { - SDL_UpdateFullscreenMode(window, true, false); - } - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_ENTER_FULLSCREEN, 0, 0); - - _data.pending_position = NO; - _data.pending_size = NO; - - /* Force the size change event in case it was delivered earlier - while the window was still animating into place. - */ - window->w = 0; - window->h = 0; - [self windowDidMove:aNotification]; - [self windowDidResize:aNotification]; - - Cocoa_UpdateClipCursor(window); - } -} - -- (void)windowWillExitFullScreen:(NSNotification *)aNotification -{ - SDL_Window *window = _data.window; - - /* If the windowed mode borders were toggled on while in a fullscreen space, - * NSWindowStyleMaskTitled has to be cleared here, or the window can end up - * in a weird, semi-decorated state upon returning to windowed mode. - */ - if (_data.border_toggled && !(window->flags & SDL_WINDOW_BORDERLESS)) { - const NSUInteger flags = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - - SetWindowStyle(window, flags); - _data.border_toggled = false; - } - - isFullscreenSpace = NO; - inFullscreenTransition = YES; -} - -- (void)windowDidFailToExitFullScreen:(NSNotification *)aNotification -{ - SDL_Window *window = _data.window; - const NSUInteger flags = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - - if (window->is_destroying) { - return; - } - - _data.pending_position = NO; - _data.pending_size = NO; - window->last_position_pending = false; - window->last_size_pending = false; - - SetWindowStyle(window, flags); - - isFullscreenSpace = YES; - inFullscreenTransition = NO; - - [self windowDidEnterFullScreen:nil]; -} - -- (void)windowDidExitFullScreen:(NSNotification *)aNotification -{ - SDL_Window *window = _data.window; - NSWindow *nswindow = _data.nswindow; - - inFullscreenTransition = NO; - _data.fullscreen_space_requested = NO; - - /* As of macOS 10.15, the window decorations can go missing sometimes after - certain fullscreen-desktop->exlusive-fullscreen->windowed mode flows - sometimes. Making sure the style mask always uses the windowed mode style - when returning to windowed mode from a space (instead of using a pending - fullscreen mode style mask) seems to work around that issue. - */ - SetWindowStyle(window, GetWindowWindowedStyle(window)); - - /* Don't recurse back into UpdateFullscreenMode() if this was hit in - * a blocking transition, as the caller is already waiting in - * UpdateFullscreenMode(). - */ - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, 0, 0); - if (!_data.in_blocking_transition) { - SDL_UpdateFullscreenMode(window, false, false); - } - - if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { - [nswindow setLevel:NSFloatingWindowLevel]; - } else { - [nswindow setLevel:kCGNormalWindowLevel]; - } - - [self clearPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN]; - - if ([self windowOperationIsPending:PENDING_OPERATION_ENTER_FULLSCREEN]) { - [self setFullscreenSpace:YES]; - } else if ([self windowOperationIsPending:PENDING_OPERATION_MINIMIZE]) { - /* There's some state that isn't quite back to normal when - * windowDidExitFullScreen triggers. For example, the minimize button on - * the title bar doesn't actually enable for another 200 milliseconds or - * so on this MacBook. Camp here and wait for that to happen before - * going on, in case we're exiting fullscreen to minimize, which need - * that window state to be normal before it will work. - */ - Cocoa_WaitForMiniaturizable(_data.window); - [self addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN]; - [nswindow miniaturize:nil]; - } else { - // Adjust the fullscreen toggle button and readd menu now that we're here. - if (window->flags & SDL_WINDOW_RESIZABLE) { - // resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. - [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - } else { - [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged]; - } - [NSMenu setMenuBarVisible:YES]; - - // Toggle zoom, if changed while fullscreen. - if ([self windowOperationIsPending:PENDING_OPERATION_ZOOM]) { - [self clearPendingWindowOperation:PENDING_OPERATION_ZOOM]; - [nswindow zoom:nil]; - } - - if (![nswindow isZoomed]) { - // Apply a pending window size, if not zoomed. - NSRect rect; - rect.origin.x = _data.pending_position ? window->pending.x : window->floating.x; - rect.origin.y = _data.pending_position ? window->pending.y : window->floating.y; - rect.size.width = _data.pending_size ? window->pending.w : window->floating.w; - rect.size.height = _data.pending_size ? window->pending.h : window->floating.h; - ConvertNSRect(&rect); - - if (_data.pending_size) { - [nswindow setContentSize:rect.size]; - } - if (_data.pending_position) { - [nswindow setFrameOrigin:rect.origin]; - } - } - - _data.pending_size = NO; - _data.pending_position = NO; - _data.was_zoomed = NO; - - /* Force the size change event in case it was delivered earlier - * while the window was still animating into place. - */ - window->w = 0; - window->h = 0; - [self windowDidMove:aNotification]; - [self windowDidResize:aNotification]; - - // FIXME: Why does the window get hidden? - if (!(window->flags & SDL_WINDOW_HIDDEN)) { - Cocoa_ShowWindow(SDL_GetVideoDevice(), window); - } - - Cocoa_UpdateClipCursor(window); - } -} - -- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions -{ - if (_data.window->fullscreen_exclusive) { - return NSApplicationPresentationFullScreen | NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar; - } else { - return proposedOptions; - } -} - -/* We'll respond to key events by mostly doing nothing so we don't beep. - * We could handle key messages here, but we lose some in the NSApp dispatch, - * where they get converted to action messages, etc. - */ -- (void)flagsChanged:(NSEvent *)theEvent -{ - // Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent); - - /* Catch capslock in here as a special case: - https://developer.apple.com/library/archive/qa/qa1519/_index.html - Note that technote's check of keyCode doesn't work. At least on the - 10.15 beta, capslock comes through here as keycode 255, but it's safe - to send duplicate key events; SDL filters them out quickly in - SDL_SendKeyboardKey(). */ - - /* Also note that SDL_SendKeyboardKey expects all capslock events to be - keypresses; it won't toggle the mod state if you send a keyrelease. */ - const bool osenabled = ([theEvent modifierFlags] & NSEventModifierFlagCapsLock) ? true : false; - const bool sdlenabled = (SDL_GetModState() & SDL_KMOD_CAPS) ? true : false; - if (osenabled ^ sdlenabled) { - SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, 0, SDL_SCANCODE_CAPSLOCK, true); - SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, 0, SDL_SCANCODE_CAPSLOCK, false); - } -} -- (void)keyDown:(NSEvent *)theEvent -{ - // Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent); -} -- (void)keyUp:(NSEvent *)theEvent -{ - // Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent); -} - -/* We'll respond to selectors by doing nothing so we don't beep. - * The escape key gets converted to a "cancel" selector, etc. - */ -- (void)doCommandBySelector:(SEL)aSelector -{ - // NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector)); -} - -- (void)updateHitTest -{ - SDL_Window *window = _data.window; - BOOL draggable = NO; - - if (window->hit_test) { - float x, y; - SDL_Point point; - - SDL_GetGlobalMouseState(&x, &y); - point.x = (int)SDL_roundf(x - window->x); - point.y = (int)SDL_roundf(y - window->y); - if (point.x >= 0 && point.x < window->w && point.y >= 0 && point.y < window->h) { - if (window->hit_test(window, &point, window->hit_test_data) == SDL_HITTEST_DRAGGABLE) { - draggable = YES; - } - } - } - - if (isDragAreaRunning != draggable) { - isDragAreaRunning = draggable; - [_data.nswindow setMovableByWindowBackground:draggable]; - } -} - -- (BOOL)processHitTest:(NSEvent *)theEvent -{ - SDL_Window *window = _data.window; - - if (window->hit_test) { // if no hit-test, skip this. - const NSPoint location = [theEvent locationInWindow]; - const SDL_Point point = { (int)location.x, window->h - (((int)location.y) - 1) }; - const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); - if (rc == SDL_HITTEST_DRAGGABLE) { - if (!isDragAreaRunning) { - isDragAreaRunning = YES; - [_data.nswindow setMovableByWindowBackground:YES]; - } - return YES; // dragging! - } else { - if (isDragAreaRunning) { - isDragAreaRunning = NO; - [_data.nswindow setMovableByWindowBackground:NO]; - return YES; // was dragging, drop event. - } - } - } - - return NO; // not a special area, carry on. -} - -static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL_Window *window, Uint8 button, bool down) -{ - SDL_MouseID mouseID = SDL_DEFAULT_MOUSE_ID; - //const int clicks = (int)[theEvent clickCount]; - SDL_Window *focus = SDL_GetKeyboardFocus(); - - // macOS will send non-left clicks to background windows without raising them, so we need to - // temporarily adjust the mouse position when this happens, as `mouse` will be tracking - // the position in the currently-focused window. We don't (currently) send a mousemove - // event for the background window, this just makes sure the button is reported at the - // correct position in its own event. - if (focus && ([theEvent window] == ((__bridge SDL_CocoaWindowData *)focus->internal).nswindow)) { - //SDL_SendMouseButtonClicks(Cocoa_GetEventTimestamp([theEvent timestamp]), window, mouseID, button, down, clicks); - SDL_SendMouseButton(Cocoa_GetEventTimestamp([theEvent timestamp]), window, mouseID, button, down); - } else { - const float orig_x = mouse->x; - const float orig_y = mouse->y; - const NSPoint point = [theEvent locationInWindow]; - mouse->x = (int)point.x; - mouse->y = (int)(window->h - point.y); - //SDL_SendMouseButtonClicks(Cocoa_GetEventTimestamp([theEvent timestamp]), window, mouseID, button, down, clicks); - SDL_SendMouseButton(Cocoa_GetEventTimestamp([theEvent timestamp]), window, mouseID, button, down); - mouse->x = orig_x; - mouse->y = orig_y; - } -} - -- (void)mouseDown:(NSEvent *)theEvent -{ - if (Cocoa_HandlePenEvent(_data, theEvent)) { - return; // pen code handled it. - } - - SDL_Mouse *mouse = SDL_GetMouse(); - int button; - - if (!mouse) { - return; - } - - // Ignore events that aren't inside the client area (i.e. title bar.) - if ([theEvent window]) { - NSRect windowRect = [[[theEvent window] contentView] frame]; - if (!NSMouseInRect([theEvent locationInWindow], windowRect, NO)) { - return; - } - } - - switch ([theEvent buttonNumber]) { - case 0: - if (([theEvent modifierFlags] & NSEventModifierFlagControl) && - GetHintCtrlClickEmulateRightClick()) { - wasCtrlLeft = YES; - button = SDL_BUTTON_RIGHT; - } else { - wasCtrlLeft = NO; - button = SDL_BUTTON_LEFT; - } - break; - case 1: - button = SDL_BUTTON_RIGHT; - break; - case 2: - button = SDL_BUTTON_MIDDLE; - break; - default: - button = (int)[theEvent buttonNumber] + 1; - break; - } - - if (button == SDL_BUTTON_LEFT && [self processHitTest:theEvent]) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_HIT_TEST, 0, 0); - return; // dragging, drop event. - } - - Cocoa_SendMouseButtonClicks(mouse, theEvent, _data.window, button, true); -} - -- (void)rightMouseDown:(NSEvent *)theEvent -{ - [self mouseDown:theEvent]; -} - -- (void)otherMouseDown:(NSEvent *)theEvent -{ - [self mouseDown:theEvent]; -} - -- (void)mouseUp:(NSEvent *)theEvent -{ - if (Cocoa_HandlePenEvent(_data, theEvent)) { - return; // pen code handled it. - } - - SDL_Mouse *mouse = SDL_GetMouse(); - int button; - - if (!mouse) { - return; - } - - switch ([theEvent buttonNumber]) { - case 0: - if (wasCtrlLeft) { - button = SDL_BUTTON_RIGHT; - wasCtrlLeft = NO; - } else { - button = SDL_BUTTON_LEFT; - } - break; - case 1: - button = SDL_BUTTON_RIGHT; - break; - case 2: - button = SDL_BUTTON_MIDDLE; - break; - default: - button = (int)[theEvent buttonNumber] + 1; - break; - } - - if (button == SDL_BUTTON_LEFT && [self processHitTest:theEvent]) { - SDL_SendWindowEvent(_data.window, SDL_EVENT_WINDOW_HIT_TEST, 0, 0); - return; // stopped dragging, drop event. - } - - Cocoa_SendMouseButtonClicks(mouse, theEvent, _data.window, button, false); -} - -- (void)rightMouseUp:(NSEvent *)theEvent -{ - [self mouseUp:theEvent]; -} - -- (void)otherMouseUp:(NSEvent *)theEvent -{ - [self mouseUp:theEvent]; -} - -- (void)mouseMoved:(NSEvent *)theEvent -{ - if (Cocoa_HandlePenEvent(_data, theEvent)) { - return; // pen code handled it. - } - - SDL_MouseID mouseID = SDL_DEFAULT_MOUSE_ID; - SDL_Mouse *mouse = SDL_GetMouse(); - NSPoint point; - float x, y; - SDL_Window *window; - NSView *contentView; - - if (!mouse) { - return; - } - - if (!Cocoa_GetMouseFocus()) { - // The mouse is no longer over any window in the application - SDL_SetMouseFocus(NULL); - return; - } - - window = _data.window; - contentView = _data.sdlContentView; - point = [theEvent locationInWindow]; - - if ([contentView mouse:[contentView convertPoint:point fromView:nil] inRect:[contentView bounds]] && - [NSCursor currentCursor] != Cocoa_GetDesiredCursor()) { - // The wrong cursor is on screen, fix it. This fixes an macOS bug that is only known to - // occur in fullscreen windows on the built-in displays of newer MacBooks with camera - // notches. When the mouse is moved near the top of such a window (within about 44 units) - // and then moved back down, the cursor rects aren't respected. - [_data.nswindow invalidateCursorRectsForView:contentView]; - } - - if (window->flags & SDL_WINDOW_TRANSPARENT) { - [self updateIgnoreMouseState:theEvent]; - } - - if ([self processHitTest:theEvent]) { - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_HIT_TEST, 0, 0); - return; // dragging, drop event. - } - - if (mouse->relative_mode) { - return; - } - - x = point.x; - y = (window->h - point.y); - - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_13_2) { - // Mouse grab is taken care of by the confinement rect - } else { - CGPoint cgpoint; - if (ShouldAdjustCoordinatesForGrab(window) && - AdjustCoordinatesForGrab(window, window->x + x, window->y + y, &cgpoint)) { - Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y); - CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); - CGAssociateMouseAndMouseCursorPosition(YES); - } - } - - SDL_SendMouseMotion(Cocoa_GetEventTimestamp([theEvent timestamp]), window, mouseID, false, x, y); -} - -- (void)mouseDragged:(NSEvent *)theEvent -{ - [self mouseMoved:theEvent]; -} - -- (void)rightMouseDragged:(NSEvent *)theEvent -{ - [self mouseMoved:theEvent]; -} - -- (void)otherMouseDragged:(NSEvent *)theEvent -{ - [self mouseMoved:theEvent]; -} - -- (void)scrollWheel:(NSEvent *)theEvent -{ - Cocoa_HandleMouseWheel(_data.window, theEvent); -} - -- (BOOL)isTouchFromTrackpad:(NSEvent *)theEvent -{ - SDL_Window *window = _data.window; - SDL_CocoaVideoData *videodata = ((__bridge SDL_CocoaWindowData *)window->internal).videodata; - - /* if this a MacBook trackpad, we'll make input look like a synthesized - event. This is backwards from reality, but better matches user - expectations. You can make it look like a generic touch device instead - with the SDL_HINT_TRACKPAD_IS_TOUCH_ONLY hint. */ - BOOL istrackpad = NO; - if (!videodata.trackpad_is_touch_only) { - @try { - istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent); - } - @catch (NSException *e) { - /* if NSEvent type doesn't have subtype, such as NSEventTypeBeginGesture on - * macOS 10.5 to 10.10, then NSInternalInconsistencyException is thrown. - * This still prints a message to terminal so catching it's not an ideal solution. - * - * *** Assertion failure in -[NSEvent subtype] - */ - } - } - return istrackpad; -} - -- (void)touchesBeganWithEvent:(NSEvent *)theEvent -{ - NSSet *touches; - SDL_TouchID touchID; - int existingTouchCount; - const BOOL istrackpad = [self isTouchFromTrackpad:theEvent]; - - touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil]; - touchID = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[[touches anyObject] device]; - existingTouchCount = 0; - - for (NSTouch *touch in touches) { - if ([touch phase] != NSTouchPhaseBegan) { - existingTouchCount++; - } - } - if (existingTouchCount == 0) { - int numFingers; - SDL_Finger **fingers = SDL_GetTouchFingers(touchID, &numFingers); - if (fingers) { - DLog("Reset Lost Fingers: %d", numFingers); - for (--numFingers; numFingers >= 0; --numFingers) { - const SDL_Finger *finger = fingers[numFingers]; - /* trackpad touches have no window. If we really wanted one we could - * use the window that has mouse or keyboard focus. - * Sending a null window currently also prevents synthetic mouse - * events from being generated from touch events. - */ - SDL_Window *window = NULL; - SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchID, finger->id, window, SDL_EVENT_FINGER_CANCELED, 0, 0, 0); - } - SDL_free(fingers); - } - } - - DLog("Began Fingers: %lu .. existing: %d", (unsigned long)[touches count], existingTouchCount); - [self handleTouches:NSTouchPhaseBegan withEvent:theEvent]; -} - -- (void)touchesMovedWithEvent:(NSEvent *)theEvent -{ - [self handleTouches:NSTouchPhaseMoved withEvent:theEvent]; -} - -- (void)touchesEndedWithEvent:(NSEvent *)theEvent -{ - [self handleTouches:NSTouchPhaseEnded withEvent:theEvent]; -} - -- (void)touchesCancelledWithEvent:(NSEvent *)theEvent -{ - [self handleTouches:NSTouchPhaseCancelled withEvent:theEvent]; -} - -- (void)handleTouches:(NSTouchPhase)phase withEvent:(NSEvent *)theEvent -{ - NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil]; - const BOOL istrackpad = [self isTouchFromTrackpad:theEvent]; - SDL_FingerID fingerId; - float x, y; - - for (NSTouch *touch in touches) { - const SDL_TouchID touchId = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(uintptr_t)[touch device]; - SDL_TouchDeviceType devtype = SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE; - - /* trackpad touches have no window. If we really wanted one we could - * use the window that has mouse or keyboard focus. - * Sending a null window currently also prevents synthetic mouse events - * from being generated from touch events. - */ - SDL_Window *window = NULL; - - /* TODO: Before implementing direct touch support here, we need to - * figure out whether the OS generates mouse events from them on its - * own. If it does, we should prevent SendTouch from generating - * synthetic mouse events for these touches itself (while also - * sending a window.) It will also need to use normalized window- - * relative coordinates via [touch locationInView:]. - */ - if ([touch type] == NSTouchTypeDirect) { - continue; - } - - if (SDL_AddTouch(touchId, devtype, "") < 0) { - return; - } - - fingerId = (SDL_FingerID)(uintptr_t)[touch identity]; - x = [touch normalizedPosition].x; - y = [touch normalizedPosition].y; - // Make the origin the upper left instead of the lower left - y = 1.0f - y; - - switch (phase) { - case NSTouchPhaseBegan: - SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, SDL_EVENT_FINGER_DOWN, x, y, 1.0f); - break; - case NSTouchPhaseEnded: - SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, SDL_EVENT_FINGER_UP, x, y, 1.0f); - break; - case NSTouchPhaseCancelled: - SDL_SendTouch(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, SDL_EVENT_FINGER_CANCELED, x, y, 1.0f); - break; - case NSTouchPhaseMoved: - SDL_SendTouchMotion(Cocoa_GetEventTimestamp([theEvent timestamp]), touchId, fingerId, window, x, y, 1.0f); - break; - default: - break; - } - } -} - -- (void)tabletProximity:(NSEvent *)theEvent -{ - Cocoa_HandlePenEvent(_data, theEvent); -} - -- (void)tabletPoint:(NSEvent *)theEvent -{ - Cocoa_HandlePenEvent(_data, theEvent); -} - -@end - -@interface SDL3View : NSView -{ - SDL_Window *_sdlWindow; -} - -- (void)setSDLWindow:(SDL_Window *)window; - -// The default implementation doesn't pass rightMouseDown to responder chain -- (void)rightMouseDown:(NSEvent *)theEvent; -- (BOOL)mouseDownCanMoveWindow; -- (void)drawRect:(NSRect)dirtyRect; -- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent; -- (BOOL)wantsUpdateLayer; -- (void)updateLayer; -@end - -@implementation SDL3View - -- (void)setSDLWindow:(SDL_Window *)window -{ - _sdlWindow = window; -} - -/* this is used on older macOS revisions, and newer ones which emulate old - NSOpenGLContext behaviour while still using a layer under the hood. 10.8 and - later use updateLayer, up until 10.14.2 or so, which uses drawRect without - a GraphicsContext and with a layer active instead (for OpenGL contexts). */ -- (void)drawRect:(NSRect)dirtyRect -{ - /* Force the graphics context to clear to black so we don't get a flash of - white until the app is ready to draw. In practice on modern macOS, this - only gets called for window creation and other extraordinary events. */ - BOOL transparent = (_sdlWindow->flags & SDL_WINDOW_TRANSPARENT) != 0; - if ([NSGraphicsContext currentContext]) { - NSColor *fillColor = transparent ? [NSColor clearColor] : [NSColor blackColor]; - [fillColor setFill]; - NSRectFill(dirtyRect); - } else if (self.layer) { - CFStringRef color = transparent ? kCGColorClear : kCGColorBlack; - self.layer.backgroundColor = CGColorGetConstantColor(color); - } - - Cocoa_SendExposedEventIfVisible(_sdlWindow); -} - -- (BOOL)wantsUpdateLayer -{ - return YES; -} - -// This is also called when a Metal layer is active. -- (void)updateLayer -{ - /* Force the graphics context to clear to black so we don't get a flash of - white until the app is ready to draw. In practice on modern macOS, this - only gets called for window creation and other extraordinary events. */ - BOOL transparent = (_sdlWindow->flags & SDL_WINDOW_TRANSPARENT) != 0; - CFStringRef color = transparent ? kCGColorClear : kCGColorBlack; - self.layer.backgroundColor = CGColorGetConstantColor(color); - ScheduleContextUpdates((__bridge SDL_CocoaWindowData *)_sdlWindow->internal); - Cocoa_SendExposedEventIfVisible(_sdlWindow); -} - -- (void)rightMouseDown:(NSEvent *)theEvent -{ - [[self nextResponder] rightMouseDown:theEvent]; -} - -- (BOOL)mouseDownCanMoveWindow -{ - /* Always say YES, but this doesn't do anything until we call - -[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle - during mouse events when we're using a drag area. */ - return YES; -} - -- (void)resetCursorRects -{ - [super resetCursorRects]; - [self addCursorRect:[self bounds] - cursor:Cocoa_GetDesiredCursor()]; -} - -- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent -{ - if (SDL_GetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)) { - return SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, false); - } else { - return SDL_GetHintBoolean("SDL_MAC_MOUSE_FOCUS_CLICKTHROUGH", false); - } -} - -@end - -static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow *nswindow, NSView *nsview) -{ - @autoreleasepool { - SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)_this->internal; - SDL_CocoaWindowData *data; - - // Allocate the window data - data = [[SDL_CocoaWindowData alloc] init]; - if (!data) { - return SDL_OutOfMemory(); - } - data.window = window; - data.nswindow = nswindow; - data.videodata = videodata; - data.window_number = nswindow.windowNumber; - data.nscontexts = [[NSMutableArray alloc] init]; - data.sdlContentView = nsview; - - // Create an event listener for the window - data.listener = [[SDL3Cocoa_WindowListener alloc] init]; - - // Fill in the SDL window with the window data - { - int x, y; - NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - ConvertNSRect(&rect); - SDL_GlobalToRelativeForWindow(window, (int)rect.origin.x, (int)rect.origin.y, &x, &y); - window->x = x; - window->y = y; - window->w = (int)rect.size.width; - window->h = (int)rect.size.height; - } - - // Set up the listener after we create the view - [data.listener listen:data]; - - if ([nswindow isVisible]) { - window->flags &= ~SDL_WINDOW_HIDDEN; - } else { - window->flags |= SDL_WINDOW_HIDDEN; - } - - { - unsigned long style = [nswindow styleMask]; - - /* NSWindowStyleMaskBorderless is zero, and it's possible to be - Resizeable _and_ borderless, so we can't do a simple bitwise AND - of NSWindowStyleMaskBorderless here. */ - if ((style & ~(NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable)) == NSWindowStyleMaskBorderless) { - window->flags |= SDL_WINDOW_BORDERLESS; - } else { - window->flags &= ~SDL_WINDOW_BORDERLESS; - } - if (style & NSWindowStyleMaskResizable) { - window->flags |= SDL_WINDOW_RESIZABLE; - } else { - window->flags &= ~SDL_WINDOW_RESIZABLE; - } - } - - // isZoomed always returns true if the window is not resizable - if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) { - window->flags |= SDL_WINDOW_MAXIMIZED; - } else { - window->flags &= ~SDL_WINDOW_MAXIMIZED; - } - - if ([nswindow isMiniaturized]) { - window->flags |= SDL_WINDOW_MINIMIZED; - } else { - window->flags &= ~SDL_WINDOW_MINIMIZED; - } - - if (window->parent) { - NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow; - [nsparent addChildWindow:nswindow ordered:NSWindowAbove]; - - /* FIXME: Should not need to call addChildWindow then orderOut. - Attaching a hidden child window to a hidden parent window will cause the child window - to show when the parent does. We therefore shouldn't attach the child window here as we're - going to do so when the child window is explicitly shown later but skipping the addChildWindow - entirely causes the child window to not get key focus correctly the first time it's shown. Adding - then immediately ordering out (removing) the window does work. */ - if (window->flags & SDL_WINDOW_HIDDEN) { - [nswindow orderOut:nil]; - } - } - - if (!SDL_WINDOW_IS_POPUP(window)) { - if ([nswindow isKeyWindow]) { - window->flags |= SDL_WINDOW_INPUT_FOCUS; - Cocoa_SetKeyboardFocus(data.window, true); - } - } else { - if (window->flags & SDL_WINDOW_TOOLTIP) { - [nswindow setIgnoresMouseEvents:YES]; - } else if (window->flags & SDL_WINDOW_POPUP_MENU) { - Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus()); - } - } - - if (nswindow.isOpaque) { - window->flags &= ~SDL_WINDOW_TRANSPARENT; - } else { - window->flags |= SDL_WINDOW_TRANSPARENT; - } - - /* SDL_CocoaWindowData will be holding a strong reference to the NSWindow, and - * it will also call [NSWindow close] in DestroyWindow before releasing the - * NSWindow, so the extra release provided by releasedWhenClosed isn't - * necessary. */ - nswindow.releasedWhenClosed = NO; - - /* Prevents the window's "window device" from being destroyed when it is - * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html - */ - [nswindow setOneShot:NO]; - - if (window->flags & SDL_WINDOW_EXTERNAL) { - // Query the title from the existing window - NSString *title = [nswindow title]; - if (title) { - window->title = SDL_strdup([title UTF8String]); - } - } - - SDL_PropertiesID props = SDL_GetWindowProperties(window); - SDL_SetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, (__bridge void *)data.nswindow); - SDL_SetNumberProperty(props, SDL_PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER, SDL_METALVIEW_TAG); - - // All done! - window->internal = (SDL_WindowData *)CFBridgingRetain(data); - return true; - } -} - -bool Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) -{ - @autoreleasepool { - SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)_this->internal; - const void *data = SDL_GetPointerProperty(create_props, "sdl2-compat.external_window", NULL); - NSWindow *nswindow = nil; - NSView *nsview = nil; - - if (data) { - if ([(__bridge id)data isKindOfClass:[NSWindow class]]) { - nswindow = (__bridge NSWindow *)data; - } else if ([(__bridge id)data isKindOfClass:[NSView class]]) { - nsview = (__bridge NSView *)data; - } else { - SDL_assert(false); - } - } else { - nswindow = (__bridge NSWindow *)SDL_GetPointerProperty(create_props, SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER, NULL); - nsview = (__bridge NSView *)SDL_GetPointerProperty(create_props, SDL_PROP_WINDOW_CREATE_COCOA_VIEW_POINTER, NULL); - } - if (nswindow && !nsview) { - nsview = [nswindow contentView]; - } - if (nsview && !nswindow) { - nswindow = [nsview window]; - } - if (nswindow) { - window->flags |= SDL_WINDOW_EXTERNAL; - } else { - int x, y; - NSScreen *screen; - NSRect rect, screenRect; - NSUInteger style; - SDL3View *contentView; - - SDL_RelativeToGlobalForWindow(window, window->x, window->y, &x, &y); - rect.origin.x = x; - rect.origin.y = y; - rect.size.width = window->w; - rect.size.height = window->h; - ConvertNSRect(&rect); - - style = GetWindowStyle(window); - - // Figure out which screen to place this window - screen = ScreenForRect(&rect); - screenRect = [screen frame]; - rect.origin.x -= screenRect.origin.x; - rect.origin.y -= screenRect.origin.y; - - // Constrain the popup - if (SDL_WINDOW_IS_POPUP(window)) { - if (rect.origin.x + rect.size.width > screenRect.origin.x + screenRect.size.width) { - rect.origin.x -= (rect.origin.x + rect.size.width) - (screenRect.origin.x + screenRect.size.width); - } - if (rect.origin.y + rect.size.height > screenRect.origin.y + screenRect.size.height) { - rect.origin.y -= (rect.origin.y + rect.size.height) - (screenRect.origin.y + screenRect.size.height); - } - rect.origin.x = SDL_max(rect.origin.x, screenRect.origin.x); - rect.origin.y = SDL_max(rect.origin.y, screenRect.origin.y); - } - - @try { - nswindow = [[SDL3Window alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen]; - } - @catch (NSException *e) { - return SDL_SetError("%s", [[e reason] UTF8String]); - } - - [nswindow setColorSpace:[NSColorSpace sRGBColorSpace]]; - - [nswindow setTabbingMode:NSWindowTabbingModeDisallowed]; - - if (videodata.allow_spaces) { - // we put fullscreen desktop windows in their own Space, without a toggle button or menubar, later - if (window->flags & SDL_WINDOW_RESIZABLE) { - // resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. - [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - } - } - - // Create a default view for this window - rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - contentView = [[SDL3View alloc] initWithFrame:rect]; - [contentView setSDLWindow:window]; - nsview = contentView; - } - - if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { - [nswindow setLevel:NSFloatingWindowLevel]; - } - - if (window->flags & SDL_WINDOW_TRANSPARENT) { - nswindow.opaque = NO; - nswindow.hasShadow = NO; - nswindow.backgroundColor = [NSColor clearColor]; - } - -// We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - /* Note: as of the macOS 10.15 SDK, this defaults to YES instead of NO when - * the NSHighResolutionCapable boolean is set in Info.plist. */ - BOOL highdpi = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) ? YES : NO; - [nsview setWantsBestResolutionOpenGLSurface:highdpi]; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#ifdef SDL_VIDEO_OPENGL_ES2 -#ifdef SDL_VIDEO_OPENGL_EGL - if ((window->flags & SDL_WINDOW_OPENGL) && - _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { - [nsview setWantsLayer:TRUE]; - if ((window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY)) { - nsview.layer.contentsScale = nswindow.screen.backingScaleFactor; - } else { - nsview.layer.contentsScale = 1; - } - } -#endif // SDL_VIDEO_OPENGL_EGL -#endif // SDL_VIDEO_OPENGL_ES2 - [nswindow setContentView:nsview]; - - if (!SetupWindowData(_this, window, nswindow, nsview)) { - return false; - } - - if (!(window->flags & SDL_WINDOW_OPENGL)) { - return true; - } - - // The rest of this macro mess is for OpenGL or OpenGL ES windows -#ifdef SDL_VIDEO_OPENGL_ES2 - if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { -#ifdef SDL_VIDEO_OPENGL_EGL - if (!Cocoa_GLES_SetupWindow(_this, window)) { - Cocoa_DestroyWindow(_this, window); - return false; - } - return true; -#else - return SDL_SetError("Could not create GLES window surface (EGL support not configured)"); -#endif // SDL_VIDEO_OPENGL_EGL - } -#endif // SDL_VIDEO_OPENGL_ES2 - return true; - } -} - -void Cocoa_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - const char *title = window->title ? window->title : ""; - NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow; - NSString *string = [[NSString alloc] initWithUTF8String:title]; - [nswindow setTitle:string]; - } -} - -bool Cocoa_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon) -{ - @autoreleasepool { - NSImage *nsimage = Cocoa_CreateImage(icon); - - if (nsimage) { - [NSApp setApplicationIconImage:nsimage]; - - return true; - } - - return SDL_SetError("Unable to set the window's icon"); - } -} - -bool Cocoa_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = windata.nswindow; - NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - BOOL fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN) ? YES : NO; - int x, y; - - if ([windata.listener isInFullscreenSpaceTransition]) { - windata.pending_position = YES; - return true; - } - - if (!(window->flags & SDL_WINDOW_MAXIMIZED)) { - if (fullscreen) { - SDL_VideoDisplay *display = SDL_GetVideoDisplayForFullscreenWindow(window); - SDL_Rect r; - SDL_GetDisplayBounds(display->id, &r); - - rect.origin.x = r.x; - rect.origin.y = r.y; - } else { - SDL_RelativeToGlobalForWindow(window, window->pending.x, window->pending.y, &x, &y); - rect.origin.x = x; - rect.origin.y = y; - } - ConvertNSRect(&rect); - - // Position and constrain the popup - if (SDL_WINDOW_IS_POPUP(window)) { - NSRect screenRect = [ScreenForRect(&rect) frame]; - - if (rect.origin.x + rect.size.width > screenRect.origin.x + screenRect.size.width) { - rect.origin.x -= (rect.origin.x + rect.size.width) - (screenRect.origin.x + screenRect.size.width); - } - if (rect.origin.y + rect.size.height > screenRect.origin.y + screenRect.size.height) { - rect.origin.y -= (rect.origin.y + rect.size.height) - (screenRect.origin.y + screenRect.size.height); - } - rect.origin.x = SDL_max(rect.origin.x, screenRect.origin.x); - rect.origin.y = SDL_max(rect.origin.y, screenRect.origin.y); - } - - [nswindow setFrameOrigin:rect.origin]; - - ScheduleContextUpdates(windata); - } - } - return true; -} - -void Cocoa_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = windata.nswindow; - - if ([windata.listener isInFullscreenSpaceTransition]) { - windata.pending_size = YES; - return; - } - - if (!Cocoa_IsWindowZoomed(window)) { - int x, y; - NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - - /* Cocoa will resize the window from the bottom-left rather than the - * top-left when -[nswindow setContentSize:] is used, so we must set the - * entire frame based on the new size, in order to preserve the position. - */ - SDL_RelativeToGlobalForWindow(window, window->floating.x, window->floating.y, &x, &y); - rect.origin.x = x; - rect.origin.y = y; - rect.size.width = window->pending.w; - rect.size.height = window->pending.h; - ConvertNSRect(&rect); - - [nswindow setFrame:[nswindow frameRectForContentRect:rect] display:YES]; - ScheduleContextUpdates(windata); - } else { - // Can't set the window size. - window->last_size_pending = false; - } - } -} - -void Cocoa_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal; - - NSSize minSize; - minSize.width = window->min_w; - minSize.height = window->min_h; - - [windata.nswindow setContentMinSize:minSize]; - } -} - -void Cocoa_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal; - - NSSize maxSize; - maxSize.width = window->max_w; - maxSize.height = window->max_h; - - [windata.nswindow setContentMaxSize:maxSize]; - } -} - -void Cocoa_SetWindowAspectRatio(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal; - - if (window->min_aspect > 0.0f && window->min_aspect == window->max_aspect) { - int numerator = 0, denominator = 1; - SDL_CalculateFraction(window->max_aspect, &numerator, &denominator); - [windata.nswindow setContentAspectRatio:NSMakeSize(numerator, denominator)]; - } else { - [windata.nswindow setContentAspectRatio:NSMakeSize(0, 0)]; - } - } -} - -void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h) -{ - @autoreleasepool { - SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal; - NSView *contentView = windata.sdlContentView; - NSRect viewport = [contentView bounds]; - - if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) { - // This gives us the correct viewport for a Retina-enabled view. - viewport = [contentView convertRectToBacking:viewport]; - } - - *w = (int)viewport.size.width; - *h = (int)viewport.size.height; - } -} - -void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windowData = ((__bridge SDL_CocoaWindowData *)window->internal); - NSWindow *nswindow = windowData.nswindow; - bool bActivate = SDL_GetHintBoolean(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, true); - - if (![nswindow isMiniaturized]) { - [windowData.listener pauseVisibleObservation]; - if (window->parent) { - NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow; - [nsparent addChildWindow:nswindow ordered:NSWindowAbove]; - - if (window->flags & SDL_WINDOW_MODAL) { - Cocoa_SetWindowModal(_this, window, true); - } - } - if (!SDL_WINDOW_IS_POPUP(window)) { - if (bActivate) { - [nswindow makeKeyAndOrderFront:nil]; - } else { - // Order this window below the key window if we're not activating it - if ([NSApp keyWindow]) { - [nswindow orderWindow:NSWindowBelow relativeTo:[[NSApp keyWindow] windowNumber]]; - } - } - } - } - [nswindow setIsVisible:YES]; - [windowData.listener resumeVisibleObservation]; - } -} - -void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow; - const BOOL waskey = [nswindow isKeyWindow]; - - /* orderOut has no effect on miniaturized windows, so close must be used to remove - * the window from the desktop and window list in this case. - * - * SDL holds a strong reference to the window (oneShot/releasedWhenClosed are 'NO'), - * and calling 'close' doesn't send a 'windowShouldClose' message, so it's safe to - * use for this purpose as nothing is implicitly released. - */ - if (![nswindow isMiniaturized]) { - [nswindow orderOut:nil]; - } else { - [nswindow close]; - } - - /* If this window is the source of a modal session, end it when - * hidden, or other windows will be prevented from closing. - */ - Cocoa_SetWindowModal(_this, window, false); - - // Transfer keyboard focus back to the parent when closing a popup menu - if (window->flags & SDL_WINDOW_POPUP_MENU) { - SDL_Window *new_focus = window->parent; - bool set_focus = window == SDL_GetKeyboardFocus(); - - // Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed. - while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) { - new_focus = new_focus->parent; - - // If some window in the chain currently had focus, set it to the new lowest-level window. - if (!set_focus) { - set_focus = new_focus == SDL_GetKeyboardFocus(); - } - } - - Cocoa_SetKeyboardFocus(new_focus, set_focus); - } else if (window->parent && waskey) { - /* Key status is not automatically set on the parent when a child is hidden. Check if the - * child window was key, and set the first visible parent to be key if so. - */ - SDL_Window *new_focus = window->parent; - - while (new_focus->parent != NULL && (new_focus->is_hiding || new_focus->is_destroying)) { - new_focus = new_focus->parent; - } - - if (new_focus) { - NSWindow *newkey = ((__bridge SDL_CocoaWindowData *)window->internal).nswindow; - [newkey makeKeyAndOrderFront:nil]; - } - } - } -} - -void Cocoa_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windowData = ((__bridge SDL_CocoaWindowData *)window->internal); - NSWindow *nswindow = windowData.nswindow; - bool bActivate = SDL_GetHintBoolean(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, true); - - /* makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing - a minimized or hidden window, so check for that before showing it. - */ - [windowData.listener pauseVisibleObservation]; - if (![nswindow isMiniaturized] && [nswindow isVisible]) { - if (window->parent) { - NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow; - [nsparent addChildWindow:nswindow ordered:NSWindowAbove]; - } - if (!SDL_WINDOW_IS_POPUP(window)) { - if (bActivate) { - [NSApp activateIgnoringOtherApps:YES]; - [nswindow makeKeyAndOrderFront:nil]; - } else { - [nswindow orderFront:nil]; - } - } else { - if (bActivate) { - [nswindow makeKeyWindow]; - } - } - } - [windowData.listener resumeVisibleObservation]; - } -} - -void Cocoa_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = windata.nswindow; - - if ([windata.listener windowOperationIsPending:(PENDING_OPERATION_ENTER_FULLSCREEN | PENDING_OPERATION_LEAVE_FULLSCREEN)] || - [windata.listener isInFullscreenSpaceTransition]) { - Cocoa_SyncWindow(_this, window); - } - - if (!(window->flags & SDL_WINDOW_FULLSCREEN) && - ![windata.listener isInFullscreenSpaceTransition] && - ![windata.listener isInFullscreenSpace]) { - [nswindow zoom:nil]; - ScheduleContextUpdates(windata); - } else if (!windata.was_zoomed) { - [windata.listener addPendingWindowOperation:PENDING_OPERATION_ZOOM]; - } else { - [windata.listener clearPendingWindowOperation:PENDING_OPERATION_ZOOM]; - } - } -} - -void Cocoa_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = data.nswindow; - - [data.listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE]; - if ([data.listener isInFullscreenSpace] || (window->flags & SDL_WINDOW_FULLSCREEN)) { - [data.listener addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN]; - SDL_UpdateFullscreenMode(window, false, true); - } else if ([data.listener isInFullscreenSpaceTransition]) { - [data.listener addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN]; - } else { - [nswindow miniaturize:nil]; - } - } -} - -void Cocoa_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = data.nswindow; - - if (([data.listener windowOperationIsPending:(PENDING_OPERATION_ENTER_FULLSCREEN | PENDING_OPERATION_LEAVE_FULLSCREEN)] && - ![data.nswindow isMiniaturized]) || [data.listener isInFullscreenSpaceTransition]) { - Cocoa_SyncWindow(_this, window); - } - - [data.listener clearPendingWindowOperation:(PENDING_OPERATION_MINIMIZE)]; - - if (!(window->flags & SDL_WINDOW_FULLSCREEN) && - ![data.listener isInFullscreenSpaceTransition] && - ![data.listener isInFullscreenSpace]) { - if ([nswindow isMiniaturized]) { - [nswindow deminiaturize:nil]; - } else if (Cocoa_IsWindowZoomed(window)) { - [nswindow zoom:nil]; - } - } else if (data.was_zoomed) { - [data.listener addPendingWindowOperation:PENDING_OPERATION_ZOOM]; - } else { - [data.listener clearPendingWindowOperation:PENDING_OPERATION_ZOOM]; - } - } -} - -void Cocoa_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, bool bordered) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - // If the window is in or transitioning to/from fullscreen, this will be set on leave. - if (!(window->flags & SDL_WINDOW_FULLSCREEN) && ![data.listener isInFullscreenSpaceTransition]) { - if (SetWindowStyle(window, GetWindowStyle(window))) { - if (bordered) { - Cocoa_SetWindowTitle(_this, window); // this got blanked out. - } - } - } else { - data.border_toggled = true; - } - Cocoa_UpdateClipCursor(window); - } -} - -void Cocoa_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable) -{ - @autoreleasepool { - /* Don't set this if we're in or transitioning to/from a space! - * The window will get permanently stuck if resizable is false. - * -flibit - */ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - SDL3Cocoa_WindowListener *listener = data.listener; - NSWindow *nswindow = data.nswindow; - SDL_CocoaVideoData *videodata = data.videodata; - if (![listener isInFullscreenSpace] && ![listener isInFullscreenSpaceTransition]) { - SetWindowStyle(window, GetWindowStyle(window)); - } - if (videodata.allow_spaces) { - if (resizable) { - // resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. - [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - } else { - [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged]; - } - } - } -} - -void Cocoa_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, bool on_top) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = data.nswindow; - - // If the window is in or transitioning to/from fullscreen, this will be set on leave. - if (!(window->flags & SDL_WINDOW_FULLSCREEN) && ![data.listener isInFullscreenSpaceTransition]) { - if (on_top) { - [nswindow setLevel:NSFloatingWindowLevel]; - } else { - [nswindow setLevel:kCGNormalWindowLevel]; - } - } - } -} - -SDL_FullscreenResult Cocoa_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = data.nswindow; - NSRect rect; - - // This is a synchronous operation, so always clear the pending flags. - [data.listener clearPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN | PENDING_OPERATION_LEAVE_FULLSCREEN]; - - // The view responder chain gets messed with during setStyleMask - if ([data.sdlContentView nextResponder] == data.listener) { - [data.sdlContentView setNextResponder:nil]; - } - - if (fullscreen) { - SDL_Rect bounds; - - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - data.was_zoomed = !!(window->flags & SDL_WINDOW_MAXIMIZED); - } - - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_ENTER_FULLSCREEN, 0, 0); - Cocoa_GetDisplayBounds(_this, display, &bounds); - rect.origin.x = bounds.x; - rect.origin.y = bounds.y; - rect.size.width = bounds.w; - rect.size.height = bounds.h; - ConvertNSRect(&rect); - - /* Hack to fix origin on macOS 10.4 - This is no longer needed as of macOS 10.15, according to bug 4822. - */ - if (SDL_floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_14) { - NSRect screenRect = [[nswindow screen] frame]; - if (screenRect.size.height >= 1.0f) { - rect.origin.y += (screenRect.size.height - rect.size.height); - } - } - - [nswindow setStyleMask:NSWindowStyleMaskBorderless]; - } else { - NSRect frameRect; - - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, 0, 0); - - rect.origin.x = data.was_zoomed ? window->windowed.x : window->floating.x; - rect.origin.y = data.was_zoomed ? window->windowed.y : window->floating.y; - rect.size.width = data.was_zoomed ? window->windowed.w : window->floating.w; - rect.size.height = data.was_zoomed ? window->windowed.h : window->floating.h; - - ConvertNSRect(&rect); - - /* The window is not meant to be fullscreen, but its flags might have a - * fullscreen bit set if it's scheduled to go fullscreen immediately - * after. Always using the windowed mode style here works around bugs in - * macOS 10.15 where the window doesn't properly restore the windowed - * mode decorations after exiting fullscreen-desktop, when the window - * was created as fullscreen-desktop. */ - [nswindow setStyleMask:GetWindowWindowedStyle(window)]; - - // Hack to restore window decorations on macOS 10.10 - frameRect = [nswindow frame]; - [nswindow setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO]; - [nswindow setFrame:frameRect display:NO]; - } - - // The view responder chain gets messed with during setStyleMask - if ([data.sdlContentView nextResponder] != data.listener) { - [data.sdlContentView setNextResponder:data.listener]; - } - - [nswindow setContentSize:rect.size]; - [nswindow setFrameOrigin:rect.origin]; - - // When the window style changes the title is cleared - if (!fullscreen) { - Cocoa_SetWindowTitle(_this, window); - data.was_zoomed = NO; - if ([data.listener windowOperationIsPending:PENDING_OPERATION_ZOOM]) { - [data.listener clearPendingWindowOperation:PENDING_OPERATION_ZOOM]; - [nswindow zoom:nil]; - } - } - - if (SDL_ShouldAllowTopmost() && fullscreen) { - // OpenGL is rendering to the window, so make it visible! - [nswindow setLevel:kCGMainMenuWindowLevel + 1]; - } else if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { - [nswindow setLevel:NSFloatingWindowLevel]; - } else { - [nswindow setLevel:kCGNormalWindowLevel]; - } - - if ([nswindow isVisible] || fullscreen) { - [data.listener pauseVisibleObservation]; - [nswindow makeKeyAndOrderFront:nil]; - [data.listener resumeVisibleObservation]; - } - - // Update the safe area insets - // The view never seems to reflect the safe area, so we'll use the screen instead - if (@available(macOS 12.0, *)) { - if (fullscreen) { - NSScreen *screen = [nswindow screen]; - - SDL_SetWindowSafeAreaInsets(data.window, - (int)SDL_ceilf(screen.safeAreaInsets.left), - (int)SDL_ceilf(screen.safeAreaInsets.right), - (int)SDL_ceilf(screen.safeAreaInsets.top), - (int)SDL_ceilf(screen.safeAreaInsets.bottom)); - } else { - SDL_SetWindowSafeAreaInsets(data.window, 0, 0, 0, 0); - } - } - - /* When coming out of fullscreen to minimize, this needs to happen after the window - * is made key again, or it won't minimize on 15.0 (Sequoia). - */ - if (!fullscreen && [data.listener windowOperationIsPending:PENDING_OPERATION_MINIMIZE]) { - Cocoa_WaitForMiniaturizable(window); - [data.listener addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN]; - [data.listener clearPendingWindowOperation:PENDING_OPERATION_MINIMIZE]; - [nswindow miniaturize:nil]; - } - - ScheduleContextUpdates(data); - Cocoa_SyncWindow(_this, window); - Cocoa_UpdateClipCursor(window); - } - - return SDL_FULLSCREEN_SUCCEEDED; -} - -void *Cocoa_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - NSWindow *nswindow = data.nswindow; - NSScreen *screen = [nswindow screen]; - NSData *iccProfileData = nil; - void *retIccProfileData = NULL; - - if (screen == nil) { - SDL_SetError("Could not get screen of window."); - return NULL; - } - - if ([screen colorSpace] == nil) { - SDL_SetError("Could not get colorspace information of screen."); - return NULL; - } - - iccProfileData = [[screen colorSpace] ICCProfileData]; - if (iccProfileData == nil) { - SDL_SetError("Could not get ICC profile data."); - return NULL; - } - - retIccProfileData = SDL_malloc([iccProfileData length]); - if (!retIccProfileData) { - return NULL; - } - - [iccProfileData getBytes:retIccProfileData length:[iccProfileData length]]; - *size = [iccProfileData length]; - return retIccProfileData; - } -} - -SDL_DisplayID Cocoa_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - NSScreen *screen; - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - // Not recognized via CHECK_WINDOW_MAGIC - if (data == nil) { - // Don't set the error here, it hides other errors and is ignored anyway - // return SDL_SetError("Window data not set"); - return 0; - } - - // NSWindow.screen may be nil when the window is off-screen. - screen = data.nswindow.screen; - - if (screen != nil) { - // https://developer.apple.com/documentation/appkit/nsscreen/1388360-devicedescription?language=objc - CGDirectDisplayID displayid = [[screen.deviceDescription objectForKey:@"NSScreenNumber"] unsignedIntValue]; - SDL_VideoDisplay *display = Cocoa_FindSDLDisplayByCGDirectDisplayID(_this, displayid); - if (display) { - return display->id; - } - } - - // The higher level code will use other logic to find the display - return 0; - } -} - -bool Cocoa_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window) -{ - Cocoa_UpdateClipCursor(window); - return true; -} - -bool Cocoa_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - Cocoa_UpdateClipCursor(window); - - if (data && (window->flags & SDL_WINDOW_FULLSCREEN) != 0) { - if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS) && ![data.listener isInFullscreenSpace]) { - // OpenGL is rendering to the window, so make it visible! - // Doing this in 10.11 while in a Space breaks things (bug #3152) - [data.nswindow setLevel:kCGMainMenuWindowLevel + 1]; - } else if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { - [data.nswindow setLevel:NSFloatingWindowLevel]; - } else { - [data.nswindow setLevel:kCGNormalWindowLevel]; - } - } - } - - return true; -} - -void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (SDL_CocoaWindowData *)CFBridgingRelease(window->internal); - - if (data) { -#ifdef SDL_VIDEO_OPENGL - - NSArray *contexts; - -#endif // SDL_VIDEO_OPENGL - SDL_Window *topmost = GetParentToplevelWindow(window); - SDL_CocoaWindowData *topmost_data = (__bridge SDL_CocoaWindowData *)topmost->internal; - - /* Reset the input focus of the root window if this window is still set as keyboard focus. - * SDL_DestroyWindow will have already taken care of reassigning focus if this is the SDL - * keyboard focus, this ensures that an inactive window with this window set as input focus - * does not try to reference it the next time it gains focus. - */ - if (topmost_data.keyboard_focus == window) { - SDL_Window *new_focus = window; - while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) { - new_focus = new_focus->parent; - } - - topmost_data.keyboard_focus = new_focus; - } - - if ([data.listener isInFullscreenSpace]) { - [NSMenu setMenuBarVisible:YES]; - } - [data.listener close]; - data.listener = nil; - - if (!(window->flags & SDL_WINDOW_EXTERNAL)) { - // Release the content view to avoid further updateLayer callbacks - [data.nswindow setContentView:nil]; - [data.nswindow close]; - } - -#ifdef SDL_VIDEO_OPENGL - - contexts = [data.nscontexts copy]; - for (SDL3OpenGLContext *context in contexts) { - // Calling setWindow:NULL causes the context to remove itself from the context list. - [context setWindow:NULL]; - } - -#endif // SDL_VIDEO_OPENGL - } - window->internal = NULL; - } -} - -bool Cocoa_SetWindowFullscreenSpace(SDL_Window *window, bool state, bool blocking) -{ - @autoreleasepool { - bool succeeded = false; - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - if (state) { - data.fullscreen_space_requested = YES; - } - data.in_blocking_transition = blocking; - if ([data.listener setFullscreenSpace:(state ? YES : NO)]) { - if (blocking) { - const int maxattempts = 3; - int attempt = 0; - while (++attempt <= maxattempts) { - /* Wait for the transition to complete, so application changes - take effect properly (e.g. setting the window size, etc.) - */ - const int limit = 10000; - int count = 0; - while ([data.listener isInFullscreenSpaceTransition]) { - if (++count == limit) { - // Uh oh, transition isn't completing. Should we assert? - break; - } - SDL_Delay(1); - SDL_PumpEvents(); - } - if ([data.listener isInFullscreenSpace] == (state ? YES : NO)) { - break; - } - // Try again, the last attempt was interrupted by user gestures - if (![data.listener setFullscreenSpace:(state ? YES : NO)]) { - break; // ??? - } - } - } - - // Return TRUE to prevent non-space fullscreen logic from running - succeeded = true; - } - - data.in_blocking_transition = NO; - return succeeded; - } -} - -bool Cocoa_SetWindowHitTest(SDL_Window *window, bool enabled) -{ - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - [data.listener updateHitTest]; - return true; -} - -void Cocoa_AcceptDragAndDrop(SDL_Window *window, bool accept) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - if (accept) { - [data.nswindow registerForDraggedTypes:@[ (NSString *)kUTTypeFileURL, - (NSString *)kUTTypeUTF8PlainText ]]; - } else { - [data.nswindow unregisterDraggedTypes]; - } - } -} - -bool Cocoa_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent) -{ - @autoreleasepool { - SDL_CocoaWindowData *child_data = (__bridge SDL_CocoaWindowData *)window->internal; - - // Remove an existing parent. - if (child_data.nswindow.parentWindow) { - NSWindow *nsparent = ((__bridge SDL_CocoaWindowData *)window->parent->internal).nswindow; - [nsparent removeChildWindow:child_data.nswindow]; - } - - if (parent) { - SDL_CocoaWindowData *parent_data = (__bridge SDL_CocoaWindowData *)parent->internal; - [parent_data.nswindow addChildWindow:child_data.nswindow ordered:NSWindowAbove]; - } - } - - return true; -} - -bool Cocoa_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - if (data.modal_session) { - [NSApp endModalSession:data.modal_session]; - data.modal_session = nil; - } - - if (modal) { - data.modal_session = [NSApp beginModalSessionForWindow:data.nswindow]; - } - } - - return true; -} - -bool Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation) -{ - @autoreleasepool { - // Note that this is app-wide and not window-specific! - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - if (data.flash_request) { - [NSApp cancelUserAttentionRequest:data.flash_request]; - data.flash_request = 0; - } - - switch (operation) { - case SDL_FLASH_CANCEL: - // Canceled above - break; - case SDL_FLASH_BRIEFLY: - data.flash_request = [NSApp requestUserAttention:NSInformationalRequest]; - break; - case SDL_FLASH_UNTIL_FOCUSED: - data.flash_request = [NSApp requestUserAttention:NSCriticalRequest]; - break; - default: - return SDL_Unsupported(); - } - return true; - } -} - -bool Cocoa_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable) -{ - return true; // just succeed, the real work is done elsewhere. -} - -bool Cocoa_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity) -{ - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - [data.nswindow setAlphaValue:opacity]; - return true; - } -} - -bool Cocoa_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window) -{ - bool result = true; - - @autoreleasepool { - SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal; - - do { - SDL_PumpEvents(); - } while ([data.listener hasPendingWindowOperation]); - } - - return result; -} - -#endif // SDL_VIDEO_DRIVER_COCOA -- cgit v1.2.3