early-access version 1611

This commit is contained in:
pineappleEA
2021-04-18 05:35:25 +02:00
parent 16f54e367d
commit 18db69f039
1409 changed files with 545335 additions and 10 deletions

View File

@@ -0,0 +1,36 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 */
struct SDL_VideoData;
extern int Cocoa_SetClipboardText(_THIS, const char *text);
extern char *Cocoa_GetClipboardText(_THIS);
extern SDL_bool Cocoa_HasClipboardText(_THIS);
extern void Cocoa_CheckClipboardUpdate(struct SDL_VideoData * data);
#endif /* SDL_cocoaclipboard_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,103 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
#include "../../events/SDL_clipboardevents_c.h"
int
Cocoa_SetClipboardText(_THIS, const char *text)
{ @autoreleasepool
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
NSPasteboard *pasteboard;
NSString *format = NSPasteboardTypeString;
pasteboard = [NSPasteboard generalPasteboard];
data->clipboard_count = [pasteboard declareTypes:[NSArray arrayWithObject:format] owner:nil];
[pasteboard setString:[NSString stringWithUTF8String:text] forType:format];
return 0;
}}
char *
Cocoa_GetClipboardText(_THIS)
{ @autoreleasepool
{
NSPasteboard *pasteboard;
NSString *format = NSPasteboardTypeString;
NSString *available;
char *text;
pasteboard = [NSPasteboard generalPasteboard];
available = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:format]];
if ([available isEqualToString:format]) {
NSString* string;
const char *utf8;
string = [pasteboard stringForType:format];
if (string == nil) {
utf8 = "";
} else {
utf8 = [string UTF8String];
}
text = SDL_strdup(utf8);
} else {
text = SDL_strdup("");
}
return text;
}}
SDL_bool
Cocoa_HasClipboardText(_THIS)
{
SDL_bool result = SDL_FALSE;
char *text = Cocoa_GetClipboardText(_this);
if (text) {
result = text[0] != '\0' ? SDL_TRUE : SDL_FALSE;
SDL_free(text);
}
return result;
}
void
Cocoa_CheckClipboardUpdate(struct SDL_VideoData * 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;
}
}}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,32 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 void Cocoa_PumpEvents(_THIS);
extern void Cocoa_SuspendScreenSaver(_THIS);
#endif /* SDL_cocoaevents_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,511 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
#include "SDL_timer.h"
#include "SDL_cocoavideo.h"
#include "../../events/SDL_events_c.h"
#include "SDL_assert.h"
#include "SDL_hints.h"
/* This define was added in the 10.9 SDK. */
#ifndef kIOPMAssertPreventUserIdleDisplaySleep
#define kIOPMAssertPreventUserIdleDisplaySleep kIOPMAssertionTypePreventUserIdleDisplaySleep
#endif
@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];
[appDefaults release];
}
@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;
@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];
}
return self;
}
- (void)dealloc
{
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self name:NSWindowWillCloseNotification object:nil];
[center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil];
[super dealloc];
}
- (void)windowWillClose:(NSNotification *)notification;
{
NSWindow *win = (NSWindow*)[notification object];
if (![win isKeyWindow]) {
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
{
/* 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;
}
SDL_VideoDevice *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);
}
}
}
- (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];
}
@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];
[mainMenu release]; /* we're done with it, let NSApp own it. */
mainMenu = nil;
/* 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 = (NSMenuItem *)[appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
[menuItem setSubmenu:serviceMenu];
[NSApp setServicesMenu:serviceMenu];
[serviceMenu release];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
menuItem = (NSMenuItem *)[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];
[menuItem release];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
[appleMenu release];
/* 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, if supported */
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) {
/* 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];
[menuItem release];
}
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
[menuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:menuItem];
[menuItem release];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
[windowMenu release];
}
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]) {
[(NSApplication *)NSApp setDelegate:appDelegate];
} else {
appDelegate->seenFirstActivate = YES;
}
}
}}
void
Cocoa_PumpEvents(_THIS)
{ @autoreleasepool
{
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
/* Update activity every 30 seconds to prevent screensaver */
SDL_VideoData *data = (SDL_VideoData *)_this->driverdata;
if (_this->suspend_screensaver && !data->screensaver_use_iopm) {
Uint32 now = SDL_GetTicks();
if (!data->screensaver_activity ||
SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) {
UpdateSystemActivity(UsrActivity);
data->screensaver_activity = now;
}
}
#endif
for ( ; ; ) {
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES ];
if ( event == nil ) {
break;
}
if (!s_bShouldHandleEventsInSDLApplication) {
Cocoa_DispatchEvent(event);
}
// Pass events down to SDLApplication to be handled in sendEvent:
[NSApp sendEvent:event];
}
}}
void
Cocoa_SuspendScreenSaver(_THIS)
{ @autoreleasepool
{
SDL_VideoData *data = (SDL_VideoData *)_this->driverdata;
if (!data->screensaver_use_iopm) {
return;
}
if (data->screensaver_assertion) {
IOPMAssertionRelease(data->screensaver_assertion);
data->screensaver_assertion = 0;
}
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 OS X power users. there's an additional optional human-readable
* (localized) reason parameter which we don't set.
*/
NSString *name = [GetApplicationName() stringByAppendingString:@" using SDL_DisableScreenSaver"];
IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep,
(CFStringRef) name,
NULL, NULL, NULL, 0, NULL,
&data->screensaver_assertion);
}
}}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,36 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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(_THIS);
extern void Cocoa_HandleKeyEvent(_THIS, NSEvent * event);
extern void Cocoa_QuitKeyboard(_THIS);
extern void Cocoa_StartTextInput(_THIS);
extern void Cocoa_StopTextInput(_THIS);
extern void Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect);
#endif /* SDL_cocoakeyboard_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,607 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 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:(SDL_Rect *)rect;
@end
@implementation SDLTranslatorResponder
- (void)setInputRect:(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];
}
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 release];
_markedText = [aString retain];
}
_selectedRange = selectedRange;
_markedRange = NSMakeRange(0, [aString length]);
SDL_SendEditingText([aString UTF8String],
(int) selectedRange.location, (int) selectedRange.length);
DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText,
selRange.location, selRange.length);
}
- (void)unmarkText
{
[_markedText release];
_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));
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
if (![window respondsToSelector:@selector(convertRectToScreen:)]) {
rect.origin = [window convertBaseToScreen:rect.origin];
} else
#endif
{
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
/* This is a helper function for HandleModifierSide. This
* function reverts back to behavior before the distinction between
* sides was made.
*/
static void
HandleNonDeviceModifier(unsigned int device_independent_mask,
unsigned int oldMods,
unsigned int newMods,
SDL_Scancode scancode)
{
unsigned int oldMask, newMask;
/* Isolate just the bits we care about in the depedent bits so we can
* figure out what changed
*/
oldMask = oldMods & device_independent_mask;
newMask = newMods & device_independent_mask;
if (oldMask && oldMask != newMask) {
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
} else if (newMask && oldMask != newMask) {
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
}
}
/* This is a helper function for HandleModifierSide.
* This function sets the actual SDL_PrivateKeyboard event.
*/
static void
HandleModifierOneSide(unsigned int oldMods, unsigned int newMods,
SDL_Scancode scancode,
unsigned int sided_device_dependent_mask)
{
unsigned int old_dep_mask, new_dep_mask;
/* Isolate just the bits we care about in the depedent bits so we can
* figure out what changed
*/
old_dep_mask = oldMods & sided_device_dependent_mask;
new_dep_mask = newMods & sided_device_dependent_mask;
/* We now know that this side bit flipped. But we don't know if
* it went pressed to released or released to pressed, so we must
* find out which it is.
*/
if (new_dep_mask && old_dep_mask != new_dep_mask) {
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
} else {
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
}
}
/* This is a helper function for DoSidedModifiers.
* This function will figure out if the modifier key is the left or right side,
* e.g. left-shift vs right-shift.
*/
static void
HandleModifierSide(int device_independent_mask,
unsigned int oldMods, unsigned int newMods,
SDL_Scancode left_scancode,
SDL_Scancode right_scancode,
unsigned int left_device_dependent_mask,
unsigned int right_device_dependent_mask)
{
unsigned int device_dependent_mask = (left_device_dependent_mask |
right_device_dependent_mask);
unsigned int diff_mod;
/* On the basis that the device independent mask is set, but there are
* no device dependent flags set, we'll assume that we can't detect this
* keyboard and revert to the unsided behavior.
*/
if ((device_dependent_mask & newMods) == 0) {
/* Revert to the old behavior */
HandleNonDeviceModifier(device_independent_mask, oldMods, newMods, left_scancode);
return;
}
/* XOR the previous state against the new state to see if there's a change */
diff_mod = (device_dependent_mask & oldMods) ^
(device_dependent_mask & newMods);
if (diff_mod) {
/* A change in state was found. Isolate the left and right bits
* to handle them separately just in case the values can simulataneously
* change or if the bits don't both exist.
*/
if (left_device_dependent_mask & diff_mod) {
HandleModifierOneSide(oldMods, newMods, left_scancode, left_device_dependent_mask);
}
if (right_device_dependent_mask & diff_mod) {
HandleModifierOneSide(oldMods, newMods, right_scancode, right_device_dependent_mask);
}
}
}
/* This is a helper function for DoSidedModifiers.
* This function will release a key press in the case that
* it is clear that the modifier has been released (i.e. one side
* can't still be down).
*/
static void
ReleaseModifierSide(unsigned int device_independent_mask,
unsigned int oldMods, unsigned int newMods,
SDL_Scancode left_scancode,
SDL_Scancode right_scancode,
unsigned int left_device_dependent_mask,
unsigned int right_device_dependent_mask)
{
unsigned int device_dependent_mask = (left_device_dependent_mask |
right_device_dependent_mask);
/* On the basis that the device independent mask is set, but there are
* no device dependent flags set, we'll assume that we can't detect this
* keyboard and revert to the unsided behavior.
*/
if ((device_dependent_mask & oldMods) == 0) {
/* In this case, we can't detect the keyboard, so use the left side
* to represent both, and release it.
*/
SDL_SendKeyboardKey(SDL_RELEASED, left_scancode);
return;
}
/*
* This could have been done in an if-else case because at this point,
* we know that all keys have been released when calling this function.
* But I'm being paranoid so I want to handle each separately,
* so I hope this doesn't cause other problems.
*/
if ( left_device_dependent_mask & oldMods ) {
SDL_SendKeyboardKey(SDL_RELEASED, left_scancode);
}
if ( right_device_dependent_mask & oldMods ) {
SDL_SendKeyboardKey(SDL_RELEASED, right_scancode);
}
}
/* This function will handle the modifier keys and also determine the
* correct side of the key.
*/
static void
DoSidedModifiers(unsigned short scancode,
unsigned int oldMods, unsigned int newMods)
{
/* Set up arrays for the key syms for the left and right side. */
const SDL_Scancode left_mapping[] = {
SDL_SCANCODE_LSHIFT,
SDL_SCANCODE_LCTRL,
SDL_SCANCODE_LALT,
SDL_SCANCODE_LGUI
};
const SDL_Scancode right_mapping[] = {
SDL_SCANCODE_RSHIFT,
SDL_SCANCODE_RCTRL,
SDL_SCANCODE_RALT,
SDL_SCANCODE_RGUI
};
/* Set up arrays for the device dependent masks with indices that
* correspond to the _mapping arrays
*/
const unsigned int left_device_mapping[] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK };
const unsigned int right_device_mapping[] = { NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
unsigned int i, bit;
/* Iterate through the bits, testing each against the old modifiers */
for (i = 0, bit = NSEventModifierFlagShift; bit <= NSEventModifierFlagCommand; bit <<= 1, ++i) {
unsigned int oldMask, newMask;
oldMask = oldMods & bit;
newMask = newMods & bit;
/* If the bit is set, we must always examine it because the left
* and right side keys may alternate or both may be pressed.
*/
if (newMask) {
HandleModifierSide(bit, oldMods, newMods,
left_mapping[i], right_mapping[i],
left_device_mapping[i], right_device_mapping[i]);
}
/* If the state changed from pressed to unpressed, we must examine
* the device dependent bits to release the correct keys.
*/
else if (oldMask && oldMask != newMask) {
ReleaseModifierSide(bit, oldMods, newMods,
left_mapping[i], right_mapping[i],
left_device_mapping[i], right_device_mapping[i]);
}
}
}
static void
HandleModifiers(_THIS, unsigned short scancode, unsigned int modifierFlags)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
if (modifierFlags == data->modifierFlags) {
return;
}
DoSidedModifiers(scancode, data->modifierFlags, modifierFlags);
data->modifierFlags = modifierFlags;
}
static void
UpdateKeymap(SDL_VideoData *data, SDL_bool send_event)
{
TISInputSourceRef key_layout;
const void *chr_data;
int i;
SDL_Scancode scancode;
SDL_Keycode keymap[SDL_NUM_SCANCODES];
/* 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 */
CFDataRef 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;
}
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);
if (send_event) {
SDL_SendKeymapChangedEvent();
}
return;
}
cleanup:
CFRelease(key_layout);
}
void
Cocoa_InitKeyboard(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _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(KMOD_CAPS, (data->modifierFlags & NSEventModifierFlagCapsLock) != 0);
}
void
Cocoa_StartTextInput(_THIS)
{ @autoreleasepool
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
SDL_Window *window = SDL_GetKeyboardFocus();
NSWindow *nswindow = nil;
if (window) {
nswindow = ((SDL_WindowData*)window->driverdata)->nswindow;
}
NSView *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(_THIS)
{ @autoreleasepool
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
if (data && data->fieldEdit) {
[data->fieldEdit removeFromSuperview];
[data->fieldEdit release];
data->fieldEdit = nil;
}
}}
void
Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
if (!rect) {
SDL_InvalidParamError("rect");
return;
}
[data->fieldEdit setInputRect:rect];
}
void
Cocoa_HandleKeyEvent(_THIS, NSEvent *event)
{
SDL_VideoData *data = _this ? ((SDL_VideoData *) _this->driverdata) : NULL;
if (!data) {
return; /* can happen when returning from fullscreen Space on shutdown */
}
unsigned short scancode = [event keyCode];
SDL_Scancode code;
#if 0
const char *text;
#endif
if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
/* see comments in SDL_cocoakeys.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(SDL_PRESSED, code);
#if 1
if (code == SDL_SCANCODE_UNKNOWN) {
fprintf(stderr, "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_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
/* 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(SDL_RELEASED, code);
break;
case NSEventTypeFlagsChanged:
/* FIXME CW 2007-08-14: check if this whole mess that takes up half of this file is really necessary */
HandleModifiers(_this, scancode, (unsigned int)[event modifierFlags]);
break;
default: /* just to avoid compiler warnings */
break;
}
}
void
Cocoa_QuitKeyboard(_THIS)
{
}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,29 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
extern int Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,157 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
#include "SDL_events.h"
#include "SDL_timer.h"
#include "SDL_messagebox.h"
#include "SDL_cocoavideo.h"
@interface SDLMessageBoxPresenter : NSObject {
@public
NSInteger clicked;
NSWindow *nswindow;
}
- (id) initWithParentWindow:(SDL_Window *)window;
- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
@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 = [((SDL_WindowData *) window->driverdata)->nswindow retain];
} else {
nswindow = NULL;
}
}
return self;
}
- (void)showAlert:(NSAlert*)alert
{
if (nswindow) {
#ifdef MAC_OS_X_VERSION_10_9
if ([alert respondsToSelector:@selector(beginSheetModalForWindow:completionHandler:)]) {
[alert beginSheetModalForWindow:nswindow completionHandler:^(NSModalResponse returnCode) {
clicked = returnCode;
}];
} else
#endif
{
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
[alert beginSheetModalForWindow:nswindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
#endif
}
while (clicked < 0) {
SDL_PumpEvents();
SDL_Delay(100);
}
[nswindow release];
} else {
clicked = [alert runModal];
}
}
- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
clicked = returnCode;
}
@end
/* Display a Cocoa message box */
int
Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{ @autoreleasepool
{
Cocoa_RegisterApp();
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
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]];
const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
int i;
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:@""];
}
}
SDLMessageBoxPresenter* presenter = [[[SDLMessageBoxPresenter alloc] initWithParentWindow:messageboxdata->window] autorelease];
[presenter performSelectorOnMainThread:@selector(showAlert:)
withObject:alert
waitUntilDone:YES];
int returnValue = 0;
NSInteger 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;
} else {
returnValue = SDL_SetError("Did not get a valid `clicked button' id: %ld", (long)clicked);
}
return returnValue;
}}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,70 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 Alex Szpakowski, @slime73 on GitHub, for his gist showing
* how to add a CAMetalLayer backed view.
*/
#include "../../SDL_internal.h"
#ifndef SDL_cocoametalview_h_
#define SDL_cocoametalview_h_
#if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL)
#import "../SDL_sysvideo.h"
#import "SDL_cocoawindow.h"
#import <Cocoa/Cocoa.h>
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
#define METALVIEW_TAG 255
@interface SDL_cocoametalview : NSView
- (instancetype)initWithFrame:(NSRect)frame
highDPI:(BOOL)highDPI
windowID:(Uint32)windowID;
- (void)updateDrawableSize;
/* 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(_THIS, SDL_Window * window);
void Cocoa_Metal_DestroyView(_THIS, SDL_MetalView view);
void Cocoa_Metal_GetDrawableSize(SDL_Window * window, int * w, int * h);
#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */
#endif /* SDL_cocoametalview_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,182 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 Alex Szpakowski, @slime73 on GitHub, for his gist showing
* how to add a CAMetalLayer backed view.
*/
#import "SDL_cocoametalview.h"
#if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL)
#include "SDL_assert.h"
#include "SDL_events.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_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_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;
{
if ((self = [super initWithFrame:frame])) {
self.highDPI = highDPI;
self.sdlWindowID = windowID;
self.wantsLayer = YES;
/* Allow resize. */
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
SDL_AddEventWatch(SDL_MetalViewEventWatch, self);
[self updateDrawableSize];
}
return self;
}
- (void)dealloc
{
SDL_DelEventWatch(SDL_MetalViewEventWatch, self);
[super dealloc];
}
- (NSInteger)tag
{
return 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);
}
@end
SDL_MetalView
Cocoa_Metal_CreateView(_THIS, SDL_Window * window)
{ @autoreleasepool {
SDL_WindowData* data = (__bridge SDL_WindowData *)window->driverdata;
NSView *view = data->nswindow.contentView;
BOOL highDPI = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
Uint32 windowID = SDL_GetWindowID(window);
SDL_cocoametalview *newview;
SDL_MetalView metalview;
newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame
highDPI:highDPI
windowID:windowID];
if (newview == nil) {
return NULL;
}
[view addSubview:newview];
metalview = (SDL_MetalView)CFBridgingRetain(newview);
[newview release];
return metalview;
}}
void
Cocoa_Metal_DestroyView(_THIS, SDL_MetalView view)
{ @autoreleasepool {
SDL_cocoametalview *metalview = CFBridgingRelease(view);
[metalview removeFromSuperview];
}}
void
Cocoa_Metal_GetDrawableSize(SDL_Window * window, int * w, int * h)
{ @autoreleasepool {
SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
NSView *view = data->nswindow.contentView;
SDL_cocoametalview* metalview = [view viewWithTag:METALVIEW_TAG];
if (metalview) {
CAMetalLayer *layer = (CAMetalLayer*)metalview.layer;
SDL_assert(layer != NULL);
if (w) {
*w = layer.drawableSize.width;
}
if (h) {
*h = layer.drawableSize.height;
}
} else {
SDL_GetWindowSize(window, w, h);
}
}}
#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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_
typedef struct
{
CGDirectDisplayID display;
} SDL_DisplayData;
typedef struct
{
CFMutableArrayRef modes;
} SDL_DisplayModeData;
extern void Cocoa_InitModes(_THIS);
extern int Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
extern int Cocoa_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect);
extern void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay * display);
extern int Cocoa_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hpdi, float * vdpi);
extern int Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
extern void Cocoa_QuitModes(_THIS);
#endif /* SDL_cocoamodes_h_ */
/* vi: set ts=4 sw=4 expandtab: */

