Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'
This commit is contained in:
37
external/sdl/SDL/src/video/cocoa/SDL_cocoaclipboard.h
vendored
Normal file
37
external/sdl/SDL/src/video/cocoa/SDL_cocoaclipboard.h
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 int Cocoa_SetClipboardText(SDL_VideoDevice *_this, const char *text);
|
||||
extern char *Cocoa_GetClipboardText(SDL_VideoDevice *_this);
|
||||
extern SDL_bool Cocoa_HasClipboardText(SDL_VideoDevice *_this);
|
||||
extern void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data);
|
||||
extern int Cocoa_SetClipboardData(SDL_VideoDevice *_this);
|
||||
extern void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
|
||||
extern SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
|
||||
|
||||
#endif /* SDL_cocoaclipboard_h_ */
|
178
external/sdl/SDL/src/video/cocoa/SDL_cocoaclipboard.m
vendored
Normal file
178
external/sdl/SDL/src/video/cocoa/SDL_cocoaclipboard.m
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_clipboardevents_c.h"
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101300
|
||||
typedef NSString *NSPasteboardType; /* Defined in macOS 10.13+ */
|
||||
#endif
|
||||
|
||||
@interface Cocoa_PasteboardDataProvider : NSObject<NSPasteboardItemDataProvider>
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSPasteboard *pasteboard;
|
||||
NSInteger count;
|
||||
|
||||
pasteboard = [NSPasteboard generalPasteboard];
|
||||
count = [pasteboard changeCount];
|
||||
if (count != data.clipboard_count) {
|
||||
if (data.clipboard_count) {
|
||||
SDL_SendClipboardUpdate();
|
||||
}
|
||||
data.clipboard_count = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_SetClipboardData(SDL_VideoDevice *_this)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
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 0;
|
||||
}
|
||||
|
||||
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 mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
|
||||
CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
|
||||
CFRelease(mimeType);
|
||||
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));
|
||||
} else {
|
||||
SDL_OutOfMemory();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
|
||||
{
|
||||
SDL_bool result = SDL_FALSE;
|
||||
@autoreleasepool {
|
||||
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
|
||||
CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
|
||||
CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
|
||||
CFRelease(mimeType);
|
||||
if ([pasteboard canReadItemWithDataConformingToTypes: @[(__bridge NSString *)utiType]]) {
|
||||
result = SDL_TRUE;
|
||||
}
|
||||
CFRelease(utiType);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
33
external/sdl/SDL/src/video/cocoa/SDL_cocoaevents.h
vendored
Normal file
33
external/sdl/SDL/src/video/cocoa/SDL_cocoaevents.h
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 int Cocoa_SuspendScreenSaver(SDL_VideoDevice *_this);
|
||||
|
||||
#endif /* SDL_cocoaevents_h_ */
|
616
external/sdl/SDL/src/video/cocoa/SDL_cocoaevents.m
vendored
Normal file
616
external/sdl/SDL/src/video/cocoa/SDL_cocoaevents.m
vendored
Normal file
@ -0,0 +1,616 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_12
|
||||
#define NSEventTypeApplicationDefined NSApplicationDefined
|
||||
#endif
|
||||
|
||||
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->driverdata).nswindow;
|
||||
if (win == nswindow) {
|
||||
return sdlwindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sdlwindow;
|
||||
}
|
||||
|
||||
@interface SDLApplication : NSApplication
|
||||
|
||||
- (void)terminate:(id)sender;
|
||||
- (void)sendEvent:(NSEvent *)theEvent;
|
||||
|
||||
+ (void)registerUserDefaults;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SDLApplication
|
||||
|
||||
// Override terminate to handle Quit and System Shutdown smoothly.
|
||||
- (void)terminate:(id)sender
|
||||
{
|
||||
SDL_SendQuit();
|
||||
}
|
||||
|
||||
static SDL_bool s_bShouldHandleEventsInSDLApplication = SDL_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:
|
||||
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
|
||||
{
|
||||
NSDictionary *appDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNumber numberWithBool:NO], @"AppleMomentumScrollSupported",
|
||||
[NSNumber numberWithBool:NO], @"ApplePressAndHoldEnabled",
|
||||
[NSNumber numberWithBool:YES], @"ApplePersistenceIgnoreState",
|
||||
nil];
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
|
||||
}
|
||||
|
||||
@end // SDLApplication
|
||||
|
||||
/* setAppleMenu disappeared from the headers in 10.4 */
|
||||
@interface NSApplication (NSAppleMenu)
|
||||
- (void)setAppleMenu:(NSMenu *)menu;
|
||||
@end
|
||||
|
||||
@interface SDLAppDelegate : NSObject <NSApplicationDelegate>
|
||||
{
|
||||
@public
|
||||
BOOL seenFirstActivate;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
- (void)localeDidChange:(NSNotification *)notification;
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context;
|
||||
@end
|
||||
|
||||
@implementation SDLAppDelegate : NSObject
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
seenFirstActivate = NO;
|
||||
|
||||
[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(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: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)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, [filename UTF8String]) && SDL_SendDropComplete(NULL);
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
/* 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, SDL_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. */
|
||||
[SDLApplication registerUserDefaults];
|
||||
}
|
||||
|
||||
- (void)handleURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
|
||||
{
|
||||
NSString *path = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
||||
SDL_SendDropFile(NULL, [path UTF8String]);
|
||||
SDL_SendDropComplete(NULL);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static SDLAppDelegate *appDelegate = nil;
|
||||
|
||||
static NSString *GetApplicationName(void)
|
||||
{
|
||||
NSString *appName;
|
||||
|
||||
/* Determine the application name */
|
||||
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];
|
||||
[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) {
|
||||
[SDLApplication sharedApplication];
|
||||
SDL_assert(NSApp != nil);
|
||||
|
||||
s_bShouldHandleEventsInSDLApplication = SDL_TRUE;
|
||||
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, SDL_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.
|
||||
*/
|
||||
[SDLApplication registerUserDefaults];
|
||||
}
|
||||
}
|
||||
if (NSApp && !appDelegate) {
|
||||
appDelegate = [[SDLAppDelegate 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)
|
||||
{
|
||||
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 SDLApplication 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->driverdata).window_number
|
||||
context:nil
|
||||
subtype:0
|
||||
data1:0
|
||||
data2:0];
|
||||
|
||||
[NSApp postEvent:event atStart:YES];
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_SuspendScreenSaver(SDL_VideoDevice *_this)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
|
||||
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 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
36
external/sdl/SDL/src/video/cocoa/SDL_cocoakeyboard.h
vendored
Normal file
36
external/sdl/SDL/src/video/cocoa/SDL_cocoakeyboard.h
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 void Cocoa_StartTextInput(SDL_VideoDevice *_this);
|
||||
extern void Cocoa_StopTextInput(SDL_VideoDevice *_this);
|
||||
extern int Cocoa_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect);
|
||||
|
||||
extern void Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
|
||||
|
||||
#endif /* SDL_cocoakeyboard_h_ */
|
467
external/sdl/SDL/src/video/cocoa/SDL_cocoakeyboard.m
vendored
Normal file
467
external/sdl/SDL/src/video/cocoa/SDL_cocoakeyboard.m
vendored
Normal file
@ -0,0 +1,467 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 <Carbon/Carbon.h>
|
||||
|
||||
/*#define DEBUG_IME NSLog */
|
||||
#define DEBUG_IME(...)
|
||||
|
||||
@interface SDLTranslatorResponder : NSView <NSTextInputClient>
|
||||
{
|
||||
NSString *_markedText;
|
||||
NSRange _markedRange;
|
||||
NSRange _selectedRange;
|
||||
SDL_Rect _inputRect;
|
||||
}
|
||||
- (void)doCommandBySelector:(SEL)myselector;
|
||||
- (void)setInputRect:(const SDL_Rect *)rect;
|
||||
@end
|
||||
|
||||
@implementation SDLTranslatorResponder
|
||||
|
||||
- (void)setInputRect:(const SDL_Rect *)rect
|
||||
{
|
||||
_inputRect = *rect;
|
||||
}
|
||||
|
||||
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
/* TODO: Make use of replacementRange? */
|
||||
|
||||
const char *str;
|
||||
|
||||
DEBUG_IME(@"insertText: %@", aString);
|
||||
|
||||
/* 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];
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
SDL_SendEditingText([aString UTF8String],
|
||||
(int)selectedRange.location, (int)selectedRange.length);
|
||||
|
||||
DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText,
|
||||
selectedRange.location, selectedRange.length);
|
||||
}
|
||||
|
||||
- (void)unmarkText
|
||||
{
|
||||
_markedText = nil;
|
||||
|
||||
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 = %@",
|
||||
aRange.location, aRange.length, windowHeight,
|
||||
NSStringFromRect(rect));
|
||||
|
||||
rect = [window convertRectToScreen:rect];
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", aRange.location, 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];
|
||||
}
|
||||
|
||||
@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_PRESSED, code);
|
||||
} else {
|
||||
SDL_SendKeyboardKey(0, SDL_RELEASED, code);
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event)
|
||||
{
|
||||
TISInputSourceRef key_layout;
|
||||
const void *chr_data;
|
||||
int i;
|
||||
SDL_Scancode scancode;
|
||||
SDL_Keycode keymap[SDL_NUM_SCANCODES];
|
||||
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;
|
||||
|
||||
SDL_GetDefaultKeymap(keymap);
|
||||
|
||||
/* Try Unicode data first */
|
||||
uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData);
|
||||
if (uchrDataRef) {
|
||||
chr_data = CFDataGetBytePtr(uchrDataRef);
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (chr_data) {
|
||||
UInt32 keyboard_type = LMGetKbdType();
|
||||
OSStatus err;
|
||||
|
||||
for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
|
||||
UniChar s[8];
|
||||
UniCharCount len;
|
||||
UInt32 dead_key_state;
|
||||
|
||||
/* Make sure this scancode is a valid character scancode */
|
||||
scancode = darwin_scancode_table[i];
|
||||
if (scancode == SDL_SCANCODE_UNKNOWN ||
|
||||
(keymap[scancode] & 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((UCKeyboardLayout *)chr_data,
|
||||
i, kUCKeyActionDown,
|
||||
0, keyboard_type,
|
||||
kUCKeyTranslateNoDeadKeysMask,
|
||||
&dead_key_state, 8, &len, s);
|
||||
if (err != noErr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len > 0 && s[0] != 0x10) {
|
||||
keymap[scancode] = s[0];
|
||||
}
|
||||
}
|
||||
SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
|
||||
return;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
CFRelease(key_layout);
|
||||
}
|
||||
|
||||
void Cocoa_InitKeyboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
|
||||
UpdateKeymap(data, SDL_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) ? SDL_TRUE : SDL_FALSE);
|
||||
}
|
||||
|
||||
void Cocoa_StartTextInput(SDL_VideoDevice *_this)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSView *parentView;
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
SDL_Window *window = SDL_GetKeyboardFocus();
|
||||
NSWindow *nswindow = nil;
|
||||
if (window) {
|
||||
nswindow = ((__bridge SDL_CocoaWindowData *)window->driverdata).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 =
|
||||
[[SDLTranslatorResponder 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cocoa_StopTextInput(SDL_VideoDevice *_this)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
|
||||
if (data && data.fieldEdit) {
|
||||
[data.fieldEdit removeFromSuperview];
|
||||
data.fieldEdit = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect)
|
||||
{
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
[data.fieldEdit setInputRect:rect];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event)
|
||||
{
|
||||
unsigned short scancode;
|
||||
SDL_Scancode code;
|
||||
SDL_CocoaVideoData *data = _this ? ((__bridge SDL_CocoaVideoData *)_this->driverdata) : nil;
|
||||
if (!data) {
|
||||
return; /* can happen when returning from fullscreen Space on shutdown */
|
||||
}
|
||||
|
||||
scancode = [event keyCode];
|
||||
#if 0
|
||||
const char *text;
|
||||
#endif
|
||||
|
||||
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, SDL_TRUE);
|
||||
}
|
||||
|
||||
SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_PRESSED, code);
|
||||
#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 <https://discourse.libsdl.org/> or to Christian Walther <cwalther@gmx.ch>. Mac virtual key code is %d.\n", scancode);
|
||||
}
|
||||
#endif
|
||||
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
|
||||
/* FIXME CW 2007-08-16: only send those events to the field editor for which we actually want text events, not e.g. esc or function keys. Arrow keys in particular seem to produce crashes sometimes. */
|
||||
[data.fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
#if 0
|
||||
text = [[event characters] UTF8String];
|
||||
if(text && *text) {
|
||||
SDL_SendKeyboardText(text);
|
||||
[data->fieldEdit setString:@""];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case NSEventTypeKeyUp:
|
||||
SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_RELEASED, code);
|
||||
break;
|
||||
case NSEventTypeFlagsChanged:
|
||||
HandleModifiers(_this, code, (unsigned int)[event modifierFlags]);
|
||||
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);
|
||||
|
||||
void Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed)
|
||||
{
|
||||
#ifdef SDL_MAC_NO_SANDBOX
|
||||
CGSSetGlobalHotKeyOperatingMode(_CGSDefaultConnection(), grabbed ? CGSGlobalHotKeyDisable : CGSGlobalHotKeyEnable);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
27
external/sdl/SDL/src/video/cocoa/SDL_cocoamessagebox.h
vendored
Normal file
27
external/sdl/SDL/src/video/cocoa/SDL_cocoamessagebox.h
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 int Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
145
external/sdl/SDL/src/video/cocoa/SDL_cocoamessagebox.m
vendored
Normal file
145
external/sdl/SDL/src/video/cocoa/SDL_cocoamessagebox.m
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 SDLMessageBoxPresenter : NSObject
|
||||
{
|
||||
@public
|
||||
NSInteger clicked;
|
||||
NSWindow *nswindow;
|
||||
}
|
||||
- (id)initWithParentWindow:(SDL_Window *)window;
|
||||
@end
|
||||
|
||||
@implementation SDLMessageBoxPresenter
|
||||
- (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->driverdata).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, int *returnValue)
|
||||
{
|
||||
NSAlert *alert;
|
||||
const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
|
||||
SDLMessageBoxPresenter *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 = [[SDLMessageBoxPresenter 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;
|
||||
*returnValue = 0;
|
||||
} else {
|
||||
*returnValue = SDL_SetError("Did not get a valid `clicked button' id: %ld", (long)clicked);
|
||||
}
|
||||
}
|
||||
|
||||
/* Display a Cocoa message box */
|
||||
int Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
||||
{
|
||||
@autoreleasepool {
|
||||
__block int returnValue = 0;
|
||||
|
||||
if ([NSThread isMainThread]) {
|
||||
Cocoa_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue);
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
Cocoa_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue);
|
||||
});
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
66
external/sdl/SDL/src/video/cocoa/SDL_cocoametalview.h
vendored
Normal file
66
external/sdl/SDL/src/video/cocoa/SDL_cocoametalview.h
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 <Cocoa/Cocoa.h>
|
||||
#import <Metal/Metal.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
@interface SDL_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_ */
|
182
external/sdl/SDL/src/video/cocoa/SDL_cocoametalview.m
vendored
Normal file
182
external/sdl/SDL/src/video/cocoa/SDL_cocoametalview.m
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
|
||||
#import "SDL_cocoametalview.h"
|
||||
|
||||
#if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL))
|
||||
|
||||
#include <SDL3/SDL_syswm.h>
|
||||
|
||||
static int 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 {
|
||||
SDL_cocoametalview *view = (__bridge SDL_cocoametalview *)userdata;
|
||||
if (view.sdlWindowID == event->window.windowID) {
|
||||
[view updateDrawableSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@implementation SDL_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_AddEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self));
|
||||
|
||||
[self updateDrawableSize];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
SDL_DelEventWatch(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->driverdata;
|
||||
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);
|
||||
SDL_cocoametalview *newview;
|
||||
SDL_MetalView metalview;
|
||||
|
||||
newview = [[SDL_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 {
|
||||
SDL_cocoametalview *metalview = CFBridgingRelease(view);
|
||||
[metalview removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
void *Cocoa_Metal_GetLayer(SDL_VideoDevice *_this, SDL_MetalView view)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_cocoametalview *cocoaview = (__bridge SDL_cocoametalview *)view;
|
||||
return (__bridge void *)cocoaview.layer;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */
|
43
external/sdl/SDL/src/video/cocoa/SDL_cocoamodes.h
vendored
Normal file
43
external/sdl/SDL/src/video/cocoa/SDL_cocoamodes.h
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 int Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
|
||||
extern int Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
|
||||
extern int Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
|
||||
extern int Cocoa_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
|
||||
extern void Cocoa_QuitModes(SDL_VideoDevice *_this);
|
||||
|
||||
#endif /* SDL_cocoamodes_h_ */
|
540
external/sdl/SDL/src/video/cocoa/SDL_cocoamodes.m
vendored
Normal file
540
external/sdl/SDL/src/video/cocoa/SDL_cocoamodes.m
vendored
Normal file
@ -0,0 +1,540 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
|
||||
/* We need this for IODisplayCreateInfoDictionary and kIODisplayOnlyPreferredName */
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
|
||||
/* We need this for CVDisplayLinkGetNominalOutputVideoRefreshPeriod */
|
||||
#include <CoreVideo/CVBase.h>
|
||||
#include <CoreVideo/CVDisplayLink.h>
|
||||
|
||||
/* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_13
|
||||
#define NSAppKitVersionNumber10_12 1504
|
||||
#endif
|
||||
#if (IOGRAPHICSTYPES_REV < 40)
|
||||
#define kDisplayModeNativeFlag 0x02000000
|
||||
#endif
|
||||
|
||||
static int 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 float GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link)
|
||||
{
|
||||
double refreshRate = 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 = (double)time.timeScale / time.timeValue;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)(refreshRate * 100) / 100.0f;
|
||||
}
|
||||
|
||||
static SDL_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 SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Filter out modes which don't have flags that we want. */
|
||||
if (!(ioflags & kDisplayModeValidFlag) || !(ioflags & kDisplayModeSafeFlag)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
return SDL_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 SDL_bool GetDisplayMode(SDL_VideoDevice *_this, CGDisplayModeRef vidmode, SDL_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 SDL_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 SDL_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 SDL_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 SDL_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 SDL_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->driverdata = data;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static const char *Cocoa_GetDisplayName(CGDirectDisplayID displayID)
|
||||
{
|
||||
/* 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]];
|
||||
const char *displayName = NULL;
|
||||
|
||||
if ([localizedNames count] > 0) {
|
||||
displayName = SDL_strdup([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]);
|
||||
}
|
||||
CFRelease(deviceInfo);
|
||||
return displayName;
|
||||
}
|
||||
|
||||
void Cocoa_InitModes(SDL_VideoDevice *_this)
|
||||
{
|
||||
@autoreleasepool {
|
||||
CGDisplayErr result;
|
||||
CGDirectDisplayID *displays;
|
||||
CGDisplayCount numDisplays;
|
||||
SDL_bool isstack;
|
||||
int pass, i;
|
||||
|
||||
result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
|
||||
if (result != kCGErrorSuccess) {
|
||||
CG_SetError("CGGetOnlineDisplayList()", result);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* Pick up the primary display in the first pass, then get the rest */
|
||||
for (pass = 0; pass < 2; ++pass) {
|
||||
for (i = 0; i < numDisplays; ++i) {
|
||||
SDL_VideoDisplay display;
|
||||
SDL_DisplayData *displaydata;
|
||||
SDL_DisplayMode mode;
|
||||
CGDisplayModeRef moderef = NULL;
|
||||
CVDisplayLinkRef link = NULL;
|
||||
|
||||
if (pass == 0) {
|
||||
if (!CGDisplayIsMain(displays[i])) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (CGDisplayIsMain(displays[i])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay) {
|
||||
continue;
|
||||
}
|
||||
|
||||
moderef = CGDisplayCopyDisplayMode(displays[i]);
|
||||
|
||||
if (!moderef) {
|
||||
continue;
|
||||
}
|
||||
|
||||
displaydata = (SDL_DisplayData *)SDL_malloc(sizeof(*displaydata));
|
||||
if (!displaydata) {
|
||||
CGDisplayModeRelease(moderef);
|
||||
continue;
|
||||
}
|
||||
displaydata->display = displays[i];
|
||||
|
||||
CVDisplayLinkCreateWithCGDisplay(displays[i], &link);
|
||||
|
||||
SDL_zero(display);
|
||||
/* this returns a stddup'ed string */
|
||||
display.name = (char *)Cocoa_GetDisplayName(displays[i]);
|
||||
if (!GetDisplayMode(_this, moderef, SDL_TRUE, NULL, link, &mode)) {
|
||||
CVDisplayLinkRelease(link);
|
||||
CGDisplayModeRelease(moderef);
|
||||
SDL_free(display.name);
|
||||
SDL_free(displaydata);
|
||||
continue;
|
||||
}
|
||||
|
||||
CVDisplayLinkRelease(link);
|
||||
CGDisplayModeRelease(moderef);
|
||||
|
||||
display.desktop_mode = mode;
|
||||
display.driverdata = displaydata;
|
||||
SDL_AddVideoDisplay(&display, SDL_FALSE);
|
||||
SDL_free(display.name);
|
||||
}
|
||||
}
|
||||
SDL_small_free(displays, isstack);
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
|
||||
{
|
||||
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
|
||||
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 0;
|
||||
}
|
||||
|
||||
int Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
|
||||
{
|
||||
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
|
||||
const CGDirectDisplayID cgdisplay = displaydata->display;
|
||||
NSArray *screens = [NSScreen screens];
|
||||
NSScreen *screen = nil;
|
||||
|
||||
/* !!! FIXME: maybe track the NSScreen in SDL_DisplayData? */
|
||||
for (NSScreen *i in screens) {
|
||||
const CGDirectDisplayID thisDisplay = (CGDirectDisplayID)[[[i deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
|
||||
if (thisDisplay == cgdisplay) {
|
||||
screen = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert(screen != nil); /* didn't find it?! */
|
||||
if (screen == nil) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
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 0;
|
||||
}
|
||||
|
||||
int Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
|
||||
{
|
||||
SDL_DisplayData *data = (SDL_DisplayData *)display->driverdata;
|
||||
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(_this, moderef, SDL_FALSE, modes, link, &mode)) {
|
||||
if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
|
||||
CFRelease(((SDL_DisplayModeData *)mode.driverdata)->modes);
|
||||
SDL_free(mode.driverdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(modes);
|
||||
}
|
||||
|
||||
CVDisplayLinkRelease(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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. */
|
||||
CFArrayExchangeValuesAtIndices(data->modes, i, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Cocoa_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
|
||||
{
|
||||
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
|
||||
SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
|
||||
CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
|
||||
CGError result = kCGErrorSuccess;
|
||||
|
||||
/* 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.driverdata) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
if (result != kCGErrorSuccess) {
|
||||
CG_SetError("CGDisplaySwitchToMode()", result);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Cocoa_QuitModes(SDL_VideoDevice *_this)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < _this->num_displays; ++i) {
|
||||
SDL_VideoDisplay *display = &_this->displays[i];
|
||||
SDL_DisplayModeData *mode;
|
||||
|
||||
if (display->current_mode->driverdata != display->desktop_mode.driverdata) {
|
||||
Cocoa_SetDisplayMode(_this, display, &display->desktop_mode);
|
||||
}
|
||||
|
||||
mode = (SDL_DisplayModeData *)display->desktop_mode.driverdata;
|
||||
CFRelease(mode->modes);
|
||||
|
||||
for (j = 0; j < display->num_fullscreen_modes; j++) {
|
||||
mode = (SDL_DisplayModeData *)display->fullscreen_modes[j].driverdata;
|
||||
CFRelease(mode->modes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
50
external/sdl/SDL/src/video/cocoa/SDL_cocoamouse.h
vendored
Normal file
50
external/sdl/SDL/src/video/cocoa/SDL_cocoamouse.h
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 int Cocoa_InitMouse(SDL_VideoDevice *_this);
|
||||
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. */
|
||||
SDL_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_ */
|
571
external/sdl/SDL/src/video/cocoa/SDL_cocoamouse.m
vendored
Normal file
571
external/sdl/SDL/src/video/cocoa/SDL_cocoamouse.m
vendored
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
|
||||
/* #define DEBUG_COCOAMOUSE */
|
||||
|
||||
#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_CreateDefaultCursor(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSCursor *nscursor;
|
||||
SDL_Cursor *cursor = NULL;
|
||||
|
||||
nscursor = [NSCursor arrowCursor];
|
||||
|
||||
if (nscursor) {
|
||||
cursor = SDL_calloc(1, sizeof(*cursor));
|
||||
if (cursor) {
|
||||
cursor->driverdata = (void *)CFBridgingRetain(nscursor);
|
||||
}
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
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->driverdata = (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_ARROW:
|
||||
nscursor = [NSCursor arrowCursor];
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_IBEAM:
|
||||
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_WAITARROW: /* !!! FIXME: this is meant to be animated */
|
||||
nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor));
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZENWSE:
|
||||
nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor));
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZENESW:
|
||||
nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor));
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZEWE:
|
||||
nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor));
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZENS:
|
||||
nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor));
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_SIZEALL:
|
||||
nscursor = LoadHiddenSystemCursor(@"move", @selector(closedHandCursor));
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_NO:
|
||||
nscursor = [NSCursor operationNotAllowedCursor];
|
||||
break;
|
||||
case SDL_SYSTEM_CURSOR_HAND:
|
||||
nscursor = [NSCursor pointingHandCursor];
|
||||
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->driverdata = (void *)CFBridgingRetain(nscursor);
|
||||
}
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
static void Cocoa_FreeCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
CFBridgingRelease(cursor->driverdata);
|
||||
SDL_free(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
static int 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_Mouse *mouse = SDL_GetMouse();
|
||||
if(mouse->focus) {
|
||||
if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
|
||||
[(__bridge NSCursor*)mouse->cur_cursor->driverdata set];
|
||||
} else {
|
||||
[[NSCursor invisibleCursor] set];
|
||||
}
|
||||
} else {
|
||||
[[NSCursor arrowCursor] set];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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 int Cocoa_WarpMouseGlobal(float x, float y)
|
||||
{
|
||||
CGPoint point;
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (mouse->focus) {
|
||||
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)mouse->focus->driverdata;
|
||||
if ([data.listener isMovingOrFocusClickPending]) {
|
||||
DLog("Postponing warp, window being moved or focused.");
|
||||
[data.listener setPendingMoveX:x Y:y];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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, mouse->mouseID, 0, x - win->x, y - win->y);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Cocoa_WarpMouse(SDL_Window *window, float x, float y)
|
||||
{
|
||||
return Cocoa_WarpMouseGlobal(window->x + x, window->y + y);
|
||||
}
|
||||
|
||||
static int Cocoa_SetRelativeMouseMode(SDL_bool enabled)
|
||||
{
|
||||
SDL_Window *window = SDL_GetKeyboardFocus();
|
||||
CGError result;
|
||||
SDL_CocoaWindowData *data;
|
||||
if (enabled) {
|
||||
if (window) {
|
||||
/* 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");
|
||||
}
|
||||
|
||||
/* We will re-apply the non-relative mode when the window gets focus, if it
|
||||
* doesn't have focus right now.
|
||||
*/
|
||||
if (!window) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We will re-apply the non-relative mode when the window finishes being moved,
|
||||
* if it is being moved right now.
|
||||
*/
|
||||
data = (__bridge SDL_CocoaWindowData *)window->driverdata;
|
||||
if ([data.listener isMovingOrFocusClickPending]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 0;
|
||||
}
|
||||
|
||||
static int 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 0;
|
||||
}
|
||||
|
||||
static Uint32 Cocoa_GetGlobalMouseState(float *x, float *y)
|
||||
{
|
||||
const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons];
|
||||
const NSPoint cocoaLocation = [NSEvent mouseLocation];
|
||||
Uint32 retval = 0;
|
||||
|
||||
*x = cocoaLocation.x;
|
||||
*y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - cocoaLocation.y);
|
||||
|
||||
retval |= (cocoaButtons & (1 << 0)) ? SDL_BUTTON_LMASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 1)) ? SDL_BUTTON_RMASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 2)) ? SDL_BUTTON_MMASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 3)) ? SDL_BUTTON_X1MASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 4)) ? SDL_BUTTON_X2MASK : 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int Cocoa_InitMouse(SDL_VideoDevice *_this)
|
||||
{
|
||||
NSPoint location;
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
SDL_MouseData *driverdata = (SDL_MouseData *)SDL_calloc(1, sizeof(SDL_MouseData));
|
||||
if (driverdata == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
mouse->driverdata = driverdata;
|
||||
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];
|
||||
driverdata->lastMoveX = location.x;
|
||||
driverdata->lastMoveY = location.y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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->driverdata;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
|
||||
{
|
||||
SDL_Mouse *mouse;
|
||||
SDL_MouseData *driverdata;
|
||||
SDL_MouseID mouseID;
|
||||
NSPoint location;
|
||||
CGFloat lastMoveX, lastMoveY;
|
||||
float deltaX, deltaY;
|
||||
SDL_bool seenWarp;
|
||||
switch ([event type]) {
|
||||
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();
|
||||
driverdata = (SDL_MouseData *)mouse->driverdata;
|
||||
if (!driverdata) {
|
||||
return; /* can happen when returning from fullscreen Space on shutdown */
|
||||
}
|
||||
|
||||
mouseID = mouse ? mouse->mouseID : 0;
|
||||
seenWarp = driverdata->seenWarp;
|
||||
driverdata->seenWarp = NO;
|
||||
|
||||
location = [NSEvent mouseLocation];
|
||||
lastMoveX = driverdata->lastMoveX;
|
||||
lastMoveY = driverdata->lastMoveY;
|
||||
driverdata->lastMoveX = location.x;
|
||||
driverdata->lastMoveY = location.y;
|
||||
DLog("Last seen mouse: (%g, %g)", location.x, location.y);
|
||||
|
||||
/* Non-relative movement is handled in -[Cocoa_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 - driverdata->lastWarpX);
|
||||
deltaY += ((CGDisplayPixelsHigh(kCGDirectMainDisplay) - lastMoveY) - driverdata->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, 1, deltaX, deltaY);
|
||||
}
|
||||
|
||||
void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
|
||||
{
|
||||
SDL_MouseID mouseID;
|
||||
SDL_MouseWheelDirection direction;
|
||||
CGFloat x, y;
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (!mouse) {
|
||||
return;
|
||||
}
|
||||
|
||||
mouseID = mouse->mouseID;
|
||||
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 *driverdata = (SDL_MouseData *)SDL_GetMouse()->driverdata;
|
||||
driverdata->lastWarpX = x;
|
||||
driverdata->lastWarpY = y;
|
||||
driverdata->seenWarp = SDL_TRUE;
|
||||
|
||||
DLog("(%g, %g)", x, y);
|
||||
}
|
||||
|
||||
void Cocoa_QuitMouse(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (mouse) {
|
||||
if (mouse->driverdata) {
|
||||
SDL_free(mouse->driverdata);
|
||||
mouse->driverdata = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
89
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengl.h
vendored
Normal file
89
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengl.h
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/CVDisplayLink.h>
|
||||
|
||||
/* 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 SDLOpenGLContext : 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 int 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 int Cocoa_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
SDL_GLContext context);
|
||||
extern int Cocoa_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
|
||||
extern int Cocoa_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
|
||||
extern int Cocoa_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int Cocoa_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif /* SDL_VIDEO_OPENGL_CGL */
|
||||
|
||||
#endif /* SDL_cocoaopengl_h_ */
|
541
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengl.m
vendored
Normal file
541
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengl.m
vendored
Normal file
@ -0,0 +1,541 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 <OpenGL/CGLTypes.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/CGLRenderers.h>
|
||||
|
||||
#include <SDL3/SDL_opengl.h>
|
||||
#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 SDL_bool SDL_opengl_async_dispatch = SDL_FALSE;
|
||||
|
||||
static void SDLCALL SDL_OpenGLAsyncDispatchChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
SDL_opengl_async_dispatch = SDL_GetStringBoolean(hint, SDL_FALSE);
|
||||
}
|
||||
|
||||
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
|
||||
{
|
||||
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)displayLinkContext;
|
||||
|
||||
/*printf("DISPLAY LINK! %u\n", (unsigned int) SDL_GetTicks()); */
|
||||
const int setting = SDL_AtomicGet(&nscontext->swapIntervalSetting);
|
||||
if (setting != 0) { /* nothing to do if vsync is disabled, don't even lock */
|
||||
SDL_LockMutex(nscontext->swapIntervalMutex);
|
||||
SDL_AtomicAdd(&nscontext->swapIntervalsPassed, 1);
|
||||
SDL_SignalCondition(nscontext->swapIntervalCond);
|
||||
SDL_UnlockMutex(nscontext->swapIntervalMutex);
|
||||
}
|
||||
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
@implementation SDLOpenGLContext : NSOpenGLContext
|
||||
|
||||
- (id)initWithFormat:(NSOpenGLPixelFormat *)format
|
||||
shareContext:(NSOpenGLContext *)share
|
||||
{
|
||||
self = [super initWithFormat:format shareContext:share];
|
||||
if (self) {
|
||||
self.openglPixelFormat = format;
|
||||
SDL_AtomicSet(&self->dirty, 0);
|
||||
self->window = NULL;
|
||||
SDL_AtomicSet(&self->swapIntervalSetting, 0);
|
||||
SDL_AtomicSet(&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_AtomicAdd(&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_AtomicSet(&self->dirty, 0);
|
||||
if (value > 0) {
|
||||
/* We call the real underlying update here, since -[SDLOpenGLContext 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->driverdata;
|
||||
|
||||
/* 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->driverdata;
|
||||
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_DelHintCallback(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
|
||||
|
||||
int Cocoa_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
/* Load the OpenGL library */
|
||||
if (path == NULL) {
|
||||
path = SDL_getenv("SDL_OPENGL_LIBRARY");
|
||||
}
|
||||
if (path == NULL) {
|
||||
path = DEFAULT_OPENGL;
|
||||
}
|
||||
_this->gl_config.dll_handle = SDL_LoadObject(path);
|
||||
if (!_this->gl_config.dll_handle) {
|
||||
return -1;
|
||||
}
|
||||
SDL_strlcpy(_this->gl_config.driver_path, path,
|
||||
SDL_arraysize(_this->gl_config.driver_path));
|
||||
return 0;
|
||||
}
|
||||
|
||||
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->driverdata;
|
||||
NSOpenGLPixelFormatAttribute attr[32];
|
||||
NSOpenGLPixelFormat *fmt;
|
||||
SDLOpenGLContext *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_DeleteContext = Cocoa_GLES_DeleteContext;
|
||||
|
||||
if (Cocoa_GLES_LoadLibrary(_this, NULL) != 0) {
|
||||
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 = [[SDLOpenGLContext 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) < 0) {
|
||||
SDL_GL_DeleteContext(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_DeleteContext(sdlcontext);
|
||||
SDL_SetError("Failed getting OpenGL glGetString entry point");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
glversion = (const char *)glGetStringFunc(GL_VERSION);
|
||||
if (glversion == NULL) {
|
||||
SDL_GL_DeleteContext(sdlcontext);
|
||||
SDL_SetError("Failed getting OpenGL context version");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) {
|
||||
SDL_GL_DeleteContext(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_DeleteContext(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;
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (context) {
|
||||
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)context;
|
||||
if ([nscontext window] != window) {
|
||||
[nscontext setWindow:window];
|
||||
[nscontext updateIfNeeded];
|
||||
}
|
||||
[nscontext makeCurrentContext];
|
||||
} else {
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)SDL_GL_GetCurrentContext();
|
||||
int status;
|
||||
|
||||
if (nscontext == nil) {
|
||||
status = SDL_SetError("No current OpenGL context");
|
||||
} else {
|
||||
SDL_LockMutex(nscontext->swapIntervalMutex);
|
||||
SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
|
||||
SDL_AtomicSet(&nscontext->swapIntervalSetting, interval);
|
||||
SDL_UnlockMutex(nscontext->swapIntervalMutex);
|
||||
status = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)SDL_GL_GetCurrentContext();
|
||||
if (nscontext) {
|
||||
*interval = SDL_AtomicGet(&nscontext->swapIntervalSetting);
|
||||
return 0;
|
||||
} else {
|
||||
return SDL_SetError("no OpenGL context");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)SDL_GL_GetCurrentContext();
|
||||
SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
const int setting = SDL_AtomicGet(&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_AtomicGet(&nscontext->swapIntervalsPassed) == 0) {
|
||||
SDL_WaitCondition(nscontext->swapIntervalCond, nscontext->swapIntervalMutex);
|
||||
}
|
||||
SDL_AtomicSet(&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_AtomicGet(&nscontext->swapIntervalsPassed) % setting) != 0);
|
||||
SDL_AtomicSet(&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 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)context;
|
||||
[nscontext cleanup];
|
||||
CFRelease(context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 */
|
48
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengles.h
vendored
Normal file
48
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengles.h
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 int Cocoa_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern SDL_GLContext Cocoa_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int Cocoa_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int Cocoa_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
|
||||
extern int Cocoa_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
extern int 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_ */
|
156
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengles.m
vendored
Normal file
156
external/sdl/SDL/src/video/cocoa/SDL_cocoaopengles.m
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 */
|
||||
|
||||
int 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_DeleteContext = Cocoa_GL_DeleteContext;
|
||||
_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 0;
|
||||
}
|
||||
|
||||
SDL_GLContext Cocoa_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_GLContext context;
|
||||
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
|
||||
|
||||
#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_DeleteContext = Cocoa_GL_DeleteContext;
|
||||
_this->GL_GetEGLSurface = NULL;
|
||||
|
||||
if (Cocoa_GL_LoadLibrary(_this, NULL) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Cocoa_GL_CreateContext(_this, window);
|
||||
}
|
||||
#endif
|
||||
|
||||
context = SDL_EGL_CreateContext(_this, data.egl_surface);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_EGL_DeleteContext(_this, context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Cocoa_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
return SDL_EGL_SwapBuffers(_this, ((__bridge SDL_CocoaWindowData *)window->driverdata).egl_surface);
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
|
||||
{
|
||||
@autoreleasepool {
|
||||
return SDL_EGL_MakeCurrent(_this, window ? ((__bridge SDL_CocoaWindowData *)window->driverdata).egl_surface : EGL_NO_SURFACE, context);
|
||||
}
|
||||
}
|
||||
|
||||
int 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->driverdata;
|
||||
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) < 0) {
|
||||
SDL_EGL_UnloadLibrary(_this);
|
||||
return -1;
|
||||
}
|
||||
_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->driverdata).egl_surface;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA && SDL_VIDEO_OPENGL_EGL */
|
38
external/sdl/SDL/src/video/cocoa/SDL_cocoashape.h
vendored
Normal file
38
external/sdl/SDL/src/video/cocoa/SDL_cocoashape.h
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_
|
||||
|
||||
#include "../SDL_shape_internals.h"
|
||||
|
||||
@interface SDL_ShapeData : NSObject
|
||||
@property(nonatomic) NSGraphicsContext *context;
|
||||
@property(nonatomic) SDL_bool saved;
|
||||
@property(nonatomic) SDL_ShapeTree *shape;
|
||||
@end
|
||||
|
||||
extern SDL_WindowShaper *Cocoa_CreateShaper(SDL_Window *window);
|
||||
extern int Cocoa_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode);
|
||||
|
||||
#endif /* SDL_cocoashape_h_ */
|
115
external/sdl/SDL/src/video/cocoa/SDL_cocoashape.m
vendored
Normal file
115
external/sdl/SDL/src/video/cocoa/SDL_cocoashape.m
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
@implementation SDL_ShapeData
|
||||
@end
|
||||
|
||||
@interface SDL_CocoaClosure : NSObject
|
||||
@property(nonatomic) NSView *view;
|
||||
@property(nonatomic) NSBezierPath *path;
|
||||
@property(nonatomic) SDL_Window *window;
|
||||
@end
|
||||
|
||||
@implementation SDL_CocoaClosure
|
||||
@end
|
||||
|
||||
SDL_WindowShaper *Cocoa_CreateShaper(SDL_Window *window)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_WindowShaper *result;
|
||||
SDL_ShapeData *data;
|
||||
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->driverdata;
|
||||
|
||||
result = (SDL_WindowShaper *)SDL_malloc(sizeof(SDL_WindowShaper));
|
||||
if (!result) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
[windata.nswindow setOpaque:NO];
|
||||
|
||||
[windata.nswindow setStyleMask:NSWindowStyleMaskBorderless];
|
||||
|
||||
result->window = window;
|
||||
result->mode.mode = ShapeModeDefault;
|
||||
result->mode.parameters.binarizationCutoff = 1;
|
||||
window->shaper = result;
|
||||
|
||||
data = [[SDL_ShapeData alloc] init];
|
||||
data.context = [windata.nswindow graphicsContext];
|
||||
data.saved = SDL_FALSE;
|
||||
data.shape = NULL;
|
||||
|
||||
/* TODO: There's no place to release this... */
|
||||
result->driverdata = (void *)CFBridgingRetain(data);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertRects(SDL_ShapeTree *tree, void *closure)
|
||||
{
|
||||
SDL_CocoaClosure *data = (__bridge SDL_CocoaClosure *)closure;
|
||||
if (tree->kind == OpaqueShape) {
|
||||
NSRect rect = NSMakeRect(tree->data.shape.x, data.window->h - tree->data.shape.y, tree->data.shape.w, tree->data.shape.h);
|
||||
[data.path appendBezierPathWithRect:[data.view convertRect:rect toView:nil]];
|
||||
}
|
||||
}
|
||||
|
||||
int Cocoa_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_ShapeData *data = (__bridge SDL_ShapeData *)shaper->driverdata;
|
||||
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)shaper->window->driverdata;
|
||||
SDL_CocoaClosure *closure;
|
||||
if (data.saved == SDL_TRUE) {
|
||||
[data.context restoreGraphicsState];
|
||||
data.saved = SDL_FALSE;
|
||||
}
|
||||
|
||||
/*[data.context saveGraphicsState];*/
|
||||
/*data.saved = SDL_TRUE;*/
|
||||
[NSGraphicsContext setCurrentContext:data.context];
|
||||
|
||||
[[NSColor clearColor] set];
|
||||
NSRectFill([windata.sdlContentView frame]);
|
||||
data.shape = SDL_CalculateShapeTree(*shape_mode, shape);
|
||||
|
||||
closure = [[SDL_CocoaClosure alloc] init];
|
||||
|
||||
closure.view = windata.sdlContentView;
|
||||
closure.path = [NSBezierPath bezierPath];
|
||||
closure.window = shaper->window;
|
||||
SDL_TraverseShapeTree(data.shape, &ConvertRects, (__bridge void *)closure);
|
||||
[closure.path addClip];
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
119
external/sdl/SDL/src/video/cocoa/SDL_cocoavideo.h
vendored
Normal file
119
external/sdl/SDL/src/video/cocoa/SDL_cocoavideo.h
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 <SDL3/SDL_opengl.h>
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
#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"
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_12
|
||||
#define DECLARE_EVENT(name) static const NSEventType NSEventType##name = NS##name
|
||||
DECLARE_EVENT(LeftMouseDown);
|
||||
DECLARE_EVENT(LeftMouseUp);
|
||||
DECLARE_EVENT(RightMouseDown);
|
||||
DECLARE_EVENT(RightMouseUp);
|
||||
DECLARE_EVENT(OtherMouseDown);
|
||||
DECLARE_EVENT(OtherMouseUp);
|
||||
DECLARE_EVENT(MouseMoved);
|
||||
DECLARE_EVENT(LeftMouseDragged);
|
||||
DECLARE_EVENT(RightMouseDragged);
|
||||
DECLARE_EVENT(OtherMouseDragged);
|
||||
DECLARE_EVENT(ScrollWheel);
|
||||
DECLARE_EVENT(KeyDown);
|
||||
DECLARE_EVENT(KeyUp);
|
||||
DECLARE_EVENT(FlagsChanged);
|
||||
#undef DECLARE_EVENT
|
||||
|
||||
static const NSEventMask NSEventMaskAny = NSAnyEventMask;
|
||||
|
||||
#define DECLARE_MODIFIER_FLAG(name) static const NSUInteger NSEventModifierFlag##name = NS##name##KeyMask
|
||||
DECLARE_MODIFIER_FLAG(Shift);
|
||||
DECLARE_MODIFIER_FLAG(Control);
|
||||
DECLARE_MODIFIER_FLAG(Command);
|
||||
DECLARE_MODIFIER_FLAG(NumericPad);
|
||||
DECLARE_MODIFIER_FLAG(Help);
|
||||
DECLARE_MODIFIER_FLAG(Function);
|
||||
#undef DECLARE_MODIFIER_FLAG
|
||||
static const NSUInteger NSEventModifierFlagCapsLock = NSAlphaShiftKeyMask;
|
||||
static const NSUInteger NSEventModifierFlagOption = NSAlternateKeyMask;
|
||||
|
||||
#define DECLARE_WINDOW_MASK(name) static const unsigned int NSWindowStyleMask##name = NS##name##WindowMask
|
||||
DECLARE_WINDOW_MASK(Borderless);
|
||||
DECLARE_WINDOW_MASK(Titled);
|
||||
DECLARE_WINDOW_MASK(Closable);
|
||||
DECLARE_WINDOW_MASK(Miniaturizable);
|
||||
DECLARE_WINDOW_MASK(Resizable);
|
||||
DECLARE_WINDOW_MASK(TexturedBackground);
|
||||
DECLARE_WINDOW_MASK(UnifiedTitleAndToolbar);
|
||||
DECLARE_WINDOW_MASK(FullScreen);
|
||||
/*DECLARE_WINDOW_MASK(FullSizeContentView);*/ /* Not used, fails compile on older SDKs */
|
||||
static const unsigned int NSWindowStyleMaskUtilityWindow = NSUtilityWindowMask;
|
||||
static const unsigned int NSWindowStyleMaskDocModalWindow = NSDocModalWindowMask;
|
||||
static const unsigned int NSWindowStyleMaskHUDWindow = NSHUDWindowMask;
|
||||
#undef DECLARE_WINDOW_MASK
|
||||
|
||||
#define DECLARE_ALERT_STYLE(name) static const NSUInteger NSAlertStyle##name = NS##name##AlertStyle
|
||||
DECLARE_ALERT_STYLE(Warning);
|
||||
DECLARE_ALERT_STYLE(Informational);
|
||||
DECLARE_ALERT_STYLE(Critical);
|
||||
#undef DECLARE_ALERT_STYLE
|
||||
#endif
|
||||
|
||||
/* Private display data */
|
||||
|
||||
@class SDLTranslatorResponder;
|
||||
|
||||
@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) SDLTranslatorResponder *fieldEdit;
|
||||
@property(nonatomic) NSInteger clipboard_count;
|
||||
@property(nonatomic) IOPMAssertionID screensaver_assertion;
|
||||
@property(nonatomic) SDL_Mutex *swaplock;
|
||||
@end
|
||||
|
||||
/* Utility functions */
|
||||
extern SDL_SystemTheme Cocoa_GetSystemTheme(void);
|
||||
extern NSImage *Cocoa_CreateImage(SDL_Surface *surface);
|
||||
|
||||
/* Fix build with the 10.11 SDK */
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||
#define NSEventSubtypeMouseEvent NSMouseEventSubtype
|
||||
#endif
|
||||
|
||||
#endif /* SDL_cocoavideo_h_ */
|
314
external/sdl/SDL/src/video/cocoa/SDL_cocoavideo.m
vendored
Normal file
314
external/sdl/SDL/src/video/cocoa/SDL_cocoavideo.m
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_cocoashape.h"
|
||||
#include "SDL_cocoavulkan.h"
|
||||
#include "SDL_cocoametalview.h"
|
||||
#include "SDL_cocoaopengles.h"
|
||||
|
||||
@implementation SDL_CocoaVideoData
|
||||
|
||||
@end
|
||||
|
||||
/* Initialization/Query functions */
|
||||
static int 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->driverdata);
|
||||
SDL_free(device);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_VideoDevice *Cocoa_CreateDevice(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_VideoDevice *device;
|
||||
SDL_CocoaVideoData *data;
|
||||
|
||||
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_OutOfMemory();
|
||||
SDL_free(device);
|
||||
return NULL;
|
||||
}
|
||||
device->driverdata = (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->CreateSDLWindowFrom = Cocoa_CreateWindowFrom;
|
||||
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->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->GetWindowWMInfo = Cocoa_GetWindowWMInfo;
|
||||
device->SetWindowHitTest = Cocoa_SetWindowHitTest;
|
||||
device->AcceptDragAndDrop = Cocoa_AcceptDragAndDrop;
|
||||
device->FlashWindow = Cocoa_FlashWindow;
|
||||
|
||||
device->shape_driver.CreateShaper = Cocoa_CreateShaper;
|
||||
device->shape_driver.SetWindowShape = Cocoa_SetWindowShape;
|
||||
|
||||
#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_DeleteContext = Cocoa_GL_DeleteContext;
|
||||
device->GL_GetEGLSurface = NULL;
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
#ifdef SDL_VIDEO_OPENGL_CGL
|
||||
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_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_DeleteContext = Cocoa_GLES_DeleteContext;
|
||||
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;
|
||||
#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->SetTextInputRect = Cocoa_SetTextInputRect;
|
||||
|
||||
device->SetClipboardData = Cocoa_SetClipboardData;
|
||||
device->GetClipboardData = Cocoa_GetClipboardData;
|
||||
device->HasClipboardData = Cocoa_HasClipboardData;
|
||||
|
||||
device->free = Cocoa_DeleteDevice;
|
||||
|
||||
device->quirk_flags = VIDEO_DEVICE_QUIRK_HAS_POPUP_WINDOW_SUPPORT;
|
||||
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
VideoBootStrap COCOA_bootstrap = {
|
||||
"cocoa", "SDL Cocoa video driver",
|
||||
Cocoa_CreateDevice
|
||||
};
|
||||
|
||||
int Cocoa_VideoInit(SDL_VideoDevice *_this)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
|
||||
Cocoa_InitModes(_this);
|
||||
Cocoa_InitKeyboard(_this);
|
||||
if (Cocoa_InitMouse(_this) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.allow_spaces = SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, SDL_TRUE);
|
||||
data.trackpad_is_touch_only = SDL_GetHintBoolean(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, SDL_FALSE);
|
||||
|
||||
data.swaplock = SDL_CreateMutex();
|
||||
if (!data.swaplock) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Cocoa_VideoQuit(SDL_VideoDevice *_this)
|
||||
{
|
||||
@autoreleasepool {
|
||||
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
|
||||
Cocoa_QuitModes(_this);
|
||||
Cocoa_QuitKeyboard(_this);
|
||||
Cocoa_QuitMouse(_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 MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 /* Added in the 10.14.0 SDK. */
|
||||
if ([[NSApplication sharedApplication] respondsToSelector:@selector(effectiveAppearance)]) {
|
||||
NSAppearance* appearance = [[NSApplication sharedApplication] effectiveAppearance];
|
||||
|
||||
if ([appearance.name containsString: @"Dark"]) {
|
||||
return SDL_SYSTEM_THEME_DARK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return SDL_SYSTEM_THEME_LIGHT;
|
||||
}
|
||||
|
||||
/* This function assumes that it's called from within an autorelease pool */
|
||||
NSImage *Cocoa_CreateImage(SDL_Surface *surface)
|
||||
{
|
||||
SDL_Surface *converted;
|
||||
NSBitmapImageRep *imgrep;
|
||||
Uint8 *pixels;
|
||||
int i;
|
||||
NSImage *img;
|
||||
|
||||
converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!converted) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
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:converted->format->BitsPerPixel];
|
||||
if (imgrep == nil) {
|
||||
SDL_DestroySurface(converted);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* Copy the pixels */
|
||||
pixels = [imgrep bitmapData];
|
||||
SDL_memcpy(pixels, converted->pixels, (size_t)converted->h * converted->pitch);
|
||||
SDL_DestroySurface(converted);
|
||||
|
||||
/* Premultiply the alpha channel */
|
||||
for (i = (surface->h * surface->w); i--;) {
|
||||
Uint8 alpha = pixels[3];
|
||||
pixels[0] = (Uint8)(((Uint16)pixels[0] * alpha) / 255);
|
||||
pixels[1] = (Uint8)(((Uint16)pixels[1] * alpha) / 255);
|
||||
pixels[2] = (Uint8)(((Uint16)pixels[2] * alpha) / 255);
|
||||
pixels += 4;
|
||||
}
|
||||
|
||||
img = [[NSImage alloc] initWithSize:NSMakeSize(surface->w, surface->h)];
|
||||
if (img != nil) {
|
||||
[img addRepresentation:imgrep];
|
||||
}
|
||||
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) {
|
||||
NSString *nsPrefix = [NSString stringWithUTF8String:prefix];
|
||||
NSLog(@"%@: %@", nsPrefix, nsText);
|
||||
} else {
|
||||
NSLog(@"%@", nsText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
49
external/sdl/SDL/src/video/cocoa/SDL_cocoavulkan.h
vendored
Normal file
49
external/sdl/SDL/src/video/cocoa/SDL_cocoavulkan.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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)
|
||||
|
||||
int Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
SDL_bool Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
|
||||
unsigned *count,
|
||||
const char **names);
|
||||
SDL_bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR *surface);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SDL_cocoavulkan_h_ */
|
304
external/sdl/SDL/src/video/cocoa/SDL_cocoavulkan.m
vendored
Normal file
304
external/sdl/SDL/src/video/cocoa/SDL_cocoavulkan.m
vendored
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 <SDL3/SDL_syswm.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
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
|
||||
|
||||
int Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
VkExtensionProperties *extensions = NULL;
|
||||
Uint32 extensionCount = 0;
|
||||
SDL_bool hasSurfaceExtension = SDL_FALSE;
|
||||
SDL_bool hasMetalSurfaceExtension = SDL_FALSE;
|
||||
SDL_bool hasMacOSSurfaceExtension = SDL_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_getenv("SDL_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 = SDL_TRUE;
|
||||
} else if (SDL_strcmp(VK_EXT_METAL_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasMetalSurfaceExtension = SDL_TRUE;
|
||||
} else if (SDL_strcmp(VK_MVK_MACOS_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasMacOSSurfaceExtension = SDL_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 0;
|
||||
|
||||
fail:
|
||||
SDL_UnloadObject(_this->vulkan_config.loader_handle);
|
||||
_this->vulkan_config.loader_handle = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
|
||||
unsigned *count,
|
||||
const char **names)
|
||||
{
|
||||
static const char *const extensionsForCocoa[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_EXTENSION_NAME
|
||||
};
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
SDL_SetError("Vulkan is not loaded");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_Vulkan_GetInstanceExtensions_Helper(
|
||||
count, names, SDL_arraysize(extensionsForCocoa),
|
||||
extensionsForCocoa);
|
||||
}
|
||||
|
||||
static SDL_bool Cocoa_Vulkan_CreateSurfaceViaMetalView(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR *surface,
|
||||
PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT,
|
||||
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK)
|
||||
{
|
||||
VkResult result;
|
||||
SDL_MetalView metalview = Cocoa_Metal_CreateView(_this, window);
|
||||
if (metalview == NULL) {
|
||||
return SDL_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);
|
||||
result = vkCreateMetalSurfaceEXT(instance, &createInfo, NULL, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
Cocoa_Metal_DestroyView(_this, metalview);
|
||||
SDL_SetError("vkCreateMetalSurfaceEXT failed: %s",
|
||||
SDL_Vulkan_GetResultString(result));
|
||||
return SDL_FALSE;
|
||||
}
|
||||
} else {
|
||||
VkMacOSSurfaceCreateInfoMVK createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
|
||||
createInfo.pNext = NULL;
|
||||
createInfo.flags = 0;
|
||||
createInfo.pView = (const void *)metalview;
|
||||
result = vkCreateMacOSSurfaceMVK(instance, &createInfo,
|
||||
NULL, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
Cocoa_Metal_DestroyView(_this, metalview);
|
||||
SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s",
|
||||
SDL_Vulkan_GetResultString(result));
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
CFBridgingRelease(metalview);
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
SDL_bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
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 result;
|
||||
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
SDL_SetError("Vulkan is not loaded");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!vkCreateMetalSurfaceEXT && !vkCreateMacOSSurfaceMVK) {
|
||||
SDL_SetError(VK_EXT_METAL_SURFACE_EXTENSION_NAME " or " VK_MVK_MACOS_SURFACE_EXTENSION_NAME
|
||||
" extensions are not enabled in the Vulkan instance.");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (window->flags & SDL_WINDOW_FOREIGN) {
|
||||
@autoreleasepool {
|
||||
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
|
||||
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;
|
||||
result = vkCreateMetalSurfaceEXT(instance, &createInfo, NULL, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
SDL_SetError("vkCreateMetalSurfaceEXT failed: %s",
|
||||
SDL_Vulkan_GetResultString(result));
|
||||
return SDL_FALSE;
|
||||
}
|
||||
} 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;
|
||||
result = vkCreateMacOSSurfaceMVK(instance, &createInfo,
|
||||
NULL, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s",
|
||||
SDL_Vulkan_GetResultString(result));
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Cocoa_Vulkan_CreateSurfaceViaMetalView(_this, window, instance, surface, vkCreateMetalSurfaceEXT, vkCreateMacOSSurfaceMVK);
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
#endif
|
173
external/sdl/SDL/src/video/cocoa/SDL_cocoawindow.h
vendored
Normal file
173
external/sdl/SDL/src/video/cocoa/SDL_cocoawindow.h
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 <Cocoa/Cocoa.h>
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
#include "../SDL_egl_c.h"
|
||||
#endif
|
||||
|
||||
@class SDL_CocoaWindowData;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PENDING_OPERATION_NONE,
|
||||
PENDING_OPERATION_ENTER_FULLSCREEN,
|
||||
PENDING_OPERATION_LEAVE_FULLSCREEN,
|
||||
PENDING_OPERATION_MINIMIZE
|
||||
} PendingWindowOperation;
|
||||
|
||||
@interface Cocoa_WindowListener : NSResponder <NSWindowDelegate>
|
||||
{
|
||||
/* 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;
|
||||
NSInteger focusClickPending;
|
||||
float pendingWindowWarpX, pendingWindowWarpY;
|
||||
BOOL isDragAreaRunning;
|
||||
}
|
||||
|
||||
- (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)setPendingMoveX:(float)x Y:(float)y;
|
||||
- (void)windowDidFinishMoving;
|
||||
- (void)onMovingOrFocusClickPendingStateCleared;
|
||||
|
||||
/* Window delegate functionality */
|
||||
- (BOOL)windowShouldClose:(id)sender;
|
||||
- (void)windowDidExpose:(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. */
|
||||
- (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;
|
||||
|
||||
@end
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@class SDLOpenGLContext;
|
||||
@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) SDL_bool created;
|
||||
@property(nonatomic) SDL_bool inWindowFullscreenTransition;
|
||||
@property(nonatomic) NSInteger window_number;
|
||||
@property(nonatomic) NSInteger flash_request;
|
||||
@property(nonatomic) SDL_Window *keyboard_focus;
|
||||
@property(nonatomic) Cocoa_WindowListener *listener;
|
||||
@property(nonatomic) SDL_CocoaVideoData *videodata;
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
@property(nonatomic) EGLSurface egl_surface;
|
||||
#endif
|
||||
@end
|
||||
|
||||
extern int Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int Cocoa_CreateWindowFrom(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
const void *data);
|
||||
extern void Cocoa_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int Cocoa_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
|
||||
extern int 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_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||
extern int 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, SDL_bool bordered);
|
||||
extern void Cocoa_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable);
|
||||
extern void Cocoa_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool on_top);
|
||||
extern void Cocoa_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool 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 void Cocoa_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Cocoa_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
|
||||
extern void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int Cocoa_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, struct SDL_SysWMinfo *info);
|
||||
extern int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||
extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
|
||||
extern int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
|
||||
#endif /* SDL_cocoawindow_h_ */
|
2674
external/sdl/SDL/src/video/cocoa/SDL_cocoawindow.m
vendored
Normal file
2674
external/sdl/SDL/src/video/cocoa/SDL_cocoawindow.m
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user