683
externals/SDL/src/video/cocoa/SDL_cocoamodes.m vendored Executable file
View File

@@ -0,0 +1,683 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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"
#include "SDL_assert.h"
#if 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>
/* we need this for ShowMenuBar() and HideMenuBar(). */
#include <Carbon/Carbon.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
static void
Cocoa_ToggleMenuBar(const BOOL show)
{
/* !!! FIXME: keep an eye on this.
* ShowMenuBar/HideMenuBar is officially unavailable for 64-bit binaries.
* It happens to work, as of 10.7, but we're going to see if
* we can just simply do without it on newer OSes...
*/
#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && !defined(__LP64__)
if (show) {
ShowMenuBar();
} else {
HideMenuBar();
}
#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 int
GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link)
{
int refreshRate = (int) (CGDisplayModeGetRefreshRate(vidmode) + 0.5);
/* 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 = (int) ((time.timeScale / (double) time.timeValue) + 0.5);
}
}
return refreshRate;
}
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(_THIS, CGDisplayModeRef vidmode, CFArrayRef modelist, CVDisplayLinkRef link, SDL_DisplayMode *mode)
{
SDL_DisplayModeData *data;
bool usableForGUI = CGDisplayModeIsUsableForDesktopGUI(vidmode);
int width = (int) CGDisplayModeGetWidth(vidmode);
int height = (int) CGDisplayModeGetHeight(vidmode);
uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
int refreshrate = GetDisplayModeRefreshRate(vidmode, link);
Uint32 format = GetDisplayModePixelFormat(vidmode);
bool interlaced = (ioflags & kDisplayModeInterlacedFlag) != 0;
CFMutableArrayRef modes;
if (format == SDL_PIXELFORMAT_UNKNOWN) {
return SDL_FALSE;
}
if (!HasValidDisplayModeFlags(vidmode)) {
return SDL_FALSE;
}
modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(modes, vidmode);
/* If a list of possible diplay 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
* prefered, and it can add CGDisplayModes to the DisplayModeData's list of
* modes to try (see comment below for why that's necessary).
* CGDisplayModeGetPixelWidth and friends are only available in 10.8+. */
#ifdef MAC_OS_X_VERSION_10_8
if (modelist != NULL && floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_7) {
int pixelW = (int) CGDisplayModeGetPixelWidth(vidmode);
int pixelH = (int) CGDisplayModeGetPixelHeight(vidmode);
CFIndex modescount = CFArrayGetCount(modelist);
for (int i = 0; i < modescount; i++) {
CGDisplayModeRef othermode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modelist, i);
uint32_t otherioflags = CGDisplayModeGetIOFlags(othermode);
if (CFEqual(vidmode, othermode)) {
continue;
}
if (!HasValidDisplayModeFlags(othermode)) {
continue;
}
int otherW = (int) CGDisplayModeGetWidth(othermode);
int otherH = (int) CGDisplayModeGetHeight(othermode);
int otherpixelW = (int) CGDisplayModeGetPixelWidth(othermode);
int otherpixelH = (int) CGDisplayModeGetPixelHeight(othermode);
int otherrefresh = GetDisplayModeRefreshRate(othermode, link);
Uint32 otherformat = GetDisplayModePixelFormat(othermode);
bool otherGUI = CGDisplayModeIsUsableForDesktopGUI(othermode);
/* Ignore this mode if it's low-dpi (@1x) and we have a high-dpi
* mode in the list with the same size in points.
*/
if (width == pixelW && height == pixelH
&& width == otherW && height == otherH
&& refreshrate == otherrefresh && format == otherformat
&& (otherpixelW != otherW || otherpixelH != otherH)) {
CFRelease(modes);
return SDL_FALSE;
}
/* 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_AddDisplayMode as being
* a duplicate.
*/
if (width == otherW && height == otherH && pixelW == otherpixelW
&& pixelH == otherpixelH && usableForGUI == otherGUI
&& refreshrate == otherrefresh && format == otherformat) {
CFArrayAppendValue(modes, othermode);
}
}
}
#endif
data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
if (!data) {
CFRelease(modes);
return SDL_FALSE;
}
data->modes = modes;
mode->format = format;
mode->w = width;
mode->h = height;
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 = [(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(_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, NULL, link, &mode)) {
CVDisplayLinkRelease(link);
CGDisplayModeRelease(moderef);
SDL_free(display.name);
SDL_free(displaydata);
continue;
}
CVDisplayLinkRelease(link);
CGDisplayModeRelease(moderef);
display.desktop_mode = mode;
display.current_mode = mode;
display.driverdata = displaydata;
SDL_AddVideoDisplay(&display);
SDL_free(display.name);
}
}
SDL_small_free(displays, isstack);
}}
int
Cocoa_GetDisplayBounds(_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(_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_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
{ @autoreleasepool
{
const float MM_IN_INCH = 25.4f;
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
/* we need the backingScaleFactor for Retina displays, which is only exposed through NSScreen, not CGDisplay, afaik, so find our screen... */
CGFloat scaleFactor = 1.0f;
NSArray *screens = [NSScreen screens];
for (NSScreen *screen in screens) {
const CGDirectDisplayID dpyid = (const CGDirectDisplayID ) [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
if (dpyid == data->display) {
if ([screen respondsToSelector:@selector(backingScaleFactor)]) { // Mac OS X 10.7 and later
scaleFactor = [screen backingScaleFactor];
break;
}
}
}
const CGSize displaySize = CGDisplayScreenSize(data->display);
const int pixelWidth = (int) CGDisplayPixelsWide(data->display);
const int pixelHeight = (int) CGDisplayPixelsHigh(data->display);
if (ddpi) {
*ddpi = (SDL_ComputeDiagonalDPI(pixelWidth, pixelHeight, displaySize.width / MM_IN_INCH, displaySize.height / MM_IN_INCH)) * scaleFactor;
}
if (hdpi) {
*hdpi = (pixelWidth * MM_IN_INCH / displaySize.width) * scaleFactor;
}
if (vdpi) {
*vdpi = (pixelHeight * MM_IN_INCH / displaySize.height) * scaleFactor;
}
return 0;
}}
void
Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
CVDisplayLinkRef link = NULL;
CGDisplayModeRef desktopmoderef;
SDL_DisplayMode desktopmode;
CFArrayRef modes;
CFDictionaryRef dict = NULL;
CVDisplayLinkCreateWithCGDisplay(data->display, &link);
desktopmoderef = CGDisplayCopyDisplayMode(data->display);
/* CopyAllDisplayModes won't always contain the desktop display mode (if
* NULL is passed in) - for example on a retina 15" MBP, System Preferences
* allows choosing 1920x1200 but it's not in the list. AddDisplayMode makes
* sure there are no duplicates so it's safe to always add the desktop mode
* even in cases where it is in the CopyAllDisplayModes list.
*/
if (desktopmoderef && GetDisplayMode(_this, desktopmoderef, NULL, link, &desktopmode)) {
if (!SDL_AddDisplayMode(display, &desktopmode)) {
CFRelease(((SDL_DisplayModeData*)desktopmode.driverdata)->modes);
SDL_free(desktopmode.driverdata);
}
}
CGDisplayModeRelease(desktopmoderef);
/* 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
*/
#ifdef MAC_OS_X_VERSION_10_8
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_7) {
const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
dict = CFDictionaryCreate(NULL,
(const void **)dictkeys,
(const void **)dictvalues,
1,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
#endif
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, modes, link, &mode)) {
if (!SDL_AddDisplayMode(display, &mode)) {
CFRelease(((SDL_DisplayModeData*)mode.driverdata)->modes);
SDL_free(mode.driverdata);
}
}
}
CFRelease(modes);
}
CVDisplayLinkRelease(link);
}
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(_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;
/* 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);
if (CGDisplayIsMain(displaydata->display)) {
CGReleaseAllDisplays();
} else {
CGDisplayRelease(displaydata->display);
}
if (CGDisplayIsMain(displaydata->display)) {
Cocoa_ToggleMenuBar(YES);
}
} else {
/* Put up the blanking window (a window above all other windows) */
if (CGDisplayIsMain(displaydata->display)) {
/* If we don't capture all displays, Cocoa tries to rearrange windows... *sigh* */
result = CGCaptureAllDisplays();
} else {
result = CGDisplayCapture(displaydata->display);
}
if (result != kCGErrorSuccess) {
CG_SetError("CGDisplayCapture()", result);
goto ERR_NO_CAPTURE;
}
/* Do the physical switch */
result = SetDisplayModeForDisplay(displaydata->display, data);
if (result != kCGErrorSuccess) {
CG_SetError("CGDisplaySwitchToMode()", result);
goto ERR_NO_SWITCH;
}
/* Hide the menu bar so it doesn't intercept events */
if (CGDisplayIsMain(displaydata->display)) {
Cocoa_ToggleMenuBar(NO);
}
}
/* 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);
}
return 0;
/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
ERR_NO_SWITCH:
if (CGDisplayIsMain(displaydata->display)) {
CGReleaseAllDisplays();
} else {
CGDisplayRelease(displaydata->display);
}
ERR_NO_CAPTURE:
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation(fade_token);
}
return -1;
}
void
Cocoa_QuitModes(_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_display_modes; j++) {
mode = (SDL_DisplayModeData*) display->display_modes[j].driverdata;
CFRelease(mode->modes);
}
}
Cocoa_ToggleMenuBar(YES);
}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,52 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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(_THIS);
extern void Cocoa_HandleMouseEvent(_THIS, NSEvent * event);
extern void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent * event);
extern void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y);
extern void Cocoa_QuitMouse(_THIS);
typedef struct {
/* Wether 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;
void *tapdata;
} SDL_MouseData;
@interface NSCursor (InvisibleCursor)
+ (NSCursor *)invisibleCursor;
@end
#endif /* SDL_cocoamouse_h_ */
/* vi: set ts=4 sw=4 expandtab: */

481
externals/SDL/src/video/cocoa/SDL_cocoamouse.m vendored Executable file
View File

@@ -0,0 +1,481 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
#include "SDL_assert.h"
#include "SDL_events.h"
#include "SDL_cocoamouse.h"
#include "SDL_cocoamousetap.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] autorelease];
invisibleCursor = [[NSCursor alloc] initWithImage:cursorImage
hotSpot:NSZeroPoint];
}
return invisibleCursor;
}
@end
static SDL_Cursor *
Cocoa_CreateDefaultCursor()
{ @autoreleasepool
{
NSCursor *nscursor;
SDL_Cursor *cursor = NULL;
nscursor = [NSCursor arrowCursor];
if (nscursor) {
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
cursor->driverdata = nscursor;
[nscursor retain];
}
}
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 = nscursor;
} else {
[nscursor release];
}
}
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_WAIT:
nscursor = [NSCursor arrowCursor];
break;
case SDL_SYSTEM_CURSOR_CROSSHAIR:
nscursor = [NSCursor crosshairCursor];
break;
case SDL_SYSTEM_CURSOR_WAITARROW:
nscursor = [NSCursor arrowCursor];
break;
case SDL_SYSTEM_CURSOR_SIZENWSE:
case SDL_SYSTEM_CURSOR_SIZENESW:
nscursor = [NSCursor closedHandCursor];
break;
case SDL_SYSTEM_CURSOR_SIZEWE:
nscursor = [NSCursor resizeLeftRightCursor];
break;
case SDL_SYSTEM_CURSOR_SIZENS:
nscursor = [NSCursor resizeUpDownCursor];
break;
case SDL_SYSTEM_CURSOR_SIZEALL:
nscursor = [NSCursor 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 */
[nscursor retain];
cursor->driverdata = nscursor;
}
}
return cursor;
}}
static void
Cocoa_FreeCursor(SDL_Cursor * cursor)
{ @autoreleasepool
{
NSCursor *nscursor = (NSCursor *)cursor->driverdata;
[nscursor release];
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_WindowData *driverdata = (SDL_WindowData *)window->driverdata;
if (driverdata) {
[driverdata->nswindow performSelectorOnMainThread:@selector(invalidateCursorRectsForView:)
withObject:[driverdata->nswindow contentView]
waitUntilDone:NO];
}
}
return 0;
}}
static SDL_Window *
SDL_FindWindowAtPoint(const int x, const int y)
{
const SDL_Point pt = { x, y };
SDL_Window *i;
for (i = SDL_GetVideoDevice()->windows; i; i = i->next) {
const SDL_Rect r = { i->x, i->y, i->w, i->h };
if (SDL_PointInRect(&pt, &r)) {
return i;
}
}
return NULL;
}
static int
Cocoa_WarpMouseGlobal(int x, int y)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->focus) {
SDL_WindowData *data = (SDL_WindowData *) mouse->focus->driverdata;
if ([data->listener isMoving]) {
DLog("Postponing warp, window being moved.");
[data->listener setPendingMoveX:x Y:y];
return 0;
}
}
const CGPoint point = CGPointMake((float)x, (float)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 of OS X 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(win, mouse->mouseID, 0, x - win->x, y - win->y);
}
}
return 0;
}
static void
Cocoa_WarpMouse(SDL_Window * window, int x, int y)
{
Cocoa_WarpMouseGlobal(x + window->x, y + window->y);
}
static int
Cocoa_SetRelativeMouseMode(SDL_bool enabled)
{
/* We will re-apply the relative mode when the window gets focus, if it
* doesn't have focus right now.
*/
SDL_Window *window = SDL_GetMouseFocus();
if (!window) {
return 0;
}
/* We will re-apply the relative mode when the window finishes being moved,
* if it is being moved right now.
*/
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
if ([data->listener isMoving]) {
return 0;
}
CGError result;
if (enabled) {
DLog("Turning on.");
result = CGAssociateMouseAndMouseCursorPosition(NO);
} else {
DLog("Turning off.");
result = CGAssociateMouseAndMouseCursorPosition(YES);
}
if (result != kCGErrorSuccess) {
return SDL_SetError("CGAssociateMouseAndMouseCursorPosition() failed");
}
/* The hide/unhide calls are redundant most of the time, but they fix
* https://bugzilla.libsdl.org/show_bug.cgi?id=2550
*/
if (enabled) {
[NSCursor hide];
} else {
[NSCursor unhide];
}
return 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(int *x, int *y)
{
const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons];
const NSPoint cocoaLocation = [NSEvent mouseLocation];
Uint32 retval = 0;
*x = (int) cocoaLocation.x;
*y = (int) (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(_THIS)
{
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());
Cocoa_InitMouseEventTap(driverdata);
const NSPoint location = [NSEvent mouseLocation];
driverdata->lastMoveX = location.x;
driverdata->lastMoveY = location.y;
return 0;
}
void
Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
{
switch ([event type]) {
case NSEventTypeMouseMoved:
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
break;
default:
/* Ignore any other events. */
return;
}
SDL_Mouse *mouse = SDL_GetMouse();
SDL_MouseData *driverdata = (SDL_MouseData*)mouse->driverdata;
if (!driverdata) {
return; /* can happen when returning from fullscreen Space on shutdown */
}
SDL_MouseID mouseID = mouse ? mouse->mouseID : 0;
const SDL_bool seenWarp = driverdata->seenWarp;
driverdata->seenWarp = NO;
const NSPoint location = [NSEvent mouseLocation];
const CGFloat lastMoveX = driverdata->lastMoveX;
const CGFloat 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;
}
}
float deltaX = [event deltaX];
float 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(mouse->focus, mouseID, 1, (int)deltaX, (int)deltaY);
}
void
Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (!mouse) {
return;
}
SDL_MouseID mouseID = mouse->mouseID;
CGFloat x = -[event deltaX];
CGFloat y = [event deltaY];
SDL_MouseWheelDirection direction = SDL_MOUSEWHEEL_NORMAL;
if ([event respondsToSelector:@selector(isDirectionInvertedFromDevice)]) {
if ([event isDirectionInvertedFromDevice] == YES) {
direction = SDL_MOUSEWHEEL_FLIPPED;
}
}
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(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(_THIS)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse) {
if (mouse->driverdata) {
Cocoa_QuitMouseEventTap(((SDL_MouseData*)mouse->driverdata));
SDL_free(mouse->driverdata);
mouse->driverdata = NULL;
}
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,34 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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_cocoamousetap_h_
#define SDL_cocoamousetap_h_
#include "SDL_cocoamouse.h"
extern void Cocoa_InitMouseEventTap(SDL_MouseData *driverdata);
extern void Cocoa_EnableMouseEventTap(SDL_MouseData *driverdata, SDL_bool enabled);
extern void Cocoa_QuitMouseEventTap(SDL_MouseData *driverdata);
#endif /* SDL_cocoamousetap_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,286 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoamousetap.h"
/* Event taps are forbidden in the Mac App Store, so we can only enable this
* code if your app doesn't need to ship through the app store.
* This code makes it so that a grabbed cursor cannot "leak" a mouse click
* past the edge of the window if moving the cursor too fast.
*/
#if SDL_MAC_NO_SANDBOX
#include "SDL_keyboard.h"
#include "SDL_cocoavideo.h"
#include "../../thread/SDL_systhread.h"
#include "../../events/SDL_mouse_c.h"
typedef struct {
CFMachPortRef tap;
CFRunLoopRef runloop;
CFRunLoopSourceRef runloopSource;
SDL_Thread *thread;
SDL_sem *runloopStartedSemaphore;
} SDL_MouseEventTapData;
static const CGEventMask movementEventsMask =
CGEventMaskBit(kCGEventLeftMouseDragged)
| CGEventMaskBit(kCGEventRightMouseDragged)
| CGEventMaskBit(kCGEventMouseMoved);
static const CGEventMask allGrabbedEventsMask =
CGEventMaskBit(kCGEventLeftMouseDown) | CGEventMaskBit(kCGEventLeftMouseUp)
| CGEventMaskBit(kCGEventRightMouseDown) | CGEventMaskBit(kCGEventRightMouseUp)
| CGEventMaskBit(kCGEventOtherMouseDown) | CGEventMaskBit(kCGEventOtherMouseUp)
| CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged)
| CGEventMaskBit(kCGEventMouseMoved);
static CGEventRef
Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
SDL_MouseEventTapData *tapdata = (SDL_MouseEventTapData*)refcon;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Window *window = SDL_GetKeyboardFocus();
NSWindow *nswindow;
NSRect windowRect;
CGPoint eventLocation;
switch (type) {
case kCGEventTapDisabledByTimeout:
{
CGEventTapEnable(tapdata->tap, true);
return NULL;
}
case kCGEventTapDisabledByUserInput:
{
return NULL;
}
default:
break;
}
if (!window || !mouse) {
return event;
}
if (mouse->relative_mode) {
return event;
}
if (!(window->flags & SDL_WINDOW_INPUT_GRABBED)) {
return event;
}
/* This is the same coordinate system as Cocoa uses. */
nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
eventLocation = CGEventGetUnflippedLocation(event);
windowRect = [nswindow contentRectForFrameRect:[nswindow frame]];
if (!NSMouseInRect(NSPointFromCGPoint(eventLocation), windowRect, NO)) {
/* This is in CGs global screenspace coordinate system, which has a
* flipped Y.
*/
CGPoint newLocation = CGEventGetLocation(event);
if (eventLocation.x < NSMinX(windowRect)) {
newLocation.x = NSMinX(windowRect);
} else if (eventLocation.x >= NSMaxX(windowRect)) {
newLocation.x = NSMaxX(windowRect) - 1.0;
}
if (eventLocation.y <= NSMinY(windowRect)) {
newLocation.y -= (NSMinY(windowRect) - eventLocation.y + 1);
} else if (eventLocation.y > NSMaxY(windowRect)) {
newLocation.y += (eventLocation.y - NSMaxY(windowRect));
}
CGWarpMouseCursorPosition(newLocation);
CGAssociateMouseAndMouseCursorPosition(YES);
if ((CGEventMaskBit(type) & movementEventsMask) == 0) {
/* For click events, we just constrain the event to the window, so
* no other app receives the click event. We can't due the same to
* movement events, since they mean that our warp cursor above
* behaves strangely.
*/
CGEventSetLocation(event, newLocation);
}
}
return event;
}
static void
SemaphorePostCallback(CFRunLoopTimerRef timer, void *info)
{
SDL_SemPost((SDL_sem*)info);
}
static int
Cocoa_MouseTapThread(void *data)
{
SDL_MouseEventTapData *tapdata = (SDL_MouseEventTapData*)data;
/* Tap was created on main thread but we own it now. */
CFMachPortRef eventTap = tapdata->tap;
if (eventTap) {
/* Try to create a runloop source we can schedule. */
CFRunLoopSourceRef runloopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
if (runloopSource) {
tapdata->runloopSource = runloopSource;
} else {
CFRelease(eventTap);
SDL_SemPost(tapdata->runloopStartedSemaphore);
/* TODO: Both here and in the return below, set some state in
* tapdata to indicate that initialization failed, which we should
* check in InitMouseEventTap, after we move the semaphore check
* from Quit to Init.
*/
return 1;
}
} else {
SDL_SemPost(tapdata->runloopStartedSemaphore);
return 1;
}
tapdata->runloop = CFRunLoopGetCurrent();
CFRunLoopAddSource(tapdata->runloop, tapdata->runloopSource, kCFRunLoopCommonModes);
CFRunLoopTimerContext context = {.info = tapdata->runloopStartedSemaphore};
/* We signal the runloop started semaphore *after* the run loop has started, indicating it's safe to CFRunLoopStop it. */
CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0, 0, 0, &SemaphorePostCallback, &context);
CFRunLoopAddTimer(tapdata->runloop, timer, kCFRunLoopCommonModes);
CFRelease(timer);
/* Run the event loop to handle events in the event tap. */
CFRunLoopRun();
/* Make sure this is signaled so that SDL_QuitMouseEventTap knows it can safely SDL_WaitThread for us. */
if (SDL_SemValue(tapdata->runloopStartedSemaphore) < 1) {
SDL_SemPost(tapdata->runloopStartedSemaphore);
}
CFRunLoopRemoveSource(tapdata->runloop, tapdata->runloopSource, kCFRunLoopCommonModes);
/* Clean up. */
CGEventTapEnable(tapdata->tap, false);
CFRelease(tapdata->runloopSource);
CFRelease(tapdata->tap);
tapdata->runloopSource = NULL;
tapdata->tap = NULL;
return 0;
}
void
Cocoa_InitMouseEventTap(SDL_MouseData* driverdata)
{
SDL_MouseEventTapData *tapdata;
driverdata->tapdata = SDL_calloc(1, sizeof(SDL_MouseEventTapData));
tapdata = (SDL_MouseEventTapData*)driverdata->tapdata;
tapdata->runloopStartedSemaphore = SDL_CreateSemaphore(0);
if (tapdata->runloopStartedSemaphore) {
tapdata->tap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
kCGEventTapOptionDefault, allGrabbedEventsMask,
&Cocoa_MouseTapCallback, tapdata);
if (tapdata->tap) {
/* Tap starts disabled, until app requests mouse grab */
CGEventTapEnable(tapdata->tap, false);
tapdata->thread = SDL_CreateThreadInternal(&Cocoa_MouseTapThread, "Event Tap Loop", 512 * 1024, tapdata);
if (tapdata->thread) {
/* Success - early out. Ownership transferred to thread. */
return;
}
CFRelease(tapdata->tap);
}
SDL_DestroySemaphore(tapdata->runloopStartedSemaphore);
}
SDL_free(driverdata->tapdata);
driverdata->tapdata = NULL;
}
void
Cocoa_EnableMouseEventTap(SDL_MouseData *driverdata, SDL_bool enabled)
{
SDL_MouseEventTapData *tapdata = (SDL_MouseEventTapData*)driverdata->tapdata;
if (tapdata && tapdata->tap)
{
CGEventTapEnable(tapdata->tap, !!enabled);
}
}
void
Cocoa_QuitMouseEventTap(SDL_MouseData *driverdata)
{
SDL_MouseEventTapData *tapdata = (SDL_MouseEventTapData*)driverdata->tapdata;
int status;
if (tapdata == NULL) {
/* event tap was already cleaned up (possibly due to CGEventTapCreate
* returning null.)
*/
return;
}
/* Ensure that the runloop has been started first.
* TODO: Move this to InitMouseEventTap, check for error conditions that can
* happen in Cocoa_MouseTapThread, and fall back to the non-EventTap way of
* grabbing the mouse if it fails to Init.
*/
status = SDL_SemWaitTimeout(tapdata->runloopStartedSemaphore, 5000);
if (status > -1) {
/* Then stop it, which will cause Cocoa_MouseTapThread to return. */
CFRunLoopStop(tapdata->runloop);
/* And then wait for Cocoa_MouseTapThread to finish cleaning up. It
* releases some of the pointers in tapdata. */
SDL_WaitThread(tapdata->thread, &status);
}
SDL_free(driverdata->tapdata);
driverdata->tapdata = NULL;
}
#else /* SDL_MAC_NO_SANDBOX */
void
Cocoa_InitMouseEventTap(SDL_MouseData *unused)
{
}
void
Cocoa_EnableMouseEventTap(SDL_MouseData *driverdata, SDL_bool enabled)
{
}
void
Cocoa_QuitMouseEventTap(SDL_MouseData *driverdata)
{
}
#endif /* !SDL_MAC_NO_SANDBOX */
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,77 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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_
#if SDL_VIDEO_OPENGL_CGL
#include "SDL_atomic.h"
#import <Cocoa/Cocoa.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_atomic_t dirty;
SDL_Window *window;
}
- (id)initWithFormat:(NSOpenGLPixelFormat *)format
shareContext:(NSOpenGLContext *)share;
- (void)scheduleUpdate;
- (void)updateIfNeeded;
- (void)setWindow:(SDL_Window *)window;
@end
/* OpenGL functions */
extern int Cocoa_GL_LoadLibrary(_THIS, const char *path);
extern void *Cocoa_GL_GetProcAddress(_THIS, const char *proc);
extern void Cocoa_GL_UnloadLibrary(_THIS);
extern SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window * window);
extern int Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window,
SDL_GLContext context);
extern void Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window,
int * w, int * h);
extern int Cocoa_GL_SetSwapInterval(_THIS, int interval);
extern int Cocoa_GL_GetSwapInterval(_THIS);
extern int Cocoa_GL_SwapWindow(_THIS, SDL_Window * window);
extern void Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context);
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif /* SDL_VIDEO_OPENGL_CGL */
#endif /* SDL_cocoaopengl_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,459 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 */
#if 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 "SDL_loadso.h"
#include "SDL_opengl.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
@implementation SDLOpenGLContext : NSOpenGLContext
- (id)initWithFormat:(NSOpenGLPixelFormat *)format
shareContext:(NSOpenGLContext *)share
{
self = [super initWithFormat:format shareContext:share];
if (self) {
SDL_AtomicSet(&self->dirty, 0);
self->window = NULL;
}
return self;
}
- (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
{
int value = SDL_AtomicSet(&self->dirty, 0);
if (value > 0) {
/* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */
[super update];
}
}
/* 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_WindowData *oldwindowdata = (SDL_WindowData *)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_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
NSView *contentview = windowdata->sdlContentView;
/* This should never be nil since sdlContentView is only nil if the
window was created via SDL_CreateWindowFrom, and SDL doesn't allow
OpenGL contexts to be created in that case. However, it doesn't hurt
to check. */
if (contentview == nil) {
/* Prefer to access the cached content view above instead of this,
since as of Xcode 11 + SDK 10.15, [window contentView] causes
Apple's Main Thread Checker to output a warning. */
contentview = [windowdata->nswindow contentView];
}
/* Now sign up for scheduled updates for the new window. */
NSMutableArray *contexts = windowdata->nscontexts;
@synchronized (contexts) {
[contexts addObject:self];
}
if ([self view] != contentview) {
[self setView:contentview];
if (self == [NSOpenGLContext currentContext]) {
[self update];
} else {
[self scheduleUpdate];
}
}
} else {
[self clearDrawable];
if (self == [NSOpenGLContext currentContext]) {
[self update];
} else {
[self scheduleUpdate];
}
}
}
@end
int
Cocoa_GL_LoadLibrary(_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;
}
void *
Cocoa_GL_GetProcAddress(_THIS, const char *proc)
{
return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
}
void
Cocoa_GL_UnloadLibrary(_THIS)
{
SDL_UnloadObject(_this->gl_config.dll_handle);
_this->gl_config.dll_handle = NULL;
}
SDL_GLContext
Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
{ @autoreleasepool
{
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
SDL_bool lion_or_later = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
NSOpenGLPixelFormatAttribute attr[32];
NSOpenGLPixelFormat *fmt;
SDLOpenGLContext *context;
NSOpenGLContext *share_context = nil;
int i = 0;
const char *glversion;
int glversion_major;
int glversion_minor;
if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
#if 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
}
if ((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) && !lion_or_later) {
SDL_SetError ("OpenGL Core Profile is not supported on this platform version");
return NULL;
}
attr[i++] = NSOpenGLPFAAllowOfflineRenderers;
/* specify a profile if we're on Lion (10.7) or later. */
if (lion_or_later) {
NSOpenGLPixelFormatAttribute 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.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 = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
}
context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
[fmt release];
if (context == nil) {
SDL_SetError("Failed creating OpenGL context");
return NULL;
}
if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
Cocoa_GL_DeleteContext(_this, context);
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) {
Cocoa_GL_DeleteContext(_this, context);
SDL_SetError ("Failed getting OpenGL glGetString entry point");
return NULL;
}
glversion = (const char *)glGetStringFunc(GL_VERSION);
if (glversion == NULL) {
Cocoa_GL_DeleteContext(_this, context);
SDL_SetError ("Failed getting OpenGL context version");
return NULL;
}
if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) {
Cocoa_GL_DeleteContext(_this, context);
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))) {
Cocoa_GL_DeleteContext(_this, context);
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 context;
}}
int
Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{ @autoreleasepool
{
if (context) {
SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
[nscontext setWindow:window];
[nscontext updateIfNeeded];
[nscontext makeCurrentContext];
} else {
[NSOpenGLContext clearCurrentContext];
}
return 0;
}}
void
Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
{
SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
NSView *contentView = [windata->nswindow contentView];
NSRect viewport = [contentView bounds];
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
/* This gives us the correct viewport for a Retina-enabled view, only
* supported on 10.7+. */
if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
viewport = [contentView convertRectToBacking:viewport];
}
}
if (w) {
*w = viewport.size.width;
}
if (h) {
*h = viewport.size.height;
}
}
int
Cocoa_GL_SetSwapInterval(_THIS, int interval)
{ @autoreleasepool
{
NSOpenGLContext *nscontext;
GLint value;
int status;
if (interval < 0) { /* no extension for this on Mac OS X at the moment. */
return SDL_SetError("Late swap tearing currently unsupported");
}
nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
if (nscontext != nil) {
value = interval;
[nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
status = 0;
} else {
status = SDL_SetError("No current OpenGL context");
}
return status;
}}
int
Cocoa_GL_GetSwapInterval(_THIS)
{ @autoreleasepool
{
NSOpenGLContext *nscontext;
GLint value;
int status = 0;
nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
if (nscontext != nil) {
[nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
status = (int)value;
}
return status;
}}
int
Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
{ @autoreleasepool
{
SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext();
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
/* 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;
}}
void
Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
{ @autoreleasepool
{
SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
[nscontext setWindow:NULL];
[nscontext release];
}}
/* 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 */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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_
#if 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_GetProcAddress
#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(_THIS, const char *path);
extern SDL_GLContext Cocoa_GLES_CreateContext(_THIS, SDL_Window * window);
extern int Cocoa_GLES_SwapWindow(_THIS, SDL_Window * window);
extern int Cocoa_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
extern void Cocoa_GLES_DeleteContext(_THIS, SDL_GLContext context);
extern int Cocoa_GLES_SetupWindow(_THIS, SDL_Window * window);
#endif /* SDL_VIDEO_OPENGL_EGL */
#endif /* SDL_cocoaopengles_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,132 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA && SDL_VIDEO_OPENGL_EGL
#include "SDL_cocoavideo.h"
#include "SDL_cocoaopengles.h"
#include "SDL_cocoaopengl.h"
#include "SDL_log.h"
/* EGL implementation of SDL OpenGL support */
int
Cocoa_GLES_LoadLibrary(_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) {
#if 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;
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, 0);
}
return 0;
}
SDL_GLContext
Cocoa_GLES_CreateContext(_THIS, SDL_Window * window)
{
SDL_GLContext context;
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
#if 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;
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;
}
void
Cocoa_GLES_DeleteContext(_THIS, SDL_GLContext context)
{
SDL_EGL_DeleteContext(_this, context);
Cocoa_GLES_UnloadLibrary(_this);
}
SDL_EGL_SwapWindow_impl(Cocoa)
SDL_EGL_MakeCurrent_impl(Cocoa)
int
Cocoa_GLES_SetupWindow(_THIS, SDL_Window * window)
{
/* The current context is lost in here; save it and reset it. */
SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
SDL_Window *current_win = SDL_GL_GetCurrentWindow();
SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
if (_this->egl_data == NULL) {
if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, 0) < 0) {
SDL_EGL_UnloadLibrary(_this);
return -1;
}
}
/* Create the GLES window surface */
NSView* v = windowdata->nswindow.contentView;
windowdata->egl_surface = SDL_EGL_CreateSurface(_this, (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);
}
#endif /* SDL_VIDEO_DRIVER_COCOA && SDL_VIDEO_OPENGL_EGL */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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_stdinc.h"
#include "SDL_video.h"
#include "SDL_shape.h"
#include "../SDL_shape_internals.h"
typedef struct {
NSGraphicsContext* context;
SDL_bool saved;
SDL_ShapeTree* shape;
} SDL_ShapeData;
extern SDL_WindowShaper* Cocoa_CreateShaper(SDL_Window* window);
extern int Cocoa_SetWindowShape(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode);
extern int Cocoa_ResizeWindowShape(SDL_Window *window);
#endif /* SDL_cocoashape_h_ */
/* vi: set ts=4 sw=4 expandtab: */

113
externals/SDL/src/video/cocoa/SDL_cocoashape.m vendored Executable file
View File

@@ -0,0 +1,113 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
#include "SDL_shape.h"
#include "SDL_cocoashape.h"
#include "../SDL_sysvideo.h"
#include "SDL_assert.h"
SDL_WindowShaper*
Cocoa_CreateShaper(SDL_Window* window)
{
SDL_WindowData* windata = (SDL_WindowData*)window->driverdata;
[windata->nswindow setOpaque:NO];
[windata->nswindow setStyleMask:NSWindowStyleMaskBorderless];
SDL_WindowShaper* result = result = malloc(sizeof(SDL_WindowShaper));
result->window = window;
result->mode.mode = ShapeModeDefault;
result->mode.parameters.binarizationCutoff = 1;
result->userx = result->usery = 0;
window->shaper = result;
SDL_ShapeData* data = malloc(sizeof(SDL_ShapeData));
result->driverdata = data;
data->context = [windata->nswindow graphicsContext];
data->saved = SDL_FALSE;
data->shape = NULL;
int resized_properly = Cocoa_ResizeWindowShape(window);
SDL_assert(resized_properly == 0);
return result;
}
typedef struct {
NSView* view;
NSBezierPath* path;
SDL_Window* window;
} SDL_CocoaClosure;
void
ConvertRects(SDL_ShapeTree* tree, void* closure)
{
SDL_CocoaClosure* data = (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 = (SDL_ShapeData*)shaper->driverdata;
SDL_WindowData* windata = (SDL_WindowData*)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->nswindow contentView] frame]);
data->shape = SDL_CalculateShapeTree(*shape_mode,shape);
closure.view = [windata->nswindow contentView];
closure.path = [NSBezierPath bezierPath];
closure.window = shaper->window;
SDL_TraverseShapeTree(data->shape,&ConvertRects,&closure);
[closure.path addClip];
return 0;
}}
int
Cocoa_ResizeWindowShape(SDL_Window *window)
{
SDL_ShapeData* data = window->shaper->driverdata;
SDL_assert(data != NULL);
return 0;
}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vi: set ts=4 sw=4 expandtab: */

123
externals/SDL/src/video/cocoa/SDL_cocoavideo.h vendored Executable file
View File

@@ -0,0 +1,123 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 "SDL_opengl.h"
#include <ApplicationServices/ApplicationServices.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <Cocoa/Cocoa.h>
#include "SDL_keycode.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;
typedef struct SDL_VideoData
{
int allow_spaces;
unsigned int modifierFlags;
void *key_layout;
SDLTranslatorResponder *fieldEdit;
NSInteger clipboard_count;
Uint32 screensaver_activity;
BOOL screensaver_use_iopm;
IOPMAssertionID screensaver_assertion;
SDL_mutex *swaplock;
} SDL_VideoData;
/* Utility functions */
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_ */
/* vi: set ts=4 sw=4 expandtab: */

273
externals/SDL/src/video/cocoa/SDL_cocoavideo.m vendored Executable file
View File

@@ -0,0 +1,273 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_DRIVER_COCOA
#include "SDL.h"
#include "SDL_endian.h"
#include "SDL_cocoavideo.h"
#include "SDL_cocoashape.h"
#include "SDL_cocoavulkan.h"
#include "SDL_cocoametalview.h"
#include "SDL_assert.h"
/* Initialization/Query functions */
static int Cocoa_VideoInit(_THIS);
static void Cocoa_VideoQuit(_THIS);
/* Cocoa driver bootstrap functions */
static int
Cocoa_Available(void)
{
return (1);
}
static void
Cocoa_DeleteDevice(SDL_VideoDevice * device)
{
SDL_free(device->driverdata);
SDL_free(device);
}
static SDL_VideoDevice *
Cocoa_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
SDL_VideoData *data;
Cocoa_RegisterApp();
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device) {
data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
} else {
data = NULL;
}
if (!data) {
SDL_OutOfMemory();
SDL_free(device);
return NULL;
}
device->driverdata = data;
/* Set the function pointers */
device->VideoInit = Cocoa_VideoInit;
device->VideoQuit = Cocoa_VideoQuit;
device->GetDisplayBounds = Cocoa_GetDisplayBounds;
device->GetDisplayUsableBounds = Cocoa_GetDisplayUsableBounds;
device->GetDisplayDPI = Cocoa_GetDisplayDPI;
device->GetDisplayModes = Cocoa_GetDisplayModes;
device->SetDisplayMode = Cocoa_SetDisplayMode;
device->PumpEvents = Cocoa_PumpEvents;
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->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->SetWindowFullscreen = Cocoa_SetWindowFullscreen;
device->SetWindowGammaRamp = Cocoa_SetWindowGammaRamp;
device->GetWindowGammaRamp = Cocoa_GetWindowGammaRamp;
device->SetWindowGrab = Cocoa_SetWindowGrab;
device->DestroyWindow = Cocoa_DestroyWindow;
device->GetWindowWMInfo = Cocoa_GetWindowWMInfo;
device->SetWindowHitTest = Cocoa_SetWindowHitTest;
device->AcceptDragAndDrop = Cocoa_AcceptDragAndDrop;
device->shape_driver.CreateShaper = Cocoa_CreateShaper;
device->shape_driver.SetWindowShape = Cocoa_SetWindowShape;
device->shape_driver.ResizeWindowShape = Cocoa_ResizeWindowShape;
#if 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_GetDrawableSize = Cocoa_GL_GetDrawableSize;
device->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval;
device->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval;
device->GL_SwapWindow = Cocoa_GL_SwapWindow;
device->GL_DeleteContext = Cocoa_GL_DeleteContext;
#elif SDL_VIDEO_OPENGL_EGL
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;
#endif
#if SDL_VIDEO_VULKAN
device->Vulkan_LoadLibrary = Cocoa_Vulkan_LoadLibrary;
device->Vulkan_UnloadLibrary = Cocoa_Vulkan_UnloadLibrary;
device->Vulkan_GetInstanceExtensions = Cocoa_Vulkan_GetInstanceExtensions;
device->Vulkan_CreateSurface = Cocoa_Vulkan_CreateSurface;
device->Vulkan_GetDrawableSize = Cocoa_Vulkan_GetDrawableSize;
#endif
#if SDL_VIDEO_METAL
device->Metal_CreateView = Cocoa_Metal_CreateView;
device->Metal_DestroyView = Cocoa_Metal_DestroyView;
#endif
device->StartTextInput = Cocoa_StartTextInput;
device->StopTextInput = Cocoa_StopTextInput;
device->SetTextInputRect = Cocoa_SetTextInputRect;
device->SetClipboardText = Cocoa_SetClipboardText;
device->GetClipboardText = Cocoa_GetClipboardText;
device->HasClipboardText = Cocoa_HasClipboardText;
device->free = Cocoa_DeleteDevice;
return device;
}
VideoBootStrap COCOA_bootstrap = {
"cocoa", "SDL Cocoa video driver",
Cocoa_Available, Cocoa_CreateDevice
};
int
Cocoa_VideoInit(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
Cocoa_InitModes(_this);
Cocoa_InitKeyboard(_this);
if (Cocoa_InitMouse(_this) < 0) {
return -1;
}
data->allow_spaces = ((floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) && SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, SDL_TRUE));
/* The IOPM assertion API can disable the screensaver as of 10.7. */
data->screensaver_use_iopm = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
data->swaplock = SDL_CreateMutex();
if (!data->swaplock) {
return -1;
}
return 0;
}
void
Cocoa_VideoQuit(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _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 */
NSImage *
Cocoa_CreateImage(SDL_Surface * surface)
{
SDL_Surface *converted;
NSBitmapImageRep *imgrep;
Uint8 *pixels;
int i;
NSImage *img;
converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA32, 0);
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] autorelease];
if (imgrep == nil) {
SDL_FreeSurface(converted);
return nil;
}
/* Copy the pixels */
pixels = [imgrep bitmapData];
SDL_memcpy(pixels, converted->pixels, converted->h * converted->pitch);
SDL_FreeSurface(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)] autorelease];
if (img != nil) {
[img addRepresentation: imgrep];
}
return img;
}
/*
* Mac OS X log support.
*
* This doesn't really have aything 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 *text)
{
NSLog(@"%s", text);
}
#endif /* SDL_VIDEO_DRIVER_COCOA */
/* vim: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,55 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_COCOA
int Cocoa_Vulkan_LoadLibrary(_THIS, const char *path);
void Cocoa_Vulkan_UnloadLibrary(_THIS);
SDL_bool Cocoa_Vulkan_GetInstanceExtensions(_THIS,
SDL_Window *window,
unsigned *count,
const char **names);
SDL_bool Cocoa_Vulkan_CreateSurface(_THIS,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface);
void Cocoa_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h);
#endif
#endif /* SDL_cocoavulkan_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,244 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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 SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
#include "SDL_cocoawindow.h"
#include "SDL_assert.h"
#include "SDL_loadso.h"
#include "SDL_cocoametalview.h"
#include "SDL_cocoavulkan.h"
#include "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(_THIS, const char *path)
{
VkExtensionProperties *extensions = NULL;
Uint32 extensionCount = 0;
SDL_bool hasSurfaceExtension = 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_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 (!hasMacOSSurfaceExtension) {
SDL_SetError("Installed Vulkan Portability library doesn't implement the "
VK_MVK_MACOS_SURFACE_EXTENSION_NAME "extension");
goto fail;
}
return 0;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return -1;
}
void Cocoa_Vulkan_UnloadLibrary(_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(_THIS,
SDL_Window *window,
unsigned *count,
const char **names)
{
static const char *const extensionsForCocoa[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_MVK_MACOS_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);
}
SDL_bool Cocoa_Vulkan_CreateSurface(_THIS,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface)
{
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK =
(PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr(
(VkInstance)instance,
"vkCreateMacOSSurfaceMVK");
VkMacOSSurfaceCreateInfoMVK createInfo = {};
VkResult result;
SDL_MetalView metalview;
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
if (!vkCreateMacOSSurfaceMVK) {
SDL_SetError(VK_MVK_MACOS_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
return SDL_FALSE;
}
metalview = Cocoa_Metal_CreateView(_this, window);
if (metalview == NULL) {
return SDL_FALSE;
}
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;
}
void Cocoa_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
{
Cocoa_Metal_GetDrawableSize(window, w, h);
}
#endif
/* vim: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,156 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 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>
#if SDL_VIDEO_OPENGL_EGL
#include "../SDL_egl_c.h"
#endif
typedef struct SDL_WindowData SDL_WindowData;
typedef enum
{
PENDING_OPERATION_NONE,
PENDING_OPERATION_ENTER_FULLSCREEN,
PENDING_OPERATION_LEAVE_FULLSCREEN,
PENDING_OPERATION_MINIMIZE
} PendingWindowOperation;
@interface Cocoa_WindowListener : NSResponder <NSWindowDelegate> {
SDL_WindowData *_data;
BOOL observingVisible;
BOOL wasCtrlLeft;
BOOL wasVisible;
BOOL isFullscreenSpace;
BOOL inFullscreenTransition;
PendingWindowOperation pendingWindowOperation;
BOOL isMoving;
int pendingWindowWarpX, pendingWindowWarpY;
BOOL isDragAreaRunning;
}
-(void) listen:(SDL_WindowData *) data;
-(void) pauseVisibleObservation;
-(void) resumeVisibleObservation;
-(BOOL) setFullscreenSpace:(BOOL) state;
-(BOOL) isInFullscreenSpace;
-(BOOL) isInFullscreenSpaceTransition;
-(void) addPendingWindowOperation:(PendingWindowOperation) operation;
-(void) close;
-(BOOL) isMoving;
-(void) setPendingMoveX:(int)x Y:(int)y;
-(void) windowDidFinishMoving;
/* 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) 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;
struct SDL_WindowData
{
SDL_Window *window;
NSWindow *nswindow;
NSView *sdlContentView; /* nil if window is created via CreateWindowFrom */
NSMutableArray *nscontexts;
SDL_bool created;
SDL_bool inWindowFullscreenTransition;
Cocoa_WindowListener *listener;
struct SDL_VideoData *videodata;
#if SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
};
extern int Cocoa_CreateWindow(_THIS, SDL_Window * window);
extern int Cocoa_CreateWindowFrom(_THIS, SDL_Window * window,
const void *data);
extern void Cocoa_SetWindowTitle(_THIS, SDL_Window * window);
extern void Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon);
extern void Cocoa_SetWindowPosition(_THIS, SDL_Window * window);
extern void Cocoa_SetWindowSize(_THIS, SDL_Window * window);
extern void Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window);
extern void Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window);
extern int Cocoa_SetWindowOpacity(_THIS, SDL_Window * window, float opacity);
extern void Cocoa_ShowWindow(_THIS, SDL_Window * window);
extern void Cocoa_HideWindow(_THIS, SDL_Window * window);
extern void Cocoa_RaiseWindow(_THIS, SDL_Window * window);
extern void Cocoa_MaximizeWindow(_THIS, SDL_Window * window);
extern void Cocoa_MinimizeWindow(_THIS, SDL_Window * window);
extern void Cocoa_RestoreWindow(_THIS, SDL_Window * window);
extern void Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered);
extern void Cocoa_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable);
extern void Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
extern void Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window);
extern SDL_bool Cocoa_GetWindowWMInfo(_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);
#endif /* SDL_cocoawindow_h_ */
/* vi: set ts=4 sw=4 expandtab: */

2096
externals/SDL/src/video/cocoa/SDL_cocoawindow.m vendored Executable file

File diff suppressed because it is too large Load Diff